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