diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-02 22:54:20 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-02 22:54:20 -0800 |
commit | 382f18c205f459fdd9ff6c0657beadcbfe3c5b01 (patch) | |
tree | cf087c09020d087526ef925668e044e39950bbf9 /sdkmanager | |
parent | 76bc028c745906e691284c685e34e72b5ccf06b5 (diff) | |
download | sdk-382f18c205f459fdd9ff6c0657beadcbfe3c5b01.zip sdk-382f18c205f459fdd9ff6c0657beadcbfe3c5b01.tar.gz sdk-382f18c205f459fdd9ff6c0657beadcbfe3c5b01.tar.bz2 |
auto import from //depot/cupcake/@137055
Diffstat (limited to 'sdkmanager')
10 files changed, 544 insertions, 55 deletions
diff --git a/sdkmanager/app/etc/android.bat b/sdkmanager/app/etc/android.bat index 1af1e47..de950ed 100755 --- a/sdkmanager/app/etc/android.bat +++ b/sdkmanager/app/etc/android.bat @@ -23,9 +23,9 @@ set prog=%~f0 rem Grab current directory before we change it set workdir=%cd% -rem Change current directory to where ddms is, to avoid issues with directories -rem containing whitespaces. -cd %~dp0 +rem Change current directory and drive to where the script is, to avoid +rem issues with directories containing whitespaces. +cd /d %~dp0 set jarfile=sdkmanager.jar set frameworkdir= diff --git a/sdkmanager/app/src/com/android/sdkmanager/Main.java b/sdkmanager/app/src/com/android/sdkmanager/Main.java index 1a15fce..154788e 100644 --- a/sdkmanager/app/src/com/android/sdkmanager/Main.java +++ b/sdkmanager/app/src/com/android/sdkmanager/Main.java @@ -383,24 +383,28 @@ class Main { */ private void displayAvdList() { try { - AvdManager avdManager = new AvdManager(mSdkManager, null /* sdklog */); + AvdManager avdManager = new AvdManager(mSdkManager, mSdkLog); mSdkLog.printf("Available Android Virtual Devices:\n"); - int index = 1; - for (AvdInfo info : avdManager.getAvds()) { - mSdkLog.printf("[%d] %s\n", index, info.getName()); - mSdkLog.printf(" Path: %s\n", info.getPath()); + AvdInfo[] avds = avdManager.getAvds(); + for (int index = 0 ; index < avds.length ; index++) { + AvdInfo info = avds[index]; + if (index > 0) { + mSdkLog.printf("---------\n"); + } + mSdkLog.printf(" Name: %s\n", info.getName()); + mSdkLog.printf(" Path: %s\n", info.getPath()); // get the target of the AVD IAndroidTarget target = info.getTarget(); if (target.isPlatform()) { - mSdkLog.printf(" Target: %s (API level %d)\n", target.getName(), + mSdkLog.printf(" Target: %s (API level %d)\n", target.getName(), target.getApiVersionNumber()); } else { - mSdkLog.printf(" Target: %s (%s)\n", target.getName(), target + mSdkLog.printf(" Target: %s (%s)\n", target.getName(), target .getVendor()); - mSdkLog.printf(" Based on Android %s (API level %d)\n", target + mSdkLog.printf(" Based on Android %s (API level %d)\n", target .getApiVersionName(), target.getApiVersionNumber()); } @@ -408,17 +412,15 @@ class Main { Map<String, String> properties = info.getProperties(); String skin = properties.get(AvdManager.AVD_INI_SKIN_NAME); if (skin != null) { - mSdkLog.printf(" Skin: %s\n", skin); + mSdkLog.printf(" Skin: %s\n", skin); } String sdcard = properties.get(AvdManager.AVD_INI_SDCARD_SIZE); if (sdcard == null) { sdcard = properties.get(AvdManager.AVD_INI_SDCARD_PATH); } if (sdcard != null) { - mSdkLog.printf(" Sdcard: %s\n", sdcard); + mSdkLog.printf(" Sdcard: %s\n", sdcard); } - - index++; } } catch (AndroidLocationException e) { errorAndExit(e.getMessage()); @@ -499,7 +501,7 @@ class Main { // Is it NNNxMMM? if (!valid) { - valid = skin.matches("[0-9]{2,}x[0-9]{2,}"); + valid = AvdManager.NUMERIC_SKIN_SIZE.matcher(skin).matches(); } if (!valid) { diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java index 87f9b56..00594d1 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java @@ -103,6 +103,8 @@ public final class SdkConstants { public final static String FD_ASSETS = "assets"; //$NON-NLS-1$ /** Default source folder name, i.e. "src" */ public final static String FD_SOURCES = "src"; //$NON-NLS-1$ + /** Default generated source folder name, i.e. "gen" */ + public final static String FD_GEN_SOURCES = "gen"; //$NON-NLS-1$ /** Default native library folder name inside the project, i.e. "libs" * While the folder inside the .apk is "lib", we call that one libs because * that's what we use in ant for both .jar and .so and we need to make the 2 development ways diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java index b44cf01..2c0f164 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java @@ -55,6 +55,12 @@ public final class AvdManager { public final static String AVD_INI_IMAGES_1 = "image.sysdir.1"; public final static String AVD_INI_IMAGES_2 = "image.sysdir.2"; + /** + * Pattern to match pixel-sized skin "names", e.g. "320x480". + */ + public final static Pattern NUMERIC_SKIN_SIZE = Pattern.compile("[0-9]{2,}x[0-9]{2,}"); + + private final static String USERDATA_IMG = "userdata.img"; private final static String CONFIG_INI = "config.ini"; private final static String SDCARD_IMG = "sdcard.img"; @@ -255,16 +261,21 @@ public final class AvdManager { skinName = target.getDefaultSkin(); } - // get the path of the skin (relative to the SDK) - // assume skin name is valid - String skinPath = getSkinRelativePath(skinName, target, log); - if (skinPath == null) { - needCleanup = true; - return null; - } + if (NUMERIC_SKIN_SIZE.matcher(skinName).matches()) { + // Skin name is an actual screen resolution, no skin.path + values.put(AVD_INI_SKIN_NAME, skinName); + } else { + // get the path of the skin (relative to the SDK) + // assume skin name is valid + String skinPath = getSkinRelativePath(skinName, target, log); + if (skinPath == null) { + needCleanup = true; + return null; + } - values.put(AVD_INI_SKIN_PATH, skinPath); - values.put(AVD_INI_SKIN_NAME, skinName); + values.put(AVD_INI_SKIN_PATH, skinPath); + values.put(AVD_INI_SKIN_NAME, skinName); + } if (sdcard != null) { File sdcardFile = new File(sdcard); diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ApkConfigurationHelper.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ApkConfigurationHelper.java index ab43f46..b89d3bd 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ApkConfigurationHelper.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ApkConfigurationHelper.java @@ -25,24 +25,30 @@ import java.util.Map.Entry; * Helper class to read and write Apk Configuration into a {@link ProjectProperties} file. */ public class ApkConfigurationHelper { + /** Prefix for property names for config definition. This prevents having config named + * after other valid properties such as "target". */ + final static String CONFIG_PREFIX = "apk-config-"; /** * Reads the Apk Configurations from a {@link ProjectProperties} file and returns them as a map. * <p/>If there are no defined configurations, the returned map will be empty. + * @return a map of apk configurations. The map contains (name, filter) where name is + * the name of the configuration (a-zA-Z0-9 only), and filter is the comma separated list of + * resource configuration to include in the apk (see aapt -c) */ public static Map<String, String> getConfigs(ProjectProperties properties) { HashMap<String, String> configMap = new HashMap<String, String>(); // get the list of configs. - String configList = properties.getProperty(ProjectProperties.PROPERTY_CONFIGS); + String configList = properties.getProperty(ProjectProperties.PROPERTY_APK_CONFIGS); if (configList != null) { // this is a comma separated list String[] configs = configList.split(","); //$NON-NLS-1$ // read the value of each config and store it in a map - for (String config : configs) { - String configValue = properties.getProperty(config); + config = config.trim(); + String configValue = properties.getProperty(CONFIG_PREFIX + config); if (configValue != null) { configMap.put(config, configValue); } @@ -54,6 +60,10 @@ public class ApkConfigurationHelper { /** * Writes the Apk Configurations from a given map into a {@link ProjectProperties}. + * @param properties the {@link ProjectProperties} in which to store the apk configurations. + * @param configMap a map of apk configurations. The map contains (name, filter) where name is + * the name of the configuration (a-zA-Z0-9 only), and filter is the comma separated list of + * resource configuration to include in the apk (see aapt -c) * @return true if the {@link ProjectProperties} contained Apk Configuration that were not * present in the map. */ @@ -62,17 +72,20 @@ public class ApkConfigurationHelper { // in case a config was removed. // get the list of configs. - String configList = properties.getProperty(ProjectProperties.PROPERTY_CONFIGS); - - // this is a comma separated list - String[] configs = configList.split(","); //$NON-NLS-1$ - + String configList = properties.getProperty(ProjectProperties.PROPERTY_APK_CONFIGS); + boolean hasRemovedConfig = false; - - for (String config : configs) { - if (configMap.containsKey(config) == false) { - hasRemovedConfig = true; - properties.removeProperty(config); + + if (configList != null) { + // this is a comma separated list + String[] configs = configList.split(","); //$NON-NLS-1$ + + for (String config : configs) { + config = config.trim(); + if (configMap.containsKey(config) == false) { + hasRemovedConfig = true; + properties.removeProperty(CONFIG_PREFIX + config); + } } } @@ -84,9 +97,9 @@ public class ApkConfigurationHelper { sb.append(","); } sb.append(entry.getKey()); - properties.setProperty(entry.getKey(), entry.getValue()); + properties.setProperty(CONFIG_PREFIX + entry.getKey(), entry.getValue()); } - properties.setProperty(ProjectProperties.PROPERTY_CONFIGS, sb.toString()); + properties.setProperty(ProjectProperties.PROPERTY_APK_CONFIGS, sb.toString()); return hasRemovedConfig; } diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectCreator.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectCreator.java index 18e2ac9..7489b65 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectCreator.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectCreator.java @@ -209,7 +209,7 @@ public class ProjectCreator { } // create the source folder and the java package folders. - final String srcFolderPath = SdkConstants.FD_SOURCES + File.separator + packagePath; + String srcFolderPath = SdkConstants.FD_SOURCES + File.separator + packagePath; File sourceFolder = createDirs(projectFolder, srcFolderPath); String javaTemplate = "java_file.template"; String activityFileName = activityName + ".java"; @@ -220,6 +220,10 @@ public class ProjectCreator { installTemplate(javaTemplate, new File(sourceFolder, activityFileName), keywords, target); + // create the generate source folder + srcFolderPath = SdkConstants.FD_GEN_SOURCES + File.separator + packagePath; + sourceFolder = createDirs(projectFolder, srcFolderPath); + // create other useful folders File resourceFodler = createDirs(projectFolder, SdkConstants.FD_RESOURCES); createDirs(projectFolder, SdkConstants.FD_OUTPUT); diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java index 1f6a047..69a16be 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java @@ -33,7 +33,7 @@ import java.util.Map.Entry; public final class ProjectProperties { /** The property name for the project target */ public final static String PROPERTY_TARGET = "target"; - public final static String PROPERTY_CONFIGS = "configs"; + public final static String PROPERTY_APK_CONFIGS = "apk-configurations"; public final static String PROPERTY_SDK = "sdk-location"; public static enum PropertyType { @@ -98,7 +98,19 @@ public final class ProjectProperties { // 1-------10--------20--------30--------40--------50--------60--------70--------80 COMMENT_MAP.put(PROPERTY_TARGET, "# Project target.\n"); - COMMENT_MAP.put(PROPERTY_SDK, "# location of the SDK. This is only used by Ant\n" + + COMMENT_MAP.put(PROPERTY_APK_CONFIGS, + "# apk configurations. This property allows creation of APK files with limited\n" + + "# resources. For example, if your application contains many locales and\n" + + "# you wish to release multiple smaller apks instead of a large one, you can\n" + + "# define configuration to create apks with limited language sets.\n" + + "# Format is a comma separated list of configuration names. For each\n" + + "# configuration, a property will declare the resource configurations to\n" + + "# include. Example:\n" + + "# " + PROPERTY_APK_CONFIGS +"=european,northamerica\n" + + "# " + ApkConfigurationHelper.CONFIG_PREFIX + "european=en,fr,it,de,es\n" + + "# " + ApkConfigurationHelper.CONFIG_PREFIX + "northamerica=en,es\n"); + COMMENT_MAP.put(PROPERTY_SDK, + "# location of the SDK. This is only used by Ant\n" + "# For customization when using a Version Control System, please read the\n" + "# header note.\n"); } diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/ApkConfigEditDialog.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/ApkConfigEditDialog.java new file mode 100644 index 0000000..1460fd7 --- /dev/null +++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/ApkConfigEditDialog.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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.sdkuilib; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.window.Window; +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.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.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +/** + * Edit dialog to create/edit APK configuration. The dialog displays 2 text fields for the config + * name and its filter. + */ +class ApkConfigEditDialog extends Dialog implements ModifyListener, VerifyListener { + + private String mName; + private String mFilter; + private Text mNameField; + private Text mFilterField; + private Button mOkButton; + + /** + * Creates an edit dialog with optional initial values for the name and filter. + * @param name optional value for the name. Can be null. + * @param filter optional value for the filter. Can be null. + * @param parentShell the parent shell. + */ + protected ApkConfigEditDialog(String name, String filter, Shell parentShell) { + super(parentShell); + mName = name; + mFilter = filter; + } + + /** + * Returns the name of the config. This is only valid if the user clicked OK and {@link #open()} + * returned {@link Window#OK} + */ + public String getName() { + return mName; + } + + /** + * Returns the filter for the config. This is only valid if the user clicked OK and + * {@link #open()} returned {@link Window#OK} + */ + public String getFilter() { + return mFilter; + } + + @Override + protected Control createContents(Composite parent) { + Control control = super.createContents(parent); + + mOkButton = getButton(IDialogConstants.OK_ID); + validateButtons(); + + return control; + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite composite = new Composite(parent, SWT.NONE); + GridLayout layout; + composite.setLayout(layout = new GridLayout(2, false)); + layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN); + layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN); + layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING); + layout.horizontalSpacing = convertHorizontalDLUsToPixels( + IDialogConstants.HORIZONTAL_SPACING); + + composite.setLayoutData(new GridData(GridData.FILL_BOTH)); + + Label l = new Label(composite, SWT.NONE); + l.setText("Name"); + + mNameField = new Text(composite, SWT.BORDER); + mNameField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + mNameField.addVerifyListener(this); + if (mName != null) { + mNameField.setText(mName); + } + mNameField.addModifyListener(this); + + l = new Label(composite, SWT.NONE); + l.setText("Filter"); + + mFilterField = new Text(composite, SWT.BORDER); + mFilterField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + if (mFilter != null) { + mFilterField.setText(mFilter); + } + mFilterField.addVerifyListener(this); + mFilterField.addModifyListener(this); + + applyDialogFont(composite); + return composite; + } + + /** + * Validates the OK button based on the content of the 2 text fields. + */ + private void validateButtons() { + mOkButton.setEnabled(mNameField.getText().trim().length() > 0 && + mFilterField.getText().trim().length() > 0); + } + + @Override + protected void okPressed() { + mName = mNameField.getText(); + mFilter = mFilterField.getText().trim(); + super.okPressed(); + } + + /** + * Callback for text modification in the 2 text fields. + */ + public void modifyText(ModifyEvent e) { + validateButtons(); + } + + /** + * Callback to ensure the content of the text field are proper. + */ + public void verifyText(VerifyEvent e) { + Text source = ((Text)e.getSource()); + if (source == mNameField) { + // check for a-zA-Z0-9. + final String text = e.text; + final int len = text.length(); + for (int i = 0 ; i < len; i++) { + char letter = text.charAt(i); + if (letter > 255 || Character.isLetterOrDigit(letter) == false) { + e.doit = false; + return; + } + } + } else if (source == mFilterField) { + // we can't validate the content as its typed, but we can at least ensure the characters + // are valid. Same as mNameFiled + the comma. + final String text = e.text; + final int len = text.length(); + for (int i = 0 ; i < len; i++) { + char letter = text.charAt(i); + if (letter > 255 || (Character.isLetterOrDigit(letter) == false && letter != ',')) { + e.doit = false; + return; + } + } + } + } +} diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/ApkConfigWidget.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/ApkConfigWidget.java new file mode 100644 index 0000000..6bf1df3 --- /dev/null +++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/ApkConfigWidget.java @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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.sdkuilib; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlAdapter; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Rectangle; +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.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * The APK Configuration widget is a table that is added to the given parent composite. + * <p/> + * To use, create it using {@link #ApkConfigWidget(Composite)} then + * call {@link #fillTable(Map) to set the initial list of configurations. + */ +public class ApkConfigWidget { + private final static int INDEX_NAME = 0; + private final static int INDEX_FILTER = 1; + + private Table mApkConfigTable; + private Button mEditButton; + private Button mDelButton; + + public ApkConfigWidget(final Composite parent) { + final Composite apkConfigComp = new Composite(parent, SWT.NONE); + apkConfigComp.setLayoutData(new GridData(GridData.FILL_BOTH)); + apkConfigComp.setLayout(new GridLayout(2, false)); + + mApkConfigTable = new Table(apkConfigComp, SWT.FULL_SELECTION | SWT.SINGLE | SWT.BORDER); + mApkConfigTable.setHeaderVisible(true); + mApkConfigTable.setLinesVisible(true); + + GridData data = new GridData(); + data.grabExcessVerticalSpace = true; + data.grabExcessHorizontalSpace = true; + data.horizontalAlignment = GridData.FILL; + data.verticalAlignment = GridData.FILL; + mApkConfigTable.setLayoutData(data); + + // create the table columns + final TableColumn column0 = new TableColumn(mApkConfigTable, SWT.NONE); + column0.setText("Name"); + column0.setWidth(100); + final TableColumn column1 = new TableColumn(mApkConfigTable, SWT.NONE); + column1.setText("Configuration"); + column1.setWidth(100); + + Composite buttonComp = new Composite(apkConfigComp, SWT.NONE); + buttonComp.setLayoutData(new GridData(GridData.FILL_VERTICAL)); + GridLayout gl; + buttonComp.setLayout(gl = new GridLayout(1, false)); + gl.marginHeight = gl.marginWidth = 0; + + Button newButton = new Button(buttonComp, SWT.PUSH | SWT.FLAT); + newButton.setText("New..."); + newButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + mEditButton = new Button(buttonComp, SWT.PUSH | SWT.FLAT); + mEditButton.setText("Edit..."); + mEditButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + mDelButton = new Button(buttonComp, SWT.PUSH | SWT.FLAT); + mDelButton.setText("Delete"); + mDelButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + newButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + ApkConfigEditDialog dlg = new ApkConfigEditDialog(null /*name*/, null /*filter*/, + apkConfigComp.getShell()); + if (dlg.open() == Dialog.OK) { + TableItem item = new TableItem(mApkConfigTable, SWT.NONE); + item.setText(INDEX_NAME, dlg.getName()); + item.setText(INDEX_FILTER, dlg.getFilter()); + + onSelectionChanged(); + } + } + }); + + mEditButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + // get the current selection (single mode so we don't care about any item beyond + // index 0). + TableItem[] items = mApkConfigTable.getSelection(); + if (items.length != 0) { + ApkConfigEditDialog dlg = new ApkConfigEditDialog( + items[0].getText(INDEX_NAME), items[0].getText(INDEX_FILTER), + apkConfigComp.getShell()); + if (dlg.open() == Dialog.OK) { + items[0].setText(INDEX_NAME, dlg.getName()); + items[0].setText(INDEX_FILTER, dlg.getFilter()); + } + } + } + }); + + mDelButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + // get the current selection (single mode so we don't care about any item beyond + // index 0). + int[] indices = mApkConfigTable.getSelectionIndices(); + if (indices.length != 0) { + TableItem item = mApkConfigTable.getItem(indices[0]); + if (MessageDialog.openQuestion(parent.getShell(), + "Apk Configuration deletion", + String.format( + "Are you sure you want to delete configuration '%1$s'?", + item.getText(INDEX_NAME)))) { + // delete the item. + mApkConfigTable.remove(indices[0]); + + onSelectionChanged(); + } + } + } + }); + + // Add a listener to resize the column to the full width of the table + mApkConfigTable.addControlListener(new ControlAdapter() { + @Override + public void controlResized(ControlEvent e) { + Rectangle r = mApkConfigTable.getClientArea(); + column0.setWidth(r.width * 30 / 100); // 30% + column1.setWidth(r.width * 70 / 100); // 70% + } + }); + + // add a selection listener on the table, to enable/disable buttons. + mApkConfigTable.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + onSelectionChanged(); + } + }); + } + + public void fillTable(Map<String, String> apkConfigMap) { + // get the names in a list so that we can sort them. + if (apkConfigMap != null) { + Set<String> keys = apkConfigMap.keySet(); + String[] keyArray = keys.toArray(new String[keys.size()]); + Arrays.sort(keyArray); + + for (String key : keyArray) { + TableItem item = new TableItem(mApkConfigTable, SWT.NONE); + item.setText(INDEX_NAME, key); + item.setText(INDEX_FILTER, apkConfigMap.get(key)); + } + } + + onSelectionChanged(); + } + + public Map<String, String> getApkConfigs() { + // go through all the items from the table and fill a new map + HashMap<String, String> map = new HashMap<String, String>(); + + TableItem[] items = mApkConfigTable.getItems(); + for (TableItem item : items) { + map.put(item.getText(INDEX_NAME), item.getText(INDEX_FILTER)); + } + + return map; + } + + /** + * Handles table selection changes. + */ + private void onSelectionChanged() { + if (mApkConfigTable.getSelectionCount() > 0) { + mEditButton.setEnabled(true); + mDelButton.setEnabled(true); + } else { + mEditButton.setEnabled(false); + mDelButton.setEnabled(false); + } + } +} diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/SdkTargetSelector.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/SdkTargetSelector.java index fc951f2..5f9e9c2 100644 --- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/SdkTargetSelector.java +++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/SdkTargetSelector.java @@ -48,32 +48,57 @@ import java.util.ArrayList; */ public class SdkTargetSelector { - private final IAndroidTarget[] mTargets; + private IAndroidTarget[] mTargets; + private final boolean mAllowSelection; private final boolean mAllowMultipleSelection; private SelectionListener mSelectionListener; private Table mTable; private Label mDescription; - + private Composite mInnerGroup; + /** * Creates a new SDK Target Selector. * * @param parent The parent composite where the selector will be added. * @param targets The list of targets. This is <em>not</em> copied, the caller must not modify. + * Targets can be null or an empty array, in which case the table is disabled. * @param allowMultipleSelection True if more than one SDK target can be selected at the same * time. */ public SdkTargetSelector(Composite parent, IAndroidTarget[] targets, boolean allowMultipleSelection) { - mTargets = targets; + this(parent, targets, true /*allowSelection*/, allowMultipleSelection); + } + /** + * Creates a new SDK Target Selector. + * + * @param parent The parent composite where the selector will be added. + * @param targets The list of targets. This is <em>not</em> copied, the caller must not modify. + * Targets can be null or an empty array, in which case the table is disabled. + * @param allowSelection True if selection is enabled. + * @param allowMultipleSelection True if more than one SDK target can be selected at the same + * time. Used only if allowSelection is true. + */ + public SdkTargetSelector(Composite parent, IAndroidTarget[] targets, + boolean allowSelection, + boolean allowMultipleSelection) { // Layout has 1 column - Composite group = new Composite(parent, SWT.NONE); - group.setLayout(new GridLayout()); - group.setLayoutData(new GridData(GridData.FILL_BOTH)); - group.setFont(parent.getFont()); + mInnerGroup = new Composite(parent, SWT.NONE); + mInnerGroup.setLayout(new GridLayout()); + mInnerGroup.setLayoutData(new GridData(GridData.FILL_BOTH)); + mInnerGroup.setFont(parent.getFont()); + mAllowSelection = allowSelection; mAllowMultipleSelection = allowMultipleSelection; - mTable = new Table(group, SWT.CHECK | SWT.FULL_SELECTION | SWT.SINGLE | SWT.BORDER); + int style = SWT.BORDER; + if (allowSelection) { + style |= SWT.CHECK | SWT.FULL_SELECTION; + } + if (!mAllowMultipleSelection) { + style |= SWT.SINGLE; + } + mTable = new Table(mInnerGroup, style); mTable.setHeaderVisible(true); mTable.setLinesVisible(false); @@ -84,7 +109,7 @@ public class SdkTargetSelector { data.verticalAlignment = GridData.FILL; mTable.setLayoutData(data); - mDescription = new Label(group, SWT.WRAP); + mDescription = new Label(mInnerGroup, SWT.WRAP); mDescription.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); // create the table columns @@ -93,15 +118,26 @@ public class SdkTargetSelector { final TableColumn column1 = new TableColumn(mTable, SWT.NONE); column1.setText("Vendor"); final TableColumn column2 = new TableColumn(mTable, SWT.NONE); - column2.setText("API Level"); + column2.setText("Version"); final TableColumn column3 = new TableColumn(mTable, SWT.NONE); - column3.setText("SDK"); + column3.setText("API Level"); adjustColumnsWidth(mTable, column0, column1, column2, column3); setupSelectionListener(mTable); - fillTable(mTable); + setTargets(targets); setupTooltip(mTable); } + + /** + * Returns the layout data of the inner composite widget that contains the target selector. + * By default the layout data is set to a {@link GridData} with a {@link GridData#FILL_BOTH} + * mode. + * <p/> + * This can be useful if you want to change the {@link GridData#horizontalSpan} for example. + */ + public Object getLayoutData() { + return mInnerGroup.getLayoutData(); + } /** * Returns the list of known targets. @@ -113,6 +149,16 @@ public class SdkTargetSelector { } /** + * Changes the targets of the SDK Target Selector. + * + * @param targets The list of targets. This is <em>not</em> copied, the caller must not modify. + */ + public void setTargets(IAndroidTarget[] targets) { + mTargets = targets; + fillTable(mTable); + } + + /** * Sets a selection listener. Set it to null to remove it. * The listener will be called <em>after</em> this table processed its selection * events so that the caller can see the updated state. @@ -139,6 +185,10 @@ public class SdkTargetSelector { * @return true if the target could be selected, false otherwise. */ public boolean setSelection(IAndroidTarget target) { + if (!mAllowSelection) { + return false; + } + boolean found = false; boolean modified = false; for (TableItem i : mTable.getItems()) { @@ -224,6 +274,10 @@ public class SdkTargetSelector { * double-clicked (aka "the default selection"). */ private void setupSelectionListener(final Table table) { + if (!mAllowSelection) { + return; + } + // Add a selection listener that will check/uncheck items when they are double-clicked table.addSelectionListener(new SelectionListener() { /** Default selection means double-click on "most" platforms */ @@ -281,6 +335,9 @@ public class SdkTargetSelector { * </ul> */ private void fillTable(final Table table) { + + table.removeAll(); + if (mTargets != null && mTargets.length > 0) { table.setEnabled(true); for (IAndroidTarget target : mTargets) { |