Home | History | Annotate | Download | only in ui
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Eclipse Public License, Version 1.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.eclipse.org/org/documents/epl-v10.php
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.ide.eclipse.adt.internal.ui;
     18 
     19 import com.android.AndroidConstants;
     20 import com.android.ide.common.resources.configuration.CountryCodeQualifier;
     21 import com.android.ide.common.resources.configuration.DensityQualifier;
     22 import com.android.ide.common.resources.configuration.FolderConfiguration;
     23 import com.android.ide.common.resources.configuration.KeyboardStateQualifier;
     24 import com.android.ide.common.resources.configuration.LanguageQualifier;
     25 import com.android.ide.common.resources.configuration.NavigationMethodQualifier;
     26 import com.android.ide.common.resources.configuration.NavigationStateQualifier;
     27 import com.android.ide.common.resources.configuration.NetworkCodeQualifier;
     28 import com.android.ide.common.resources.configuration.NightModeQualifier;
     29 import com.android.ide.common.resources.configuration.RegionQualifier;
     30 import com.android.ide.common.resources.configuration.ResourceQualifier;
     31 import com.android.ide.common.resources.configuration.ScreenDimensionQualifier;
     32 import com.android.ide.common.resources.configuration.ScreenHeightQualifier;
     33 import com.android.ide.common.resources.configuration.ScreenOrientationQualifier;
     34 import com.android.ide.common.resources.configuration.ScreenRatioQualifier;
     35 import com.android.ide.common.resources.configuration.ScreenSizeQualifier;
     36 import com.android.ide.common.resources.configuration.ScreenWidthQualifier;
     37 import com.android.ide.common.resources.configuration.SmallestScreenWidthQualifier;
     38 import com.android.ide.common.resources.configuration.TextInputMethodQualifier;
     39 import com.android.ide.common.resources.configuration.TouchScreenQualifier;
     40 import com.android.ide.common.resources.configuration.UiModeQualifier;
     41 import com.android.ide.common.resources.configuration.VersionQualifier;
     42 import com.android.ide.eclipse.adt.internal.resources.ResourceHelper;
     43 import com.android.resources.Density;
     44 import com.android.resources.Keyboard;
     45 import com.android.resources.KeyboardState;
     46 import com.android.resources.Navigation;
     47 import com.android.resources.NavigationState;
     48 import com.android.resources.NightMode;
     49 import com.android.resources.ResourceEnum;
     50 import com.android.resources.ScreenOrientation;
     51 import com.android.resources.ScreenRatio;
     52 import com.android.resources.ScreenSize;
     53 import com.android.resources.TouchScreen;
     54 import com.android.resources.UiMode;
     55 
     56 import org.eclipse.jface.viewers.ILabelProviderListener;
     57 import org.eclipse.jface.viewers.ISelection;
     58 import org.eclipse.jface.viewers.ISelectionChangedListener;
     59 import org.eclipse.jface.viewers.IStructuredContentProvider;
     60 import org.eclipse.jface.viewers.IStructuredSelection;
     61 import org.eclipse.jface.viewers.ITableLabelProvider;
     62 import org.eclipse.jface.viewers.SelectionChangedEvent;
     63 import org.eclipse.jface.viewers.StructuredSelection;
     64 import org.eclipse.jface.viewers.TableViewer;
     65 import org.eclipse.jface.viewers.Viewer;
     66 import org.eclipse.swt.SWT;
     67 import org.eclipse.swt.custom.StackLayout;
     68 import org.eclipse.swt.events.ControlAdapter;
     69 import org.eclipse.swt.events.ControlEvent;
     70 import org.eclipse.swt.events.FocusAdapter;
     71 import org.eclipse.swt.events.FocusEvent;
     72 import org.eclipse.swt.events.ModifyEvent;
     73 import org.eclipse.swt.events.ModifyListener;
     74 import org.eclipse.swt.events.SelectionAdapter;
     75 import org.eclipse.swt.events.SelectionEvent;
     76 import org.eclipse.swt.events.SelectionListener;
     77 import org.eclipse.swt.events.VerifyEvent;
     78 import org.eclipse.swt.events.VerifyListener;
     79 import org.eclipse.swt.graphics.Image;
     80 import org.eclipse.swt.graphics.Rectangle;
     81 import org.eclipse.swt.layout.GridData;
     82 import org.eclipse.swt.layout.GridLayout;
     83 import org.eclipse.swt.widgets.Button;
     84 import org.eclipse.swt.widgets.Combo;
     85 import org.eclipse.swt.widgets.Composite;
     86 import org.eclipse.swt.widgets.Label;
     87 import org.eclipse.swt.widgets.Table;
     88 import org.eclipse.swt.widgets.TableColumn;
     89 import org.eclipse.swt.widgets.Text;
     90 
     91 import java.util.ArrayList;
     92 import java.util.HashMap;
     93 
     94 /**
     95  * Custom UI widget to let user build a Folder configuration.
     96  * <p/>
     97  * To use this, instantiate somewhere in the UI and then:
     98  * <ul>
     99  * <li>Use {@link #setConfiguration(String)} or {@link #setConfiguration(FolderConfiguration)}.
    100  * <li>Retrieve the configuration using {@link #getConfiguration(FolderConfiguration)}.
    101  * </ul>
    102  */
    103 public class ConfigurationSelector extends Composite {
    104 
    105     public static final int WIDTH_HINT = 600;
    106     public static final int HEIGHT_HINT = 250;
    107 
    108     private Runnable mOnChangeListener;
    109 
    110     private TableViewer mFullTableViewer;
    111     private TableViewer mSelectionTableViewer;
    112     private Button mAddButton;
    113     private Button mRemoveButton;
    114     private StackLayout mStackLayout;
    115 
    116     private boolean mOnRefresh = false;
    117 
    118     private final FolderConfiguration mBaseConfiguration = new FolderConfiguration();
    119     private final FolderConfiguration mSelectedConfiguration = new FolderConfiguration();
    120 
    121     private final HashMap<Class<? extends ResourceQualifier>, QualifierEditBase> mUiMap =
    122         new HashMap<Class<? extends ResourceQualifier>, QualifierEditBase>();
    123     private final SelectorMode mMode;
    124     private Composite mQualifierEditParent;
    125     private IQualifierFilter mQualifierFilter;
    126 
    127     /**
    128      * Basic of {@link VerifyListener} to only accept digits.
    129      */
    130     private static class DigitVerifier implements VerifyListener {
    131         public void verifyText(VerifyEvent e) {
    132             // check for digit only.
    133             for (int i = 0 ; i < e.text.length(); i++) {
    134                 char letter = e.text.charAt(i);
    135                 if (letter < '0' || letter > '9') {
    136                     e.doit = false;
    137                     return;
    138                 }
    139             }
    140         }
    141     }
    142 
    143     /**
    144      * Implementation of {@link VerifyListener} for Country Code qualifiers.
    145      */
    146     public static class MobileCodeVerifier extends DigitVerifier {
    147         @Override
    148         public void verifyText(VerifyEvent e) {
    149             super.verifyText(e);
    150 
    151             // basic tests passed?
    152             if (e.doit) {
    153                 // check the max 3 digits.
    154                 if (e.text.length() - e.end + e.start +
    155                         ((Text)e.getSource()).getText().length() > 3) {
    156                     e.doit = false;
    157                 }
    158             }
    159         }
    160     }
    161 
    162     /**
    163      * Implementation of {@link VerifyListener} for the Language and Region qualifiers.
    164      */
    165     public static class LanguageRegionVerifier implements VerifyListener {
    166         public void verifyText(VerifyEvent e) {
    167             // check for length
    168             if (e.text.length() - e.end + e.start + ((Combo)e.getSource()).getText().length() > 2) {
    169                 e.doit = false;
    170                 return;
    171             }
    172 
    173             // check for lower case only.
    174             for (int i = 0 ; i < e.text.length(); i++) {
    175                 char letter = e.text.charAt(i);
    176                 if ((letter < 'a' || letter > 'z') && (letter < 'A' || letter > 'Z')) {
    177                     e.doit = false;
    178                     return;
    179                 }
    180             }
    181         }
    182     }
    183 
    184     /**
    185      * Implementation of {@link VerifyListener} for the Density qualifier.
    186      */
    187     public static class DensityVerifier extends DigitVerifier { }
    188 
    189     /**
    190      * Implementation of {@link VerifyListener} for the Screen Dimension qualifier.
    191      */
    192     public static class DimensionVerifier extends DigitVerifier { }
    193 
    194     /**
    195      * Enum for the state of the configuration being created.
    196      */
    197     public enum ConfigurationState {
    198         OK, INVALID_CONFIG, REGION_WITHOUT_LANGUAGE;
    199     }
    200 
    201     /**
    202      * Behavior mode for the Selector.
    203      *
    204      * @see #DEFAULT
    205      * @see #DEVICE_ONLY
    206      * @see #CONFIG_ONLY
    207      */
    208     public enum SelectorMode {
    209         /** the default mode */
    210         DEFAULT,
    211         /** mode forcing the qualifier values to be valid on a device.
    212          * For instance {@link Density#NODPI} is a valid qualifier for a resource configuration but
    213          * this is not valid on a device */
    214         DEVICE_ONLY,
    215         /** mode where only the specific config can be edited. The user can only select
    216          * which non-empty qualifier to select. */
    217         CONFIG_ONLY;
    218     }
    219 
    220     /**
    221      * A filter for {@link ResourceQualifier}.
    222      * @see ConfigurationSelector#setQualifierFilter(IQualifierFilter)
    223      */
    224     public interface IQualifierFilter {
    225         /**
    226          * Returns true of the qualifier is accepted.
    227          */
    228         boolean accept(ResourceQualifier qualifier);
    229     }
    230 
    231     /**
    232      * Creates the selector.
    233      * <p/>
    234      * The {@link SelectorMode} changes the behavior of the selector depending on what is being
    235      * edited (a device config, a resource config, a given configuration).
    236      *
    237      * @param parent the composite parent.
    238      * @param mode the mode for the selector.
    239      */
    240     public ConfigurationSelector(Composite parent, SelectorMode mode) {
    241         super(parent, SWT.NONE);
    242 
    243         mMode  = mode;
    244         mBaseConfiguration.createDefault();
    245 
    246         GridLayout gl = new GridLayout(4, false);
    247         gl.marginWidth = gl.marginHeight = 0;
    248         setLayout(gl);
    249 
    250         // first column is the first table
    251         final Table fullTable = new Table(this, SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER);
    252         fullTable.setLayoutData(new GridData(GridData.FILL_BOTH));
    253         fullTable.setHeaderVisible(true);
    254         fullTable.setLinesVisible(true);
    255 
    256         // create the column
    257         final TableColumn fullTableColumn = new TableColumn(fullTable, SWT.LEFT);
    258         // set the header
    259         fullTableColumn.setText("Available Qualifiers");
    260 
    261         fullTable.addControlListener(new ControlAdapter() {
    262             @Override
    263             public void controlResized(ControlEvent e) {
    264                 Rectangle r = fullTable.getClientArea();
    265                 fullTableColumn.setWidth(r.width);
    266             }
    267         });
    268 
    269         mFullTableViewer = new TableViewer(fullTable);
    270         mFullTableViewer.setContentProvider(new QualifierContentProvider());
    271         // the label provider must return the value of the label only if the mode is
    272         // CONFIG_ONLY
    273         mFullTableViewer.setLabelProvider(new QualifierLabelProvider(
    274                 mMode == SelectorMode.CONFIG_ONLY));
    275         mFullTableViewer.setInput(mBaseConfiguration);
    276         mFullTableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
    277             public void selectionChanged(SelectionChangedEvent event) {
    278                 ISelection selection = event.getSelection();
    279                 if (selection instanceof IStructuredSelection) {
    280                     IStructuredSelection structSelection = (IStructuredSelection)selection;
    281                     Object first = structSelection.getFirstElement();
    282 
    283                     if (first instanceof ResourceQualifier) {
    284                         mAddButton.setEnabled(true);
    285                         return;
    286                     }
    287                 }
    288 
    289                 mAddButton.setEnabled(false);
    290             }
    291         });
    292 
    293         // 2nd column is the left/right arrow button
    294         Composite buttonComposite = new Composite(this, SWT.NONE);
    295         gl = new GridLayout(1, false);
    296         gl.marginWidth = gl.marginHeight = 0;
    297         buttonComposite.setLayout(gl);
    298         buttonComposite.setLayoutData(new GridData(GridData.FILL_VERTICAL));
    299 
    300         new Composite(buttonComposite, SWT.NONE);
    301         mAddButton = new Button(buttonComposite, SWT.BORDER | SWT.PUSH);
    302         mAddButton.setText("->");
    303         mAddButton.setEnabled(false);
    304         mAddButton.addSelectionListener(new SelectionAdapter() {
    305             @Override
    306             public void widgetSelected(SelectionEvent e) {
    307                 IStructuredSelection selection =
    308                     (IStructuredSelection)mFullTableViewer.getSelection();
    309 
    310                 Object first = selection.getFirstElement();
    311                 if (first instanceof ResourceQualifier) {
    312                     ResourceQualifier qualifier = (ResourceQualifier)first;
    313 
    314                     mBaseConfiguration.removeQualifier(qualifier);
    315                     mSelectedConfiguration.addQualifier(qualifier);
    316 
    317                     mFullTableViewer.refresh();
    318                     mSelectionTableViewer.refresh();
    319                     mSelectionTableViewer.setSelection(new StructuredSelection(qualifier), true);
    320 
    321                     onChange(false /* keepSelection */);
    322                 }
    323             }
    324         });
    325 
    326         mRemoveButton = new Button(buttonComposite, SWT.BORDER | SWT.PUSH);
    327         mRemoveButton.setText("<-");
    328         mRemoveButton.setEnabled(false);
    329         mRemoveButton.addSelectionListener(new SelectionAdapter() {
    330             @Override
    331             public void widgetSelected(SelectionEvent e) {
    332                 IStructuredSelection selection =
    333                     (IStructuredSelection)mSelectionTableViewer.getSelection();
    334 
    335                 Object first = selection.getFirstElement();
    336                 if (first instanceof ResourceQualifier) {
    337                     ResourceQualifier qualifier = (ResourceQualifier)first;
    338 
    339                     mSelectedConfiguration.removeQualifier(qualifier);
    340                     mBaseConfiguration.addQualifier(qualifier);
    341 
    342                     mFullTableViewer.refresh();
    343                     mSelectionTableViewer.refresh();
    344 
    345                     onChange(false /* keepSelection */);
    346                 }
    347             }
    348         });
    349 
    350         // 3rd column is the selected config table
    351         final Table selectionTable = new Table(this, SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER);
    352         selectionTable.setLayoutData(new GridData(GridData.FILL_BOTH));
    353         selectionTable.setHeaderVisible(true);
    354         selectionTable.setLinesVisible(true);
    355 
    356         // create the column
    357         final TableColumn selectionTableColumn = new TableColumn(selectionTable, SWT.LEFT);
    358         // set the header
    359         selectionTableColumn.setText("Chosen Qualifiers");
    360 
    361         selectionTable.addControlListener(new ControlAdapter() {
    362             @Override
    363             public void controlResized(ControlEvent e) {
    364                 Rectangle r = selectionTable.getClientArea();
    365                 selectionTableColumn.setWidth(r.width);
    366             }
    367         });
    368         mSelectionTableViewer = new TableViewer(selectionTable);
    369         mSelectionTableViewer.setContentProvider(new QualifierContentProvider());
    370         // always show the qualifier value in this case.
    371         mSelectionTableViewer.setLabelProvider(new QualifierLabelProvider(
    372                 true /* showQualifierValue */));
    373         mSelectionTableViewer.setInput(mSelectedConfiguration);
    374         mSelectionTableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
    375             public void selectionChanged(SelectionChangedEvent event) {
    376                 // ignore selection changes during resfreshes in some cases.
    377                 if (mOnRefresh) {
    378                     return;
    379                 }
    380 
    381                 ISelection selection = event.getSelection();
    382                 if (selection instanceof IStructuredSelection) {
    383                     IStructuredSelection structSelection = (IStructuredSelection)selection;
    384 
    385                     if (structSelection.isEmpty() == false) {
    386                         Object first = structSelection.getFirstElement();
    387 
    388                         if (first instanceof ResourceQualifier) {
    389                             mRemoveButton.setEnabled(true);
    390 
    391                             if (mMode != SelectorMode.CONFIG_ONLY) {
    392                                 QualifierEditBase composite = mUiMap.get(first.getClass());
    393 
    394                                 if (composite != null) {
    395                                     composite.setQualifier((ResourceQualifier)first);
    396                                 }
    397 
    398                                 mStackLayout.topControl = composite;
    399                                 mQualifierEditParent.layout();
    400                             }
    401 
    402                             return;
    403                         }
    404                     } else {
    405                         if (mMode != SelectorMode.CONFIG_ONLY) {
    406                             mStackLayout.topControl = null;
    407                             mQualifierEditParent.layout();
    408                         }
    409                     }
    410                 }
    411 
    412                 mRemoveButton.setEnabled(false);
    413             }
    414         });
    415 
    416         if (mMode != SelectorMode.CONFIG_ONLY) {
    417             // 4th column is the detail of the selected qualifier
    418             mQualifierEditParent = new Composite(this, SWT.NONE);
    419             mQualifierEditParent.setLayout(mStackLayout = new StackLayout());
    420             mQualifierEditParent.setLayoutData(new GridData(GridData.FILL_VERTICAL));
    421 
    422             // create the UI for all the qualifiers, and associate them to the
    423             // ResourceQualifer class.
    424             mUiMap.put(CountryCodeQualifier.class, new MCCEdit(mQualifierEditParent));
    425             mUiMap.put(NetworkCodeQualifier.class, new MNCEdit(mQualifierEditParent));
    426             mUiMap.put(LanguageQualifier.class, new LanguageEdit(mQualifierEditParent));
    427             mUiMap.put(RegionQualifier.class, new RegionEdit(mQualifierEditParent));
    428             mUiMap.put(SmallestScreenWidthQualifier.class,
    429                     new SmallestScreenWidthEdit(mQualifierEditParent));
    430             mUiMap.put(ScreenWidthQualifier.class, new ScreenWidthEdit(mQualifierEditParent));
    431             mUiMap.put(ScreenHeightQualifier.class, new ScreenHeightEdit(mQualifierEditParent));
    432             mUiMap.put(ScreenSizeQualifier.class, new ScreenSizeEdit(mQualifierEditParent));
    433             mUiMap.put(ScreenRatioQualifier.class, new ScreenRatioEdit(mQualifierEditParent));
    434             mUiMap.put(ScreenOrientationQualifier.class, new OrientationEdit(mQualifierEditParent));
    435             mUiMap.put(UiModeQualifier.class, new UiModeEdit(mQualifierEditParent));
    436             mUiMap.put(NightModeQualifier.class, new NightModeEdit(mQualifierEditParent));
    437             mUiMap.put(DensityQualifier.class, new DensityEdit(mQualifierEditParent));
    438             mUiMap.put(TouchScreenQualifier.class, new TouchEdit(mQualifierEditParent));
    439             mUiMap.put(KeyboardStateQualifier.class, new KeyboardEdit(mQualifierEditParent));
    440             mUiMap.put(TextInputMethodQualifier.class, new TextInputEdit(mQualifierEditParent));
    441             mUiMap.put(NavigationStateQualifier.class,
    442                     new NavigationStateEdit(mQualifierEditParent));
    443             mUiMap.put(NavigationMethodQualifier.class, new NavigationEdit(mQualifierEditParent));
    444             mUiMap.put(ScreenDimensionQualifier.class,
    445                     new ScreenDimensionEdit(mQualifierEditParent));
    446             mUiMap.put(VersionQualifier.class, new VersionEdit(mQualifierEditParent));
    447         }
    448     }
    449 
    450     /**
    451      * Sets a {@link IQualifierFilter}. If non null, this will restrict the qualifiers that
    452      * can be chosen.
    453      * @param filter the filter to set.
    454      */
    455     public void setQualifierFilter(IQualifierFilter filter) {
    456         mQualifierFilter = filter;
    457     }
    458 
    459     /**
    460      * Sets a listener to be notified when the configuration changes.
    461      * @param listener A {@link Runnable} whose <code>run()</code> method is called when the
    462      * configuration is changed. The method is called from the UI thread.
    463      */
    464     public void setOnChangeListener(Runnable listener) {
    465         mOnChangeListener = listener;
    466     }
    467 
    468     /**
    469      * Initialize the UI with a given {@link FolderConfiguration}. This must
    470      * be called from the UI thread.
    471      * @param config The configuration.
    472      */
    473     public void setConfiguration(FolderConfiguration config) {
    474 
    475         if (mMode != SelectorMode.CONFIG_ONLY) {
    476             mSelectedConfiguration.set(config, true /*nonFakeValuesOnly*/);
    477 
    478             // create the base config, which is the default config minus the qualifiers
    479             // in SelectedConfiguration
    480             mBaseConfiguration.substract(mSelectedConfiguration);
    481         } else {
    482             // set the base config to the edited config.
    483             // reset the config to be empty
    484             mBaseConfiguration.reset();
    485             mBaseConfiguration.set(config, true /*nonFakeValuesOnly*/);
    486         }
    487 
    488         mSelectionTableViewer.refresh();
    489         mFullTableViewer.refresh();
    490     }
    491 
    492     /**
    493      * Initialize the UI with the configuration represented by a resource folder name.
    494      * This must be called from the UI thread.
    495      *
    496      * @param folderSegments the segments of the folder name,
    497      *                       split using {@link FolderConfiguration#QUALIFIER_SEP}.
    498      * @return true if success, or false if the folder name is not a valid name.
    499      */
    500     public boolean setConfiguration(String[] folderSegments) {
    501         FolderConfiguration config = FolderConfiguration.getConfig(folderSegments);
    502 
    503         if (config == null) {
    504             return false;
    505         }
    506 
    507         setConfiguration(config);
    508 
    509         return true;
    510     }
    511 
    512     /**
    513      * Initialize the UI with the configuration represented by a resource folder name.
    514      * This must be called from the UI thread.
    515      * @param folderName the name of the folder.
    516      * @return true if success, or false if the folder name is not a valid name.
    517      */
    518     public boolean setConfiguration(String folderName) {
    519         // split the name of the folder in segments.
    520         String[] folderSegments = folderName.split(AndroidConstants.RES_QUALIFIER_SEP);
    521 
    522         return setConfiguration(folderSegments);
    523     }
    524 
    525     /**
    526      * Gets the configuration as setup by the widget.
    527      * @param config the {@link FolderConfiguration} object to be filled with the information
    528      * from the UI.
    529      */
    530     public void getConfiguration(FolderConfiguration config) {
    531         config.set(mSelectedConfiguration);
    532     }
    533 
    534     /**
    535      * Returns the state of the configuration being edited/created.
    536      */
    537     public ConfigurationState getState() {
    538         if (mSelectedConfiguration.getInvalidQualifier() != null) {
    539             return ConfigurationState.INVALID_CONFIG;
    540         }
    541 
    542         if (mSelectedConfiguration.checkRegion() == false) {
    543             return ConfigurationState.REGION_WITHOUT_LANGUAGE;
    544         }
    545 
    546         return ConfigurationState.OK;
    547     }
    548 
    549     /**
    550      * Returns the first invalid qualifier of the configuration being edited/created,
    551      * or <code>null<code> if they are all valid (or if none exists).
    552      * <p/>If {@link #getState()} return {@link ConfigurationState#INVALID_CONFIG} then this will
    553      * not return <code>null</code>.
    554      */
    555     public ResourceQualifier getInvalidQualifier() {
    556         return mSelectedConfiguration.getInvalidQualifier();
    557     }
    558 
    559     /**
    560      * Handle changes in the configuration.
    561      * @param keepSelection if <code>true</code> attemps to avoid triggering selection change in
    562      * {@link #mSelectedConfiguration}.
    563      */
    564     private void onChange(boolean keepSelection) {
    565         ISelection selection = null;
    566         if (keepSelection) {
    567             mOnRefresh = true;
    568             selection = mSelectionTableViewer.getSelection();
    569         }
    570 
    571         mSelectionTableViewer.refresh(true);
    572 
    573         if (keepSelection) {
    574             mSelectionTableViewer.setSelection(selection);
    575             mOnRefresh = false;
    576         }
    577 
    578         if (mOnChangeListener != null) {
    579             mOnChangeListener.run();
    580         }
    581     }
    582 
    583     private void fillCombo(Combo combo, ResourceEnum[] resEnums) {
    584         for (ResourceEnum resEnum : resEnums) {
    585             // only add the enum if:
    586             // not in device mode OR (device mode is true and) it's a valid device value.
    587             // Also, always ignore fake values.
    588             if ((mMode == SelectorMode.DEFAULT || resEnum.isValidValueForDevice()) &&
    589                     resEnum.isFakeValue() == false) {
    590                 combo.add(resEnum.getShortDisplayValue());
    591             }
    592         }
    593     }
    594 
    595     /**
    596      * Content provider around a {@link FolderConfiguration}.
    597      */
    598     private class QualifierContentProvider implements IStructuredContentProvider {
    599 
    600         private FolderConfiguration mInput;
    601 
    602         public QualifierContentProvider() {
    603         }
    604 
    605         public void dispose() {
    606             // pass
    607         }
    608 
    609         public Object[] getElements(Object inputElement) {
    610             // default easy case
    611             if (mQualifierFilter == null) {
    612                 return mInput.getQualifiers();
    613             }
    614 
    615             // in this case we have to compute the list
    616             ArrayList<ResourceQualifier> list = new ArrayList<ResourceQualifier>();
    617             for (ResourceQualifier qual : mInput.getQualifiers()) {
    618                 if (mQualifierFilter.accept(qual)) {
    619                     list.add(qual);
    620                 }
    621             }
    622 
    623             return list.toArray();
    624         }
    625 
    626         public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
    627             mInput = null;
    628             if (newInput instanceof FolderConfiguration) {
    629                 mInput = (FolderConfiguration)newInput;
    630             }
    631         }
    632     }
    633 
    634     /**
    635      * Label provider for {@link ResourceQualifier} objects.
    636      */
    637     private static class QualifierLabelProvider implements ITableLabelProvider {
    638 
    639         private final boolean mShowQualifierValue;
    640 
    641         public QualifierLabelProvider(boolean showQualifierValue) {
    642             mShowQualifierValue = showQualifierValue;
    643         }
    644 
    645         public String getColumnText(Object element, int columnIndex) {
    646             // only one column, so we can ignore columnIndex
    647             if (element instanceof ResourceQualifier) {
    648                 if (mShowQualifierValue) {
    649                     String value = ((ResourceQualifier)element).getShortDisplayValue();
    650                     if (value.length() == 0) {
    651                         return String.format("%1$s (?)",
    652                                 ((ResourceQualifier)element).getShortName());
    653                     } else {
    654                         return value;
    655                     }
    656 
    657                 } else {
    658                     return ((ResourceQualifier)element).getShortName();
    659                 }
    660             }
    661 
    662             return null;
    663         }
    664 
    665         public Image getColumnImage(Object element, int columnIndex) {
    666             // only one column, so we can ignore columnIndex
    667             if (element instanceof ResourceQualifier) {
    668                 return ResourceHelper.getIcon(((ResourceQualifier)element).getClass());
    669             }
    670 
    671             return null;
    672         }
    673 
    674         public void addListener(ILabelProviderListener listener) {
    675             // pass
    676         }
    677 
    678         public void dispose() {
    679             // pass
    680         }
    681 
    682         public boolean isLabelProperty(Object element, String property) {
    683             // pass
    684             return false;
    685         }
    686 
    687         public void removeListener(ILabelProviderListener listener) {
    688             // pass
    689         }
    690     }
    691 
    692     /**
    693      * Base class for Edit widget for {@link ResourceQualifier}.
    694      */
    695     private abstract static class QualifierEditBase extends Composite {
    696 
    697         public QualifierEditBase(Composite parent, String title) {
    698             super(parent, SWT.NONE);
    699             setLayout(new GridLayout(1, false));
    700 
    701             new Label(this, SWT.NONE).setText(title);
    702         }
    703 
    704         public abstract void setQualifier(ResourceQualifier qualifier);
    705     }
    706 
    707     /**
    708      * Edit widget for {@link CountryCodeQualifier}.
    709      */
    710     private class MCCEdit extends QualifierEditBase {
    711 
    712         private Text mText;
    713 
    714         public MCCEdit(Composite parent) {
    715             super(parent, CountryCodeQualifier.NAME);
    716 
    717             mText = new Text(this, SWT.BORDER);
    718             mText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    719             mText.addVerifyListener(new MobileCodeVerifier());
    720             mText.addModifyListener(new ModifyListener() {
    721                 public void modifyText(ModifyEvent e) {
    722                     onTextChange();
    723                 }
    724             });
    725 
    726             mText.addFocusListener(new FocusAdapter() {
    727                 @Override
    728                 public void focusLost(FocusEvent e) {
    729                     onTextChange();
    730                 }
    731             });
    732 
    733             new Label(this, SWT.NONE).setText("(3 digit code)");
    734         }
    735 
    736         private void onTextChange() {
    737             String value = mText.getText();
    738 
    739             if (value.length() == 0) {
    740                 // empty string, means a qualifier with no value.
    741                 // Since the qualifier classes are immutable, and we don't want to
    742                 // remove the qualifier from the configuration, we create a new default one.
    743                 mSelectedConfiguration.setCountryCodeQualifier(new CountryCodeQualifier());
    744             } else {
    745                 try {
    746                     CountryCodeQualifier qualifier = CountryCodeQualifier.getQualifier(
    747                             CountryCodeQualifier.getFolderSegment(Integer.parseInt(value)));
    748                     if (qualifier != null) {
    749                         mSelectedConfiguration.setCountryCodeQualifier(qualifier);
    750                     } else {
    751                         // Failure! Looks like the value is wrong
    752                         // (for instance not exactly 3 digits).
    753                         mSelectedConfiguration.setCountryCodeQualifier(new CountryCodeQualifier());
    754                     }
    755                 } catch (NumberFormatException nfe) {
    756                     // Looks like the code is not a number. This should not happen since the text
    757                     // field has a VerifyListener that prevents it.
    758                     mSelectedConfiguration.setCountryCodeQualifier(new CountryCodeQualifier());
    759                 }
    760             }
    761 
    762             // notify of change
    763             onChange(true /* keepSelection */);
    764         }
    765 
    766         @Override
    767         public void setQualifier(ResourceQualifier qualifier) {
    768             CountryCodeQualifier q = (CountryCodeQualifier)qualifier;
    769 
    770             mText.setText(Integer.toString(q.getCode()));
    771         }
    772     }
    773 
    774     /**
    775      * Edit widget for {@link NetworkCodeQualifier}.
    776      */
    777     private class MNCEdit extends QualifierEditBase {
    778         private Text mText;
    779 
    780         public MNCEdit(Composite parent) {
    781             super(parent, NetworkCodeQualifier.NAME);
    782 
    783             mText = new Text(this, SWT.BORDER);
    784             mText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    785             mText.addVerifyListener(new MobileCodeVerifier());
    786             mText.addModifyListener(new ModifyListener() {
    787                 public void modifyText(ModifyEvent e) {
    788                     onTextChange();
    789                 }
    790             });
    791             mText.addFocusListener(new FocusAdapter() {
    792                 @Override
    793                 public void focusLost(FocusEvent e) {
    794                     onTextChange();
    795                 }
    796             });
    797 
    798             new Label(this, SWT.NONE).setText("(1-3 digit code)");
    799         }
    800 
    801         private void onTextChange() {
    802             String value = mText.getText();
    803 
    804             if (value.length() == 0) {
    805                 // empty string, means a qualifier with no value.
    806                 // Since the qualifier classes are immutable, and we don't want to
    807                 // remove the qualifier from the configuration, we create a new default one.
    808                 mSelectedConfiguration.setNetworkCodeQualifier(new NetworkCodeQualifier());
    809             } else {
    810                 try {
    811                     NetworkCodeQualifier qualifier = NetworkCodeQualifier.getQualifier(
    812                             NetworkCodeQualifier.getFolderSegment(Integer.parseInt(value)));
    813                     if (qualifier != null) {
    814                         mSelectedConfiguration.setNetworkCodeQualifier(qualifier);
    815                     } else {
    816                         // Failure! Looks like the value is wrong
    817                         // (for instance not exactly 3 digits).
    818                         mSelectedConfiguration.setNetworkCodeQualifier(new NetworkCodeQualifier());
    819                     }
    820                 } catch (NumberFormatException nfe) {
    821                     // Looks like the code is not a number. This should not happen since the text
    822                     // field has a VerifyListener that prevents it.
    823                     mSelectedConfiguration.setNetworkCodeQualifier(new NetworkCodeQualifier());
    824                 }
    825             }
    826 
    827             // notify of change
    828             onChange(true /* keepSelection */);
    829         }
    830 
    831         @Override
    832         public void setQualifier(ResourceQualifier qualifier) {
    833             NetworkCodeQualifier q = (NetworkCodeQualifier)qualifier;
    834 
    835             mText.setText(Integer.toString(q.getCode()));
    836         }
    837     }
    838 
    839     /**
    840      * Edit widget for {@link LanguageQualifier}.
    841      */
    842     private class LanguageEdit extends QualifierEditBase {
    843         private Combo mLanguage;
    844 
    845         public LanguageEdit(Composite parent) {
    846             super(parent, LanguageQualifier.NAME);
    847 
    848             mLanguage = new Combo(this, SWT.DROP_DOWN);
    849             mLanguage.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    850             mLanguage.addVerifyListener(new LanguageRegionVerifier());
    851             mLanguage.addSelectionListener(new SelectionListener() {
    852                 public void widgetDefaultSelected(SelectionEvent e) {
    853                     onLanguageChange();
    854                 }
    855                 public void widgetSelected(SelectionEvent e) {
    856                     onLanguageChange();
    857                 }
    858             });
    859             mLanguage.addModifyListener(new ModifyListener() {
    860                 public void modifyText(ModifyEvent e) {
    861                     onLanguageChange();
    862                 }
    863             });
    864 
    865             new Label(this, SWT.NONE).setText("(2 letter code)");
    866         }
    867 
    868         private void onLanguageChange() {
    869             // update the current config
    870             String value = mLanguage.getText();
    871 
    872             if (value.length() == 0) {
    873                 // empty string, means no qualifier.
    874                 // Since the qualifier classes are immutable, and we don't want to
    875                 // remove the qualifier from the configuration, we create a new default one.
    876                 mSelectedConfiguration.setLanguageQualifier(new LanguageQualifier());
    877             } else {
    878                 LanguageQualifier qualifier = null;
    879                 String segment = LanguageQualifier.getFolderSegment(value);
    880                 if (segment != null) {
    881                     qualifier = LanguageQualifier.getQualifier(segment);
    882                 }
    883 
    884                 if (qualifier != null) {
    885                     mSelectedConfiguration.setLanguageQualifier(qualifier);
    886                 } else {
    887                     // Failure! Looks like the value is wrong (for instance a one letter string).
    888                     mSelectedConfiguration.setLanguageQualifier(new LanguageQualifier());
    889                 }
    890             }
    891 
    892             // notify of change
    893             onChange(true /* keepSelection */);
    894         }
    895 
    896         @Override
    897         public void setQualifier(ResourceQualifier qualifier) {
    898             LanguageQualifier q = (LanguageQualifier)qualifier;
    899 
    900             String value = q.getValue();
    901             if (value != null) {
    902                 mLanguage.setText(value);
    903             }
    904         }
    905     }
    906 
    907     /**
    908      * Edit widget for {@link RegionQualifier}.
    909      */
    910     private class RegionEdit extends QualifierEditBase {
    911         private Combo mRegion;
    912 
    913         public RegionEdit(Composite parent) {
    914             super(parent, RegionQualifier.NAME);
    915 
    916             mRegion = new Combo(this, SWT.DROP_DOWN);
    917             mRegion.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    918             mRegion.addVerifyListener(new LanguageRegionVerifier());
    919             mRegion.addSelectionListener(new SelectionListener() {
    920                 public void widgetDefaultSelected(SelectionEvent e) {
    921                     onRegionChange();
    922                 }
    923                 public void widgetSelected(SelectionEvent e) {
    924                     onRegionChange();
    925                 }
    926             });
    927             mRegion.addModifyListener(new ModifyListener() {
    928                 public void modifyText(ModifyEvent e) {
    929                     onRegionChange();
    930                 }
    931             });
    932 
    933             new Label(this, SWT.NONE).setText("(2 letter code)");
    934         }
    935 
    936         private void onRegionChange() {
    937             // update the current config
    938             String value = mRegion.getText();
    939 
    940             if (value.length() == 0) {
    941                 // empty string, means no qualifier.
    942                 // Since the qualifier classes are immutable, and we don't want to
    943                 // remove the qualifier from the configuration, we create a new default one.
    944                 mSelectedConfiguration.setRegionQualifier(new RegionQualifier());
    945             } else {
    946                 RegionQualifier qualifier = null;
    947                 String segment = RegionQualifier.getFolderSegment(value);
    948                 if (segment != null) {
    949                     qualifier = RegionQualifier.getQualifier(segment);
    950                 }
    951 
    952                 if (qualifier != null) {
    953                     mSelectedConfiguration.setRegionQualifier(qualifier);
    954                 } else {
    955                     // Failure! Looks like the value is wrong (for instance a one letter string).
    956                     mSelectedConfiguration.setRegionQualifier(new RegionQualifier());
    957                 }
    958             }
    959 
    960             // notify of change
    961             onChange(true /* keepSelection */);
    962         }
    963 
    964         @Override
    965         public void setQualifier(ResourceQualifier qualifier) {
    966             RegionQualifier q = (RegionQualifier)qualifier;
    967 
    968             String value = q.getValue();
    969             if (value != null) {
    970                 mRegion.setText(q.getValue());
    971             }
    972         }
    973     }
    974 
    975     /**
    976      * Edit widget for {@link SmallestScreenWidthQualifier}.
    977      */
    978     private class SmallestScreenWidthEdit extends QualifierEditBase {
    979 
    980         private Text mSize;
    981 
    982         public SmallestScreenWidthEdit(Composite parent) {
    983             super(parent, SmallestScreenWidthQualifier.NAME);
    984 
    985             ModifyListener modifyListener = new ModifyListener() {
    986                 public void modifyText(ModifyEvent e) {
    987                     onSizeChange();
    988                 }
    989             };
    990 
    991             FocusAdapter focusListener = new FocusAdapter() {
    992                 @Override
    993                 public void focusLost(FocusEvent e) {
    994                     onSizeChange();
    995                 }
    996             };
    997 
    998             mSize = new Text(this, SWT.BORDER);
    999             mSize.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
   1000             mSize.addVerifyListener(new DimensionVerifier());
   1001             mSize.addModifyListener(modifyListener);
   1002             mSize.addFocusListener(focusListener);
   1003         }
   1004 
   1005         private void onSizeChange() {
   1006             // update the current config
   1007             String size = mSize.getText();
   1008 
   1009             if (size.length() == 0) {
   1010                 // if one of the strings is empty, reset to no qualifier.
   1011                 // Since the qualifier classes are immutable, and we don't want to
   1012                 // remove the qualifier from the configuration, we create a new default one.
   1013                 mSelectedConfiguration.setSmallestScreenWidthQualifier(
   1014                         new SmallestScreenWidthQualifier());
   1015             } else {
   1016                 SmallestScreenWidthQualifier qualifier = SmallestScreenWidthQualifier.getQualifier(
   1017                         size);
   1018 
   1019                 if (qualifier != null) {
   1020                     mSelectedConfiguration.setSmallestScreenWidthQualifier(qualifier);
   1021                 } else {
   1022                     // Failure! Looks like the value is wrong, reset the qualifier
   1023                     // Since the qualifier classes are immutable, and we don't want to
   1024                     // remove the qualifier from the configuration, we create a new default one.
   1025                     mSelectedConfiguration.setSmallestScreenWidthQualifier(
   1026                             new SmallestScreenWidthQualifier());
   1027                 }
   1028             }
   1029 
   1030             // notify of change
   1031             onChange(true /* keepSelection */);
   1032         }
   1033 
   1034         @Override
   1035         public void setQualifier(ResourceQualifier qualifier) {
   1036             SmallestScreenWidthQualifier q = (SmallestScreenWidthQualifier)qualifier;
   1037 
   1038             mSize.setText(Integer.toString(q.getValue()));
   1039         }
   1040     }
   1041 
   1042     /**
   1043      * Edit widget for {@link ScreenWidthQualifier}.
   1044      */
   1045     private class ScreenWidthEdit extends QualifierEditBase {
   1046 
   1047         private Text mSize;
   1048 
   1049         public ScreenWidthEdit(Composite parent) {
   1050             super(parent, ScreenWidthQualifier.NAME);
   1051 
   1052             ModifyListener modifyListener = new ModifyListener() {
   1053                 public void modifyText(ModifyEvent e) {
   1054                     onSizeChange();
   1055                 }
   1056             };
   1057 
   1058             FocusAdapter focusListener = new FocusAdapter() {
   1059                 @Override
   1060                 public void focusLost(FocusEvent e) {
   1061                     onSizeChange();
   1062                 }
   1063             };
   1064 
   1065             mSize = new Text(this, SWT.BORDER);
   1066             mSize.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
   1067             mSize.addVerifyListener(new DimensionVerifier());
   1068             mSize.addModifyListener(modifyListener);
   1069             mSize.addFocusListener(focusListener);
   1070         }
   1071 
   1072         private void onSizeChange() {
   1073             // update the current config
   1074             String size = mSize.getText();
   1075 
   1076             if (size.length() == 0) {
   1077                 // if one of the strings is empty, reset to no qualifier.
   1078                 // Since the qualifier classes are immutable, and we don't want to
   1079                 // remove the qualifier from the configuration, we create a new default one.
   1080                 mSelectedConfiguration.setScreenWidthQualifier(new ScreenWidthQualifier());
   1081             } else {
   1082                 ScreenWidthQualifier qualifier = ScreenWidthQualifier.getQualifier(size);
   1083 
   1084                 if (qualifier != null) {
   1085                     mSelectedConfiguration.setScreenWidthQualifier(qualifier);
   1086                 } else {
   1087                     // Failure! Looks like the value is wrong, reset the qualifier
   1088                     // Since the qualifier classes are immutable, and we don't want to
   1089                     // remove the qualifier from the configuration, we create a new default one.
   1090                     mSelectedConfiguration.setScreenWidthQualifier(
   1091                             new ScreenWidthQualifier());
   1092                 }
   1093             }
   1094 
   1095             // notify of change
   1096             onChange(true /* keepSelection */);
   1097         }
   1098 
   1099         @Override
   1100         public void setQualifier(ResourceQualifier qualifier) {
   1101             ScreenWidthQualifier q = (ScreenWidthQualifier)qualifier;
   1102 
   1103             mSize.setText(Integer.toString(q.getValue()));
   1104         }
   1105     }
   1106 
   1107     /**
   1108      * Edit widget for {@link ScreenHeightQualifier}.
   1109      */
   1110     private class ScreenHeightEdit extends QualifierEditBase {
   1111 
   1112         private Text mSize;
   1113 
   1114         public ScreenHeightEdit(Composite parent) {
   1115             super(parent, ScreenHeightQualifier.NAME);
   1116 
   1117             ModifyListener modifyListener = new ModifyListener() {
   1118                 public void modifyText(ModifyEvent e) {
   1119                     onSizeChange();
   1120                 }
   1121             };
   1122 
   1123             FocusAdapter focusListener = new FocusAdapter() {
   1124                 @Override
   1125                 public void focusLost(FocusEvent e) {
   1126                     onSizeChange();
   1127                 }
   1128             };
   1129 
   1130             mSize = new Text(this, SWT.BORDER);
   1131             mSize.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
   1132             mSize.addVerifyListener(new DimensionVerifier());
   1133             mSize.addModifyListener(modifyListener);
   1134             mSize.addFocusListener(focusListener);
   1135         }
   1136 
   1137         private void onSizeChange() {
   1138             // update the current config
   1139             String size = mSize.getText();
   1140 
   1141             if (size.length() == 0) {
   1142                 // if one of the strings is empty, reset to no qualifier.
   1143                 // Since the qualifier classes are immutable, and we don't want to
   1144                 // remove the qualifier from the configuration, we create a new default one.
   1145                 mSelectedConfiguration.setScreenHeightQualifier(new ScreenHeightQualifier());
   1146             } else {
   1147                 ScreenHeightQualifier qualifier = ScreenHeightQualifier.getQualifier(size);
   1148 
   1149                 if (qualifier != null) {
   1150                     mSelectedConfiguration.setScreenHeightQualifier(qualifier);
   1151                 } else {
   1152                     // Failure! Looks like the value is wrong, reset the qualifier
   1153                     // Since the qualifier classes are immutable, and we don't want to
   1154                     // remove the qualifier from the configuration, we create a new default one.
   1155                     mSelectedConfiguration.setScreenHeightQualifier(
   1156                             new ScreenHeightQualifier());
   1157                 }
   1158             }
   1159 
   1160             // notify of change
   1161             onChange(true /* keepSelection */);
   1162         }
   1163 
   1164         @Override
   1165         public void setQualifier(ResourceQualifier qualifier) {
   1166             ScreenHeightQualifier q = (ScreenHeightQualifier)qualifier;
   1167 
   1168             mSize.setText(Integer.toString(q.getValue()));
   1169         }
   1170     }
   1171 
   1172 
   1173     /**
   1174      * Edit widget for {@link ScreenSizeQualifier}.
   1175      */
   1176     private class ScreenSizeEdit extends QualifierEditBase {
   1177 
   1178         private Combo mSize;
   1179 
   1180         public ScreenSizeEdit(Composite parent) {
   1181             super(parent, ScreenSizeQualifier.NAME);
   1182 
   1183             mSize = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);
   1184             fillCombo(mSize, ScreenSize.values());
   1185 
   1186             mSize.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
   1187             mSize.addSelectionListener(new SelectionListener() {
   1188                 public void widgetDefaultSelected(SelectionEvent e) {
   1189                     onScreenSizeChange();
   1190                 }
   1191                 public void widgetSelected(SelectionEvent e) {
   1192                     onScreenSizeChange();
   1193                 }
   1194             });
   1195         }
   1196 
   1197         protected void onScreenSizeChange() {
   1198             // update the current config
   1199             int index = mSize.getSelectionIndex();
   1200 
   1201             if (index != -1) {
   1202                 mSelectedConfiguration.setScreenSizeQualifier(new ScreenSizeQualifier(
   1203                         ScreenSize.getByIndex(index)));
   1204             } else {
   1205                 // empty selection, means no qualifier.
   1206                 // Since the qualifier classes are immutable, and we don't want to
   1207                 // remove the qualifier from the configuration, we create a new default one.
   1208                 mSelectedConfiguration.setScreenSizeQualifier(
   1209                         new ScreenSizeQualifier());
   1210             }
   1211 
   1212             // notify of change
   1213             onChange(true /* keepSelection */);
   1214         }
   1215 
   1216         @Override
   1217         public void setQualifier(ResourceQualifier qualifier) {
   1218             ScreenSizeQualifier q = (ScreenSizeQualifier)qualifier;
   1219 
   1220             ScreenSize value = q.getValue();
   1221             if (value == null) {
   1222                 mSize.clearSelection();
   1223             } else {
   1224                 mSize.select(ScreenSize.getIndex(value));
   1225             }
   1226         }
   1227     }
   1228 
   1229     /**
   1230      * Edit widget for {@link ScreenRatioQualifier}.
   1231      */
   1232     private class ScreenRatioEdit extends QualifierEditBase {
   1233 
   1234         private Combo mRatio;
   1235 
   1236         public ScreenRatioEdit(Composite parent) {
   1237             super(parent, ScreenRatioQualifier.NAME);
   1238 
   1239             mRatio = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);
   1240             fillCombo(mRatio, ScreenRatio.values());
   1241 
   1242             mRatio.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
   1243             mRatio.addSelectionListener(new SelectionListener() {
   1244                 public void widgetDefaultSelected(SelectionEvent e) {
   1245                     onScreenRatioChange();
   1246                 }
   1247                 public void widgetSelected(SelectionEvent e) {
   1248                     onScreenRatioChange();
   1249                 }
   1250             });
   1251         }
   1252 
   1253         protected void onScreenRatioChange() {
   1254             // update the current config
   1255             int index = mRatio.getSelectionIndex();
   1256 
   1257             if (index != -1) {
   1258                 mSelectedConfiguration.setScreenRatioQualifier(new ScreenRatioQualifier(
   1259                         ScreenRatio.getByIndex(index)));
   1260             } else {
   1261                 // empty selection, means no qualifier.
   1262                 // Since the qualifier classes are immutable, and we don't want to
   1263                 // remove the qualifier from the configuration, we create a new default one.
   1264                 mSelectedConfiguration.setScreenRatioQualifier(
   1265                         new ScreenRatioQualifier());
   1266             }
   1267 
   1268             // notify of change
   1269             onChange(true /* keepSelection */);
   1270         }
   1271 
   1272         @Override
   1273         public void setQualifier(ResourceQualifier qualifier) {
   1274             ScreenRatioQualifier q = (ScreenRatioQualifier)qualifier;
   1275 
   1276             ScreenRatio value = q.getValue();
   1277             if (value == null) {
   1278                 mRatio.clearSelection();
   1279             } else {
   1280                 mRatio.select(ScreenRatio.getIndex(value));
   1281             }
   1282         }
   1283     }
   1284 
   1285     /**
   1286      * Edit widget for {@link ScreenOrientationQualifier}.
   1287      */
   1288     private class OrientationEdit extends QualifierEditBase {
   1289 
   1290         private Combo mOrientation;
   1291 
   1292         public OrientationEdit(Composite parent) {
   1293             super(parent, ScreenOrientationQualifier.NAME);
   1294 
   1295             mOrientation = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);
   1296             fillCombo(mOrientation, ScreenOrientation.values());
   1297 
   1298             mOrientation.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
   1299             mOrientation.addSelectionListener(new SelectionListener() {
   1300                 public void widgetDefaultSelected(SelectionEvent e) {
   1301                     onOrientationChange();
   1302                 }
   1303                 public void widgetSelected(SelectionEvent e) {
   1304                     onOrientationChange();
   1305                 }
   1306             });
   1307         }
   1308 
   1309         protected void onOrientationChange() {
   1310             // update the current config
   1311             int index = mOrientation.getSelectionIndex();
   1312 
   1313             if (index != -1) {
   1314                 mSelectedConfiguration.setScreenOrientationQualifier(new ScreenOrientationQualifier(
   1315                     ScreenOrientation.getByIndex(index)));
   1316             } else {
   1317                 // empty selection, means no qualifier.
   1318                 // Since the qualifier classes are immutable, and we don't want to
   1319                 // remove the qualifier from the configuration, we create a new default one.
   1320                 mSelectedConfiguration.setScreenOrientationQualifier(
   1321                         new ScreenOrientationQualifier());
   1322             }
   1323 
   1324             // notify of change
   1325             onChange(true /* keepSelection */);
   1326         }
   1327 
   1328         @Override
   1329         public void setQualifier(ResourceQualifier qualifier) {
   1330             ScreenOrientationQualifier q = (ScreenOrientationQualifier)qualifier;
   1331 
   1332             ScreenOrientation value = q.getValue();
   1333             if (value == null) {
   1334                 mOrientation.clearSelection();
   1335             } else {
   1336                 mOrientation.select(ScreenOrientation.getIndex(value));
   1337             }
   1338         }
   1339     }
   1340 
   1341     /**
   1342      * Edit widget for {@link DockModeQualifier}.
   1343      */
   1344     private class UiModeEdit extends QualifierEditBase {
   1345 
   1346         private Combo mUiMode;
   1347 
   1348         public UiModeEdit(Composite parent) {
   1349             super(parent, UiModeQualifier.NAME);
   1350 
   1351             mUiMode = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);
   1352             fillCombo(mUiMode, UiMode.values());
   1353 
   1354             mUiMode.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
   1355             mUiMode.addSelectionListener(new SelectionListener() {
   1356                 public void widgetDefaultSelected(SelectionEvent e) {
   1357                     onDockModeChange();
   1358                 }
   1359                 public void widgetSelected(SelectionEvent e) {
   1360                     onDockModeChange();
   1361                 }
   1362             });
   1363         }
   1364 
   1365         protected void onDockModeChange() {
   1366             // update the current config
   1367             int index = mUiMode.getSelectionIndex();
   1368 
   1369             if (index != -1) {
   1370                 mSelectedConfiguration.setUiModeQualifier(
   1371                         new UiModeQualifier(UiMode.getByIndex(index)));
   1372             } else {
   1373                 // empty selection, means no qualifier.
   1374                 // Since the qualifier classes are immutable, and we don't want to
   1375                 // remove the qualifier from the configuration, we create a new default one.
   1376                 mSelectedConfiguration.setUiModeQualifier(new UiModeQualifier());
   1377             }
   1378 
   1379             // notify of change
   1380             onChange(true /* keepSelection */);
   1381         }
   1382 
   1383         @Override
   1384         public void setQualifier(ResourceQualifier qualifier) {
   1385             UiModeQualifier q = (UiModeQualifier)qualifier;
   1386 
   1387             UiMode value = q.getValue();
   1388             if (value == null) {
   1389                 mUiMode.clearSelection();
   1390             } else {
   1391                 mUiMode.select(UiMode.getIndex(value));
   1392             }
   1393         }
   1394     }
   1395 
   1396     /**
   1397      * Edit widget for {@link NightModeQualifier}.
   1398      */
   1399     private class NightModeEdit extends QualifierEditBase {
   1400 
   1401         private Combo mNightMode;
   1402 
   1403         public NightModeEdit(Composite parent) {
   1404             super(parent, NightModeQualifier.NAME);
   1405 
   1406             mNightMode = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);
   1407             fillCombo(mNightMode, NightMode.values());
   1408 
   1409             mNightMode.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
   1410             mNightMode.addSelectionListener(new SelectionListener() {
   1411                 public void widgetDefaultSelected(SelectionEvent e) {
   1412                     onNightModeChange();
   1413                 }
   1414                 public void widgetSelected(SelectionEvent e) {
   1415                     onNightModeChange();
   1416                 }
   1417             });
   1418         }
   1419 
   1420         protected void onNightModeChange() {
   1421             // update the current config
   1422             int index = mNightMode.getSelectionIndex();
   1423 
   1424             if (index != -1) {
   1425                 mSelectedConfiguration.setNightModeQualifier(
   1426                         new NightModeQualifier(NightMode.getByIndex(index)));
   1427             } else {
   1428                 // empty selection, means no qualifier.
   1429                 // Since the qualifier classes are immutable, and we don't want to
   1430                 // remove the qualifier from the configuration, we create a new default one.
   1431                 mSelectedConfiguration.setNightModeQualifier(new NightModeQualifier());
   1432             }
   1433 
   1434             // notify of change
   1435             onChange(true /* keepSelection */);
   1436         }
   1437 
   1438         @Override
   1439         public void setQualifier(ResourceQualifier qualifier) {
   1440             NightModeQualifier q = (NightModeQualifier)qualifier;
   1441 
   1442             NightMode value = q.getValue();
   1443             if (value == null) {
   1444                 mNightMode.clearSelection();
   1445             } else {
   1446                 mNightMode.select(NightMode.getIndex(value));
   1447             }
   1448         }
   1449     }
   1450 
   1451 
   1452     /**
   1453      * Edit widget for {@link DensityQualifier}.
   1454      */
   1455     private class DensityEdit extends QualifierEditBase {
   1456         private Combo mDensity;
   1457 
   1458         public DensityEdit(Composite parent) {
   1459             super(parent, DensityQualifier.NAME);
   1460 
   1461             mDensity = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);
   1462             fillCombo(mDensity, Density.values());
   1463 
   1464             mDensity.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
   1465             mDensity.addSelectionListener(new SelectionListener() {
   1466                 public void widgetDefaultSelected(SelectionEvent e) {
   1467                     onDensityChange();
   1468                 }
   1469                 public void widgetSelected(SelectionEvent e) {
   1470                     onDensityChange();
   1471                 }
   1472             });
   1473         }
   1474 
   1475         private void onDensityChange() {
   1476             // update the current config
   1477             int index = mDensity.getSelectionIndex();
   1478 
   1479             if (index != -1) {
   1480                 mSelectedConfiguration.setDensityQualifier(new DensityQualifier(
   1481                     Density.getByIndex(index)));
   1482             } else {
   1483                 // empty selection, means no qualifier.
   1484                 // Since the qualifier classes are immutable, and we don't want to
   1485                 // remove the qualifier from the configuration, we create a new default one.
   1486                 mSelectedConfiguration.setDensityQualifier(
   1487                         new DensityQualifier());
   1488             }
   1489 
   1490             // notify of change
   1491             onChange(true /* keepSelection */);
   1492         }
   1493 
   1494         @Override
   1495         public void setQualifier(ResourceQualifier qualifier) {
   1496             DensityQualifier q = (DensityQualifier)qualifier;
   1497 
   1498             Density value = q.getValue();
   1499             if (value == null) {
   1500                 mDensity.clearSelection();
   1501             } else {
   1502                 mDensity.select(Density.getIndex(value));
   1503             }
   1504         }
   1505     }
   1506 
   1507     /**
   1508      * Edit widget for {@link TouchScreenQualifier}.
   1509      */
   1510     private class TouchEdit extends QualifierEditBase {
   1511 
   1512         private Combo mTouchScreen;
   1513 
   1514         public TouchEdit(Composite parent) {
   1515             super(parent, TouchScreenQualifier.NAME);
   1516 
   1517             mTouchScreen = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);
   1518             fillCombo(mTouchScreen, TouchScreen.values());
   1519 
   1520             mTouchScreen.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
   1521             mTouchScreen.addSelectionListener(new SelectionListener() {
   1522                 public void widgetDefaultSelected(SelectionEvent e) {
   1523                     onTouchChange();
   1524                 }
   1525                 public void widgetSelected(SelectionEvent e) {
   1526                     onTouchChange();
   1527                 }
   1528             });
   1529         }
   1530 
   1531         protected void onTouchChange() {
   1532             // update the current config
   1533             int index = mTouchScreen.getSelectionIndex();
   1534 
   1535             if (index != -1) {
   1536                 mSelectedConfiguration.setTouchTypeQualifier(new TouchScreenQualifier(
   1537                         TouchScreen.getByIndex(index)));
   1538             } else {
   1539                 // empty selection, means no qualifier.
   1540                 // Since the qualifier classes are immutable, and we don't want to
   1541                 // remove the qualifier from the configuration, we create a new default one.
   1542                 mSelectedConfiguration.setTouchTypeQualifier(new TouchScreenQualifier());
   1543             }
   1544 
   1545             // notify of change
   1546             onChange(true /* keepSelection */);
   1547         }
   1548 
   1549         @Override
   1550         public void setQualifier(ResourceQualifier qualifier) {
   1551             TouchScreenQualifier q = (TouchScreenQualifier)qualifier;
   1552 
   1553             TouchScreen value = q.getValue();
   1554             if (value == null) {
   1555                 mTouchScreen.clearSelection();
   1556             } else {
   1557                 mTouchScreen.select(TouchScreen.getIndex(value));
   1558             }
   1559         }
   1560     }
   1561 
   1562     /**
   1563      * Edit widget for {@link KeyboardStateQualifier}.
   1564      */
   1565     private class KeyboardEdit extends QualifierEditBase {
   1566 
   1567         private Combo mKeyboardState;
   1568 
   1569         public KeyboardEdit(Composite parent) {
   1570             super(parent, KeyboardStateQualifier.NAME);
   1571 
   1572             mKeyboardState = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);
   1573             fillCombo(mKeyboardState, KeyboardState.values());
   1574 
   1575             mKeyboardState.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
   1576             mKeyboardState.addSelectionListener(new SelectionListener() {
   1577                 public void widgetDefaultSelected(SelectionEvent e) {
   1578                     onKeyboardChange();
   1579                 }
   1580                 public void widgetSelected(SelectionEvent e) {
   1581                     onKeyboardChange();
   1582                 }
   1583             });
   1584         }
   1585 
   1586         protected void onKeyboardChange() {
   1587             // update the current config
   1588             int index = mKeyboardState.getSelectionIndex();
   1589 
   1590             if (index != -1) {
   1591                 mSelectedConfiguration.setKeyboardStateQualifier(new KeyboardStateQualifier(
   1592                         KeyboardState.getByIndex(index)));
   1593             } else {
   1594                 // empty selection, means no qualifier.
   1595                 // Since the qualifier classes are immutable, and we don't want to
   1596                 // remove the qualifier from the configuration, we create a new default one.
   1597                 mSelectedConfiguration.setKeyboardStateQualifier(
   1598                         new KeyboardStateQualifier());
   1599             }
   1600 
   1601             // notify of change
   1602             onChange(true /* keepSelection */);
   1603         }
   1604 
   1605         @Override
   1606         public void setQualifier(ResourceQualifier qualifier) {
   1607             KeyboardStateQualifier q = (KeyboardStateQualifier)qualifier;
   1608 
   1609             KeyboardState value = q.getValue();
   1610             if (value == null) {
   1611                 mKeyboardState.clearSelection();
   1612             } else {
   1613                 mKeyboardState.select(KeyboardState.getIndex(value));
   1614             }
   1615         }
   1616     }
   1617 
   1618     /**
   1619      * Edit widget for {@link TextInputMethodQualifier}.
   1620      */
   1621     private class TextInputEdit extends QualifierEditBase {
   1622 
   1623         private Combo mTextInput;
   1624 
   1625         public TextInputEdit(Composite parent) {
   1626             super(parent, TextInputMethodQualifier.NAME);
   1627 
   1628             mTextInput = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);
   1629             fillCombo(mTextInput, Keyboard.values());
   1630 
   1631             mTextInput.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
   1632             mTextInput.addSelectionListener(new SelectionListener() {
   1633                 public void widgetDefaultSelected(SelectionEvent e) {
   1634                     onTextInputChange();
   1635                 }
   1636                 public void widgetSelected(SelectionEvent e) {
   1637                     onTextInputChange();
   1638                 }
   1639             });
   1640         }
   1641 
   1642         protected void onTextInputChange() {
   1643             // update the current config
   1644             int index = mTextInput.getSelectionIndex();
   1645 
   1646             if (index != -1) {
   1647                 mSelectedConfiguration.setTextInputMethodQualifier(new TextInputMethodQualifier(
   1648                         Keyboard.getByIndex(index)));
   1649             } else {
   1650                 // empty selection, means no qualifier.
   1651                 // Since the qualifier classes are immutable, and we don't want to
   1652                 // remove the qualifier from the configuration, we create a new default one.
   1653                 mSelectedConfiguration.setTextInputMethodQualifier(
   1654                         new TextInputMethodQualifier());
   1655             }
   1656 
   1657             // notify of change
   1658             onChange(true /* keepSelection */);
   1659         }
   1660 
   1661         @Override
   1662         public void setQualifier(ResourceQualifier qualifier) {
   1663             TextInputMethodQualifier q = (TextInputMethodQualifier)qualifier;
   1664 
   1665             Keyboard value = q.getValue();
   1666             if (value == null) {
   1667                 mTextInput.clearSelection();
   1668             } else {
   1669                 mTextInput.select(Keyboard.getIndex(value));
   1670             }
   1671         }
   1672     }
   1673 
   1674     /**
   1675      * Edit widget for {@link NavigationStateQualifier}.
   1676      */
   1677     private class NavigationStateEdit extends QualifierEditBase {
   1678 
   1679         private Combo mNavigationState;
   1680 
   1681         public NavigationStateEdit(Composite parent) {
   1682             super(parent, NavigationStateQualifier.NAME);
   1683 
   1684             mNavigationState = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);
   1685             fillCombo(mNavigationState, NavigationState.values());
   1686 
   1687             mNavigationState.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
   1688             mNavigationState.addSelectionListener(new SelectionListener() {
   1689                 public void widgetDefaultSelected(SelectionEvent e) {
   1690                     onNavigationChange();
   1691                 }
   1692                 public void widgetSelected(SelectionEvent e) {
   1693                     onNavigationChange();
   1694                 }
   1695             });
   1696         }
   1697 
   1698         protected void onNavigationChange() {
   1699             // update the current config
   1700             int index = mNavigationState.getSelectionIndex();
   1701 
   1702             if (index != -1) {
   1703                 mSelectedConfiguration.setNavigationStateQualifier(
   1704                         new NavigationStateQualifier(NavigationState.getByIndex(index)));
   1705             } else {
   1706                 // empty selection, means no qualifier.
   1707                 // Since the qualifier classes are immutable, and we don't want to
   1708                 // remove the qualifier from the configuration, we create a new default one.
   1709                 mSelectedConfiguration.setNavigationStateQualifier(new NavigationStateQualifier());
   1710             }
   1711 
   1712             // notify of change
   1713             onChange(true /* keepSelection */);
   1714         }
   1715 
   1716         @Override
   1717         public void setQualifier(ResourceQualifier qualifier) {
   1718             NavigationStateQualifier q = (NavigationStateQualifier)qualifier;
   1719 
   1720             NavigationState value = q.getValue();
   1721             if (value == null) {
   1722                 mNavigationState.clearSelection();
   1723             } else {
   1724                 mNavigationState.select(NavigationState.getIndex(value));
   1725             }
   1726         }
   1727     }
   1728 
   1729 
   1730     /**
   1731      * Edit widget for {@link NavigationMethodQualifier}.
   1732      */
   1733     private class NavigationEdit extends QualifierEditBase {
   1734 
   1735         private Combo mNavigation;
   1736 
   1737         public NavigationEdit(Composite parent) {
   1738             super(parent, NavigationMethodQualifier.NAME);
   1739 
   1740             mNavigation = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);
   1741             fillCombo(mNavigation, Navigation.values());
   1742 
   1743             mNavigation.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
   1744             mNavigation.addSelectionListener(new SelectionListener() {
   1745                 public void widgetDefaultSelected(SelectionEvent e) {
   1746                     onNavigationChange();
   1747                 }
   1748                 public void widgetSelected(SelectionEvent e) {
   1749                     onNavigationChange();
   1750                 }
   1751             });
   1752         }
   1753 
   1754         protected void onNavigationChange() {
   1755             // update the current config
   1756             int index = mNavigation.getSelectionIndex();
   1757 
   1758             if (index != -1) {
   1759                 mSelectedConfiguration.setNavigationMethodQualifier(new NavigationMethodQualifier(
   1760                         Navigation.getByIndex(index)));
   1761             } else {
   1762                 // empty selection, means no qualifier.
   1763                 // Since the qualifier classes are immutable, and we don't want to
   1764                 // remove the qualifier from the configuration, we create a new default one.
   1765                 mSelectedConfiguration.setNavigationMethodQualifier(
   1766                         new NavigationMethodQualifier());
   1767             }
   1768 
   1769             // notify of change
   1770             onChange(true /* keepSelection */);
   1771         }
   1772 
   1773         @Override
   1774         public void setQualifier(ResourceQualifier qualifier) {
   1775             NavigationMethodQualifier q = (NavigationMethodQualifier)qualifier;
   1776 
   1777             Navigation value = q.getValue();
   1778             if (value == null) {
   1779                 mNavigation.clearSelection();
   1780             } else {
   1781                 mNavigation.select(Navigation.getIndex(value));
   1782             }
   1783         }
   1784     }
   1785 
   1786     /**
   1787      * Edit widget for {@link ScreenDimensionQualifier}.
   1788      */
   1789     private class ScreenDimensionEdit extends QualifierEditBase {
   1790 
   1791         private Text mSize1;
   1792         private Text mSize2;
   1793 
   1794         public ScreenDimensionEdit(Composite parent) {
   1795             super(parent, ScreenDimensionQualifier.NAME);
   1796 
   1797             ModifyListener modifyListener = new ModifyListener() {
   1798                 public void modifyText(ModifyEvent e) {
   1799                     onSizeChange();
   1800                 }
   1801             };
   1802 
   1803             FocusAdapter focusListener = new FocusAdapter() {
   1804                 @Override
   1805                 public void focusLost(FocusEvent e) {
   1806                     onSizeChange();
   1807                 }
   1808             };
   1809 
   1810             mSize1 = new Text(this, SWT.BORDER);
   1811             mSize1.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
   1812             mSize1.addVerifyListener(new DimensionVerifier());
   1813             mSize1.addModifyListener(modifyListener);
   1814             mSize1.addFocusListener(focusListener);
   1815 
   1816             mSize2 = new Text(this, SWT.BORDER);
   1817             mSize2.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
   1818             mSize2.addVerifyListener(new DimensionVerifier());
   1819             mSize2.addModifyListener(modifyListener);
   1820             mSize2.addFocusListener(focusListener);
   1821         }
   1822 
   1823         private void onSizeChange() {
   1824             // update the current config
   1825             String size1 = mSize1.getText();
   1826             String size2 = mSize2.getText();
   1827 
   1828             if (size1.length() == 0 || size2.length() == 0) {
   1829                 // if one of the strings is empty, reset to no qualifier.
   1830                 // Since the qualifier classes are immutable, and we don't want to
   1831                 // remove the qualifier from the configuration, we create a new default one.
   1832                 mSelectedConfiguration.setScreenDimensionQualifier(new ScreenDimensionQualifier());
   1833             } else {
   1834                 ScreenDimensionQualifier qualifier = ScreenDimensionQualifier.getQualifier(size1,
   1835                         size2);
   1836 
   1837                 if (qualifier != null) {
   1838                     mSelectedConfiguration.setScreenDimensionQualifier(qualifier);
   1839                 } else {
   1840                     // Failure! Looks like the value is wrong, reset the qualifier
   1841                     // Since the qualifier classes are immutable, and we don't want to
   1842                     // remove the qualifier from the configuration, we create a new default one.
   1843                     mSelectedConfiguration.setScreenDimensionQualifier(
   1844                             new ScreenDimensionQualifier());
   1845                 }
   1846             }
   1847 
   1848             // notify of change
   1849             onChange(true /* keepSelection */);
   1850         }
   1851 
   1852         @Override
   1853         public void setQualifier(ResourceQualifier qualifier) {
   1854             ScreenDimensionQualifier q = (ScreenDimensionQualifier)qualifier;
   1855 
   1856             mSize1.setText(Integer.toString(q.getValue1()));
   1857             mSize2.setText(Integer.toString(q.getValue2()));
   1858         }
   1859     }
   1860 
   1861     /**
   1862      * Edit widget for {@link VersionQualifier}.
   1863      */
   1864     private class VersionEdit extends QualifierEditBase {
   1865         private Text mText;
   1866 
   1867         public VersionEdit(Composite parent) {
   1868             super(parent, VersionQualifier.NAME);
   1869 
   1870             mText = new Text(this, SWT.BORDER);
   1871             mText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
   1872             mText.addVerifyListener(new MobileCodeVerifier());
   1873             mText.addModifyListener(new ModifyListener() {
   1874                 public void modifyText(ModifyEvent e) {
   1875                     onVersionChange();
   1876                 }
   1877             });
   1878             mText.addFocusListener(new FocusAdapter() {
   1879                 @Override
   1880                 public void focusLost(FocusEvent e) {
   1881                     onVersionChange();
   1882                 }
   1883             });
   1884 
   1885             new Label(this, SWT.NONE).setText("(Platform API level)");
   1886         }
   1887 
   1888         private void onVersionChange() {
   1889             String value = mText.getText();
   1890 
   1891             if (value.length() == 0) {
   1892                 // empty string, means a qualifier with no value.
   1893                 // Since the qualifier classes are immutable, and we don't want to
   1894                 // remove the qualifier from the configuration, we create a new default one.
   1895                 mSelectedConfiguration.setVersionQualifier(new VersionQualifier());
   1896             } else {
   1897                 try {
   1898                     VersionQualifier qualifier = VersionQualifier.getQualifier(
   1899                             VersionQualifier.getFolderSegment(Integer.parseInt(value)));
   1900                     if (qualifier != null) {
   1901                         mSelectedConfiguration.setVersionQualifier(qualifier);
   1902                     } else {
   1903                         // Failure! Looks like the value is wrong
   1904                         mSelectedConfiguration.setVersionQualifier(new VersionQualifier());
   1905                     }
   1906                 } catch (NumberFormatException nfe) {
   1907                     // Looks like the code is not a number. This should not happen since the text
   1908                     // field has a VerifyListener that prevents it.
   1909                     mSelectedConfiguration.setVersionQualifier(new VersionQualifier());
   1910                 }
   1911             }
   1912 
   1913             // notify of change
   1914             onChange(true /* keepSelection */);
   1915         }
   1916 
   1917         @Override
   1918         public void setQualifier(ResourceQualifier qualifier) {
   1919             VersionQualifier q = (VersionQualifier)qualifier;
   1920 
   1921             mText.setText(Integer.toString(q.getVersion()));
   1922         }
   1923     }
   1924 
   1925 }
   1926