diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java index c08c0f433..e69c9f093 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java @@ -65,7 +65,6 @@ import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.window.Window; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; @@ -484,26 +483,22 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener AdtPlugin.printToConsole(project, String.format( "Failed to find an AVD compatible with target '%1$s'.", projectTarget.getName())); - + final Display display = AdtPlugin.getDisplay(); - final int[] result = new int[] { Window.CANCEL }; + final boolean[] searchAgain = new boolean[] { false }; // ask the user to create a new one. display.syncExec(new Runnable() { public void run() { Shell shell = display.getActiveShell(); - if (MessageDialog.openQuestion(shell, "AVD Error", - "No Compatible targets were found. Do you wish to create one?")) { + if (MessageDialog.openQuestion(shell, "Android AVD Error", + "No compatible targets were found. Do you wish to a add new Android Virtual Device?")) { AvdManagerAction action = new AvdManagerAction(); action.run(null /*action*/); - result[0] = action.getDialogResult(); + searchAgain[0] = true; } } }); - if (result[0] == Window.CANCEL) { - AdtPlugin.printErrorToConsole(project, String.format("Launch aborted.")); - stopLaunch(launchInfo); - return; - } else { + if (searchAgain[0]) { // attempt to reload the AVDs and find one compatible. defaultAvd = findMatchingAvd(avdManager, projectTarget); @@ -588,9 +583,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener } /** - * @param avdManager - * @param projectTarget - * @return + * Find a matching AVD. */ private AvdInfo findMatchingAvd(AvdManager avdManager, final IAndroidTarget projectTarget) { AvdInfo[] avds = avdManager.getValidAvds(); diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java index 1b7a63a30..52ba42f9e 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java @@ -33,6 +33,7 @@ import com.android.sdklib.IAndroidTarget; import com.android.sdklib.avd.AvdManager; import com.android.sdklib.avd.AvdManager.AvdInfo; import com.android.sdkuilib.AvdSelector; +import com.android.sdkuilib.AvdSelector.SelectionMode; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; @@ -327,7 +328,7 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener if (deviceMode) { handleDeviceSelection(); } else { - mResponse.setAvdToLaunch(mPreferredAvdSelector.getFirstSelected()); + mResponse.setAvdToLaunch(mPreferredAvdSelector.getSelected()); } enableOkButton(); @@ -417,13 +418,22 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener mPreferredAvdSelector = new AvdSelector(offsetComp, getNonRunningAvds(false /*reloadAvds*/), mProjectTarget, - new Runnable() { + new AvdSelector.IExtraAction() { public void run() { AvdManagerAction action = new AvdManagerAction(); action.run(null); refillAvdList(true /*reloadAvds*/); } - }); + + public boolean isEnabled() { + return true; + } + + public String label() { + return "AVD Manager..."; + } + }, + SelectionMode.CHECK); mPreferredAvdSelector.setTableHeightHint(100); mPreferredAvdSelector.setEnabled(false); mPreferredAvdSelector.setSelectionListener(new SelectionAdapter() { @@ -434,7 +444,7 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener @Override public void widgetSelected(SelectionEvent e) { if (mDisableAvdSelectionChange == false) { - mResponse.setAvdToLaunch(mPreferredAvdSelector.getFirstSelected()); + mResponse.setAvdToLaunch(mPreferredAvdSelector.getSelected()); enableOkButton(); } } @@ -735,7 +745,7 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener AvdInfo[] array = getNonRunningAvds(reloadAvds); // save the current selection - AvdInfo selected = mPreferredAvdSelector.getFirstSelected(); + AvdInfo selected = mPreferredAvdSelector.getSelected(); // disable selection change. mDisableAvdSelectionChange = true; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmulatorConfigTab.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmulatorConfigTab.java index 48a6b59b2..fd9a1c282 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmulatorConfigTab.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmulatorConfigTab.java @@ -27,6 +27,7 @@ import com.android.sdklib.IAndroidTarget; import com.android.sdklib.avd.AvdManager; import com.android.sdklib.avd.AvdManager.AvdInfo; import com.android.sdkuilib.AvdSelector; +import com.android.sdkuilib.AvdSelector.SelectionMode; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; @@ -192,13 +193,22 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab { mPreferredAvdLabel.setText("Select a preferred Android Virtual Device for deployment:"); mPreferredAvdSelector = new AvdSelector(offsetComp, null /*avds*/, - new Runnable() { + new AvdSelector.IExtraAction() { public void run() { AvdManagerAction action = new AvdManagerAction(); action.run(null); updateAvdList(null); } - }); + + public boolean isEnabled() { + return true; + } + + public String label() { + return "AVD Manager..."; + } + }, + SelectionMode.CHECK); mPreferredAvdSelector.setTableHeightHint(100); mPreferredAvdSelector.setSelectionListener(new SelectionAdapter() { @Override @@ -445,7 +455,7 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab { public void performApply(ILaunchConfigurationWorkingCopy configuration) { configuration.setAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE, mAutoTargetButton.getSelection()); - AvdInfo avd = mPreferredAvdSelector.getFirstSelected(); + AvdInfo avd = mPreferredAvdSelector.getSelected(); if (avd != null) { configuration.setAttribute(LaunchConfigDelegate.ATTR_AVD_NAME, avd.getName()); } else { diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/IUpdateWizardDialog.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/IUpdateWizardDialog.java new file mode 100755 index 000000000..997c6eb07 --- /dev/null +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/IUpdateWizardDialog.java @@ -0,0 +1,30 @@ +/* + * 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.ui; + +import org.eclipse.jface.wizard.WizardDialog; + + +/** + * An interface that enables a client to update {@link WizardDialog} after its creation. + */ +public interface IUpdateWizardDialog { + /** + * Invoked after {@link WizardDialog#create()} to let the caller update the dialog. + */ + public void updateWizardDialog(WizardDialogEx dialog); +} diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/WizardDialogEx.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/WizardDialogEx.java new file mode 100755 index 000000000..ba83b255e --- /dev/null +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/WizardDialogEx.java @@ -0,0 +1,46 @@ +/* + * 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.ui; + +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.wizard.IWizard; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Shell; + +/** + * A {@link WizardDialog} that gives access to some inner controls. + */ +public final class WizardDialogEx extends WizardDialog { + + /** + * @see WizardDialog#WizardDialog(Shell, IWizard) + */ + public WizardDialogEx(Shell parentShell, IWizard newWizard) { + super(parentShell, newWizard); + } + + /** + * Returns the cancel button. + *

