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