Update AVD creation UI to be easier for skin/sdcard.

BUG: 2162198

Change-Id: I47bf273a730a1bf6e0c3f47fb5247f02d06259a5
This commit is contained in:
Xavier Ducrohet
2009-10-06 16:54:20 -07:00
parent b5c1840392
commit 2eae036a59

View File

@@ -32,6 +32,8 @@ import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.layout.GridLayout;
@@ -40,6 +42,7 @@ import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Text;
@@ -53,8 +56,6 @@ import java.util.TreeMap;
* TODO: * TODO:
* - support custom hardware properties * - support custom hardware properties
* - use SdkTargetSelector instead of Combo * - use SdkTargetSelector instead of Combo
* - Better UI for the sdcard (radio button for K or M, info about what is valid value)
* - Support for ###x### skins
* - tooltips on widgets. * - tooltips on widgets.
* *
*/ */
@@ -66,8 +67,15 @@ final class AvdCreationDialog extends Dialog {
private Text mAvdName; private Text mAvdName;
private Combo mTargetCombo; private Combo mTargetCombo;
private Text mSdCard;
private Button mSdCardSizeRadio;
private Text mSdCardSize;
private Combo mSdCardSizeCombo;
private Text mSdCardFile;
private Button mBrowseSdCard; private Button mBrowseSdCard;
private Button mSdCardFileRadio;
private Combo mSkinCombo; private Combo mSkinCombo;
private Button mForceCreation; private Button mForceCreation;
private Button mOkButton; private Button mOkButton;
@@ -75,13 +83,32 @@ final class AvdCreationDialog extends Dialog {
private Label mStatusLabel; private Label mStatusLabel;
private Composite mStatusComposite; private Composite mStatusComposite;
private final ImageFactory mImageFactory; private final ImageFactory mImageFactory;
private Button mSkinListRadio;
private Button mSkinSizeRadio;
private Text mSkinSizeWidth;
private Text mSkinSizeHeight;
/**
* {@link VerifyListener} for {@link Text} widgets that should only contains numbers.
*/
private final VerifyListener mDigitVerifier = new VerifyListener() {
public void verifyText(VerifyEvent event) {
int count = event.text.length();
for (int i = 0 ; i < count ; i++) {
char c = event.text.charAt(i);
if (c < '0' || c > '9') {
event.doit = false;
return;
}
}
}
};
/** /**
* Callback when the AVD name is changed. * Callback when the AVD name is changed.
* Enables the force checkbox if the name is a duplicate. * Enables the force checkbox if the name is a duplicate.
*/ */
private class CreateNameModifyListener implements ModifyListener { private class CreateNameModifyListener implements ModifyListener {
public void modifyText(ModifyEvent e) { public void modifyText(ModifyEvent e) {
String name = mAvdName.getText().trim(); String name = mAvdName.getText().trim();
AvdInfo avdMatch = mAvdManager.getAvd(name, false /*validAvdOnly*/); AvdInfo avdMatch = mAvdManager.getAvd(name, false /*validAvdOnly*/);
@@ -96,8 +123,10 @@ final class AvdCreationDialog extends Dialog {
} }
} }
/**
* {@link ModifyListener} used for live-validation of the fields content.
*/
private class ValidateListener extends SelectionAdapter implements ModifyListener { private class ValidateListener extends SelectionAdapter implements ModifyListener {
public void modifyText(ModifyEvent e) { public void modifyText(ModifyEvent e) {
validatePage(); validatePage();
} }
@@ -140,24 +169,31 @@ final class AvdCreationDialog extends Dialog {
@Override @Override
protected Control createDialogArea(Composite parent) { protected Control createDialogArea(Composite parent) {
GridData gd;
final int groupIndent = 30;
Composite top = new Composite(parent, SWT.NONE); Composite top = new Composite(parent, SWT.NONE);
GridLayout 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);
top.setLayout(layout);
top.setLayoutData(new GridData(GridData.FILL_BOTH)); top.setLayoutData(new GridData(GridData.FILL_BOTH));
top.setLayout(new GridLayout(3, false));
Label label = new Label(top, SWT.NONE); Label label = new Label(top, SWT.NONE);
label.setText("Name:"); label.setText("Name:");
mAvdName = new Text(top, SWT.BORDER); mAvdName = new Text(top, SWT.BORDER);
mAvdName.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, mAvdName.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
true, false, 2, 1));
mAvdName.addModifyListener(new CreateNameModifyListener()); mAvdName.addModifyListener(new CreateNameModifyListener());
label = new Label(top, SWT.NONE); label = new Label(top, SWT.NONE);
label.setText("Target:"); label.setText("Target:");
mTargetCombo = new Combo(top, SWT.READ_ONLY | SWT.DROP_DOWN); mTargetCombo = new Combo(top, SWT.READ_ONLY | SWT.DROP_DOWN);
mTargetCombo.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, mTargetCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
true, false, 2, 1));
mTargetCombo.addSelectionListener(new SelectionAdapter() { mTargetCombo.addSelectionListener(new SelectionAdapter() {
@Override @Override
public void widgetSelected(SelectionEvent e) { public void widgetSelected(SelectionEvent e) {
@@ -167,18 +203,48 @@ final class AvdCreationDialog extends Dialog {
} }
}); });
// --- sd card group
label = new Label(top, SWT.NONE); label = new Label(top, SWT.NONE);
label.setText("SD Card:"); label.setText("SD Card:");
label.setToolTipText("Either a path to an existing SD card image\n" + label.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
"or an image size in K or M (e.g. 512K, 10M)."); gd.horizontalSpan = 2;
final Group sdCardGroup = new Group(top, SWT.NONE);
sdCardGroup.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
gd.horizontalIndent = groupIndent;
gd.horizontalSpan = 2;
sdCardGroup.setLayout(new GridLayout(3, false));
mSdCardSizeRadio = new Button(sdCardGroup, SWT.RADIO);
mSdCardSizeRadio.setText("Size:");
mSdCardSizeRadio.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent arg0) {
boolean sizeMode = mSdCardSizeRadio.getSelection();
enableSdCardWidgets(sizeMode);
validatePage();
}
});
ValidateListener validateListener = new ValidateListener(); ValidateListener validateListener = new ValidateListener();
mSdCard = new Text(top, SWT.BORDER); mSdCardSize = new Text(sdCardGroup, SWT.BORDER);
mSdCard.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); mSdCardSize.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mSdCard.addModifyListener(validateListener); mSdCardSize.addVerifyListener(mDigitVerifier);
mBrowseSdCard = new Button(top, SWT.PUSH); mSdCardSizeCombo = new Combo(sdCardGroup, SWT.DROP_DOWN | SWT.READ_ONLY);
mSdCardSizeCombo.add("K");
mSdCardSizeCombo.add("M");
mSdCardSizeCombo.select(1);
mSdCardFileRadio = new Button(sdCardGroup, SWT.RADIO);
mSdCardFileRadio.setText("File:");
mSdCardFile = new Text(sdCardGroup, SWT.BORDER);
mSdCardFile.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mSdCardFile.addModifyListener(validateListener);
mBrowseSdCard = new Button(sdCardGroup, SWT.PUSH);
mBrowseSdCard.setText("Browse..."); mBrowseSdCard.setText("Browse...");
mBrowseSdCard.addSelectionListener(new SelectionAdapter() { mBrowseSdCard.addSelectionListener(new SelectionAdapter() {
@Override @Override
@@ -188,19 +254,60 @@ final class AvdCreationDialog extends Dialog {
} }
}); });
label = new Label(top, SWT.NONE); mSdCardSizeRadio.setSelection(true);
label.setText("Skin"); enableSdCardWidgets(true);
mSkinCombo = new Combo(top, SWT.READ_ONLY | SWT.DROP_DOWN); // --- skin group
mSkinCombo.setLayoutData(new GridData(GridData.FILL, GridData.CENTER,
true, false, 2, 1));
// dummies for alignment
label = new Label(top, SWT.NONE); label = new Label(top, SWT.NONE);
label.setText("Skin:");
label.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
gd.horizontalSpan = 2;
final Group skinGroup = new Group(top, SWT.NONE);
skinGroup.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
gd.horizontalIndent = groupIndent;
gd.horizontalSpan = 2;
skinGroup.setLayout(new GridLayout(4, false));
mSkinListRadio = new Button(skinGroup, SWT.RADIO);
mSkinListRadio.setText("Built-in:");
mSkinListRadio.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent arg0) {
boolean listMode = mSkinListRadio.getSelection();
enableSkinWidgets(listMode);
validatePage();
}
});
mSkinCombo = new Combo(skinGroup, SWT.READ_ONLY | SWT.DROP_DOWN);
mSkinCombo.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
gd.horizontalSpan = 3;
mSkinSizeRadio = new Button(skinGroup, SWT.RADIO);
mSkinSizeRadio.setText("Size:");
mSkinSizeWidth = new Text(skinGroup, SWT.BORDER);
mSkinSizeWidth.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mSkinSizeWidth.addVerifyListener(mDigitVerifier);
mSkinSizeWidth.addModifyListener(validateListener);
new Label(skinGroup, SWT.NONE).setText("x");
mSkinSizeHeight = new Text(skinGroup, SWT.BORDER);
mSkinSizeHeight.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mSkinSizeHeight.addVerifyListener(mDigitVerifier);
mSkinSizeHeight.addModifyListener(validateListener);
mSkinListRadio.setSelection(true);
enableSkinWidgets(true);
// --- end skin group
mForceCreation = new Button(top, SWT.CHECK); mForceCreation = new Button(top, SWT.CHECK);
mForceCreation.setText("Force"); mForceCreation.setText("Force create");
mForceCreation.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, mForceCreation.setToolTipText("Select this to override any existing AVD");
mForceCreation.setLayoutData(new GridData(GridData.END, GridData.CENTER,
true, false, 2, 1)); true, false, 2, 1));
mForceCreation.setEnabled(false); mForceCreation.setEnabled(false);
mForceCreation.addSelectionListener(validateListener); mForceCreation.addSelectionListener(validateListener);
@@ -226,6 +333,7 @@ final class AvdCreationDialog extends Dialog {
reloadTargetCombo(); reloadTargetCombo();
applyDialogFont(top);
return top; return top;
} }
@@ -240,18 +348,44 @@ final class AvdCreationDialog extends Dialog {
@Override @Override
protected void okPressed() { protected void okPressed() {
if (onCreate()) { if (createAvd()) {
super.okPressed(); super.okPressed();
} }
} }
/**
* Enable or disable the sd card widgets.
* @param sizeMode if true the size-based widgets are to be enabled, and the file-based ones
* disabled.
*/
private void enableSdCardWidgets(boolean sizeMode) {
mSdCardSize.setEnabled(sizeMode);
mSdCardSizeCombo.setEnabled(sizeMode);
mSdCardFile.setEnabled(!sizeMode);
mBrowseSdCard.setEnabled(!sizeMode);
}
/**
* Enable or disable the skin widgets.
* @param listMode if true the list-based widgets are to be enabled, and the size-based ones
* disabled.
*/
private void enableSkinWidgets(boolean listMode) {
mSkinCombo.setEnabled(listMode);
mSkinSizeWidth.setEnabled(!listMode);
mSkinSizeHeight.setEnabled(!listMode);
}
private void onBrowseSdCard() { private void onBrowseSdCard() {
FileDialog dlg = new FileDialog(getContents().getShell(), SWT.OPEN); FileDialog dlg = new FileDialog(getContents().getShell(), SWT.OPEN);
dlg.setText("Choose SD Card image file."); dlg.setText("Choose SD Card image file.");
String fileName = dlg.open(); String fileName = dlg.open();
if (fileName != null) { if (fileName != null) {
mSdCard.setText(fileName); mSdCardFile.setText(fileName);
} }
} }
@@ -363,12 +497,29 @@ final class AvdCreationDialog extends Dialog {
// Validate SDCard path or value // Validate SDCard path or value
if (error == null) { if (error == null) {
String sdName = mSdCard.getText().trim(); // get the mode. We only need to check the file since the
// verifier on the size Text will prevent invalid input
boolean sdcardFileMode = mSdCardFileRadio.getSelection();
if (sdcardFileMode) {
String sdName = mSdCardFile.getText().trim();
if (sdName.length() > 0 && !new File(sdName).isFile()) {
error = "SD Card path isn't valid.";
}
}
}
if (sdName.length() > 0 && // validate the skin
!new File(sdName).isFile() && if (error == null) {
!AvdManager.SDCARD_SIZE_PATTERN.matcher(sdName).matches()) { // get the mode, we should only check if it's in size mode since
error = "SD Card must be either a file path or a size\nsuch as 128K or 64M."; // the built-in list mode is always valid.
if (mSkinSizeRadio.getSelection()) {
// need both with and heigh to be non null
String width = mSkinSizeWidth.getText(); // no need for trim, since the verifier
String height = mSkinSizeHeight.getText(); // rejects non digit.
if (width.length() == 0 || height.length() == 0) {
error = "Skin size is incorrect.\nBoth dimensions must be > 0";
}
} }
} }
@@ -378,7 +529,7 @@ final class AvdCreationDialog extends Dialog {
if (avdMatch != null && !mForceCreation.getSelection()) { if (avdMatch != null && !mForceCreation.getSelection()) {
error = String.format( error = String.format(
"The AVD name '%s' is already used.\n" + "The AVD name '%s' is already used.\n" +
"Check \"Force\" to override existing AVD.", "Check \"Force create\" to override existing AVD.",
avdName); avdName);
} }
} }
@@ -405,27 +556,60 @@ final class AvdCreationDialog extends Dialog {
/** /**
* Creates an AVD from the values in the UI. Called when the user presses the OK button. * Creates an AVD from the values in the UI. Called when the user presses the OK button.
*/ */
private boolean onCreate() { private boolean createAvd() {
String avdName = mAvdName.getText().trim(); String avdName = mAvdName.getText().trim();
String sdName = mSdCard.getText().trim();
int targetIndex = mTargetCombo.getSelectionIndex(); int targetIndex = mTargetCombo.getSelectionIndex();
int skinIndex = mSkinCombo.getSelectionIndex();
boolean force = mForceCreation.getSelection();
// quick check on the name and the target selection
if (avdName.length() == 0 || targetIndex < 0) { if (avdName.length() == 0 || targetIndex < 0) {
return false; return false;
} }
// resolve the target.
String targetName = mTargetCombo.getItem(targetIndex); String targetName = mTargetCombo.getItem(targetIndex);
IAndroidTarget target = mCurrentTargets.get(targetName); IAndroidTarget target = mCurrentTargets.get(targetName);
if (target == null) { if (target == null) {
return false; return false;
} }
// get the SD card data from the UI.
String sdName = null;
if (mSdCardSizeRadio.getSelection()) {
// size mode
String value = mSdCardSize.getText().trim();
if (value.length() > 0) {
sdName = value;
// add the unit
switch (mSdCardSizeCombo.getSelectionIndex()) {
case 0:
sdName += "K";
break;
case 1:
sdName += "M";
break;
default:
// shouldn't be here
assert false;
}
}
} else {
// file mode.
sdName = mSdCardFile.getText().trim();
}
// get the Skin data from the UI
String skinName = null; String skinName = null;
if (skinIndex > 0) { if (mSkinListRadio.getSelection()) {
// index 0 is the default, we don't use it // built-in list provides the skin
skinName = mSkinCombo.getItem(skinIndex); int skinIndex = mSkinCombo.getSelectionIndex();
if (skinIndex > 0) {
// index 0 is the default, we don't use it
skinName = mSkinCombo.getItem(skinIndex);
}
} else {
// size mode. get both size and writes it as a skin name
// thanks to validatePage() we know the content of the fields is correct
skinName = mSkinSizeWidth.getText() + "x" + mSkinSizeHeight.getText(); //$NON-NLS-1$
} }
SdkLog log = new SdkLog(String.format("Result of creating AVD '%s':", avdName), SdkLog log = new SdkLog(String.format("Result of creating AVD '%s':", avdName),
@@ -440,6 +624,8 @@ final class AvdCreationDialog extends Dialog {
return false; return false;
} }
boolean force = mForceCreation.getSelection();
boolean success = false; boolean success = false;
AvdInfo avdInfo = mAvdManager.createAvd( AvdInfo avdInfo = mAvdManager.createAvd(
avdFolder, avdFolder,
@@ -454,7 +640,6 @@ final class AvdCreationDialog extends Dialog {
success = avdInfo != null; success = avdInfo != null;
log.displayResult(success); log.displayResult(success);
return success; return success;
} }
} }