+ * Note: there is already a protected, deprecated method that does the same thing. + * To avoid overriding a deprecated method, the name as be changed to ...Ex. + */ + public Button getCancelButtonEx() { + return getButton(IDialogConstants.CANCEL_ID); + } +} diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/OpenWizardAction.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/OpenWizardAction.java index 13031ff6b..3f0393d6c 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/OpenWizardAction.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/OpenWizardAction.java @@ -16,12 +16,14 @@ package com.android.ide.eclipse.adt.wizards.actions; +import com.android.ide.eclipse.adt.ui.IUpdateWizardDialog; +import com.android.ide.eclipse.adt.ui.WizardDialogEx; + import org.eclipse.jface.action.IAction; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorInput; @@ -124,9 +126,13 @@ import org.eclipse.ui.internal.util.Util; // It's not visible yet until a dialog is created and opened Shell parent = window.getShell(); - WizardDialog dialog = new WizardDialog(parent, mWizard); + WizardDialogEx dialog = new WizardDialogEx(parent, mWizard); dialog.create(); + if (mWizard instanceof IUpdateWizardDialog) { + ((IUpdateWizardDialog) mWizard).updateWizardDialog(dialog); + } + // This code comes straight from NewWizardShortcutAction#run() Point defaultSize = dialog.getShell().getSize(); dialog.getShell().setSize( diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/avdmanager/AvdManagerListPage.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/avdmanager/AvdManagerListPage.java index d569b6917..ba5d0a24b 100755 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/avdmanager/AvdManagerListPage.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/avdmanager/AvdManagerListPage.java @@ -27,6 +27,7 @@ import com.android.sdklib.ISdkLog; import com.android.sdklib.avd.AvdManager; import com.android.sdklib.avd.AvdManager.AvdInfo; import com.android.sdkuilib.AvdSelector; +import com.android.sdkuilib.AvdSelector.SelectionMode; import org.eclipse.core.resources.IProject; import org.eclipse.jface.wizard.WizardPage; @@ -56,7 +57,6 @@ import java.util.TreeMap; class AvdManagerListPage extends WizardPage { private AvdSelector mAvdSelector; - private Button mDeleteButton; private Button mRefreshButton; private Text mCreateName; private Combo mCreateTargetCombo; @@ -162,32 +162,21 @@ class AvdManagerListPage extends WizardPage { } }); - mAvdSelector = new AvdSelector(parent, null); - mAvdSelector.setSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - super.widgetSelected(e); - updateDeleteButton(); - } - }); + mAvdSelector = new AvdSelector(parent, + SelectionMode.SELECT, + new AvdSelector.IExtraAction() { + public String label() { + return "Delete AVD..."; + } - mDeleteButton = new Button(parent, SWT.PUSH); - mDeleteButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, true, false)); - mDeleteButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - onDelete(); - } - }); - updateDeleteButton(); - } - - private void updateDeleteButton() { - AvdInfo selected = mAvdSelector.getFirstSelected(); - mDeleteButton.setText(String.format("Delete %s...", - selected == null ? "" : selected.getName())); //$NON-NLS-1$ - mDeleteButton.pack(); - mDeleteButton.setEnabled(selected != null); + public boolean isEnabled() { + return mAvdSelector != null && mAvdSelector.getSelected() != null; + } + + public void run() { + onDelete(); + } + }); } /** @@ -441,19 +430,24 @@ class AvdManagerListPage extends WizardPage { * Tries to preserve the selection. */ private void reloadAvdList() { - AvdInfo selected = mAvdSelector.getFirstSelected(); + AvdInfo selected = mAvdSelector.getSelected(); AvdManager avdm = getAvdManager(); + AvdInfo[] avds = null; // For the AVD manager to reload the list, in case AVDs where created using the // command line tool. - try { - avdm.reloadAvds(); - } catch (AndroidLocationException e) { - AdtPlugin.log(e, "AVD Manager reload failed"); //$NON-NLS-1$ + // The AVD manager may not exist yet, typically when loading the SDK. + if (avdm != null) { + try { + avdm.reloadAvds(); + } catch (AndroidLocationException e) { + AdtPlugin.log(e, "AVD Manager reload failed"); //$NON-NLS-1$ + } + + avds = avdm.getValidAvds(); } - AvdInfo[] avds = avdm == null ? null : avdm.getValidAvds(); mAvdSelector.setAvds(avds, null /*filter*/); // Keep the list of known AVD names to check if they exist quickly. however @@ -473,11 +467,11 @@ class AvdManagerListPage extends WizardPage { } /** - * Triggered when the user selects the "delete" button. + * Triggered when the user selects the "delete" button (the extra action in the selector) * Deletes the currently selected AVD, if any. */ private void onDelete() { - AvdInfo avdInfo = mAvdSelector.getFirstSelected(); + AvdInfo avdInfo = mAvdSelector.getSelected(); AvdManager avdm = getAvdManager(); if (avdInfo == null || avdm == null) { return; @@ -496,7 +490,6 @@ class AvdManagerListPage extends WizardPage { log.display(success); reloadAvdList(); - updateDeleteButton(); } /** diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/avdmanager/AvdManagerWizard.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/avdmanager/AvdManagerWizard.java index 20cad5a5b..19ceed828 100755 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/avdmanager/AvdManagerWizard.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/avdmanager/AvdManagerWizard.java @@ -18,11 +18,14 @@ package com.android.ide.eclipse.adt.wizards.avdmanager; +import com.android.ide.eclipse.adt.ui.IUpdateWizardDialog; +import com.android.ide.eclipse.adt.ui.WizardDialogEx; import com.android.ide.eclipse.editors.IconFactory; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.wizard.Wizard; +import org.eclipse.swt.widgets.Button; import org.eclipse.ui.INewWizard; import org.eclipse.ui.IWorkbench; @@ -34,7 +37,7 @@ import org.eclipse.ui.IWorkbench; * to get something quick out of the door. We'll need to revisit this when we implement * the final standalone AVD Manager UI and this Wizard will go away. */ -public class AvdManagerWizard extends Wizard implements INewWizard { +public class AvdManagerWizard extends Wizard implements INewWizard, IUpdateWizardDialog { private static final String PROJECT_LOGO_LARGE = "android_large"; //$NON-NLS-1$ @@ -97,4 +100,15 @@ public class AvdManagerWizard extends Wizard implements INewWizard { setDefaultPageImageDescriptor(desc); } + /** + * Invoked once the dialog frame as been created. + * We use it to hide the cancel button, which looks odd here. + */ + public void updateWizardDialog(WizardDialogEx dialog) { + Button cancel = dialog.getCancelButtonEx(); + if (cancel != null) { + cancel.setVisible(false); + } + } + } diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java index 6ccc66bbd..05a31e6a5 100644 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java @@ -42,9 +42,9 @@ import org.eclipse.swt.widgets.TableItem; /** * The AVD selector is a table that is added to the given parent composite. *

