From 4551d2839965391f869205ea7d84a5c67047e9b5 Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Mon, 29 Jun 2009 05:27:02 -0700 Subject: [PATCH] Details dialog for AVD from the avd selector. --- .../internal/repository/ProgressDialog.java | 2 +- .../internal/widgets/AvdDetailsDialog.java | 221 ++++++++++++++++++ .../internal/widgets/AvdSelector.java | 42 +++- 3 files changed, 258 insertions(+), 7 deletions(-) create mode 100644 tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdDetailsDialog.java diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ProgressDialog.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ProgressDialog.java index ca847c3c1..fe73ac564 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ProgressDialog.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ProgressDialog.java @@ -46,7 +46,7 @@ import org.eclipse.swt.events.ShellEvent; */ final class ProgressDialog extends Dialog { - private enum CancelMode { + private static enum CancelMode { /** Cancel button says "Cancel" and is enabled. Waiting for user to cancel. */ ACTIVE, /** Cancel button has been clicked. Waiting for thread to finish. */ diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdDetailsDialog.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdDetailsDialog.java new file mode 100644 index 000000000..5eb74f198 --- /dev/null +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdDetailsDialog.java @@ -0,0 +1,221 @@ +/* + * 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.internal.widgets; + +import com.android.sdklib.IAndroidTarget; +import com.android.sdklib.internal.avd.AvdManager; +import com.android.sdklib.internal.avd.AvdManager.AvdInfo; +import com.android.sdklib.internal.avd.AvdManager.AvdInfo.AvdStatus; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ShellAdapter; +import org.eclipse.swt.events.ShellEvent; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Dialog; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * Dialog displaying the details of an AVD. + */ +final class AvdDetailsDialog extends Dialog { + + /** Last dialog size for this session. */ + private static Point sLastSize; + + private Shell mDialogShell; + private final AvdInfo mAvdInfo; + + private Composite mRootComposite; + + public AvdDetailsDialog(Shell shell, AvdInfo avdInfo) { + super(shell, SWT.APPLICATION_MODAL); + mAvdInfo = avdInfo; + + setText("AVD details"); + } + + /** + * Open the dialog and blocks till it gets closed + */ + public void open() { + createContents(); + positionShell(); //$hide$ (hide from SWT designer) + mDialogShell.open(); + mDialogShell.layout(); + + Display display = getParent().getDisplay(); + while (!mDialogShell.isDisposed()) { + if (!display.readAndDispatch()) { + display.sleep(); + } + } + + if (!mDialogShell.isDisposed()) { + sLastSize = mDialogShell.getSize(); + mDialogShell.close(); + } + } + + /** + * Create contents of the dialog. + */ + private void createContents() { + mDialogShell = new Shell(getParent(), SWT.DIALOG_TRIM | SWT.RESIZE); + mDialogShell.addShellListener(new ShellAdapter() { + @Override + public void shellClosed(ShellEvent e) { + onShellClosed(e); + } + }); + mDialogShell.setLayout(new GridLayout(1, false)); + mDialogShell.setSize(450, 300); + mDialogShell.setText(getText()); + + mRootComposite = new Composite(mDialogShell, SWT.NONE); + mRootComposite.setLayout(new GridLayout(2, false)); + mRootComposite.setLayoutData(new GridData(GridData.FILL_BOTH)); + + GridLayout gl; + + Composite c = new Composite(mRootComposite, SWT.NONE); + c.setLayout(gl = new GridLayout(2, false)); + gl.marginHeight = gl.marginWidth = 0; + c.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + if (mAvdInfo != null) { + displayValue(c, "Name:", mAvdInfo.getName()); + displayValue(c, "Path:", mAvdInfo.getPath()); + + if (mAvdInfo.getStatus() != AvdStatus.OK) { + displayValue(c, "Error:", mAvdInfo.getErrorMessage()); + } else { + IAndroidTarget target = mAvdInfo.getTarget(); + displayValue(c, "Target:", String.format("%s (API level %d)", + target.getName(), target.getApiVersionNumber())); + + // display some extra values. + Map properties = mAvdInfo.getProperties(); + if (properties != null) { + String skin = properties.get(AvdManager.AVD_INI_SKIN_NAME); + if (skin != null) { + displayValue(c, "Skin:", skin); + } + + String sdcard = properties.get(AvdManager.AVD_INI_SDCARD_SIZE); + if (sdcard == null) { + sdcard = properties.get(AvdManager.AVD_INI_SDCARD_PATH); + } + if (sdcard != null) { + displayValue(c, "sdcard:", sdcard); + } + + // display other hardware + HashMap copy = new HashMap(properties); + // remove stuff we already displayed (or that we don't want to display) + copy.remove(AvdManager.AVD_INI_SKIN_NAME); + copy.remove(AvdManager.AVD_INI_SKIN_PATH); + copy.remove(AvdManager.AVD_INI_SDCARD_SIZE); + copy.remove(AvdManager.AVD_INI_SDCARD_PATH); + copy.remove(AvdManager.AVD_INI_IMAGES_1); + copy.remove(AvdManager.AVD_INI_IMAGES_2); + + if (copy.size() > 0) { + Label l = new Label(mRootComposite, SWT.SEPARATOR | SWT.HORIZONTAL); + l.setLayoutData(new GridData( + GridData.FILL, GridData.CENTER, false, false, 2, 1)); + + c = new Composite(mRootComposite, SWT.NONE); + c.setLayout(gl = new GridLayout(2, false)); + gl.marginHeight = gl.marginWidth = 0; + c.setLayoutData(new GridData(GridData.FILL_BOTH)); + + Set keys = copy.keySet(); + for (String key : keys) { + displayValue(c, key + ":", copy.get(key)); + } + } + } + } + } + } + + // -- Start of internal part ---------- + // Hide everything down-below from SWT designer + //$hide>>$ + + /** + * Displays a value with a label. + * + * @param parent the parent Composite in which to display the value. This Composite must use a + * {@link GridLayout} with 2 columns. + * @param label the label of the value to display. + * @param value the string value to display. + */ + private void displayValue(Composite parent, String label, String value) { + Label l = new Label(parent, SWT.NONE); + l.setText(label); + l.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false)); + + l = new Label(parent, SWT.NONE); + l.setText(value); + l.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false)); + } + + private void onShellClosed(ShellEvent e) { + // TODO Auto-generated method stub + } + + /** + * Centers the dialog in its parent shell. + */ + private void positionShell() { + // Centers the dialog in its parent shell + Shell child = mDialogShell; + Shell parent = getParent(); + if (child != null && parent != null) { + + // get the parent client area with a location relative to the display + Rectangle parentArea = parent.getClientArea(); + Point parentLoc = parent.getLocation(); + int px = parentLoc.x; + int py = parentLoc.y; + int pw = parentArea.width; + int ph = parentArea.height; + + // Reuse the last size if there's one, otherwise use the default + Point childSize = sLastSize != null ? sLastSize : child.getSize(); + int cw = childSize.x; + int ch = childSize.y; + + child.setLocation(px + (pw - cw) / 2, py + (ph - ch) / 2); + child.setSize(cw, ch); + } + } + + // End of hiding from SWT Designer + //$hide<<$ +} diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java index 37dada9a0..7144e949e 100644 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java @@ -136,7 +136,11 @@ public final class AvdSelector { } public boolean accept(AvdInfo avd) { - return mTarget.isCompatibleBaseFor(avd.getTarget()); + if (avd != null) { + return mTarget.isCompatibleBaseFor(avd.getTarget()); + } + + return false; } public void cleanup() { @@ -195,8 +199,7 @@ public final class AvdSelector { if (displayMode == DisplayMode.MANAGER) { Button newButton = new Button(buttons, SWT.PUSH | SWT.FLAT); newButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - newButton.setText("New"); - // TODO: callback for button + newButton.setText("New..."); Button deleteButton = new Button(buttons, SWT.PUSH | SWT.FLAT); deleteButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); @@ -214,8 +217,13 @@ public final class AvdSelector { Button infoButton = new Button(buttons, SWT.PUSH | SWT.FLAT); infoButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - infoButton.setText("Info..."); - // TODO: callback for button + infoButton.setText("Details..."); + infoButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent arg0) { + onDetails(); + } + }); Composite padding = new Composite(buttons, SWT.NONE); padding.setLayoutData(new GridData(GridData.FILL_VERTICAL)); @@ -378,6 +386,12 @@ public final class AvdSelector { * The {@link TableItem#getData()} contains an {@link IAndroidTarget}. *

* It is recommended that the caller uses the {@link #getSelected()} method instead. + *

+ * The default behavior for double click (when not in {@link DisplayMode#SIMPLE_CHECK}) is to + * display the details of the selected AVD.
+ * To disable it (when you provide your own double click action), set + * {@link SelectionEvent#doit} to false in + * {@link SelectionListener#widgetDefaultSelected(SelectionEvent)} * * @param selectionListener The new listener or null to remove it. */ @@ -451,6 +465,7 @@ public final class AvdSelector { return (AvdInfo) mTable.getItem(selIndex).getData(); } } + return null; } @@ -527,10 +542,19 @@ public final class AvdSelector { i.setChecked(true); } enforceSingleSelection(i); + } + //whether or not we display details. default: true when not in SIMPLE_CHECK mode. + boolean showDetails = mDisplayMode != DisplayMode.SIMPLE_CHECK; + if (mSelectionListener != null) { mSelectionListener.widgetDefaultSelected(e); + showDetails &= e.doit; // enforce false in SIMPLE_CHECK + } + + if (showDetails) { + onDetails(); } } @@ -622,6 +646,13 @@ public final class AvdSelector { } } + private void onDetails() { + final AvdInfo avdInfo = getSelected(); + + AvdDetailsDialog dlg = new AvdDetailsDialog(mTable.getShell(), avdInfo); + dlg.open(); + } + private void onDelete() { final AvdInfo avdInfo = getSelected(); @@ -661,7 +692,6 @@ public final class AvdSelector { } } - /** * Collects all log from the AVD action and displays it in a dialog. */