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