am e19c0298: Merge change Idc447b41 into eclair
Merge commit 'e19c02984fd10c9fa35b036aafc1181cb8384069' into eclair-mr2 * commit 'e19c02984fd10c9fa35b036aafc1181cb8384069': 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 IAndroidTarget[] targets = sdk.getTargets();
|
||||||
final int n = targets.length;
|
final int n = targets.length;
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
// load the layout devices.
|
// load the rest of the targets.
|
||||||
sdk.parseAddOnLayoutDevices();
|
|
||||||
|
|
||||||
// load the rest of the targes.
|
|
||||||
// TODO: make this on-demand.
|
// TODO: make this on-demand.
|
||||||
int w = 60 / n;
|
int w = 60 / n;
|
||||||
for (IAndroidTarget target : targets) {
|
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.AdtPlugin;
|
||||||
import com.android.ide.eclipse.adt.internal.editors.layout.LayoutReloadMonitor.ILayoutReloadListener;
|
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.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.configuration.ConfigurationComposite.IConfigListener;
|
||||||
import com.android.ide.eclipse.adt.internal.editors.layout.parts.ElementCreateCommand;
|
import com.android.ide.eclipse.adt.internal.editors.layout.parts.ElementCreateCommand;
|
||||||
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode;
|
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.LayoutEditor.UiEditorActions;
|
||||||
import com.android.ide.eclipse.adt.internal.editors.layout.LayoutReloadMonitor.ILayoutReloadListener;
|
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.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.configuration.ConfigurationComposite.IConfigListener;
|
||||||
import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
|
import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
|
||||||
import com.android.ide.eclipse.adt.internal.editors.layout.parts.ElementCreateCommand;
|
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.PixelDensityQualifier.Density;
|
||||||
import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenOrientationQualifier.ScreenOrientation;
|
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.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.sdk.Sdk;
|
||||||
import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector.LanguageRegionVerifier;
|
import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector.LanguageRegionVerifier;
|
||||||
import com.android.layoutlib.api.IResourceValue;
|
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 */
|
/** The {@link FolderConfiguration} representing the state of the UI controls */
|
||||||
private final FolderConfiguration mCurrentConfig = new FolderConfiguration();
|
private final FolderConfiguration mCurrentConfig = new FolderConfiguration();
|
||||||
|
|
||||||
private List<DeviceConfiguration> mDevices;
|
private List<LayoutDevice> mDevices;
|
||||||
|
|
||||||
private final ArrayList<ResourceQualifier[] > mLocaleList =
|
private final ArrayList<ResourceQualifier[] > mLocaleList =
|
||||||
new ArrayList<ResourceQualifier[]>();
|
new ArrayList<ResourceQualifier[]>();
|
||||||
@@ -86,7 +87,7 @@ public class ConfigurationComposite extends Composite {
|
|||||||
|
|
||||||
private boolean mClipping = true;
|
private boolean mClipping = true;
|
||||||
|
|
||||||
private DeviceConfiguration mCurrentDevice;
|
private LayoutDevice mCurrentDevice;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface implemented by the part which owns a {@link ConfigurationComposite}.
|
* 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) {
|
public ConfigurationComposite(IConfigListener listener, Composite parent, int style) {
|
||||||
super(parent, style);
|
super(parent, style);
|
||||||
mListener = listener;
|
mListener = listener;
|
||||||
if (Sdk.getCurrent() != null) {
|
|
||||||
mDevices = Sdk.getCurrent().getLayoutDevices();
|
|
||||||
}
|
|
||||||
|
|
||||||
GridLayout gl;
|
GridLayout gl;
|
||||||
GridData gd;
|
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
|
* @param notifyListener
|
||||||
*/
|
*/
|
||||||
public void reloadDevices(boolean notifyListener) {
|
public void reloadDevices(boolean notifyListener) {
|
||||||
mDevices = Sdk.getCurrent().getLayoutDevices();
|
loadDevices();
|
||||||
initUiWithDevices();
|
initUiWithDevices();
|
||||||
onDeviceChange(notifyListener);
|
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.
|
* Init the UI with the list of Devices.
|
||||||
*/
|
*/
|
||||||
@@ -531,7 +539,7 @@ public class ConfigurationComposite extends Composite {
|
|||||||
|
|
||||||
// fill with the devices
|
// fill with the devices
|
||||||
if (mDevices != null) {
|
if (mDevices != null) {
|
||||||
for (DeviceConfiguration device : mDevices) {
|
for (LayoutDevice device : mDevices) {
|
||||||
mDeviceList.add(device.getName());
|
mDeviceList.add(device.getName());
|
||||||
}
|
}
|
||||||
mDeviceList.select(0);
|
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();
|
int deviceIndex = mDeviceList.getSelectionIndex();
|
||||||
if (deviceIndex != -1) {
|
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);
|
mCurrentDevice = mDevices.get(deviceIndex);
|
||||||
} else {
|
} else {
|
||||||
mCurrentDevice = null;
|
mCurrentDevice = null;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* 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.editors.IconFactory;
|
||||||
import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration;
|
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;
|
||||||
import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector.ConfigurationState;
|
import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector.ConfigurationState;
|
||||||
import com.android.sdklib.IAndroidTarget;
|
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.IDialogConstants;
|
||||||
import org.eclipse.jface.dialogs.TrayDialog;
|
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.layout.GridData;
|
import org.eclipse.swt.layout.GridData;
|
||||||
import org.eclipse.swt.layout.GridLayout;
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
import org.eclipse.swt.widgets.Control;
|
|
||||||
import org.eclipse.swt.widgets.Label;
|
import org.eclipse.swt.widgets.Label;
|
||||||
import org.eclipse.swt.widgets.Shell;
|
import org.eclipse.swt.widgets.Shell;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dialog to choose a non existing {@link FolderConfiguration}.
|
* Dialog to choose a non existing {@link FolderConfiguration}.
|
||||||
*/
|
*/
|
||||||
class LayoutCreatorDialog extends TrayDialog {
|
public final class LayoutCreatorDialog extends GridDialog {
|
||||||
|
|
||||||
private ConfigurationSelector mSelector;
|
private ConfigurationSelector mSelector;
|
||||||
private Composite mStatusComposite;
|
private Composite mStatusComposite;
|
||||||
@@ -53,9 +53,9 @@ class LayoutCreatorDialog extends TrayDialog {
|
|||||||
* @param parentShell the parent {@link Shell}.
|
* @param parentShell the parent {@link Shell}.
|
||||||
* @param config The starting configuration.
|
* @param config The starting configuration.
|
||||||
*/
|
*/
|
||||||
LayoutCreatorDialog(Shell parentShell, String fileName, IAndroidTarget target,
|
public LayoutCreatorDialog(Shell parentShell, String fileName, IAndroidTarget target,
|
||||||
FolderConfiguration config) {
|
FolderConfiguration config) {
|
||||||
super(parentShell);
|
super(parentShell, 1, false);
|
||||||
|
|
||||||
mFileName = fileName;
|
mFileName = fileName;
|
||||||
mTarget = target;
|
mTarget = target;
|
||||||
@@ -65,15 +65,11 @@ class LayoutCreatorDialog extends TrayDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Control createDialogArea(Composite parent) {
|
public void createDialogContent(Composite parent) {
|
||||||
Composite top = new Composite(parent, SWT.NONE);
|
new Label(parent, SWT.NONE).setText(
|
||||||
top.setLayoutData(new GridData());
|
|
||||||
top.setLayout(new GridLayout(1, false));
|
|
||||||
|
|
||||||
new Label(top, SWT.NONE).setText(
|
|
||||||
String.format("Configuration for the alternate version of %1$s", mFileName));
|
String.format("Configuration for the alternate version of %1$s", mFileName));
|
||||||
|
|
||||||
mSelector = new ConfigurationSelector(top);
|
mSelector = new ConfigurationSelector(parent);
|
||||||
mSelector.setConfiguration(mConfig);
|
mSelector.setConfiguration(mConfig);
|
||||||
|
|
||||||
// parent's layout is a GridLayout as specified in the javadoc.
|
// 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));
|
mStatusComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||||
GridLayout gl = new GridLayout(2, false);
|
GridLayout gl = new GridLayout(2, false);
|
||||||
mStatusComposite.setLayout(gl);
|
mStatusComposite.setLayout(gl);
|
||||||
@@ -127,8 +123,6 @@ class LayoutCreatorDialog extends TrayDialog {
|
|||||||
mStatusLabel = new Label(mStatusComposite, SWT.NONE);
|
mStatusLabel = new Label(mStatusComposite, SWT.NONE);
|
||||||
mStatusLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
mStatusLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||||
resetStatus();
|
resetStatus();
|
||||||
|
|
||||||
return top;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getConfiguration(FolderConfiguration config) {
|
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.
|
* resets the status label to show the file that will be created.
|
||||||
*/
|
*/
|
||||||
private void resetStatus() {
|
private void resetStatus() {
|
||||||
mStatusLabel.setText(String.format("New File: res/%1$s/%2$s",
|
String displayString = Dialog.shortenText(String.format("New File: res/%1$s/%2$s",
|
||||||
mConfig.getFolderName(ResourceFolderType.LAYOUT, mTarget), mFileName));
|
mConfig.getFolderName(ResourceFolderType.LAYOUT, mTarget), mFileName),
|
||||||
|
mStatusLabel);
|
||||||
|
mStatusLabel.setText(displayString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,10 +60,12 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
|
|||||||
* @param config
|
* @param config
|
||||||
*/
|
*/
|
||||||
public void set(FolderConfiguration config) {
|
public void set(FolderConfiguration config) {
|
||||||
|
if (config != null) {
|
||||||
for (int i = 0 ; i < INDEX_COUNT ; i++) {
|
for (int i = 0 ; i < INDEX_COUNT ; i++) {
|
||||||
mQualifiers[i] = config.mQualifiers[i];
|
mQualifiers[i] = config.mQualifiers[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the qualifiers from the receiver if they are present (and valid)
|
* Removes the qualifiers from the receiver if they are present (and valid)
|
||||||
|
|||||||
@@ -86,7 +86,6 @@ public class AndroidTargetData {
|
|||||||
private LayoutBridge mLayoutBridge;
|
private LayoutBridge mLayoutBridge;
|
||||||
|
|
||||||
private boolean mLayoutBridgeInit = false;
|
private boolean mLayoutBridgeInit = false;
|
||||||
private DeviceConfiguration[] mDevices;
|
|
||||||
|
|
||||||
AndroidTargetData(IAndroidTarget androidTarget) {
|
AndroidTargetData(IAndroidTarget androidTarget) {
|
||||||
mTarget = androidTarget;
|
mTarget = androidTarget;
|
||||||
@@ -114,7 +113,6 @@ public class AndroidTargetData {
|
|||||||
String[] intentCategoryValues,
|
String[] intentCategoryValues,
|
||||||
String[] platformLibraries,
|
String[] platformLibraries,
|
||||||
IOptionalLibrary[] optionalLibraries,
|
IOptionalLibrary[] optionalLibraries,
|
||||||
DeviceConfiguration[] devices,
|
|
||||||
ProjectResources resources,
|
ProjectResources resources,
|
||||||
LayoutBridge layoutBridge) {
|
LayoutBridge layoutBridge) {
|
||||||
|
|
||||||
@@ -124,7 +122,6 @@ public class AndroidTargetData {
|
|||||||
mMenuDescriptors = menuDescriptors;
|
mMenuDescriptors = menuDescriptors;
|
||||||
mXmlDescriptors = xmlDescriptors;
|
mXmlDescriptors = xmlDescriptors;
|
||||||
mEnumValueMap = enumValueMap;
|
mEnumValueMap = enumValueMap;
|
||||||
mDevices = devices;
|
|
||||||
mFrameworkResources = resources;
|
mFrameworkResources = resources;
|
||||||
mLayoutBridge = layoutBridge;
|
mLayoutBridge = layoutBridge;
|
||||||
|
|
||||||
@@ -276,10 +273,6 @@ public class AndroidTargetData {
|
|||||||
return mLayoutBridge;
|
return mLayoutBridge;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeviceConfiguration[] getDevices() {
|
|
||||||
return mDevices;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the permission values
|
* Sets the permission values
|
||||||
* @param permissionValues the list of permissions
|
* @param permissionValues the list of permissions
|
||||||
|
|||||||
@@ -254,9 +254,6 @@ public final class AndroidTargetParser {
|
|||||||
LayoutBridge layoutBridge = loadLayoutBridge();
|
LayoutBridge layoutBridge = loadLayoutBridge();
|
||||||
progress.worked(1);
|
progress.worked(1);
|
||||||
|
|
||||||
// get the devices
|
|
||||||
DeviceConfiguration[] devices = getDevices();
|
|
||||||
|
|
||||||
// and finally create the PlatformData with all that we loaded.
|
// and finally create the PlatformData with all that we loaded.
|
||||||
targetData.setExtraData(frameworkRepository,
|
targetData.setExtraData(frameworkRepository,
|
||||||
manifestDescriptors,
|
manifestDescriptors,
|
||||||
@@ -271,7 +268,6 @@ public final class AndroidTargetParser {
|
|||||||
categories.toArray(new String[categories.size()]),
|
categories.toArray(new String[categories.size()]),
|
||||||
mAndroidTarget.getPlatformLibraries(),
|
mAndroidTarget.getPlatformLibraries(),
|
||||||
mAndroidTarget.getOptionalLibraries(),
|
mAndroidTarget.getOptionalLibraries(),
|
||||||
devices,
|
|
||||||
resources,
|
resources,
|
||||||
layoutBridge);
|
layoutBridge);
|
||||||
|
|
||||||
@@ -705,10 +701,4 @@ public final class AndroidTargetParser {
|
|||||||
|
|
||||||
return layoutBridge;
|
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().
|
* 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 mDefaultConfig;
|
||||||
private FolderConfiguration mCurrentConfig;
|
private FolderConfiguration mCurrentConfig;
|
||||||
private final StringBuilder mStringAccumulator = new StringBuilder();
|
private final StringBuilder mStringAccumulator = new StringBuilder();
|
||||||
|
|
||||||
private String mSize1, mSize2;
|
private String mSize1, mSize2;
|
||||||
|
|
||||||
public List<DeviceConfiguration> getDevices() {
|
public List<LayoutDevice> getDevices() {
|
||||||
return mDevices;
|
return mDevices;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ class LayoutDeviceHandler extends DefaultHandler {
|
|||||||
String deviceName = attributes.getValue("", LayoutConfigsXsd.ATTR_NAME);
|
String deviceName = attributes.getValue("", LayoutConfigsXsd.ATTR_NAME);
|
||||||
|
|
||||||
// create a device and add it to the list
|
// create a device and add it to the list
|
||||||
mCurrentDevice = new DeviceConfiguration(deviceName);
|
mCurrentDevice = new LayoutDevice(deviceName);
|
||||||
mDevices.add(mCurrentDevice);
|
mDevices.add(mCurrentDevice);
|
||||||
} else if (LayoutConfigsXsd.NODE_DEFAULT.equals(localName)) {
|
} else if (LayoutConfigsXsd.NODE_DEFAULT.equals(localName)) {
|
||||||
// create a new default config
|
// 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.core.runtime.IStatus;
|
||||||
import org.eclipse.jdt.core.IJavaProject;
|
import org.eclipse.jdt.core.IJavaProject;
|
||||||
import org.eclipse.jdt.core.JavaCore;
|
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.File;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
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
|
* Central point to load, manipulate and deal with the Android SDK. Only one SDK can be used
|
||||||
* at the same time.
|
* at the same time.
|
||||||
@@ -89,7 +73,7 @@ public class Sdk implements IProjectListener {
|
|||||||
new HashMap<IProject, ApkSettings>();
|
new HashMap<IProject, ApkSettings>();
|
||||||
private final String mDocBaseUrl;
|
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.
|
* 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) {
|
private Sdk(SdkManager manager, AvdManager avdManager) {
|
||||||
mManager = manager;
|
mManager = manager;
|
||||||
mAvdManager = avdManager;
|
mAvdManager = avdManager;
|
||||||
@@ -451,8 +439,10 @@ public class Sdk implements IProjectListener {
|
|||||||
mDocBaseUrl = getDocumentationBaseUrl(mManager.getLocation() +
|
mDocBaseUrl = getDocumentationBaseUrl(mManager.getLocation() +
|
||||||
SdkConstants.OS_SDK_DOCS_FOLDER);
|
SdkConstants.OS_SDK_DOCS_FOLDER);
|
||||||
|
|
||||||
// load the built-in layout devices
|
// load the built-in and user layout devices
|
||||||
loadDefaultLayoutDevices();
|
mLayoutDeviceManager.load(mManager.getLocation());
|
||||||
|
// and the ones from the add-on
|
||||||
|
loadLayoutDevices();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -505,6 +495,24 @@ public class Sdk implements IProjectListener {
|
|||||||
return null;
|
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) {
|
public void projectClosed(IProject project) {
|
||||||
// get the target project
|
// get the target project
|
||||||
synchronized (AdtPlugin.getDefault().getSdkLockObject()) {
|
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
|
// ignore this. The project will be added to the map the first time the target needs
|
||||||
// to be resolved.
|
// 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.TableColumn;
|
||||||
import org.eclipse.swt.widgets.Text;
|
import org.eclipse.swt.widgets.Text;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -109,6 +110,8 @@ public class ConfigurationSelector extends Composite {
|
|||||||
private final HashMap<Class<? extends ResourceQualifier>, QualifierEditBase> mUiMap =
|
private final HashMap<Class<? extends ResourceQualifier>, QualifierEditBase> mUiMap =
|
||||||
new HashMap<Class<? extends ResourceQualifier>, QualifierEditBase>();
|
new HashMap<Class<? extends ResourceQualifier>, QualifierEditBase>();
|
||||||
private Composite mQualifierEditParent;
|
private Composite mQualifierEditParent;
|
||||||
|
private boolean mDeviceMode = false;
|
||||||
|
private IQualifierFilter mQualifierFilter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basic of {@link VerifyListener} to only accept digits.
|
* Basic of {@link VerifyListener} to only accept digits.
|
||||||
@@ -184,6 +187,17 @@ public class ConfigurationSelector extends Composite {
|
|||||||
OK, INVALID_CONFIG, REGION_WITHOUT_LANGUAGE;
|
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) {
|
public ConfigurationSelector(Composite parent) {
|
||||||
super(parent, SWT.NONE);
|
super(parent, SWT.NONE);
|
||||||
|
|
||||||
@@ -374,6 +388,28 @@ public class ConfigurationSelector extends Composite {
|
|||||||
mUiMap.put(VersionQualifier.class, new VersionEdit(mQualifierEditParent));
|
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.
|
* Sets a listener to be notified when the configuration changes.
|
||||||
* @param listener A {@link Runnable} whose <code>run()</code> method is called when the
|
* @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}.
|
* Content provider around a {@link FolderConfiguration}.
|
||||||
*/
|
*/
|
||||||
private static class QualifierContentProvider implements IStructuredContentProvider {
|
private class QualifierContentProvider implements IStructuredContentProvider {
|
||||||
|
|
||||||
private FolderConfiguration mInput;
|
private FolderConfiguration mInput;
|
||||||
|
|
||||||
@@ -504,9 +540,22 @@ public class ConfigurationSelector extends Composite {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Object[] getElements(Object inputElement) {
|
public Object[] getElements(Object inputElement) {
|
||||||
|
// default easy case
|
||||||
|
if (mQualifierFilter == null) {
|
||||||
return mInput.getQualifiers();
|
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) {
|
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
|
||||||
mInput = null;
|
mInput = null;
|
||||||
if (newInput instanceof FolderConfiguration) {
|
if (newInput instanceof FolderConfiguration) {
|
||||||
@@ -1043,8 +1092,10 @@ public class ConfigurationSelector extends Composite {
|
|||||||
mDensity = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);
|
mDensity = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);
|
||||||
Density[] soValues = Density.values();
|
Density[] soValues = Density.values();
|
||||||
for (Density value : soValues) {
|
for (Density value : soValues) {
|
||||||
|
if (mDeviceMode == false || value != Density.NODPI) {
|
||||||
mDensity.add(value.getDisplayValue());
|
mDensity.add(value.getDisplayValue());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mDensity.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
mDensity.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||||
mDensity.addSelectionListener(new SelectionListener() {
|
mDensity.addSelectionListener(new SelectionListener() {
|
||||||
@@ -1055,7 +1106,6 @@ public class ConfigurationSelector extends Composite {
|
|||||||
onDensityChange();
|
onDensityChange();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDensityChange() {
|
private void onDensityChange() {
|
||||||
|
|||||||
Reference in New Issue
Block a user