diff options
Diffstat (limited to 'src/plugins/emulator/src/com/motorola/studio/android/emulator/core/emulationui/SrcDestComposite.java')
-rw-r--r-- | src/plugins/emulator/src/com/motorola/studio/android/emulator/core/emulationui/SrcDestComposite.java | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/src/plugins/emulator/src/com/motorola/studio/android/emulator/core/emulationui/SrcDestComposite.java b/src/plugins/emulator/src/com/motorola/studio/android/emulator/core/emulationui/SrcDestComposite.java new file mode 100644 index 0000000..a70194e --- /dev/null +++ b/src/plugins/emulator/src/com/motorola/studio/android/emulator/core/emulationui/SrcDestComposite.java @@ -0,0 +1,439 @@ +/* +* Copyright (C) 2012 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.motorola.studio.android.emulator.core.emulationui; + +import static com.motorola.studio.android.common.log.StudioLogger.debug; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.FontMetrics; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; + +import com.motorola.studio.android.emulator.core.devfrm.DeviceFrameworkManager; +import com.motorola.studio.android.emulator.core.model.IAndroidEmulatorInstance; +import com.motorola.studio.android.emulator.i18n.EmulatorNLS; + +/** + * DESCRIPTION: + * This is a composite that is used by several emulation UI elements to choose source and + * destination elements + * + * RESPONSIBILITY: + * Provide means for the user to choose which emulator and phone number will be involved + * in a emulation + * + * COLABORATORS: + * None. + * + * USAGE: + * Add the composite to a UI element that needs to have a emulator and a phone number + * chosen by the user + */ +public class SrcDestComposite extends Composite +{ + /** + * Message that will be shown near the emulator combo + */ + private String emulatorLabelStr; + + /** + * Message that will be shown near the phone number text field + */ + private String phoneNumberLabelStr; + + /** + * Emulator currently selected + */ + private String selectedEmulator; + + /** + * Phone number currently selected + */ + private String selectedPhoneNumber; + + /** + * True if the composite is valid and can provide information to the user class + * False if not. + */ + private boolean isValid = false; + + /** + * Error message to be shown to the user if the composite data is not valid + */ + private String errorMessage = + NLS.bind(EmulatorNLS.ERR_SrcDestComposite_InvalidFillingBase, + EmulatorNLS.ERR_SrcDestComposite_InvalidFillingPhoneNumber, + EmulatorNLS.ERR_SrcDestComposite_InvalidFillingEmulator); + + // Widgets + private Combo runningEmulatorsCombo; + + private Text phoneNumberText; + + // attribute for calculating label sizes (for layout purposes) + private FontMetrics fontMetrics = null; + + /** + * Constructor. + * + * @param parent The parent composite of this one + * @param style Style of the composite. See constants at SWT class + * @param showSrcControls True if this composite should show + * the emulation source controls. False otherwise + * @param isEmulatorSrc True if this composite will have the emulator + * part as source in emulation. False if the phone number + * will be the source + */ + public SrcDestComposite(Composite parent, int style, boolean showSrcControls, + boolean isEmulatorSrc) + { + super(parent, style); + + GridLayout layout = new GridLayout(2, false); + layout.marginHeight = 5; + layout.marginWidth = 5; + layout.verticalSpacing = 5; + layout.horizontalSpacing = 2; + this.setLayout(layout); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); + this.setLayoutData(data); + + // initialize font metrics + GC gc = new GC(this); + gc.setFont(this.getFont()); + fontMetrics = gc.getFontMetrics(); + gc.dispose(); + + if (isEmulatorSrc) + { + // When emulator is the source part, its UI is build prior to phone number UI, + // and appropriate labels are used for both + debug("Using emulator as source"); + emulatorLabelStr = EmulatorNLS.UI_SrcDestComposite_OriginatingRunningEmulatorLabel; + phoneNumberLabelStr = EmulatorNLS.UI_SrcDestComposite_DestinationPhoneNumberLabel; + if (showSrcControls) + { + debug("Showing source controls"); + createEmulatorUI(); + } + createPhoneNumberUI(); + } + else + { + // When phone number is the source part, its UI is build prior to emulator UI, + // and appropriate labels are used for both + debug("Using phone number as source"); + emulatorLabelStr = EmulatorNLS.UI_SrcDestComposite_DestinationRunningEmulatorLabel; + phoneNumberLabelStr = EmulatorNLS.UI_SrcDestComposite_OriginatingPhoneNumberLabel; + if (showSrcControls) + { + debug("Showing source controls"); + createPhoneNumberUI(); + } + createEmulatorUI(); + } + + addListeners(); + + // call the check method to refresh error message. + checkData(); + + } + + /** + * Build the emulator part controls + */ + private void createEmulatorUI() + { + + Label runningEmulatorsLabel = new Label(this, SWT.NONE); + runningEmulatorsLabel.setText(emulatorLabelStr); + GridData data = new GridData(SWT.FILL, SWT.CENTER, false, false); + data.widthHint = getLabelWidthHint(runningEmulatorsLabel); + runningEmulatorsLabel.setLayoutData(data); + + this.runningEmulatorsCombo = new Combo(this, SWT.BORDER | SWT.READ_ONLY); + data = new GridData(SWT.FILL, SWT.FILL, true, false); + this.runningEmulatorsCombo.setLayoutData(data); + populateEmulatorCombo(); + + } + + /** + * Build the phone number part controls + */ + private void createPhoneNumberUI() + { + + Label phoneNumberLabel = new Label(this, SWT.NONE); + phoneNumberLabel.setText(phoneNumberLabelStr); + GridData data = new GridData(SWT.FILL, SWT.CENTER, false, false); + data.widthHint = getLabelWidthHint(phoneNumberLabel); + phoneNumberLabel.setLayoutData(data); + + this.phoneNumberText = new Text(this, SWT.BORDER); + data = new GridData(SWT.FILL, SWT.FILL, true, false); + this.phoneNumberText.setLayoutData(data); + this.phoneNumberText.setTextLimit(40); + + } + + /** + * Add listeners to the composite controls + */ + private void addListeners() + { + + if (runningEmulatorsCombo != null) + { + runningEmulatorsCombo.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + selectedEmulator = getCurrentlySelectedIdentifier(); + checkData(); + } + }); + } + + if (phoneNumberText != null) + { + phoneNumberText.addModifyListener(new ModifyListener() + { + public void modifyText(ModifyEvent e) + { + selectedPhoneNumber = phoneNumberText.getText(); + checkData(); + } + }); + } + } + + /** + * Defines the width hint to be used for the given label on a GridData object. + * + * @param label the label to calculate the width hint for + * + * @return the width hint + */ + private int getLabelWidthHint(Label label) + { + int widthHint = Dialog.convertHorizontalDLUsToPixels(fontMetrics, label.getText().length()); + return Math.max(widthHint, label.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x); + } + + /** + * Populates the emulator combo box with the currently running emulators + */ + private void populateEmulatorCombo() + { + + // Populating emulator combo with all running emulator names + // Besides, keeping an array of the identifiers as combo data. + Map<String, String> identifiersAndNames = new HashMap<String, String>(); + Collection<IAndroidEmulatorInstance> startedInstances = + DeviceFrameworkManager.getInstance().getAllStartedInstances(); + for (IAndroidEmulatorInstance instance : startedInstances) + { + identifiersAndNames.put(instance.getInstanceIdentifier(), instance.getName()); + } + + String[] instanceNamesArray = new String[identifiersAndNames.size()]; + String[] identifiersArray = new String[identifiersAndNames.size()]; + int i = 0; + + Set<String> identifiers = identifiersAndNames.keySet(); + for (String identifier : identifiers) + { + + String viewerName = identifiersAndNames.get(identifier); + + // It is VERY important that the index used at the data array is equal to the + // index used at the items array. According to the selected item in the combo, the + // corresponding identifier is retrieved from the data array in the future + instanceNamesArray[i] = viewerName; + identifiersArray[i] = identifier; + i++; + } + + runningEmulatorsCombo.setItems(instanceNamesArray); + runningEmulatorsCombo.setData(identifiersArray); + + // if there is just one emulator in the combo list, + // it will be chose by default. + if (runningEmulatorsCombo.getItemCount() == 1) + { + runningEmulatorsCombo.select(0); + selectedEmulator = getCurrentlySelectedIdentifier(); + checkData(); + } + + } + + /** + * Retrieve the identifier of the selected instance at Android Emulator combo box + * + * @return The identifier, or an empty string if no emulator is selected + */ + private String getCurrentlySelectedIdentifier() + { + + String currentlySelectedSerial = ""; + int index = runningEmulatorsCombo.getSelectionIndex(); + + if (index >= 0) + { + String[] serials = (String[]) runningEmulatorsCombo.getData(); + currentlySelectedSerial = serials[index]; + + } + + return currentlySelectedSerial; + } + + /** + * Get the emulator identifier that was selected by the user + * + * @return The selected emulator identifier + */ + public String getSelectedEmulator() + { + return selectedEmulator; + } + + /** + * Get the phone number that was typed by the user + * + * @return The phone number typed by the user + */ + public String getSelectedPhoneNumber() + { + return selectedPhoneNumber; + } + + /** + * Tests if the values chosen/typed by the user are valid + * By invoking this method, the user class is able to know if it can proceed + * + * @return True if the user has chosen valid values. False otherwise + */ + public boolean isValid() + { + return isValid; + } + + /** + * Retrieves the error message to be shown to the user if the composite is + * not valid + * + * @return The error message if the composite is not valid, or <code>null</code> if + * the composite is valid and no error message should be displayed. + */ + public String getErrorMessage() + { + return errorMessage; + } + + /** + * Check if the data entered by the user is correct and set instance variables + * to store the test results + */ + private void checkData() + { + + isValid = false; + + boolean isEmulatorValid = false; + boolean isPhoneNumberValid = false; + + boolean isUsingPhoneNumber = (phoneNumberText != null); + boolean isUsingEmulator = (runningEmulatorsCombo != null); + + // Tests if emulator selection is valid. + // + // If the emulator combo is null, that means that the user decided not to use it. In + // this case, it will always be valid. Otherwise, the combo selection needs to be + // not null and not blank + if ((!isUsingEmulator) || ((selectedEmulator != null) && (!selectedEmulator.equals("")))) + { + isEmulatorValid = true; + } + + // Tests if phone number selection is valid. + // + // If the phone number text is null, that means that the user decided not to use it. In + // this case, it will always be valid. Otherwise, the text field selection needs to be + // not null, not blank and can be parsed to double (that means that the contents are + // composed by numerals only) + if (!isUsingPhoneNumber) + { + isPhoneNumberValid = true; + } + else if ((selectedPhoneNumber != null) && (!selectedPhoneNumber.equals(""))) + { + Pattern p = Pattern.compile("(\\d)+"); + Matcher m = p.matcher(selectedPhoneNumber); + isPhoneNumberValid = m.matches(); + } + + // Based on previous checks, determine if the composite state is valid + if (isEmulatorValid && isPhoneNumberValid) + { + isValid = true; + errorMessage = null; + } + else + { + // If not valid, an error message will be shown. The following calculations + // are for determining which error has happened to build the message + String phoneNumberError = ""; + String emulatorError = ""; + + if (isUsingPhoneNumber && (!isPhoneNumberValid)) + { + phoneNumberError = EmulatorNLS.ERR_SrcDestComposite_InvalidFillingPhoneNumber; + } + if (isUsingEmulator && (!isEmulatorValid)) + { + emulatorError = EmulatorNLS.ERR_SrcDestComposite_InvalidFillingEmulator; + } + + errorMessage = + NLS.bind(EmulatorNLS.ERR_SrcDestComposite_InvalidFillingBase, + phoneNumberError, emulatorError); + } + + } +} |