| 1 11 package org.eclipse.ui.internal.themes; 12 13 import com.ibm.icu.text.MessageFormat; 14 import java.util.ArrayList ; 15 import java.util.Arrays ; 16 import java.util.HashMap ; 17 import java.util.HashSet ; 18 import java.util.Iterator ; 19 import java.util.List ; 20 import java.util.Map ; 21 import java.util.ResourceBundle ; 22 import java.util.Set ; 23 24 import org.eclipse.core.runtime.CoreException; 25 import org.eclipse.core.runtime.IStatus; 26 import org.eclipse.jface.preference.ColorSelector; 27 import org.eclipse.jface.preference.PreferenceConverter; 28 import org.eclipse.jface.preference.PreferencePage; 29 import org.eclipse.jface.resource.JFaceResources; 30 import org.eclipse.jface.resource.StringConverter; 31 import org.eclipse.jface.util.IPropertyChangeListener; 32 import org.eclipse.jface.util.PropertyChangeEvent; 33 import org.eclipse.jface.viewers.AbstractTreeViewer; 34 import org.eclipse.jface.viewers.DoubleClickEvent; 35 import org.eclipse.jface.viewers.IDoubleClickListener; 36 import org.eclipse.jface.viewers.IFontProvider; 37 import org.eclipse.jface.viewers.ISelectionChangedListener; 38 import org.eclipse.jface.viewers.IStructuredSelection; 39 import org.eclipse.jface.viewers.ITreeContentProvider; 40 import org.eclipse.jface.viewers.LabelProvider; 41 import org.eclipse.jface.viewers.LabelProviderChangedEvent; 42 import org.eclipse.jface.viewers.SelectionChangedEvent; 43 import org.eclipse.jface.viewers.StructuredSelection; 44 import org.eclipse.jface.viewers.Viewer; 45 import org.eclipse.jface.viewers.ViewerComparator; 46 import org.eclipse.swt.SWT; 47 import org.eclipse.swt.custom.StackLayout; 48 import org.eclipse.swt.events.DisposeEvent; 49 import org.eclipse.swt.events.DisposeListener; 50 import org.eclipse.swt.events.SelectionAdapter; 51 import org.eclipse.swt.events.SelectionEvent; 52 import org.eclipse.swt.graphics.Color; 53 import org.eclipse.swt.graphics.Font; 54 import org.eclipse.swt.graphics.FontData; 55 import org.eclipse.swt.graphics.GC; 56 import org.eclipse.swt.graphics.Image; 57 import org.eclipse.swt.graphics.RGB; 58 import org.eclipse.swt.layout.FillLayout; 59 import org.eclipse.swt.layout.GridData; 60 import org.eclipse.swt.layout.GridLayout; 61 import org.eclipse.swt.widgets.Button; 62 import org.eclipse.swt.widgets.Composite; 63 import org.eclipse.swt.widgets.Control; 64 import org.eclipse.swt.widgets.Display; 65 import org.eclipse.swt.widgets.FontDialog; 66 import org.eclipse.swt.widgets.Label; 67 import org.eclipse.swt.widgets.Text; 68 import org.eclipse.ui.IWorkbench; 69 import org.eclipse.ui.IWorkbenchPreferencePage; 70 import org.eclipse.ui.PlatformUI; 71 import org.eclipse.ui.dialogs.FilteredTree; 72 import org.eclipse.ui.dialogs.PatternFilter; 73 import org.eclipse.ui.internal.IWorkbenchGraphicConstants; 74 import org.eclipse.ui.internal.IWorkbenchHelpContextIds; 75 import org.eclipse.ui.internal.Workbench; 76 import org.eclipse.ui.internal.WorkbenchMessages; 77 import org.eclipse.ui.internal.WorkbenchPlugin; 78 import org.eclipse.ui.internal.misc.StatusUtil; 79 import org.eclipse.ui.internal.util.PrefUtil; 80 import org.eclipse.ui.internal.util.Util; 81 import org.eclipse.ui.themes.ITheme; 82 import org.eclipse.ui.themes.IThemeManager; 83 import org.eclipse.ui.themes.IThemePreview; 84 85 90 public final class ColorsAndFontsPreferencePage extends PreferencePage 91 implements IWorkbenchPreferencePage { 92 93 private static final String SELECTED_ELEMENT_PREF = "ColorsAndFontsPreferencePage.selectedElement"; 97 private static final String EXPANDED_ELEMENTS_PREF = "ColorsAndFontsPreferencePage.expandedCategories"; 101 private static final String EXPANDED_ELEMENTS_TOKEN = "\t"; 103 106 private static final char MARKER_CATEGORY = 'T'; 107 108 111 private static final char MARKER_COLOR = 'C'; 112 113 116 private static final char MARKER_FONT = 'F'; 117 118 private class ThemeContentProvider implements ITreeContentProvider { 119 120 private IThemeRegistry registry; 121 122 125 public Object [] getChildren(Object parentElement) { 126 if (parentElement instanceof ThemeElementCategory) { 127 String categoryId = ((ThemeElementCategory) parentElement) 128 .getId(); 129 Object [] defintions = (Object []) categoryMap.get(categoryId); 130 if (defintions == null) { 131 defintions = getCategoryChildren(categoryId); 132 categoryMap.put(categoryId, defintions); 133 } 134 return defintions; 135 } 136 137 ArrayList list = new ArrayList (); 138 IHierarchalThemeElementDefinition def = (IHierarchalThemeElementDefinition) parentElement; 139 String id = def.getId(); 140 IHierarchalThemeElementDefinition[] defs; 141 if (def instanceof ColorDefinition) { 142 defs = registry.getColors(); 143 } else { 144 defs = registry.getFonts(); 145 } 146 147 for (int i = 0; i < defs.length; i++) { 148 if (id.equals(defs[i].getDefaultsTo()) 149 && ColorsAndFontsPreferencePage.equals( 150 ((ICategorizedThemeElementDefinition) def) 151 .getCategoryId(), 152 ((ICategorizedThemeElementDefinition) defs[i]) 153 .getCategoryId())) { 154 list.add(defs[i]); 155 } 156 } 157 return list.toArray(); 158 } 159 160 private Object [] getCategoryChildren(String categoryId) { 161 ArrayList list = new ArrayList (); 162 163 if (categoryId != null) { 164 ThemeElementCategory[] categories = registry.getCategories(); 165 for (int i = 0; i < categories.length; i++) { 166 if (categoryId.equals(categories[i].getParentId())) { 167 Set bindings = themeRegistry 168 .getPresentationsBindingsFor(categories[i]); 169 if (bindings == null 170 || bindings.contains(workbench 171 .getPresentationId())) { 172 list.add(categories[i]); 173 } 174 } 175 } 176 } 177 { 178 ColorDefinition[] colorDefinitions = themeRegistry 179 .getColorsFor(currentTheme.getId()); 180 for (int i = 0; i < colorDefinitions.length; i++) { 181 if (!colorDefinitions[i].isEditable()) { 182 continue; 183 } 184 String catId = colorDefinitions[i].getCategoryId(); 185 if ((catId == null && categoryId == null) 186 || (catId != null && categoryId != null && categoryId 187 .equals(catId))) { 188 if (colorDefinitions[i].getDefaultsTo() != null 189 && parentIsInSameCategory(colorDefinitions[i])) { 190 continue; 191 } 192 list.add(colorDefinitions[i]); 193 } 194 } 195 } 196 { 197 FontDefinition[] fontDefinitions = themeRegistry 198 .getFontsFor(currentTheme.getId()); 199 for (int i = 0; i < fontDefinitions.length; i++) { 200 if (!fontDefinitions[i].isEditable()) { 201 continue; 202 } 203 String catId = fontDefinitions[i].getCategoryId(); 204 if ((catId == null && categoryId == null) 205 || (catId != null && categoryId != null && categoryId 206 .equals(catId))) { 207 if (fontDefinitions[i].getDefaultsTo() != null 208 && parentIsInSameCategory(fontDefinitions[i])) { 209 continue; 210 } 211 list.add(fontDefinitions[i]); 212 } 213 } 214 } 215 return list.toArray(new Object [list.size()]); 216 } 217 218 222 private boolean parentIsInSameCategory(ColorDefinition definition) { 223 String defaultsTo = definition.getDefaultsTo(); 224 ColorDefinition[] defs = registry.getColors(); 225 for (int i = 0; i < defs.length; i++) { 226 if (defs[i].getId().equals(defaultsTo) 227 && ColorsAndFontsPreferencePage.equals(defs[i] 228 .getCategoryId(), definition.getCategoryId())) { 229 return true; 230 } 231 } 232 return false; 233 } 234 235 239 private boolean parentIsInSameCategory(FontDefinition definition) { 240 String defaultsTo = definition.getDefaultsTo(); 241 FontDefinition[] defs = registry.getFonts(); 242 for (int i = 0; i < defs.length; i++) { 243 if (defs[i].getId().equals(defaultsTo) 244 && ColorsAndFontsPreferencePage.equals(defs[i] 245 .getCategoryId(), definition.getCategoryId())) { 246 return true; 247 } 248 } 249 return false; 250 } 251 252 255 public Object getParent(Object element) { 256 return null; 257 } 258 259 262 public boolean hasChildren(Object element) { 263 if (element instanceof ThemeElementCategory) { 264 return true; 265 } 266 267 IHierarchalThemeElementDefinition def = (IHierarchalThemeElementDefinition) element; 268 String id = def.getId(); 269 IHierarchalThemeElementDefinition[] defs; 270 if (def instanceof ColorDefinition) { 271 defs = registry.getColors(); 272 } else { 273 defs = registry.getFonts(); 274 } 275 276 for (int i = 0; i < defs.length; i++) { 277 if (id.equals(defs[i].getDefaultsTo()) 278 && ColorsAndFontsPreferencePage.equals( 279 ((ICategorizedThemeElementDefinition) def) 280 .getCategoryId(), 281 ((ICategorizedThemeElementDefinition) defs[i]) 282 .getCategoryId())) { 283 return true; 284 } 285 } 286 287 return false; 288 } 289 290 295 public Object [] getElements(Object inputElement) { 296 ArrayList list = new ArrayList (); 297 Object [] uncatChildren = getCategoryChildren(null); 298 list.addAll(Arrays.asList(uncatChildren)); 299 ThemeElementCategory[] categories = ((IThemeRegistry) inputElement) 300 .getCategories(); 301 for (int i = 0; i < categories.length; i++) { 302 if (categories[i].getParentId() == null) { 303 Set bindings = themeRegistry 304 .getPresentationsBindingsFor(categories[i]); 305 if (bindings == null 306 || bindings.contains(workbench.getPresentationId())) { 307 list.add(categories[i]); 308 } 309 } 310 } 311 return list.toArray(new Object [list.size()]); 312 } 313 314 317 public void dispose() { 318 categoryMap.clear(); 319 } 320 321 324 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { 325 categoryMap.clear(); 326 registry = (IThemeRegistry) newInput; 327 } 328 329 } 330 331 private class PresentationLabelProvider extends LabelProvider implements 332 IFontProvider { 333 334 private HashMap fonts = new HashMap (); 335 336 private HashMap images = new HashMap (); 337 338 private int imageSize = -1; 339 340 private int usableImageSize = -1; 341 342 private IPropertyChangeListener listener = new IPropertyChangeListener() { 343 public void propertyChange(PropertyChangeEvent event) { 344 fireLabelProviderChanged(new LabelProviderChangedEvent( 345 PresentationLabelProvider.this)); 346 } 347 }; 348 349 private Image emptyImage; 350 351 354 public PresentationLabelProvider() { 355 hookListeners(); 356 } 357 358 361 public void hookListeners() { 362 colorRegistry.addListener(listener); 363 fontRegistry.addListener(listener); 364 } 365 366 369 public void dispose() { 370 super.dispose(); 371 colorRegistry.removeListener(listener); 372 fontRegistry.removeListener(listener); 373 for (Iterator i = images.values().iterator(); i.hasNext();) { 374 ((Image) i.next()).dispose(); 375 } 376 images.clear(); 377 378 if (emptyImage != null) { 379 emptyImage.dispose(); 380 emptyImage = null; 381 } 382 383 clearFontCache(); 385 } 386 387 390 public void clearFontCache() { 391 for (Iterator i = fonts.values().iterator(); i.hasNext();) { 392 ((Font) i.next()).dispose(); 393 } 394 fonts.clear(); 395 } 396 397 400 public void clearFontCacheAndUpdate() { 401 clearFontCache(); 402 fireLabelProviderChanged(new LabelProviderChangedEvent( 403 PresentationLabelProvider.this)); 404 } 405 406 409 public Font getFont(Object element) { 410 Display display = tree.getDisplay(); 411 if (element instanceof FontDefinition) { 412 int parentHeight = tree.getViewer().getControl().getFont() 413 .getFontData()[0].getHeight(); 414 Font baseFont = fontRegistry.get(((FontDefinition) element) 415 .getId()); 416 Font font = (Font) fonts.get(baseFont); 417 if (font == null) { 418 FontData[] data = baseFont.getFontData(); 419 for (int i = 0; i < data.length; i++) { 420 data[i].setHeight(parentHeight); 421 } 422 font = new Font(display, data); 423 424 fonts.put(baseFont, font); 425 } 426 return font; 427 } 428 429 return JFaceResources.getDialogFont(); 430 } 431 432 435 public Image getImage(Object element) { 436 if (element instanceof ColorDefinition) { 437 Color c = colorRegistry 438 .get(((ColorDefinition) element).getId()); 439 Image image = (Image) images.get(c); 440 if (image == null) { 441 Display display = tree.getDisplay(); 442 ensureImageSize(display); 443 image = new Image(display, imageSize, imageSize); 445 446 GC gc = new GC(image); 447 gc.setBackground(tree.getViewer().getControl() 448 .getBackground()); 449 gc.setForeground(tree.getViewer().getControl() 450 .getBackground()); 451 gc.drawRectangle(0, 0, imageSize - 1, imageSize - 1); 452 453 gc.setForeground(tree.getViewer().getControl() 454 .getForeground()); 455 gc.setBackground(c); 456 457 int offset = (imageSize - usableImageSize) / 2; 458 gc.drawRectangle(offset, offset, usableImageSize - offset, 459 usableImageSize - offset); 460 gc.fillRectangle(offset + 1, offset + 1, usableImageSize 461 - offset - 1, usableImageSize - offset - 1); 462 gc.dispose(); 463 464 images.put(c, image); 465 } 466 return image; 467 468 } else if (element instanceof FontDefinition) { 469 return workbench.getSharedImages().getImage( 470 IWorkbenchGraphicConstants.IMG_OBJ_FONT); 471 } else { 472 return workbench.getSharedImages().getImage( 473 IWorkbenchGraphicConstants.IMG_OBJ_THEME_CATEGORY); 474 } 475 } 476 477 481 private void ensureImageSize(Display display) { 482 if (imageSize == -1) { 483 imageSize = tree.getViewer().getTree().getItemHeight(); 484 usableImageSize = Math.max(1, imageSize - 4); 485 } 486 } 487 488 491 public String getText(Object element) { 492 if (element instanceof IHierarchalThemeElementDefinition) { 493 IHierarchalThemeElementDefinition themeElement = (IHierarchalThemeElementDefinition) element; 494 if (themeElement 495 .getDefaultsTo() != null) { 496 String myCategory = ((ICategorizedThemeElementDefinition) themeElement) 497 .getCategoryId(); 498 ICategorizedThemeElementDefinition def; 499 if (element instanceof ColorDefinition) { 500 def = themeRegistry 501 .findColor(themeElement 502 .getDefaultsTo()); 503 } else { 504 def = themeRegistry 505 .findFont(themeElement 506 .getDefaultsTo()); 507 } 508 509 if (!ColorsAndFontsPreferencePage.equals(def 510 .getCategoryId(), myCategory)) { 511 if (isDefault(themeElement)) { 512 return MessageFormat 513 .format( 514 RESOURCE_BUNDLE 515 .getString("defaultFormat_default"), new Object [] { themeElement.getName(), def.getName() }); } 517 518 return MessageFormat 519 .format( 520 RESOURCE_BUNDLE 521 .getString("defaultFormat_override"), new Object [] { themeElement.getName(), def.getName() }); } 523 } 524 } 525 return ((IThemeElementDefinition) element).getName(); 526 } 527 528 535 private boolean isDefault(IThemeElementDefinition def) { 536 if (def instanceof FontDefinition) { 537 return ColorsAndFontsPreferencePage.this.isDefault((FontDefinition)def); 538 } else if (def instanceof ColorDefinition) { 539 return ColorsAndFontsPreferencePage.this.isDefault((ColorDefinition)def); 540 } 541 return false; 542 } 543 } 544 545 548 private final static ResourceBundle RESOURCE_BUNDLE = ResourceBundle 549 .getBundle(ColorsAndFontsPreferencePage.class.getName()); 550 551 554 private Map categoryMap = new HashMap (7); 555 556 private Font appliedDialogFont; 557 558 561 private Composite colorControls; 562 563 568 private Map colorPreferencesToSet = new HashMap (7); 569 570 private CascadingColorRegistry colorRegistry; 571 572 private Button colorResetButton; 573 574 private ColorSelector colorSelector; 575 576 580 private Map colorValuesToSet = new HashMap (7); 581 582 585 private Composite controlArea; 586 587 590 private StackLayout controlAreaLayout; 591 592 595 private Composite defaultPreviewControl; 596 597 private Text descriptionText; 598 599 private List dialogFontWidgets = new ArrayList (); 600 601 private Button fontChangeButton; 602 603 606 private Composite fontControls; 607 608 private Map fontPreferencesToSet = new HashMap (7); 609 610 private CascadingFontRegistry fontRegistry; 611 612 private Button fontResetButton; 613 614 private Button fontSystemButton; 615 616 621 private Map fontValuesToSet = new HashMap (7); 622 623 626 630 private Composite previewComposite; 631 632 635 private Map previewMap = new HashMap (7); 636 637 640 private Set previewSet = new HashSet (7); 641 642 645 private StackLayout stackLayout; 646 647 private final IThemeRegistry themeRegistry; 648 649 private ITheme currentTheme; 650 651 private PresentationLabelProvider labelProvider; 652 653 private CascadingTheme cascadingTheme; 654 655 private IPropertyChangeListener themeChangeListener; 656 657 private Workbench workbench; 658 659 private FilteredTree tree; 660 661 664 public ColorsAndFontsPreferencePage() { 665 themeRegistry = WorkbenchPlugin.getDefault().getThemeRegistry(); 666 } 668 669 674 private static boolean equals(String string, String string2) { 675 if ((string == null && string2 == null)) { 676 return true; 677 } 678 if (string == null || string2 == null) { 679 return false; 680 } 681 if (string.equals(string2)) { 682 return true; 683 } 684 685 return false; 686 } 687 688 |