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