- * To use, create it using {@link #AvdSelector(Composite, AvdInfo[])} then + * To use, create it using {@link #AvdSelector(Composite, SelectionMode, IExtraAction)} then * call {@link #setSelection(AvdInfo)}, {@link #setSelectionListener(SelectionListener)} - * and finally use {@link #getFirstSelected()} to retrieve the selection. + * and finally use {@link #getSelected()} to retrieve the selection. */ public final class AvdSelector { @@ -54,6 +54,51 @@ public final class AvdSelector { private Label mDescription; private static int NUM_COL = 2; + private final SelectionMode mSelectionMode; + private final IExtraAction mExtraAction; + private Button mExtraActionButton; + + /** The selection mode, either {@link #SELECT} or {@link #CHECK} */ + public enum SelectionMode { + /** + * In the "check" selection mode, checkboxes are displayed on each line + * and {@link AvdSelector#getSelected()} returns the line that is checked + * even if it is not the currently selected line. Only one line can + * be checked at once. + */ + CHECK, + /** + * In the "select" selection mode, there are no checkboxes and + * {@link AvdSelector#getSelected()} returns the line currently selected. + * Only one line can be selected at once. + */ + SELECT + } + + /** + * Defines an "extra action" button that can be shown under the AVD Selector. + */ + public interface IExtraAction { + /** + * Label of the button that will be created. + * This is invoked once when the button is created and cannot be changed later. + */ + public String label(); + + /** + * This is invoked just after the selection has changed to update the "enabled" + * state of the action. Implementation should use {@link AvdSelector#getSelected()}. + */ + public boolean isEnabled(); + + /** + * Run the action, invoked when the button is clicked. + * + * The caller's action is responsible for reloading the AVD list + * using {@link AvdSelector#setAvds(AvdInfo[], IAndroidTarget)}. + */ + public void run(); + } /** * Creates a new SDK Target Selector, and fills it with a list of {@link AvdInfo}, filtered @@ -65,23 +110,29 @@ public final class AvdSelector { * @param avds The list of AVDs. This is not copied, the caller must not modify. * It can be null. * @param filter When non-null, will display only the AVDs matching this target. - * @param avdManagerAction A runnable to associate with an "AVD Manager" button. This button - * is hidden if null is passed. The caller's action is responsible for reloading - * the AVD list using {@link #setAvds(AvdInfo[], IAndroidTarget)}. + * @param extraAction When non-null, displays an extra action button. + * @param selectionMode One of {@link SelectionMode#SELECT} or {@link SelectionMode#CHECK} */ public AvdSelector(Composite parent, AvdInfo[] avds, IAndroidTarget filter, - final Runnable avdManagerAction) { + IExtraAction extraAction, + SelectionMode selectionMode) { mAvds = avds; + mExtraAction = extraAction; + mSelectionMode = selectionMode; // Layout has 2 columns Composite group = new Composite(parent, SWT.NONE); group.setLayout(new GridLayout(NUM_COL, false /*makeColumnsEqualWidth*/)); group.setLayoutData(new GridData(GridData.FILL_BOTH)); group.setFont(parent.getFont()); - - mTable = new Table(group, SWT.CHECK | SWT.FULL_SELECTION | SWT.SINGLE | SWT.BORDER); + + int style = SWT.FULL_SELECTION | SWT.SINGLE | SWT.BORDER; + if (selectionMode == SelectionMode.CHECK) { + style |= SWT.CHECK; + } + mTable = new Table(group, style); mTable.setHeaderVisible(true); mTable.setLinesVisible(false); setTableHeightHint(0); @@ -89,14 +140,15 @@ public final class AvdSelector { mDescription = new Label(group, SWT.WRAP); mDescription.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - if (avdManagerAction != null) { - Button avdManagerButton = new Button(group, SWT.PUSH); - avdManagerButton.setText("AVD Manager..."); - avdManagerButton.addSelectionListener(new SelectionAdapter() { + if (extraAction != null) { + mExtraActionButton = new Button(group, SWT.PUSH); + mExtraActionButton.setText(extraAction.label()); + mExtraActionButton.setEnabled(extraAction.isEnabled()); + mExtraActionButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { super.widgetSelected(e); - avdManagerAction.run(); + mExtraAction.run(); } }); } @@ -123,29 +175,33 @@ public final class AvdSelector { * @param parent The parent composite where the selector will be added. * @param avds The list of AVDs. This is not copied, the caller must not modify. * It can be null. + * @param extraAction When non-null, displays an extra action button. + * @param selectionMode One of {@link SelectionMode#SELECT} or {@link SelectionMode#CHECK} */ - public AvdSelector(Composite parent, AvdInfo[] avds) { - this(parent, avds, null /* filter */, null /* avdManagerAction */); + public AvdSelector(Composite parent, + AvdInfo[] avds, + IExtraAction extraAction, + SelectionMode selectionMode) { + this(parent, avds, null /* filter */, extraAction, selectionMode); } /** * Creates a new SDK Target Selector, and fills it with a list of {@link AvdInfo}. * * @param parent The parent composite where the selector will be added. - * @param avds The list of AVDs. This is not copied, the caller must not modify. - * It can be null. - * @param avdManagerAction A runnable to associate with an "AVD Manager" button. This button - * is hidden if null is passed. The caller's action is responsible for reloading - * the AVD list using {@link #setAvds(AvdInfo[], IAndroidTarget)}. + * @param extraAction When non-null, displays an extra action button. + * @param selectionMode One of {@link SelectionMode#SELECT} or {@link SelectionMode#CHECK} */ - public AvdSelector(Composite parent, AvdInfo[] avds, Runnable avdManagerAction) { - this(parent, avds, null /* filter */, avdManagerAction); + public AvdSelector(Composite parent, + SelectionMode selectionMode, + IExtraAction extraAction) { + this(parent, null /*avds*/, null /* filter */, extraAction, selectionMode); } /** * Sets the table grid layout data. * - * @param heightHint If > 0, tthe height hint is set to the requested value. + * @param heightHint If > 0, the height hint is set to the requested value. */ public void setTableHeightHint(int heightHint) { GridData data = new GridData(); @@ -162,7 +218,10 @@ public final class AvdSelector { /** * Sets a new set of AVD, with an optional filter. - *

This must be called from the UI thread. + * Tries to keep the selection. + *

+ * This must be called from the UI thread. + * * * @param avds The list of AVDs. This is not copied, the caller must not modify. * It can be null. @@ -170,8 +229,13 @@ public final class AvdSelector { * filter target will displayed an available for selection. */ public void setAvds(AvdInfo[] avds, IAndroidTarget filter) { + + AvdInfo selected = getSelected(); + mAvds = avds; fillTable(mTable, filter); + + setSelection(selected); } /** @@ -191,7 +255,7 @@ public final class AvdSelector { * The event's item contains a {@link TableItem}. * The {@link TableItem#getData()} contains an {@link IAndroidTarget}. *

- * It is recommended that the caller uses the {@link #getFirstSelected()} method instead. + * It is recommended that the caller uses the {@link #getSelected()} method instead. * * @param selectionListener The new listener or null to remove it. */ @@ -211,16 +275,33 @@ public final class AvdSelector { public boolean setSelection(AvdInfo target) { boolean found = false; boolean modified = false; + + int selIndex = mTable.getSelectionIndex(); + int index = 0; for (TableItem i : mTable.getItems()) { - if ((AvdInfo) i.getData() == target) { - found = true; - if (!i.getChecked()) { - modified = true; - i.setChecked(true); + if (mSelectionMode == SelectionMode.SELECT) { + if ((AvdInfo) i.getData() == target) { + found = true; + if (index != selIndex) { + mTable.setSelection(index); + modified = true; + } + break; + } + + index++; + + } else if (mSelectionMode == SelectionMode.CHECK){ + if ((AvdInfo) i.getData() == target) { + found = true; + if (!i.getChecked()) { + modified = true; + i.setChecked(true); + } + } else if (i.getChecked()) { + modified = true; + i.setChecked(false); } - } else if (i.getChecked()) { - modified = true; - i.setChecked(false); } } @@ -228,19 +309,30 @@ public final class AvdSelector { mSelectionListener.widgetSelected(null); } + if (mExtraAction != null && mExtraActionButton != null) { + mExtraActionButton.setEnabled(mExtraAction.isEnabled()); + } + return found; } /** - * Returns the first selected item. - * This is useful when the table is in single-selection mode. + * Returns the currently selected item. * - * @return The first selected item or null. + * @return The currently selected item or null. */ - public AvdInfo getFirstSelected() { - for (TableItem i : mTable.getItems()) { - if (i.getChecked()) { - return (AvdInfo) i.getData(); + public AvdInfo getSelected() { + if (mSelectionMode == SelectionMode.SELECT) { + int selIndex = mTable.getSelectionIndex(); + if (selIndex >= 0) { + return (AvdInfo) mTable.getItem(selIndex).getData(); + } + + } else if (mSelectionMode == SelectionMode.CHECK) { + for (TableItem i : mTable.getItems()) { + if (i.getChecked()) { + return (AvdInfo) i.getData(); + } } } return null; @@ -305,6 +397,10 @@ public final class AvdSelector { if (mSelectionListener != null) { mSelectionListener.widgetSelected(e); } + + if (mExtraAction != null && mExtraActionButton != null) { + mExtraActionButton.setEnabled(mExtraAction.isEnabled()); + } } /** @@ -318,7 +414,9 @@ public final class AvdSelector { public void widgetDefaultSelected(SelectionEvent e) { if (e.item instanceof TableItem) { TableItem i = (TableItem) e.item; - i.setChecked(true); + if (mSelectionMode == SelectionMode.CHECK) { + i.setChecked(true); + } enforceSingleSelection(i); updateDescription(i); } @@ -326,6 +424,10 @@ public final class AvdSelector { if (mSelectionListener != null) { mSelectionListener.widgetDefaultSelected(e); } + + if (mExtraAction != null && mExtraActionButton != null) { + mExtraActionButton.setEnabled(mExtraAction.isEnabled()); + } } /** @@ -333,11 +435,16 @@ public final class AvdSelector { * This makes the chekboxes act as radio buttons. */ private void enforceSingleSelection(TableItem item) { - if (item.getChecked()) { - Table parentTable = item.getParent(); - for (TableItem i2 : parentTable.getItems()) { - if (i2 != item && i2.getChecked()) { - i2.setChecked(false); + if (mSelectionMode == SelectionMode.SELECT) { + // pass + + } else if (mSelectionMode == SelectionMode.CHECK) { + if (item.getChecked()) { + Table parentTable = item.getParent(); + for (TableItem i2 : parentTable.getItems()) { + if (i2 != item && i2.getChecked()) { + i2.setChecked(false); + } } } }