Merge change Idc447b41 into eclair
* changes: UI to manage/create custom Layout Devices.
This commit is contained in:
@@ -146,4 +146,58 @@ public final class TableHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a TreeColumn with the specified parameters. If a
|
||||
* <code>PreferenceStore</code> object and a preference entry name String
|
||||
* object are provided then the column will listen to change in its width
|
||||
* and update the preference store accordingly.
|
||||
*
|
||||
* @param parent The Table parent object
|
||||
* @param header The header string
|
||||
* @param style The column style
|
||||
* @param width the width of the column if the preference value is missing
|
||||
* @param pref_name The preference entry name for column width
|
||||
* @param prefs The preference store
|
||||
*/
|
||||
public static void createTreeColumn(Tree parent, String header, int style,
|
||||
int width, final String pref_name,
|
||||
final IPreferenceStore prefs) {
|
||||
|
||||
// create the column
|
||||
TreeColumn col = new TreeColumn(parent, style);
|
||||
|
||||
// if there is no pref store or the entry is missing, we use the sample
|
||||
// text and pack the column.
|
||||
// Otherwise we just read the width from the prefs and apply it.
|
||||
if (prefs == null || prefs.contains(pref_name) == false) {
|
||||
col.setWidth(width);
|
||||
|
||||
// init the prefs store with the current value
|
||||
if (prefs != null) {
|
||||
prefs.setValue(pref_name, width);
|
||||
}
|
||||
} else {
|
||||
col.setWidth(prefs.getInt(pref_name));
|
||||
}
|
||||
|
||||
// set the header
|
||||
col.setText(header);
|
||||
|
||||
// if there is a pref store and a pref entry name, then we setup a
|
||||
// listener to catch column resize to put store the new width value.
|
||||
if (prefs != null && pref_name != null) {
|
||||
col.addControlListener(new ControlListener() {
|
||||
public void controlMoved(ControlEvent e) {
|
||||
}
|
||||
|
||||
public void controlResized(ControlEvent e) {
|
||||
// get the new width
|
||||
int w = ((TreeColumn)e.widget).getWidth();
|
||||
|
||||
// store in pref store
|
||||
prefs.setValue(pref_name, w);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1029,10 +1029,7 @@ public class AdtPlugin extends AbstractUIPlugin {
|
||||
final IAndroidTarget[] targets = sdk.getTargets();
|
||||
final int n = targets.length;
|
||||
if (n > 0) {
|
||||
// load the layout devices.
|
||||
sdk.parseAddOnLayoutDevices();
|
||||
|
||||
// load the rest of the targes.
|
||||
// load the rest of the targets.
|
||||
// TODO: make this on-demand.
|
||||
int w = 60 / n;
|
||||
for (IAndroidTarget target : targets) {
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.ide.eclipse.adt.internal.editors.layout;
|
||||
import com.android.ide.eclipse.adt.AdtPlugin;
|
||||
import com.android.ide.eclipse.adt.internal.editors.layout.LayoutReloadMonitor.ILayoutReloadListener;
|
||||
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationComposite;
|
||||
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.LayoutCreatorDialog;
|
||||
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationComposite.IConfigListener;
|
||||
import com.android.ide.eclipse.adt.internal.editors.layout.parts.ElementCreateCommand;
|
||||
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode;
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.android.ide.eclipse.adt.internal.editors.IconFactory;
|
||||
import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditor.UiEditorActions;
|
||||
import com.android.ide.eclipse.adt.internal.editors.layout.LayoutReloadMonitor.ILayoutReloadListener;
|
||||
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationComposite;
|
||||
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.LayoutCreatorDialog;
|
||||
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationComposite.IConfigListener;
|
||||
import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
|
||||
import com.android.ide.eclipse.adt.internal.editors.layout.parts.ElementCreateCommand;
|
||||
|
||||
@@ -0,0 +1,295 @@
|
||||
package com.android.ide.eclipse.adt.internal.editors.layout.configuration;
|
||||
|
||||
import com.android.ide.eclipse.adt.internal.editors.IconFactory;
|
||||
import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration;
|
||||
import com.android.ide.eclipse.adt.internal.resources.configurations.LanguageQualifier;
|
||||
import com.android.ide.eclipse.adt.internal.resources.configurations.RegionQualifier;
|
||||
import com.android.ide.eclipse.adt.internal.resources.configurations.ResourceQualifier;
|
||||
import com.android.ide.eclipse.adt.internal.resources.configurations.VersionQualifier;
|
||||
import com.android.ide.eclipse.adt.internal.sdk.LayoutDevice;
|
||||
import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector;
|
||||
import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector.ConfigurationState;
|
||||
import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector.IQualifierFilter;
|
||||
import com.android.sdkuilib.ui.GridDialog;
|
||||
|
||||
import org.eclipse.jface.dialogs.Dialog;
|
||||
import org.eclipse.jface.dialogs.IDialogConstants;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.events.ModifyEvent;
|
||||
import org.eclipse.swt.events.ModifyListener;
|
||||
import org.eclipse.swt.events.VerifyEvent;
|
||||
import org.eclipse.swt.events.VerifyListener;
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Group;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Dialog to edit both a {@link LayoutDevice}, and a {@link FolderConfiguration} at the same time.
|
||||
*/
|
||||
public class ConfigEditDialog extends GridDialog {
|
||||
|
||||
private static final Pattern FLOAT_PATTERN = Pattern.compile("\\d*(\\.\\d?)?");
|
||||
|
||||
|
||||
private final FolderConfiguration mConfig = new FolderConfiguration();
|
||||
|
||||
private ConfigurationSelector mConfigSelector;
|
||||
private Composite mStatusComposite;
|
||||
private Label mStatusLabel;
|
||||
private Label mStatusImage;
|
||||
|
||||
private Image mError;
|
||||
|
||||
private String mDeviceName;
|
||||
private String mConfigName;
|
||||
private float mXDpi = 0f;
|
||||
private float mYDpi = 0f;
|
||||
|
||||
|
||||
public ConfigEditDialog(Shell parentShell, FolderConfiguration config) {
|
||||
super(parentShell, 1, false);
|
||||
mConfig.set(config);
|
||||
}
|
||||
|
||||
public void setDeviceName(String name) {
|
||||
mDeviceName = name;
|
||||
}
|
||||
|
||||
public String getDeviceName() {
|
||||
return mDeviceName;
|
||||
}
|
||||
|
||||
public void setXDpi(float xdpi) {
|
||||
mXDpi = xdpi;
|
||||
}
|
||||
|
||||
public float getXDpi() {
|
||||
return mXDpi;
|
||||
}
|
||||
|
||||
public void setYDpi(float ydpi) {
|
||||
mYDpi = ydpi;
|
||||
}
|
||||
|
||||
public float getYDpi() {
|
||||
return mYDpi;
|
||||
}
|
||||
|
||||
public void setConfigName(String name) {
|
||||
mConfigName = name;
|
||||
}
|
||||
|
||||
public String getConfigName() {
|
||||
return mConfigName;
|
||||
}
|
||||
|
||||
public void setConfig(FolderConfiguration config) {
|
||||
mConfig.set(config);
|
||||
}
|
||||
|
||||
public void getConfig(FolderConfiguration config) {
|
||||
config.set(mConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createDialogContent(Composite parent) {
|
||||
mError = IconFactory.getInstance().getIcon("error"); //$NON-NLS-1$
|
||||
|
||||
Group deviceGroup = new Group(parent, SWT.NONE);
|
||||
deviceGroup.setText("Device");
|
||||
deviceGroup.setLayoutData(new GridData(GridData.FILL_BOTH));
|
||||
deviceGroup.setLayout(new GridLayout(2, false));
|
||||
|
||||
Label l = new Label(deviceGroup, SWT.None);
|
||||
l.setText("Name");
|
||||
|
||||
final Text deviceNameText = new Text(deviceGroup, SWT.BORDER);
|
||||
deviceNameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||
if (mDeviceName != null) {
|
||||
deviceNameText.setText(mDeviceName);
|
||||
}
|
||||
deviceNameText.addModifyListener(new ModifyListener() {
|
||||
public void modifyText(ModifyEvent e) {
|
||||
mDeviceName = deviceNameText.getText().trim();
|
||||
validateOk();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
VerifyListener floatVerifier = new VerifyListener() {
|
||||
public void verifyText(VerifyEvent event) {
|
||||
// combine the current content and the new text
|
||||
String text = ((Text)event.widget).getText();
|
||||
text = text.substring(0, event.start) + event.text + text.substring(event.end);
|
||||
|
||||
// now make sure it's a match for the regex
|
||||
event.doit = FLOAT_PATTERN.matcher(text).matches();
|
||||
}
|
||||
};
|
||||
|
||||
l = new Label(deviceGroup, SWT.None);
|
||||
l.setText("x dpi");
|
||||
|
||||
final Text deviceXDpiText = new Text(deviceGroup, SWT.BORDER);
|
||||
deviceXDpiText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||
if (mXDpi != 0f) {
|
||||
deviceXDpiText.setText(String.format("%.1f", mXDpi)); //$NON-NLS-1$
|
||||
}
|
||||
deviceXDpiText.addVerifyListener(floatVerifier);
|
||||
deviceXDpiText.addModifyListener(new ModifyListener() {
|
||||
public void modifyText(ModifyEvent e) {
|
||||
mXDpi = Float.parseFloat(deviceXDpiText.getText());
|
||||
}
|
||||
});
|
||||
|
||||
l = new Label(deviceGroup, SWT.None);
|
||||
l.setText("y dpi");
|
||||
|
||||
final Text deviceYDpiText = new Text(deviceGroup, SWT.BORDER);
|
||||
deviceYDpiText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||
if (mYDpi != 0f) {
|
||||
deviceYDpiText.setText(String.format("%.1f", mYDpi)); //$NON-NLS-1$
|
||||
}
|
||||
deviceYDpiText.addVerifyListener(floatVerifier);
|
||||
deviceYDpiText.addModifyListener(new ModifyListener() {
|
||||
public void modifyText(ModifyEvent e) {
|
||||
mYDpi = Float.parseFloat(deviceYDpiText.getText());
|
||||
}
|
||||
});
|
||||
|
||||
Group configGroup = new Group(parent, SWT.NONE);
|
||||
configGroup.setText("Configuration");
|
||||
configGroup.setLayoutData(new GridData(GridData.FILL_BOTH));
|
||||
configGroup.setLayout(new GridLayout(2, false));
|
||||
|
||||
l = new Label(configGroup, SWT.None);
|
||||
l.setText("Name");
|
||||
|
||||
final Text configNameText = new Text(configGroup, SWT.BORDER);
|
||||
configNameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||
if (mConfigName != null) {
|
||||
configNameText.setText(mConfigName);
|
||||
}
|
||||
configNameText.addModifyListener(new ModifyListener() {
|
||||
public void modifyText(ModifyEvent e) {
|
||||
mConfigName = configNameText.getText().trim();
|
||||
validateOk();
|
||||
}
|
||||
});
|
||||
|
||||
mConfigSelector = new ConfigurationSelector(configGroup);
|
||||
// configure the selector to be in "device mode" and not accept language/region/version
|
||||
// since those are selected from a different combo
|
||||
// FIXME: add version combo.
|
||||
mConfigSelector.setDeviceMode(true);
|
||||
mConfigSelector.setQualifierFilter(new IQualifierFilter() {
|
||||
public boolean accept(ResourceQualifier qualifier) {
|
||||
if (qualifier instanceof LanguageQualifier ||
|
||||
qualifier instanceof RegionQualifier ||
|
||||
qualifier instanceof VersionQualifier) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
mConfigSelector.setConfiguration(mConfig);
|
||||
GridData gd;
|
||||
mConfigSelector.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
|
||||
gd.horizontalSpan = 2;
|
||||
gd.widthHint = ConfigurationSelector.WIDTH_HINT;
|
||||
gd.heightHint = ConfigurationSelector.HEIGHT_HINT;
|
||||
|
||||
// add a listener to check on the validity of the FolderConfiguration as
|
||||
// they are built.
|
||||
mConfigSelector.setOnChangeListener(new Runnable() {
|
||||
public void run() {
|
||||
if (mConfigSelector.getState() == ConfigurationState.OK) {
|
||||
mConfigSelector.getConfiguration(mConfig);
|
||||
}
|
||||
|
||||
validateOk();
|
||||
}
|
||||
});
|
||||
|
||||
mStatusComposite = new Composite(parent, SWT.NONE);
|
||||
mStatusComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||
GridLayout gl = new GridLayout(2, false);
|
||||
mStatusComposite.setLayout(gl);
|
||||
gl.marginHeight = gl.marginWidth = 0;
|
||||
|
||||
mStatusImage = new Label(mStatusComposite, SWT.NONE);
|
||||
mStatusLabel = new Label(mStatusComposite, SWT.NONE);
|
||||
mStatusLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||
resetStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Control createContents(Composite parent) {
|
||||
Control c = super.createContents(parent);
|
||||
validateOk();
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* resets the status label to show the file that will be created.
|
||||
*/
|
||||
private void resetStatus() {
|
||||
String displayString = Dialog.shortenText(
|
||||
String.format("Config: %1$s", mConfig.toString()),
|
||||
mStatusLabel);
|
||||
mStatusLabel.setText(displayString);
|
||||
}
|
||||
|
||||
private void setError(String text) {
|
||||
String displayString = Dialog.shortenText(text, mStatusLabel);
|
||||
mStatusLabel.setText(displayString);
|
||||
mStatusImage.setImage(mError);
|
||||
getButton(IDialogConstants.OK_ID).setEnabled(false);
|
||||
}
|
||||
|
||||
private void validateOk() {
|
||||
// check the device name
|
||||
if (mDeviceName == null || mDeviceName.length() == 0) {
|
||||
setError("Device name must not be empty");
|
||||
return;
|
||||
}
|
||||
|
||||
// check the config name
|
||||
if (mConfigName == null || mConfigName.length() == 0) {
|
||||
setError("Configuration name must not be empty");
|
||||
return;
|
||||
}
|
||||
|
||||
// and check the config itself
|
||||
ConfigurationState state = mConfigSelector.getState();
|
||||
|
||||
switch (state) {
|
||||
case INVALID_CONFIG:
|
||||
ResourceQualifier invalidQualifier = mConfigSelector.getInvalidQualifier();
|
||||
setError(String.format(
|
||||
"Invalid Configuration: %1$s has no filter set.",
|
||||
invalidQualifier.getName()));
|
||||
return;
|
||||
case REGION_WITHOUT_LANGUAGE:
|
||||
setError("The Region qualifier requires the Language qualifier.");
|
||||
return;
|
||||
}
|
||||
|
||||
// no error
|
||||
mStatusImage.setImage(null);
|
||||
resetStatus();
|
||||
getButton(IDialogConstants.OK_ID).setEnabled(true);
|
||||
|
||||
// need to relayout, because of the change in size in mErrorImage.
|
||||
mStatusComposite.layout();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,552 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Eclipse Public License, Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.eclipse.org/org/documents/epl-v10.php
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.ide.eclipse.adt.internal.editors.layout.configuration;
|
||||
|
||||
import com.android.ddmuilib.TableHelper;
|
||||
import com.android.ide.eclipse.adt.AdtPlugin;
|
||||
import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration;
|
||||
import com.android.ide.eclipse.adt.internal.sdk.LayoutDevice;
|
||||
import com.android.ide.eclipse.adt.internal.sdk.LayoutDeviceManager;
|
||||
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
|
||||
import com.android.sdkuilib.ui.GridDialog;
|
||||
|
||||
import org.eclipse.jface.dialogs.IDialogConstants;
|
||||
import org.eclipse.jface.viewers.ILabelProviderListener;
|
||||
import org.eclipse.jface.viewers.ISelectionChangedListener;
|
||||
import org.eclipse.jface.viewers.ITableLabelProvider;
|
||||
import org.eclipse.jface.viewers.ITreeContentProvider;
|
||||
import org.eclipse.jface.viewers.SelectionChangedEvent;
|
||||
import org.eclipse.jface.viewers.TreePath;
|
||||
import org.eclipse.jface.viewers.TreeSelection;
|
||||
import org.eclipse.jface.viewers.TreeViewer;
|
||||
import org.eclipse.jface.viewers.Viewer;
|
||||
import org.eclipse.jface.window.Window;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.events.SelectionAdapter;
|
||||
import org.eclipse.swt.events.SelectionEvent;
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.eclipse.swt.widgets.Tree;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* Dialog to view the layout devices with action button to create/edit/delete/copy layout devices
|
||||
* and configs.
|
||||
*
|
||||
*/
|
||||
public class ConfigManagerDialog extends GridDialog {
|
||||
|
||||
private final static String COL_NAME = AdtPlugin.PLUGIN_ID + ".configmanager.name"; //$NON-NLS-1$
|
||||
private final static String COL_CONFIG = AdtPlugin.PLUGIN_ID + ".configmanager.config"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* enum to represent the different origin of the layout devices.
|
||||
*/
|
||||
private static enum DeviceType {
|
||||
DEFAULT("Default"),
|
||||
ADDON("Add-on"),
|
||||
CUSTOM("Custom");
|
||||
|
||||
private final String mDisplay;
|
||||
|
||||
DeviceType(String display) {
|
||||
mDisplay = display;
|
||||
}
|
||||
|
||||
String getDisplayString() {
|
||||
return mDisplay;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* simple class representing the tree selection with the proper types.
|
||||
*/
|
||||
private static class DeviceSelection {
|
||||
public DeviceSelection(DeviceType type, LayoutDevice device,
|
||||
Entry<String, FolderConfiguration> entry) {
|
||||
this.type = type;
|
||||
this.device = device;
|
||||
this.entry = entry;
|
||||
}
|
||||
|
||||
final DeviceType type;
|
||||
final LayoutDevice device;
|
||||
final Entry<String, FolderConfiguration> entry;
|
||||
}
|
||||
|
||||
private final LayoutDeviceManager mManager;
|
||||
|
||||
private TreeViewer mTreeViewer;
|
||||
private Button mNewButton;
|
||||
private Button mEditButton;
|
||||
private Button mCopyButton;
|
||||
private Button mDeleteButton;
|
||||
|
||||
/**
|
||||
* Content provider of the {@link TreeViewer}. The expected input is
|
||||
* {@link LayoutDeviceManager}.
|
||||
*
|
||||
*/
|
||||
private final static class DeviceContentProvider implements ITreeContentProvider {
|
||||
private final static DeviceType[] sCategory = new DeviceType[] {
|
||||
DeviceType.DEFAULT, DeviceType.ADDON, DeviceType.CUSTOM
|
||||
};
|
||||
|
||||
private LayoutDeviceManager mLayoutDeviceManager;
|
||||
|
||||
public DeviceContentProvider() {
|
||||
}
|
||||
|
||||
public Object[] getElements(Object inputElement) {
|
||||
return sCategory;
|
||||
}
|
||||
|
||||
public Object[] getChildren(Object parentElement) {
|
||||
if (parentElement instanceof DeviceType) {
|
||||
if (DeviceType.DEFAULT.equals(parentElement)) {
|
||||
return mLayoutDeviceManager.getDefaultLayoutDevices().toArray();
|
||||
} else if (DeviceType.ADDON.equals(parentElement)) {
|
||||
return mLayoutDeviceManager.getAddOnLayoutDevice().toArray();
|
||||
} else if (DeviceType.CUSTOM.equals(parentElement)) {
|
||||
return mLayoutDeviceManager.getUserLayoutDevices().toArray();
|
||||
}
|
||||
} else if (parentElement instanceof LayoutDevice) {
|
||||
LayoutDevice device = (LayoutDevice)parentElement;
|
||||
return device.getConfigs().entrySet().toArray();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object getParent(Object element) {
|
||||
// parent cannot be computed. this is fine.
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean hasChildren(Object element) {
|
||||
if (element instanceof DeviceType) {
|
||||
if (DeviceType.DEFAULT.equals(element)) {
|
||||
return mLayoutDeviceManager.getDefaultLayoutDevices().size() > 0;
|
||||
} else if (DeviceType.ADDON.equals(element)) {
|
||||
return mLayoutDeviceManager.getAddOnLayoutDevice().size() > 0;
|
||||
} else if (DeviceType.CUSTOM.equals(element)) {
|
||||
return mLayoutDeviceManager.getUserLayoutDevices().size() > 0;
|
||||
}
|
||||
} else if (element instanceof LayoutDevice) {
|
||||
LayoutDevice device = (LayoutDevice)element;
|
||||
return device.getConfigs().size() > 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public void dispose() {
|
||||
// nothing to dispose
|
||||
}
|
||||
|
||||
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
|
||||
if (newInput instanceof LayoutDeviceManager) {
|
||||
mLayoutDeviceManager = (LayoutDeviceManager)newInput;
|
||||
return;
|
||||
}
|
||||
|
||||
// when the dialog closes we get null input
|
||||
if (newInput != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"ConfigContentProvider requires input to be LayoutDeviceManager");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Label provider for the {@link TreeViewer}.
|
||||
* Supported elements are {@link DeviceType}, {@link LayoutDevice}, and {@link Entry} (where
|
||||
* the key is a {@link String} object, and the value is a {@link FolderConfiguration} object).
|
||||
*
|
||||
*/
|
||||
private final static class DeviceLabelProvider implements ITableLabelProvider {
|
||||
|
||||
public String getColumnText(Object element, int columnIndex) {
|
||||
if (element instanceof DeviceType) {
|
||||
if (columnIndex == 0) {
|
||||
return ((DeviceType)element).getDisplayString();
|
||||
}
|
||||
} else if (element instanceof LayoutDevice) {
|
||||
if (columnIndex == 0) {
|
||||
return ((LayoutDevice)element).getName();
|
||||
}
|
||||
} else if (element instanceof Entry<?, ?>) {
|
||||
if (columnIndex == 0) {
|
||||
return (String)((Entry<?,?>)element).getKey();
|
||||
} else {
|
||||
return ((Entry<?,?>)element).getValue().toString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Image getColumnImage(Object element, int columnIndex) {
|
||||
// no image
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addListener(ILabelProviderListener listener) {
|
||||
// no listener
|
||||
}
|
||||
|
||||
public void removeListener(ILabelProviderListener listener) {
|
||||
// no listener
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
// nothing to dispose
|
||||
}
|
||||
|
||||
public boolean isLabelProperty(Object element, String property) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected ConfigManagerDialog(Shell parentShell) {
|
||||
super(parentShell, 2, false);
|
||||
mManager = Sdk.getCurrent().getLayoutDeviceManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getShellStyle() {
|
||||
return super.getShellStyle() | SWT.RESIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureShell(Shell newShell) {
|
||||
super.configureShell(newShell);
|
||||
newShell.setText("Device Configurations");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createDialogContent(final Composite parent) {
|
||||
GridData gd;
|
||||
GridLayout gl;
|
||||
|
||||
Tree tree = new Tree(parent, SWT.SINGLE | SWT.FULL_SELECTION);
|
||||
tree.setLayoutData(gd = new GridData(GridData.FILL_BOTH));
|
||||
gd.widthHint = 700;
|
||||
|
||||
tree.setHeaderVisible(true);
|
||||
tree.setLinesVisible(true);
|
||||
TableHelper.createTreeColumn(tree, "Name", SWT.LEFT, 150, COL_NAME,
|
||||
AdtPlugin.getDefault().getPreferenceStore());
|
||||
TableHelper.createTreeColumn(tree, "Configuration", SWT.LEFT, 500, COL_CONFIG,
|
||||
AdtPlugin.getDefault().getPreferenceStore());
|
||||
|
||||
mTreeViewer = new TreeViewer(tree);
|
||||
mTreeViewer.setContentProvider(new DeviceContentProvider());
|
||||
mTreeViewer.setLabelProvider(new DeviceLabelProvider());
|
||||
mTreeViewer.setAutoExpandLevel(TreeViewer.ALL_LEVELS);
|
||||
mTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
|
||||
public void selectionChanged(SelectionChangedEvent event) {
|
||||
setEnabled(getSelection());
|
||||
}
|
||||
});
|
||||
|
||||
Composite buttons = new Composite(parent, SWT.NONE);
|
||||
buttons.setLayoutData(new GridData(GridData.FILL_VERTICAL));
|
||||
buttons.setLayout(gl = new GridLayout());
|
||||
gl.marginHeight = gl.marginWidth = 0;
|
||||
|
||||
mNewButton = new Button(buttons, SWT.PUSH | SWT.FLAT);
|
||||
mNewButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||
mNewButton.setText("New...");
|
||||
mNewButton.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
DeviceSelection selection = getSelection();
|
||||
|
||||
ConfigEditDialog dlg = new ConfigEditDialog(parent.getShell(), null);
|
||||
if (selection.device != null) {
|
||||
dlg.setDeviceName(selection.device.getName());
|
||||
dlg.setXDpi(selection.device.getXDpi());
|
||||
dlg.setYDpi(selection.device.getYDpi());
|
||||
}
|
||||
if (selection.entry != null) {
|
||||
dlg.setConfigName(selection.entry.getKey());
|
||||
dlg.setConfig(selection.entry.getValue());
|
||||
}
|
||||
|
||||
if (dlg.open() == Window.OK) {
|
||||
String deviceName = dlg.getDeviceName();
|
||||
String configName = dlg.getConfigName();
|
||||
FolderConfiguration config = new FolderConfiguration();
|
||||
dlg.getConfig(config);
|
||||
|
||||
// first if there was no original device, we create one.
|
||||
// Because the new button is disabled when something else than "custom" is
|
||||
// selected, we always add to the user devices without checking.
|
||||
LayoutDevice d;
|
||||
if (selection.device == null) {
|
||||
// FIXME: this doesn't check if the device name is taken.
|
||||
d = mManager.addUserDevice(deviceName, dlg.getXDpi(), dlg.getYDpi());
|
||||
} else {
|
||||
// search for it.
|
||||
d = mManager.getUserLayoutDevice(deviceName);
|
||||
}
|
||||
|
||||
if (d != null) {
|
||||
// then if there was no config, we add it, otherwise we edit it
|
||||
// (same method that adds/replace a config).
|
||||
// FIXME this doesn't check if the name was already taken.
|
||||
mManager.addUserConfiguration(d, configName, config);
|
||||
|
||||
mTreeViewer.refresh();
|
||||
select(d, configName);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mEditButton = new Button(buttons, SWT.PUSH | SWT.FLAT);
|
||||
mEditButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||
mEditButton.setText("Edit...");
|
||||
mEditButton.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
DeviceSelection selection = getSelection();
|
||||
ConfigEditDialog dlg = new ConfigEditDialog(parent.getShell(), null);
|
||||
dlg.setDeviceName(selection.device.getName());
|
||||
dlg.setConfigName(selection.entry.getKey());
|
||||
dlg.setConfig(selection.entry.getValue());
|
||||
|
||||
if (dlg.open() == Window.OK) {
|
||||
String deviceName = dlg.getDeviceName();
|
||||
String configName = dlg.getConfigName();
|
||||
FolderConfiguration config = new FolderConfiguration();
|
||||
dlg.getConfig(config);
|
||||
|
||||
// replace the device if needed.
|
||||
// FIXME: this doesn't check if the replacement name doesn't exist already.
|
||||
LayoutDevice d = mManager.replaceUserDevice(selection.device, deviceName,
|
||||
dlg.getXDpi(), dlg.getYDpi());
|
||||
|
||||
// and add/replace the config
|
||||
mManager.replaceUserConfiguration(d, selection.entry.getKey(), configName,
|
||||
config);
|
||||
|
||||
mTreeViewer.refresh();
|
||||
select(d, configName);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mCopyButton = new Button(buttons, SWT.PUSH | SWT.FLAT);
|
||||
mCopyButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||
mCopyButton.setText("Copy");
|
||||
mCopyButton.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
DeviceSelection selection = getSelection();
|
||||
|
||||
// is the source a default/add-on device, or are we copying a full device?
|
||||
// if so the target device is a new device.
|
||||
LayoutDevice targetDevice = selection.device;
|
||||
if (selection.type == DeviceType.DEFAULT || selection.type == DeviceType.ADDON ||
|
||||
selection.entry == null) {
|
||||
// create a new device
|
||||
targetDevice = mManager.addUserDevice(
|
||||
selection.device.getName() + " Copy", // new name
|
||||
selection.device.getXDpi(),
|
||||
selection.device.getYDpi());
|
||||
}
|
||||
|
||||
String newConfigName = null; // name of the single new config. used for the select.
|
||||
|
||||
// are we copying the full device?
|
||||
if (selection.entry == null) {
|
||||
// get the config from the origin device
|
||||
Map<String, FolderConfiguration> configs = selection.device.getConfigs();
|
||||
|
||||
// and copy them in the target device
|
||||
for (Entry<String, FolderConfiguration> entry : configs.entrySet()) {
|
||||
// we need to make a copy of the config object, or it could be modified
|
||||
// in default/addon by editing the version in the new device.
|
||||
FolderConfiguration copy = new FolderConfiguration();
|
||||
copy.set(entry.getValue());
|
||||
|
||||
// the name can stay the same since we are copying a full device
|
||||
// and the target device has its own new name.
|
||||
mManager.addUserConfiguration(targetDevice, entry.getKey(), copy);
|
||||
}
|
||||
} else {
|
||||
// only copy the config. target device is not the same as the selection, don't
|
||||
// change the config name as we already changed the name of the device.
|
||||
newConfigName = (selection.device != targetDevice) ?
|
||||
selection.entry.getKey() : selection.entry.getKey() + " Copy";
|
||||
|
||||
// copy of the config
|
||||
FolderConfiguration copy = new FolderConfiguration();
|
||||
copy.set(selection.entry.getValue());
|
||||
|
||||
// and create the config
|
||||
mManager.addUserConfiguration(targetDevice, newConfigName, copy);
|
||||
}
|
||||
|
||||
mTreeViewer.refresh();
|
||||
|
||||
select(targetDevice, newConfigName);
|
||||
}
|
||||
});
|
||||
|
||||
mDeleteButton = new Button(buttons, SWT.PUSH | SWT.FLAT);
|
||||
mDeleteButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||
mDeleteButton.setText("Delete");
|
||||
mDeleteButton.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
DeviceSelection selection = getSelection();
|
||||
|
||||
if (selection.entry != null) {
|
||||
mManager.removeUserConfiguration(selection.device, selection.entry.getKey());
|
||||
} else if (selection.device != null) {
|
||||
mManager.removeUserDevice(selection.device);
|
||||
}
|
||||
|
||||
mTreeViewer.refresh();
|
||||
|
||||
// either select the device (if we removed a entry, or the top custom node if
|
||||
// we removed a device)
|
||||
select(selection.entry != null ? selection.device : null, null);
|
||||
}
|
||||
});
|
||||
|
||||
Label separator = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
|
||||
separator.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
|
||||
gd.horizontalSpan = 2;
|
||||
|
||||
mTreeViewer.setInput(mManager);
|
||||
setEnabled(null); // no selection at the start
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createButtonsForButtonBar(Composite parent) {
|
||||
// we only want an OK button.
|
||||
createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link DeviceSelection} object representing the selected path in the
|
||||
* {@link TreeViewer}
|
||||
*/
|
||||
private DeviceSelection getSelection() {
|
||||
// get the selection paths
|
||||
TreeSelection selection = (TreeSelection)mTreeViewer.getSelection();
|
||||
TreePath[] paths =selection.getPaths();
|
||||
|
||||
if (paths.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TreePath pathSelection = paths[0];
|
||||
|
||||
DeviceType type = (DeviceType)pathSelection.getFirstSegment();
|
||||
LayoutDevice device = null;
|
||||
Entry<String, FolderConfiguration> entry = null;
|
||||
switch (pathSelection.getSegmentCount()) {
|
||||
case 2: // layout device is selected
|
||||
device = (LayoutDevice)pathSelection.getLastSegment();
|
||||
break;
|
||||
case 3: // config is selected
|
||||
device = (LayoutDevice)pathSelection.getSegment(1);
|
||||
entry = (Entry<String, FolderConfiguration>)pathSelection.getLastSegment();
|
||||
}
|
||||
|
||||
return new DeviceSelection(type, device, entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables/disables the action button based on the {@link DeviceSelection}.
|
||||
* @param selection the selection
|
||||
*/
|
||||
protected void setEnabled(DeviceSelection selection) {
|
||||
if (selection == null) {
|
||||
mNewButton.setEnabled(false);
|
||||
mEditButton.setEnabled(false);
|
||||
mCopyButton.setEnabled(false);
|
||||
mDeleteButton.setEnabled(false);
|
||||
} else {
|
||||
switch (selection.type) {
|
||||
case DEFAULT:
|
||||
case ADDON:
|
||||
// only allow copy if device is not null
|
||||
mNewButton.setEnabled(false);
|
||||
mEditButton.setEnabled(false);
|
||||
mDeleteButton.setEnabled(false);
|
||||
mCopyButton.setEnabled(selection.device != null);
|
||||
break;
|
||||
case CUSTOM:
|
||||
mNewButton.setEnabled(true); // always true to create new devices.
|
||||
mEditButton.setEnabled(selection.entry != null); // only edit config for now
|
||||
|
||||
boolean enabled = selection.device != null; // need at least selected device
|
||||
mDeleteButton.setEnabled(enabled); // for delete and copy buttons
|
||||
mCopyButton.setEnabled(enabled);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects a device and optionally a config. Because this is meant to show newly created/edited
|
||||
* device/config, it'll only do so for {@link DeviceType#CUSTOM} devices.
|
||||
* @param device the device to select
|
||||
* @param configName the config to select (optional)
|
||||
*/
|
||||
private void select(LayoutDevice device, String configName) {
|
||||
Object[] path;
|
||||
if (device == null) {
|
||||
// select the "custom" node
|
||||
path = new Object[] { DeviceType.CUSTOM };
|
||||
} else if (configName == null) {
|
||||
// this is the easy case. no config to select
|
||||
path = new Object[] { DeviceType.CUSTOM, device };
|
||||
} else {
|
||||
// this is more complex. we have the configName, but the tree contains Entry<?,?>
|
||||
// Look for the entry.
|
||||
Entry<?, ?> match = null;
|
||||
for (Entry<?, ?> entry : device.getConfigs().entrySet()) {
|
||||
if (entry.getKey().equals(configName)) {
|
||||
match = entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match != null) {
|
||||
path = new Object[] { DeviceType.CUSTOM, device, match };
|
||||
} else {
|
||||
path = new Object[] { DeviceType.CUSTOM, device };
|
||||
}
|
||||
}
|
||||
|
||||
mTreeViewer.setSelection(new TreeSelection(new TreePath(path)), true /*reveal*/);
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,8 @@ import com.android.ide.eclipse.adt.internal.resources.configurations.VersionQual
|
||||
import com.android.ide.eclipse.adt.internal.resources.configurations.PixelDensityQualifier.Density;
|
||||
import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenOrientationQualifier.ScreenOrientation;
|
||||
import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources;
|
||||
import com.android.ide.eclipse.adt.internal.sdk.DeviceConfiguration;
|
||||
import com.android.ide.eclipse.adt.internal.sdk.LayoutDevice;
|
||||
import com.android.ide.eclipse.adt.internal.sdk.LayoutDeviceManager;
|
||||
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
|
||||
import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector.LanguageRegionVerifier;
|
||||
import com.android.layoutlib.api.IResourceValue;
|
||||
@@ -77,7 +78,7 @@ public class ConfigurationComposite extends Composite {
|
||||
/** The {@link FolderConfiguration} representing the state of the UI controls */
|
||||
private final FolderConfiguration mCurrentConfig = new FolderConfiguration();
|
||||
|
||||
private List<DeviceConfiguration> mDevices;
|
||||
private List<LayoutDevice> mDevices;
|
||||
|
||||
private final ArrayList<ResourceQualifier[] > mLocaleList =
|
||||
new ArrayList<ResourceQualifier[]>();
|
||||
@@ -86,7 +87,7 @@ public class ConfigurationComposite extends Composite {
|
||||
|
||||
private boolean mClipping = true;
|
||||
|
||||
private DeviceConfiguration mCurrentDevice;
|
||||
private LayoutDevice mCurrentDevice;
|
||||
|
||||
/**
|
||||
* Interface implemented by the part which owns a {@link ConfigurationComposite}.
|
||||
@@ -109,9 +110,6 @@ public class ConfigurationComposite extends Composite {
|
||||
public ConfigurationComposite(IConfigListener listener, Composite parent, int style) {
|
||||
super(parent, style);
|
||||
mListener = listener;
|
||||
if (Sdk.getCurrent() != null) {
|
||||
mDevices = Sdk.getCurrent().getLayoutDevices();
|
||||
}
|
||||
|
||||
GridLayout gl;
|
||||
GridData gd;
|
||||
@@ -512,15 +510,25 @@ public class ConfigurationComposite extends Composite {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the list of {@link DeviceConfiguration} from the {@link Sdk}.
|
||||
* Reloads the list of {@link LayoutDevice} from the {@link Sdk}.
|
||||
* @param notifyListener
|
||||
*/
|
||||
public void reloadDevices(boolean notifyListener) {
|
||||
mDevices = Sdk.getCurrent().getLayoutDevices();
|
||||
loadDevices();
|
||||
initUiWithDevices();
|
||||
onDeviceChange(notifyListener);
|
||||
}
|
||||
|
||||
private void loadDevices() {
|
||||
mDevices = null;
|
||||
|
||||
Sdk sdk = Sdk.getCurrent();
|
||||
if (sdk != null) {
|
||||
LayoutDeviceManager manager = sdk.getLayoutDeviceManager();
|
||||
mDevices = manager.getCombinedList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Init the UI with the list of Devices.
|
||||
*/
|
||||
@@ -531,7 +539,7 @@ public class ConfigurationComposite extends Composite {
|
||||
|
||||
// fill with the devices
|
||||
if (mDevices != null) {
|
||||
for (DeviceConfiguration device : mDevices) {
|
||||
for (LayoutDevice device : mDevices) {
|
||||
mDeviceList.add(device.getName());
|
||||
}
|
||||
mDeviceList.select(0);
|
||||
@@ -548,6 +556,9 @@ public class ConfigurationComposite extends Composite {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add the custom item
|
||||
mDeviceList.add("Custom...");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -575,6 +586,31 @@ public class ConfigurationComposite extends Composite {
|
||||
|
||||
int deviceIndex = mDeviceList.getSelectionIndex();
|
||||
if (deviceIndex != -1) {
|
||||
// check if the user is ask for the custom item
|
||||
if (deviceIndex == mDeviceList.getItemCount() - 1) {
|
||||
ConfigManagerDialog dialog = new ConfigManagerDialog(getShell());
|
||||
dialog.open();
|
||||
|
||||
// reload the combo with the new content.
|
||||
loadDevices();
|
||||
initUiWithDevices();
|
||||
|
||||
// at this point we need to reset the combo to something (hopefully) valid.
|
||||
// look for the previous selected device
|
||||
int index = mDevices.indexOf(mCurrentDevice);
|
||||
if (index != -1) {
|
||||
mDeviceList.select(index);
|
||||
} else {
|
||||
// we should at least have one built-in device, so we select it
|
||||
mDeviceList.select(0);
|
||||
}
|
||||
|
||||
// force a redraw
|
||||
onDeviceChange(true /*recomputeLayout*/);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
mCurrentDevice = mDevices.get(deviceIndex);
|
||||
} else {
|
||||
mCurrentDevice = null;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.ide.eclipse.adt.internal.editors.layout;
|
||||
package com.android.ide.eclipse.adt.internal.editors.layout.configuration;
|
||||
|
||||
import com.android.ide.eclipse.adt.internal.editors.IconFactory;
|
||||
import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration;
|
||||
@@ -23,21 +23,21 @@ import com.android.ide.eclipse.adt.internal.resources.manager.ResourceFolderType
|
||||
import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector;
|
||||
import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector.ConfigurationState;
|
||||
import com.android.sdklib.IAndroidTarget;
|
||||
import com.android.sdkuilib.ui.GridDialog;
|
||||
|
||||
import org.eclipse.jface.dialogs.Dialog;
|
||||
import org.eclipse.jface.dialogs.IDialogConstants;
|
||||
import org.eclipse.jface.dialogs.TrayDialog;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
|
||||
/**
|
||||
* Dialog to choose a non existing {@link FolderConfiguration}.
|
||||
*/
|
||||
class LayoutCreatorDialog extends TrayDialog {
|
||||
public final class LayoutCreatorDialog extends GridDialog {
|
||||
|
||||
private ConfigurationSelector mSelector;
|
||||
private Composite mStatusComposite;
|
||||
@@ -53,9 +53,9 @@ class LayoutCreatorDialog extends TrayDialog {
|
||||
* @param parentShell the parent {@link Shell}.
|
||||
* @param config The starting configuration.
|
||||
*/
|
||||
LayoutCreatorDialog(Shell parentShell, String fileName, IAndroidTarget target,
|
||||
public LayoutCreatorDialog(Shell parentShell, String fileName, IAndroidTarget target,
|
||||
FolderConfiguration config) {
|
||||
super(parentShell);
|
||||
super(parentShell, 1, false);
|
||||
|
||||
mFileName = fileName;
|
||||
mTarget = target;
|
||||
@@ -65,15 +65,11 @@ class LayoutCreatorDialog extends TrayDialog {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Control createDialogArea(Composite parent) {
|
||||
Composite top = new Composite(parent, SWT.NONE);
|
||||
top.setLayoutData(new GridData());
|
||||
top.setLayout(new GridLayout(1, false));
|
||||
|
||||
new Label(top, SWT.NONE).setText(
|
||||
public void createDialogContent(Composite parent) {
|
||||
new Label(parent, SWT.NONE).setText(
|
||||
String.format("Configuration for the alternate version of %1$s", mFileName));
|
||||
|
||||
mSelector = new ConfigurationSelector(top);
|
||||
mSelector = new ConfigurationSelector(parent);
|
||||
mSelector.setConfiguration(mConfig);
|
||||
|
||||
// parent's layout is a GridLayout as specified in the javadoc.
|
||||
@@ -117,7 +113,7 @@ class LayoutCreatorDialog extends TrayDialog {
|
||||
}
|
||||
});
|
||||
|
||||
mStatusComposite = new Composite(top, SWT.NONE);
|
||||
mStatusComposite = new Composite(parent, SWT.NONE);
|
||||
mStatusComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||
GridLayout gl = new GridLayout(2, false);
|
||||
mStatusComposite.setLayout(gl);
|
||||
@@ -127,8 +123,6 @@ class LayoutCreatorDialog extends TrayDialog {
|
||||
mStatusLabel = new Label(mStatusComposite, SWT.NONE);
|
||||
mStatusLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||
resetStatus();
|
||||
|
||||
return top;
|
||||
}
|
||||
|
||||
public void getConfiguration(FolderConfiguration config) {
|
||||
@@ -139,7 +133,9 @@ class LayoutCreatorDialog extends TrayDialog {
|
||||
* resets the status label to show the file that will be created.
|
||||
*/
|
||||
private void resetStatus() {
|
||||
mStatusLabel.setText(String.format("New File: res/%1$s/%2$s",
|
||||
mConfig.getFolderName(ResourceFolderType.LAYOUT, mTarget), mFileName));
|
||||
String displayString = Dialog.shortenText(String.format("New File: res/%1$s/%2$s",
|
||||
mConfig.getFolderName(ResourceFolderType.LAYOUT, mTarget), mFileName),
|
||||
mStatusLabel);
|
||||
mStatusLabel.setText(displayString);
|
||||
}
|
||||
}
|
||||
@@ -60,8 +60,10 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
|
||||
* @param config
|
||||
*/
|
||||
public void set(FolderConfiguration config) {
|
||||
for (int i = 0 ; i < INDEX_COUNT ; i++) {
|
||||
mQualifiers[i] = config.mQualifiers[i];
|
||||
if (config != null) {
|
||||
for (int i = 0 ; i < INDEX_COUNT ; i++) {
|
||||
mQualifiers[i] = config.mQualifiers[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,6 @@ public class AndroidTargetData {
|
||||
private LayoutBridge mLayoutBridge;
|
||||
|
||||
private boolean mLayoutBridgeInit = false;
|
||||
private DeviceConfiguration[] mDevices;
|
||||
|
||||
AndroidTargetData(IAndroidTarget androidTarget) {
|
||||
mTarget = androidTarget;
|
||||
@@ -114,7 +113,6 @@ public class AndroidTargetData {
|
||||
String[] intentCategoryValues,
|
||||
String[] platformLibraries,
|
||||
IOptionalLibrary[] optionalLibraries,
|
||||
DeviceConfiguration[] devices,
|
||||
ProjectResources resources,
|
||||
LayoutBridge layoutBridge) {
|
||||
|
||||
@@ -124,7 +122,6 @@ public class AndroidTargetData {
|
||||
mMenuDescriptors = menuDescriptors;
|
||||
mXmlDescriptors = xmlDescriptors;
|
||||
mEnumValueMap = enumValueMap;
|
||||
mDevices = devices;
|
||||
mFrameworkResources = resources;
|
||||
mLayoutBridge = layoutBridge;
|
||||
|
||||
@@ -276,10 +273,6 @@ public class AndroidTargetData {
|
||||
return mLayoutBridge;
|
||||
}
|
||||
|
||||
public DeviceConfiguration[] getDevices() {
|
||||
return mDevices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the permission values
|
||||
* @param permissionValues the list of permissions
|
||||
|
||||
@@ -254,9 +254,6 @@ public final class AndroidTargetParser {
|
||||
LayoutBridge layoutBridge = loadLayoutBridge();
|
||||
progress.worked(1);
|
||||
|
||||
// get the devices
|
||||
DeviceConfiguration[] devices = getDevices();
|
||||
|
||||
// and finally create the PlatformData with all that we loaded.
|
||||
targetData.setExtraData(frameworkRepository,
|
||||
manifestDescriptors,
|
||||
@@ -271,7 +268,6 @@ public final class AndroidTargetParser {
|
||||
categories.toArray(new String[categories.size()]),
|
||||
mAndroidTarget.getPlatformLibraries(),
|
||||
mAndroidTarget.getOptionalLibraries(),
|
||||
devices,
|
||||
resources,
|
||||
layoutBridge);
|
||||
|
||||
@@ -705,10 +701,4 @@ public final class AndroidTargetParser {
|
||||
|
||||
return layoutBridge;
|
||||
}
|
||||
|
||||
private DeviceConfiguration[] getDevices() {
|
||||
// TODO: load this from the target.
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Eclipse Public License, Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.eclipse.org/org/documents/epl-v10.php
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.ide.eclipse.adt.internal.sdk;
|
||||
|
||||
import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class DeviceConfiguration {
|
||||
|
||||
private final String mName;
|
||||
|
||||
private Map<String, FolderConfiguration> mMap =
|
||||
new HashMap<String, FolderConfiguration>();
|
||||
private float mXDpi = Float.NaN;
|
||||
private float mYDpi = Float.NaN;
|
||||
|
||||
DeviceConfiguration(String name) {
|
||||
mName = name;
|
||||
}
|
||||
|
||||
void addConfig(String name, FolderConfiguration config) {
|
||||
mMap.put(name, config);
|
||||
}
|
||||
|
||||
void seal() {
|
||||
mMap = Collections.unmodifiableMap(mMap);
|
||||
}
|
||||
|
||||
void setXDpi(float xdpi) {
|
||||
mXDpi = xdpi;
|
||||
}
|
||||
|
||||
void setYDpi(float ydpi) {
|
||||
mYDpi = ydpi;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
public Map<String, FolderConfiguration> getConfigs() {
|
||||
return mMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the dpi of the Device screen in X.
|
||||
* @return the dpi of screen or {@link Float#NaN} if it's not set.
|
||||
*/
|
||||
public float getXDpi() {
|
||||
return mXDpi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the dpi of the Device screen in Y.
|
||||
* @return the dpi of screen or {@link Float#NaN} if it's not set.
|
||||
*/
|
||||
public float getYDpi() {
|
||||
return mYDpi;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Eclipse Public License, Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.eclipse.org/org/documents/epl-v10.php
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.ide.eclipse.adt.internal.sdk;
|
||||
|
||||
import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Class representing a layout device.
|
||||
*
|
||||
* A Layout device is a collection of {@link FolderConfiguration} that can be used to render Android
|
||||
* layout files.
|
||||
*
|
||||
* It also contains a single xdpi/ydpi that is independent of the {@link FolderConfiguration}.
|
||||
*
|
||||
* If the device is meant to represent a true device, then most of the FolderConfigurations' content
|
||||
* should be identical, with only a few qualifiers (orientation, keyboard state) that would differ.
|
||||
* However it is simpler to reuse the FolderConfiguration class (with the non changing qualifiers
|
||||
* duplicated in each configuration) as it's what's being used by the rendering library.
|
||||
*
|
||||
* To create, edit and delete LayoutDevice objects, see {@link LayoutDeviceManager}.
|
||||
* The class is not technically immutable but behaves as such outside of its package.
|
||||
*/
|
||||
public class LayoutDevice {
|
||||
|
||||
private final String mName;
|
||||
|
||||
/** editable map of the config */
|
||||
private Map<String, FolderConfiguration> mEditMap = new HashMap<String, FolderConfiguration>();
|
||||
/** unmodifiable map returned by {@link #getConfigs()}. */
|
||||
private Map<String, FolderConfiguration> mMap;
|
||||
private float mXDpi = Float.NaN;
|
||||
private float mYDpi = Float.NaN;
|
||||
|
||||
LayoutDevice(String name) {
|
||||
mName = name;
|
||||
}
|
||||
|
||||
void addConfig(String name, FolderConfiguration config) {
|
||||
mEditMap.put(name, config);
|
||||
_seal();
|
||||
}
|
||||
|
||||
void addConfigs(Map<String, FolderConfiguration> configs) {
|
||||
mEditMap.putAll(configs);
|
||||
_seal();
|
||||
}
|
||||
|
||||
void removeConfig(String name) {
|
||||
mEditMap.remove(name);
|
||||
_seal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds config to the LayoutDevice. This is to be used to add plenty of configurations.
|
||||
* It must be followed by {@link #_seal()}.
|
||||
* @param name the name of the config
|
||||
* @param config the config.
|
||||
*/
|
||||
void _addConfig(String name, FolderConfiguration config) {
|
||||
mEditMap.put(name, config);
|
||||
}
|
||||
|
||||
void _seal() {
|
||||
mMap = Collections.unmodifiableMap(mEditMap);
|
||||
}
|
||||
|
||||
void setXDpi(float xdpi) {
|
||||
mXDpi = xdpi;
|
||||
}
|
||||
|
||||
void setYDpi(float ydpi) {
|
||||
mYDpi = ydpi;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
public Map<String, FolderConfiguration> getConfigs() {
|
||||
return mMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the dpi of the Device screen in X.
|
||||
* @return the dpi of screen or {@link Float#NaN} if it's not set.
|
||||
*/
|
||||
public float getXDpi() {
|
||||
return mXDpi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the dpi of the Device screen in Y.
|
||||
* @return the dpi of screen or {@link Float#NaN} if it's not set.
|
||||
*/
|
||||
public float getYDpi() {
|
||||
return mYDpi;
|
||||
}
|
||||
}
|
||||
@@ -58,16 +58,16 @@ class LayoutDeviceHandler extends DefaultHandler {
|
||||
* on the endElement, by using the content found in characters().
|
||||
*/
|
||||
|
||||
private List<DeviceConfiguration> mDevices = new ArrayList<DeviceConfiguration>();
|
||||
private List<LayoutDevice> mDevices = new ArrayList<LayoutDevice>();
|
||||
|
||||
private DeviceConfiguration mCurrentDevice;
|
||||
private LayoutDevice mCurrentDevice;
|
||||
private FolderConfiguration mDefaultConfig;
|
||||
private FolderConfiguration mCurrentConfig;
|
||||
private final StringBuilder mStringAccumulator = new StringBuilder();
|
||||
|
||||
private String mSize1, mSize2;
|
||||
|
||||
public List<DeviceConfiguration> getDevices() {
|
||||
public List<LayoutDevice> getDevices() {
|
||||
return mDevices;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ class LayoutDeviceHandler extends DefaultHandler {
|
||||
String deviceName = attributes.getValue("", LayoutConfigsXsd.ATTR_NAME);
|
||||
|
||||
// create a device and add it to the list
|
||||
mCurrentDevice = new DeviceConfiguration(deviceName);
|
||||
mCurrentDevice = new LayoutDevice(deviceName);
|
||||
mDevices.add(mCurrentDevice);
|
||||
} else if (LayoutConfigsXsd.NODE_DEFAULT.equals(localName)) {
|
||||
// create a new default config
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Eclipse Public License, Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.eclipse.org/org/documents/epl-v10.php
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.ide.eclipse.adt.internal.sdk;
|
||||
|
||||
import com.android.ide.eclipse.adt.AdtPlugin;
|
||||
import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration;
|
||||
import com.android.sdklib.SdkConstants;
|
||||
|
||||
import org.xml.sax.ErrorHandler;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import javax.xml.validation.Validator;
|
||||
|
||||
/**
|
||||
* Manages the layout devices.
|
||||
* They can come from 3 sources: built-in, add-ons, user.
|
||||
*/
|
||||
public class LayoutDeviceManager {
|
||||
|
||||
/**
|
||||
* A SAX error handler that captures the errors and warnings.
|
||||
* This allows us to capture *all* errors and just not get an exception on the first one.
|
||||
*/
|
||||
private static class CaptureErrorHandler implements ErrorHandler {
|
||||
|
||||
private final String mSourceLocation;
|
||||
|
||||
private boolean mFoundError = false;
|
||||
|
||||
CaptureErrorHandler(String sourceLocation) {
|
||||
mSourceLocation = sourceLocation;
|
||||
}
|
||||
|
||||
public boolean foundError() {
|
||||
return mFoundError;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws SAXException
|
||||
*/
|
||||
public void error(SAXParseException ex) throws SAXException {
|
||||
mFoundError = true;
|
||||
AdtPlugin.log(ex, "Error validating %1$s", mSourceLocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws SAXException
|
||||
*/
|
||||
public void fatalError(SAXParseException ex) throws SAXException {
|
||||
mFoundError = true;
|
||||
AdtPlugin.log(ex, "Error validating %1$s", mSourceLocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws SAXException
|
||||
*/
|
||||
public void warning(SAXParseException ex) throws SAXException {
|
||||
// ignore those for now.
|
||||
}
|
||||
}
|
||||
|
||||
private final SAXParserFactory mParserFactory;
|
||||
|
||||
private List<LayoutDevice> mDefaultLayoutDevices =
|
||||
new ArrayList<LayoutDevice>();
|
||||
private List<LayoutDevice> mAddOnLayoutDevices =
|
||||
new ArrayList<LayoutDevice>();
|
||||
private final List<LayoutDevice> mUserLayoutDevices =
|
||||
new ArrayList<LayoutDevice>();
|
||||
private List<LayoutDevice> mLayoutDevices;
|
||||
|
||||
LayoutDeviceManager() {
|
||||
mParserFactory = SAXParserFactory.newInstance();
|
||||
mParserFactory.setNamespaceAware(true);
|
||||
}
|
||||
|
||||
public List<LayoutDevice> getCombinedList() {
|
||||
return mLayoutDevices;
|
||||
}
|
||||
|
||||
public List<LayoutDevice> getDefaultLayoutDevices() {
|
||||
return mDefaultLayoutDevices;
|
||||
}
|
||||
|
||||
public List<LayoutDevice> getAddOnLayoutDevice() {
|
||||
return mAddOnLayoutDevices;
|
||||
}
|
||||
|
||||
public List<LayoutDevice> getUserLayoutDevices() {
|
||||
return mUserLayoutDevices;
|
||||
}
|
||||
|
||||
public LayoutDevice getUserLayoutDevice(String name) {
|
||||
for (LayoutDevice d : mUserLayoutDevices) {
|
||||
if (d.getName().equals(name)) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public LayoutDevice addUserDevice(String name, float xdpi, float ydpi) {
|
||||
LayoutDevice d = new LayoutDevice(name);
|
||||
d.setXDpi(xdpi);
|
||||
d.setYDpi(ydpi);
|
||||
mUserLayoutDevices.add(d);
|
||||
combineLayoutDevices();
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
public void removeUserDevice(LayoutDevice device) {
|
||||
if (mUserLayoutDevices.remove(device)) {
|
||||
combineLayoutDevices();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces a device with a new one with new name and/or x/y dpi, and return the new device.
|
||||
* If the name and dpi values are identical the given device is returned an nothing is done
|
||||
* @param device the {@link LayoutDevice} to replace
|
||||
* @param newName the new name.
|
||||
* @param newXDpi the new X dpi value
|
||||
* @param newYDpi the new Y dpi value.
|
||||
* @return the new LayoutDevice
|
||||
*/
|
||||
public LayoutDevice replaceUserDevice(LayoutDevice device, String newName,
|
||||
float newXDpi, float newYDpi) {
|
||||
if (device.getName().equals(newName) && device.getXDpi() == newXDpi &&
|
||||
device.getYDpi() == newYDpi) {
|
||||
return device;
|
||||
}
|
||||
|
||||
// else create a new device
|
||||
LayoutDevice newDevice = new LayoutDevice(newName);
|
||||
newDevice.setXDpi(newXDpi);
|
||||
newDevice.setYDpi(newYDpi);
|
||||
|
||||
// and get the Folderconfiguration
|
||||
Map<String, FolderConfiguration> configs = device.getConfigs();
|
||||
newDevice.addConfigs(configs);
|
||||
|
||||
// replace the old device with the new
|
||||
mUserLayoutDevices.remove(device);
|
||||
mUserLayoutDevices.add(newDevice);
|
||||
combineLayoutDevices();
|
||||
|
||||
return newDevice;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds or replaces a configuration in a given {@link LayoutDevice}.
|
||||
* @param device the device to modify
|
||||
* @param configName the configuration name to add or replace
|
||||
* @param config the configuration to set
|
||||
*/
|
||||
public void addUserConfiguration(LayoutDevice device, String configName,
|
||||
FolderConfiguration config) {
|
||||
// check that the device does belong to the user list.
|
||||
// the main goal is to make sure that this does not belong to the default/addon list.
|
||||
if (mUserLayoutDevices.contains(device)) {
|
||||
device.addConfig(configName, config);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces a configuration in a given {@link LayoutDevice}.
|
||||
* @param device the device to modify
|
||||
* @param oldConfigName the name of the config to replace. If null, the new config is simply
|
||||
* added.
|
||||
* @param newConfigName the configuration name to add or replace
|
||||
* @param config the configuration to set
|
||||
*/
|
||||
public void replaceUserConfiguration(LayoutDevice device, String oldConfigName,
|
||||
String newConfigName, FolderConfiguration config) {
|
||||
// check that the device does belong to the user list.
|
||||
// the main goal is to make sure that this does not belong to the default/addon list.
|
||||
if (mUserLayoutDevices.contains(device)) {
|
||||
// if the old and new config name are different, remove the old one
|
||||
if (oldConfigName != null && oldConfigName.equals(newConfigName) == false) {
|
||||
device.removeConfig(oldConfigName);
|
||||
}
|
||||
|
||||
// and then add the new one
|
||||
device.addConfig(newConfigName, config);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a configuration from a given user {@link LayoutDevice}
|
||||
* @param device the device to modify
|
||||
* @param configName the name of the config to remove
|
||||
*/
|
||||
public void removeUserConfiguration(LayoutDevice device, String configName) {
|
||||
// check that the device does belong to the user list.
|
||||
// the main goal is to make sure that this does not belong to the default/addon list.
|
||||
if (mUserLayoutDevices.contains(device)) {
|
||||
device.removeConfig(configName);
|
||||
}
|
||||
}
|
||||
|
||||
void load(String sdkOsLocation) {
|
||||
// load the default devices
|
||||
loadDefaultLayoutDevices(sdkOsLocation);
|
||||
|
||||
// load the user devices;
|
||||
}
|
||||
|
||||
void parseAddOnLayoutDevice(File deviceXml) {
|
||||
parseLayoutDevices(deviceXml, mAddOnLayoutDevices);
|
||||
}
|
||||
|
||||
void sealAddonLayoutDevices() {
|
||||
mAddOnLayoutDevices = Collections.unmodifiableList(mAddOnLayoutDevices);
|
||||
|
||||
combineLayoutDevices();
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the actual parsing of a devices.xml file.
|
||||
*/
|
||||
private void parseLayoutDevices(File deviceXml, List<LayoutDevice> list) {
|
||||
// first we validate the XML
|
||||
try {
|
||||
Source source = new StreamSource(new FileReader(deviceXml));
|
||||
|
||||
CaptureErrorHandler errorHandler = new CaptureErrorHandler(deviceXml.getAbsolutePath());
|
||||
|
||||
Validator validator = LayoutConfigsXsd.getValidator(errorHandler);
|
||||
validator.validate(source);
|
||||
|
||||
if (errorHandler.foundError() == false) {
|
||||
// do the actual parsing
|
||||
LayoutDeviceHandler handler = new LayoutDeviceHandler();
|
||||
|
||||
SAXParser parser = mParserFactory.newSAXParser();
|
||||
parser.parse(new InputSource(new FileInputStream(deviceXml)), handler);
|
||||
|
||||
// get the parsed devices
|
||||
list.addAll(handler.getDevices());
|
||||
}
|
||||
} catch (SAXException e) {
|
||||
AdtPlugin.log(e, "Error parsing %1$s", deviceXml.getAbsoluteFile());
|
||||
} catch (FileNotFoundException e) {
|
||||
// this shouldn't happen as we check above.
|
||||
} catch (IOException e) {
|
||||
AdtPlugin.log(e, "Error reading %1$s", deviceXml.getAbsoluteFile());
|
||||
} catch (ParserConfigurationException e) {
|
||||
AdtPlugin.log(e, "Error parsing %1$s", deviceXml.getAbsoluteFile());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates some built-it layout devices.
|
||||
*/
|
||||
private void loadDefaultLayoutDevices(String sdkOsLocation) {
|
||||
ArrayList<LayoutDevice> list = new ArrayList<LayoutDevice>();
|
||||
File toolsFolder = new File(sdkOsLocation, SdkConstants.OS_SDK_TOOLS_LIB_FOLDER);
|
||||
if (toolsFolder.isDirectory()) {
|
||||
File deviceXml = new File(toolsFolder, SdkConstants.FN_DEVICES_XML);
|
||||
if (deviceXml.isFile()) {
|
||||
parseLayoutDevices(deviceXml, list);
|
||||
}
|
||||
}
|
||||
mDefaultLayoutDevices = Collections.unmodifiableList(list);
|
||||
}
|
||||
|
||||
private void combineLayoutDevices() {
|
||||
ArrayList<LayoutDevice> list = new ArrayList<LayoutDevice>();
|
||||
list.addAll(mDefaultLayoutDevices);
|
||||
list.addAll(mAddOnLayoutDevices);
|
||||
list.addAll(mUserLayoutDevices);
|
||||
|
||||
mLayoutDevices = Collections.unmodifiableList(list);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -41,31 +41,15 @@ import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.jdt.core.IJavaProject;
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
import org.xml.sax.ErrorHandler;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import javax.xml.validation.Validator;
|
||||
|
||||
/**
|
||||
* Central point to load, manipulate and deal with the Android SDK. Only one SDK can be used
|
||||
* at the same time.
|
||||
@@ -89,7 +73,7 @@ public class Sdk implements IProjectListener {
|
||||
new HashMap<IProject, ApkSettings>();
|
||||
private final String mDocBaseUrl;
|
||||
|
||||
private List<DeviceConfiguration> mLayoutDevices = new ArrayList<DeviceConfiguration>();
|
||||
private final LayoutDeviceManager mLayoutDeviceManager = new LayoutDeviceManager();
|
||||
|
||||
/**
|
||||
* Classes implementing this interface will receive notification when targets are changed.
|
||||
@@ -439,6 +423,10 @@ public class Sdk implements IProjectListener {
|
||||
}
|
||||
}
|
||||
|
||||
public LayoutDeviceManager getLayoutDeviceManager() {
|
||||
return mLayoutDeviceManager;
|
||||
}
|
||||
|
||||
private Sdk(SdkManager manager, AvdManager avdManager) {
|
||||
mManager = manager;
|
||||
mAvdManager = avdManager;
|
||||
@@ -451,8 +439,10 @@ public class Sdk implements IProjectListener {
|
||||
mDocBaseUrl = getDocumentationBaseUrl(mManager.getLocation() +
|
||||
SdkConstants.OS_SDK_DOCS_FOLDER);
|
||||
|
||||
// load the built-in layout devices
|
||||
loadDefaultLayoutDevices();
|
||||
// load the built-in and user layout devices
|
||||
mLayoutDeviceManager.load(mManager.getLocation());
|
||||
// and the ones from the add-on
|
||||
loadLayoutDevices();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -505,6 +495,24 @@ public class Sdk implements IProjectListener {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the SDK add-ons to look for files called {@link SdkConstants#FN_DEVICES_XML} to
|
||||
* load {@link LayoutDevice} from them.
|
||||
*/
|
||||
private void loadLayoutDevices() {
|
||||
IAndroidTarget[] targets = mManager.getTargets();
|
||||
for (IAndroidTarget target : targets) {
|
||||
if (target.isPlatform() == false) {
|
||||
File deviceXml = new File(target.getLocation(), SdkConstants.FN_DEVICES_XML);
|
||||
if (deviceXml.isFile()) {
|
||||
mLayoutDeviceManager.parseAddOnLayoutDevice(deviceXml);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mLayoutDeviceManager.sealAddonLayoutDevices();
|
||||
}
|
||||
|
||||
public void projectClosed(IProject project) {
|
||||
// get the target project
|
||||
synchronized (AdtPlugin.getDefault().getSdkLockObject()) {
|
||||
@@ -539,128 +547,5 @@ public class Sdk implements IProjectListener {
|
||||
// ignore this. The project will be added to the map the first time the target needs
|
||||
// to be resolved.
|
||||
}
|
||||
|
||||
|
||||
// ---------- Device Configuration methods ----------
|
||||
|
||||
/**
|
||||
* A SAX error handler that captures the errors and warnings.
|
||||
* This allows us to capture *all* errors and just not get an exception on the first one.
|
||||
*/
|
||||
private static class CaptureErrorHandler implements ErrorHandler {
|
||||
|
||||
private final String mSourceLocation;
|
||||
|
||||
private boolean mFoundError = false;
|
||||
|
||||
CaptureErrorHandler(String sourceLocation) {
|
||||
mSourceLocation = sourceLocation;
|
||||
}
|
||||
|
||||
public boolean foundError() {
|
||||
return mFoundError;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws SAXException
|
||||
*/
|
||||
public void error(SAXParseException ex) throws SAXException {
|
||||
mFoundError = true;
|
||||
AdtPlugin.log(ex, "Error validating %1$s", mSourceLocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws SAXException
|
||||
*/
|
||||
public void fatalError(SAXParseException ex) throws SAXException {
|
||||
mFoundError = true;
|
||||
AdtPlugin.log(ex, "Error validating %1$s", mSourceLocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws SAXException
|
||||
*/
|
||||
public void warning(SAXParseException ex) throws SAXException {
|
||||
// ignore those for now.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of {@link DeviceConfiguration} found in the SDK.
|
||||
*/
|
||||
public List<DeviceConfiguration> getLayoutDevices() {
|
||||
return mLayoutDevices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the SDK add-ons to look for files called {@link SdkConstants#FN_DEVICES_XML} to
|
||||
* load {@link DeviceConfiguration} from them.
|
||||
*/
|
||||
public void parseAddOnLayoutDevices() {
|
||||
SAXParserFactory parserFactory = SAXParserFactory.newInstance();
|
||||
parserFactory.setNamespaceAware(true);
|
||||
|
||||
IAndroidTarget[] targets = mManager.getTargets();
|
||||
for (IAndroidTarget target : targets) {
|
||||
if (target.isPlatform() == false) {
|
||||
File deviceXml = new File(target.getLocation(), SdkConstants.FN_DEVICES_XML);
|
||||
if (deviceXml.isFile()) {
|
||||
parseLayoutDevices(parserFactory, deviceXml);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mLayoutDevices = Collections.unmodifiableList(mLayoutDevices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the actual parsing of a devices.xml file.
|
||||
*/
|
||||
private void parseLayoutDevices(SAXParserFactory parserFactory, File deviceXml) {
|
||||
// first we validate the XML
|
||||
try {
|
||||
Source source = new StreamSource(new FileReader(deviceXml));
|
||||
|
||||
CaptureErrorHandler errorHandler = new CaptureErrorHandler(deviceXml.getAbsolutePath());
|
||||
|
||||
Validator validator = LayoutConfigsXsd.getValidator(errorHandler);
|
||||
validator.validate(source);
|
||||
|
||||
if (errorHandler.foundError() == false) {
|
||||
// do the actual parsing
|
||||
LayoutDeviceHandler handler = new LayoutDeviceHandler();
|
||||
|
||||
SAXParser parser = parserFactory.newSAXParser();
|
||||
parser.parse(new InputSource(new FileInputStream(deviceXml)), handler);
|
||||
|
||||
// get the parsed devices
|
||||
mLayoutDevices.addAll(handler.getDevices());
|
||||
}
|
||||
} catch (SAXException e) {
|
||||
AdtPlugin.log(e, "Error parsing %1$s", deviceXml.getAbsoluteFile());
|
||||
} catch (FileNotFoundException e) {
|
||||
// this shouldn't happen as we check above.
|
||||
} catch (IOException e) {
|
||||
AdtPlugin.log(e, "Error reading %1$s", deviceXml.getAbsoluteFile());
|
||||
} catch (ParserConfigurationException e) {
|
||||
AdtPlugin.log(e, "Error parsing %1$s", deviceXml.getAbsoluteFile());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates some built-it layout devices.
|
||||
*/
|
||||
private void loadDefaultLayoutDevices() {
|
||||
SAXParserFactory parserFactory = SAXParserFactory.newInstance();
|
||||
parserFactory.setNamespaceAware(true);
|
||||
|
||||
File toolsFolder = new File(mManager.getLocation(), SdkConstants.OS_SDK_TOOLS_LIB_FOLDER);
|
||||
if (toolsFolder.isDirectory()) {
|
||||
File deviceXml = new File(toolsFolder, SdkConstants.FN_DEVICES_XML);
|
||||
if (deviceXml.isFile()) {
|
||||
parseLayoutDevices(parserFactory, deviceXml);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ import org.eclipse.swt.widgets.Table;
|
||||
import org.eclipse.swt.widgets.TableColumn;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
@@ -109,6 +110,8 @@ public class ConfigurationSelector extends Composite {
|
||||
private final HashMap<Class<? extends ResourceQualifier>, QualifierEditBase> mUiMap =
|
||||
new HashMap<Class<? extends ResourceQualifier>, QualifierEditBase>();
|
||||
private Composite mQualifierEditParent;
|
||||
private boolean mDeviceMode = false;
|
||||
private IQualifierFilter mQualifierFilter;
|
||||
|
||||
/**
|
||||
* Basic of {@link VerifyListener} to only accept digits.
|
||||
@@ -184,6 +187,17 @@ public class ConfigurationSelector extends Composite {
|
||||
OK, INVALID_CONFIG, REGION_WITHOUT_LANGUAGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* A filter for {@link ResourceQualifier}.
|
||||
* @see ConfigurationSelector#setQualifierFilter(IQualifierFilter)
|
||||
*/
|
||||
public interface IQualifierFilter {
|
||||
/**
|
||||
* Returns true of the qualifier is accepted.
|
||||
*/
|
||||
boolean accept(ResourceQualifier qualifier);
|
||||
}
|
||||
|
||||
public ConfigurationSelector(Composite parent) {
|
||||
super(parent, SWT.NONE);
|
||||
|
||||
@@ -374,6 +388,28 @@ public class ConfigurationSelector extends Composite {
|
||||
mUiMap.put(VersionQualifier.class, new VersionEdit(mQualifierEditParent));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the device mode. If <code>true</code> then the configuration selector only
|
||||
* allows to create configuration that are valid on a device (as opposed to resource
|
||||
* configuration).
|
||||
* For instance {@link Density#NODPI} is a valid qualifier for a resource configuration but
|
||||
* this is not valid on a device.
|
||||
* Default is false.
|
||||
* @param deviceMode the device mode.
|
||||
*/
|
||||
public void setDeviceMode(boolean deviceMode) {
|
||||
mDeviceMode = deviceMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a {@link IQualifierFilter}. If non null, this will restrict the qualifiers that
|
||||
* can be chosen.
|
||||
* @param filter the filter to set.
|
||||
*/
|
||||
public void setQualifierFilter(IQualifierFilter filter) {
|
||||
mQualifierFilter = filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a listener to be notified when the configuration changes.
|
||||
* @param listener A {@link Runnable} whose <code>run()</code> method is called when the
|
||||
@@ -492,7 +528,7 @@ public class ConfigurationSelector extends Composite {
|
||||
/**
|
||||
* Content provider around a {@link FolderConfiguration}.
|
||||
*/
|
||||
private static class QualifierContentProvider implements IStructuredContentProvider {
|
||||
private class QualifierContentProvider implements IStructuredContentProvider {
|
||||
|
||||
private FolderConfiguration mInput;
|
||||
|
||||
@@ -504,7 +540,20 @@ public class ConfigurationSelector extends Composite {
|
||||
}
|
||||
|
||||
public Object[] getElements(Object inputElement) {
|
||||
return mInput.getQualifiers();
|
||||
// default easy case
|
||||
if (mQualifierFilter == null) {
|
||||
return mInput.getQualifiers();
|
||||
}
|
||||
|
||||
// in this case we have to compute the list
|
||||
ArrayList<ResourceQualifier> list = new ArrayList<ResourceQualifier>();
|
||||
for (ResourceQualifier qual : mInput.getQualifiers()) {
|
||||
if (mQualifierFilter.accept(qual)) {
|
||||
list.add(qual);
|
||||
}
|
||||
}
|
||||
|
||||
return list.toArray();
|
||||
}
|
||||
|
||||
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
|
||||
@@ -1043,7 +1092,9 @@ public class ConfigurationSelector extends Composite {
|
||||
mDensity = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);
|
||||
Density[] soValues = Density.values();
|
||||
for (Density value : soValues) {
|
||||
mDensity.add(value.getDisplayValue());
|
||||
if (mDeviceMode == false || value != Density.NODPI) {
|
||||
mDensity.add(value.getDisplayValue());
|
||||
}
|
||||
}
|
||||
|
||||
mDensity.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||
@@ -1055,7 +1106,6 @@ public class ConfigurationSelector extends Composite {
|
||||
onDensityChange();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void onDensityChange() {
|
||||
|
||||
Reference in New Issue
Block a user