OSDN Git Service

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