KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > themes > ColorsAndFontsPreferencePage


1 /*******************************************************************************
2  * Copyright (c) 2003, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.ui.internal.themes;
12
13 import com.ibm.icu.text.MessageFormat;
14 import java.util.ArrayList JavaDoc;
15 import java.util.Arrays JavaDoc;
16 import java.util.HashMap JavaDoc;
17 import java.util.HashSet JavaDoc;
18 import java.util.Iterator JavaDoc;
19 import java.util.List JavaDoc;
20 import java.util.Map JavaDoc;
21 import java.util.ResourceBundle JavaDoc;
22 import java.util.Set JavaDoc;
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 /**
86  * Preference page for management of system colors, gradients and fonts.
87  *
88  * @since 3.0
89  */

90 public final class ColorsAndFontsPreferencePage extends PreferencePage
91         implements IWorkbenchPreferencePage {
92     
93     private static final String JavaDoc SELECTED_ELEMENT_PREF = "ColorsAndFontsPreferencePage.selectedElement"; //$NON-NLS-1$
94
/**
95      * The preference that stores the expanded state.
96      */

97     private static final String JavaDoc EXPANDED_ELEMENTS_PREF = "ColorsAndFontsPreferencePage.expandedCategories"; //$NON-NLS-1$
98
/**
99      * The token that seperates expanded elements in EXPANDED_ELEMENTS_PREF.
100      */

101     private static final String JavaDoc EXPANDED_ELEMENTS_TOKEN = "\t"; //$NON-NLS-1$
102

103     /**
104      * Marks category tokens in EXPANDED_ELEMENTS_PREF and SELECTED_ELEMENT_PREF.
105      */

106     private static final char MARKER_CATEGORY = 'T';
107     
108     /**
109      * Marks color tokens in EXPANDED_ELEMENTS_PREF and SELECTED_ELEMENT_PREF.
110      */

111     private static final char MARKER_COLOR = 'C';
112     
113     /**
114      * Marks font tokens in EXPANDED_ELEMENTS_PREF and SELECTED_ELEMENT_PREF.
115      */

116     private static final char MARKER_FONT = 'F';
117             
118     private class ThemeContentProvider implements ITreeContentProvider {
119
120         private IThemeRegistry registry;
121
122         /* (non-Javadoc)
123          * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
124          */

125         public Object JavaDoc[] getChildren(Object JavaDoc parentElement) {
126             if (parentElement instanceof ThemeElementCategory) {
127                 String JavaDoc categoryId = ((ThemeElementCategory) parentElement)
128                         .getId();
129                 Object JavaDoc[] defintions = (Object JavaDoc[]) categoryMap.get(categoryId);
130                 if (defintions == null) {
131                     defintions = getCategoryChildren(categoryId);
132                     categoryMap.put(categoryId, defintions);
133                 }
134                 return defintions;
135             }
136
137             ArrayList JavaDoc list = new ArrayList JavaDoc();
138             IHierarchalThemeElementDefinition def = (IHierarchalThemeElementDefinition) parentElement;
139             String JavaDoc 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 JavaDoc[] getCategoryChildren(String JavaDoc categoryId) {
161             ArrayList JavaDoc list = new ArrayList JavaDoc();
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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc[list.size()]);
216         }
217
218         /**
219          * @param definition
220          * @return
221          */

222         private boolean parentIsInSameCategory(ColorDefinition definition) {
223             String JavaDoc 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         /**
236          * @param definition
237          * @return
238          */

239         private boolean parentIsInSameCategory(FontDefinition definition) {
240             String JavaDoc 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         /* (non-Javadoc)
253          * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
254          */

255         public Object JavaDoc getParent(Object JavaDoc element) {
256             return null;
257         }
258
259         /* (non-Javadoc)
260          * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
261          */

262         public boolean hasChildren(Object JavaDoc element) {
263             if (element instanceof ThemeElementCategory) {
264                 return true;
265             }
266
267             IHierarchalThemeElementDefinition def = (IHierarchalThemeElementDefinition) element;
268             String JavaDoc 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         /*
291          * (non-Javadoc)
292          *
293          * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
294          */

295         public Object JavaDoc[] getElements(Object JavaDoc inputElement) {
296             ArrayList JavaDoc list = new ArrayList JavaDoc();
297             Object JavaDoc[] 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 JavaDoc 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 JavaDoc[list.size()]);
312         }
313
314         /* (non-Javadoc)
315          * @see org.eclipse.jface.viewers.IContentProvider#dispose()
316          */

317         public void dispose() {
318             categoryMap.clear();
319         }
320
321         /* (non-Javadoc)
322          * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
323          */

324         public void inputChanged(Viewer viewer, Object JavaDoc oldInput, Object JavaDoc 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 JavaDoc fonts = new HashMap JavaDoc();
335
336         private HashMap JavaDoc images = new HashMap JavaDoc();
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         /**
352          *
353          */

354         public PresentationLabelProvider() {
355             hookListeners();
356         }
357
358         /**
359          * Hook the listeners onto the various registries.
360          */

361         public void hookListeners() {
362             colorRegistry.addListener(listener);
363             fontRegistry.addListener(listener);
364         }
365
366         /* (non-Javadoc)
367          * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
368          */

369         public void dispose() {
370             super.dispose();
371             colorRegistry.removeListener(listener);
372             fontRegistry.removeListener(listener);
373             for (Iterator JavaDoc 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             //clear the fonts.
384
clearFontCache();
385         }
386
387         /**
388          * Clears and disposes all fonts.
389          */

390         public void clearFontCache() {
391             for (Iterator JavaDoc i = fonts.values().iterator(); i.hasNext();) {
392                 ((Font) i.next()).dispose();
393             }
394             fonts.clear();
395         }
396         
397         /**
398          * Clears and disposes all fonts and fires a label update.
399          */

400         public void clearFontCacheAndUpdate() {
401             clearFontCache();
402             fireLabelProviderChanged(new LabelProviderChangedEvent(
403                     PresentationLabelProvider.this));
404         }
405
406         /* (non-Javadoc)
407          * @see org.eclipse.jface.viewers.IFontProvider#getFont(java.lang.Object)
408          */

409         public Font getFont(Object JavaDoc 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         /* (non-Javadoc)
433          * @see org.eclipse.jface.viewers.ILabelProvider#getImage(java.lang.Object)
434          */

435         public Image getImage(Object JavaDoc 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                     //int size = presentationList.getControl().getFont().getFontData()[0].getHeight();
444
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         /**
478          * @param display
479          * @return
480          */

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         /* (non-Javadoc)
489          * @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object)
490          */

491         public String JavaDoc getText(Object JavaDoc element) {
492             if (element instanceof IHierarchalThemeElementDefinition) {
493                 IHierarchalThemeElementDefinition themeElement = (IHierarchalThemeElementDefinition) element;
494                 if (themeElement
495                         .getDefaultsTo() != null) {
496                     String JavaDoc 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 JavaDoc[] { themeElement.getName(), def.getName() }); //$NON-NLS-1$
516
}
517                         
518                             return MessageFormat
519                             .format(
520                                     RESOURCE_BUNDLE
521                                             .getString("defaultFormat_override"), new Object JavaDoc[] { themeElement.getName(), def.getName() }); //$NON-NLS-1$
522
}
523                 }
524             }
525             return ((IThemeElementDefinition) element).getName();
526         }
527
528         /**
529          * Return whether the element is set to default.
530          *
531          * @param def the definition
532          * @return whether the element is set to default
533          * @since 3.2
534          */

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     /**
546      * The translation bundle in which to look up internationalized text.
547      */

548     private final static ResourceBundle JavaDoc RESOURCE_BUNDLE = ResourceBundle
549             .getBundle(ColorsAndFontsPreferencePage.class.getName());
550
551     /**
552      * Map to precalculate category color lists.
553      */

554     private Map JavaDoc categoryMap = new HashMap JavaDoc(7);
555
556     private Font appliedDialogFont;
557
558     /**
559      * The composite containing all color-specific controls.
560      */

561     private Composite colorControls;
562
563     /**
564      * Map of defintion id->RGB objects that map to changes expressed in this
565      * UI session. These changes should be made in preferences and the
566      * registry.
567      */

568     private Map JavaDoc colorPreferencesToSet = new HashMap JavaDoc(7);
569
570     private CascadingColorRegistry colorRegistry;
571
572     private Button colorResetButton;
573
574     private ColorSelector colorSelector;
575
576     /**
577      * Map of defintion id->RGB objects that map to changes expressed in this
578      * UI session. These changes should be made in the registry.
579      */

580     private Map JavaDoc colorValuesToSet = new HashMap JavaDoc(7);
581
582     /**
583      * The composite that contains the font or color controls (or none).
584      */

585     private Composite controlArea;
586
587     /**
588      * The layout for the controlArea.
589      */

590     private StackLayout controlAreaLayout;
591
592     /**
593      * The composite to use when no preview is available.
594      */

595     private Composite defaultPreviewControl;
596
597     private Text descriptionText;
598
599     private List JavaDoc dialogFontWidgets = new ArrayList JavaDoc();
600
601     private Button fontChangeButton;
602
603     /**
604      * The composite containing all font-specific controls.
605      */

606     private Composite fontControls;
607
608     private Map JavaDoc fontPreferencesToSet = new HashMap JavaDoc(7);
609
610     private CascadingFontRegistry fontRegistry;
611
612     private Button fontResetButton;
613
614     private Button fontSystemButton;
615
616     /**
617      * Map of defintion id->FontData[] objects that map to changes expressed in
618      * this UI session. These changes should be made in preferences and the
619      * registry.
620      */

621     private Map JavaDoc fontValuesToSet = new HashMap JavaDoc(7);
622
623     /**
624      * The list of fonts and colors.
625      */

626     //private TreeViewer presentationList;
627
/**
628      * The composite that is parent to all previews.
629      */

630     private Composite previewComposite;
631
632     /**
633      * A mapping from PresentationCategory->Composite for the created previews.
634      */

635     private Map JavaDoc previewMap = new HashMap JavaDoc(7);
636
637     /**
638      * Set containing all IPresentationPreviews created.
639      */

640     private Set JavaDoc previewSet = new HashSet JavaDoc(7);
641
642     /**
643      * The layout for the previewComposite.
644      */

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     /**
662      * Create a new instance of the receiver.
663      */

664     public ColorsAndFontsPreferencePage() {
665         themeRegistry = WorkbenchPlugin.getDefault().getThemeRegistry();
666         //no-op
667
}
668
669     /**
670      * @param string
671      * @param string2
672      * @return
673      */

674     private static boolean equals(String JavaDoc string, String JavaDoc 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     /**
689      * Create a button for the preference page.
690      * @param parent
691      * @param label
692      */

693     private Button createButton(Composite parent, String JavaDoc label) {
694         Button button = new Button(parent, SWT.PUSH | SWT.CENTER);
695         button.setText(label);
696         myApplyDialogFont(button);
697         setButtonLayoutData(button);
698         button.setEnabled(false);
699         return button;
700     }
701
702     /**
703      * Create the color selection control.
704      */

705     private void createColorControl() {
706         Composite composite = new Composite(colorControls, SWT.NONE);
707         GridLayout layout = new GridLayout(2, false);
708         layout.marginHeight = 0;
709         layout.marginWidth = 0;
710         composite.setLayout(layout);
711
712         colorSelector = new ColorSelector(composite);
713         colorSelector.getButton().setLayoutData(new GridData());
714         myApplyDialogFont(colorSelector.getButton());
715         colorSelector.setEnabled(false);
716
717         colorResetButton = createButton(composite, RESOURCE_BUNDLE
718                 .getString("reset")); //$NON-NLS-1$
719
}
720
721     /* (non-Javadoc)
722      * @see org.eclipse.jface.preference.PreferencePage#createContents(org.eclipse.swt.widgets.Composite)
723      */

724     protected Control createContents(Composite parent) {
725         
726         PlatformUI.getWorkbench().getHelpSystem().setHelp(parent,
727                 IWorkbenchHelpContextIds.FONTS_PREFERENCE_PAGE);
728         
729         parent.addDisposeListener(new DisposeListener() {
730             public void widgetDisposed(DisposeEvent e) {
731                 if (appliedDialogFont != null) {
732                     appliedDialogFont.dispose();
733                 }
734             }
735         });
736         Composite mainColumn = new Composite(parent, SWT.NONE);
737         GridLayout layout = new GridLayout();
738         layout.marginWidth = 0;
739         layout.marginHeight = 0;
740         mainColumn.setFont(parent.getFont());
741         mainColumn.setLayout(layout);
742
743         GridData data = new GridData(GridData.BEGINNING);
744         Label label = new Label(mainColumn, SWT.LEFT);
745         label.setText(RESOURCE_BUNDLE.getString("colorsAndFonts")); //$NON-NLS-1$
746
myApplyDialogFont(label);
747         label.setLayoutData(data);
748
749         Composite controlRow = new Composite(mainColumn, SWT.NONE);
750         layout = new GridLayout();
751         layout.numColumns = 2;
752         layout.marginHeight = 0;
753         layout.marginWidth = 0;
754         controlRow.setLayout(layout);
755         data = new GridData(GridData.FILL_HORIZONTAL);
756         controlRow.setLayoutData(data);
757
758         createTree(controlRow);
759         Composite controlColumn = new Composite(controlRow, SWT.NONE);
760         data = new GridData(GridData.FILL_VERTICAL);
761         controlColumn.setLayoutData(data);
762         layout = new GridLayout();
763         layout.marginHeight = 0;
764         layout.marginWidth = 0;
765         controlColumn.setLayout(layout);
766
767         controlArea = new Composite(controlColumn, SWT.NONE);
768         controlAreaLayout = new StackLayout();
769         controlArea.setLayout(controlAreaLayout);
770
771         colorControls = new Composite(controlArea, SWT.NONE);
772         colorControls.setLayout(new FillLayout());
773         createColorControl();
774
775         fontControls = new Composite(controlArea, SWT.NONE);
776         fontControls.setLayout(new FillLayout());
777         createFontControl();
778
779         createDescriptionControl(mainColumn);
780
781         createPreviewControl(mainColumn);
782
783         hookListeners();
784
785         return mainColumn;
786     }
787
788     /**
789      * Create the text box that will contain the current color/font description
790      * text (if any).
791      *
792      * @param parent the parent <code>Composite</code>.
793      */

794     private void createDescriptionControl(Composite parent) {
795         Composite composite = new Composite(parent, SWT.NONE);
796         GridLayout layout = new GridLayout();
797         layout.marginWidth = 0;
798         layout.marginHeight = 0;
799         composite.setLayout(layout);
800         GridData data = new GridData(GridData.FILL_BOTH);
801         data.heightHint = convertHeightInCharsToPixels(5);
802         composite.setLayoutData(data);
803
804         Label label = new Label(composite, SWT.LEFT);
805         label.setText(RESOURCE_BUNDLE.getString("description")); //$NON-NLS-1$
806
myApplyDialogFont(label);
807
808         descriptionText = new Text(composite, SWT.H_SCROLL | SWT.V_SCROLL
809                 | SWT.READ_ONLY | SWT.BORDER | SWT.WRAP);
810         data = new GridData(GridData.FILL_BOTH);
811         descriptionText.setLayoutData(data);
812         myApplyDialogFont(descriptionText);
813     }
814
815     private void createFontControl() {
816         Composite composite = new Composite(fontControls, SWT.NONE);
817         GridLayout layout = new GridLayout(1, false);
818         layout.marginHeight = 0;
819         layout.marginWidth = 0;
820         composite.setLayout(layout);
821
822         fontSystemButton = createButton(composite, WorkbenchMessages.FontsPreference_useSystemFont);
823
824         fontChangeButton = createButton(composite, JFaceResources
825                 .getString("openChange")); //$NON-NLS-1$
826

827         fontResetButton = createButton(composite, RESOURCE_BUNDLE
828                 .getString("reset")); //$NON-NLS-1$
829
}
830
831     /**
832      * Create the <code>ListViewer</code> that will contain all color
833      * definitions as defined in the extension point.
834      *
835      * @param parent the parent <code>Composite</code>.
836      */

837     private void createTree(Composite parent) {
838         labelProvider = new PresentationLabelProvider();
839         // create a new tree with a custom pattern matcher that will allow
840
// non-category elements to be returned in the event that their children
841
// do not
842
tree = new FilteredTree(parent, SWT.SINGLE | SWT.H_SCROLL
843                 | SWT.V_SCROLL | SWT.BORDER, new PatternFilter() {
844             
845             /* (non-Javadoc)
846              * @see org.eclipse.ui.dialogs.PatternFilter#isParentMatch(org.eclipse.jface.viewers.Viewer, java.lang.Object)
847              */

848             protected boolean isParentMatch(Viewer viewer, Object JavaDoc element) {
849                 Object JavaDoc[] children = ((ITreeContentProvider) ((AbstractTreeViewer) viewer)
850                         .getContentProvider()).getChildren(element);
851                 if (children.length > 0
852                         && element instanceof ThemeElementCategory) {
853                     return filter(viewer, element, children).length > 0;
854                 }
855                 return false;
856             }
857         });
858
859         GridData data = new GridData(GridData.FILL_HORIZONTAL
860                 | GridData.VERTICAL_ALIGN_FILL);
861         data.heightHint = Math.max(175, convertHeightInCharsToPixels(10));
862         tree.setLayoutData(data);
863         myApplyDialogFont(tree.getViewer().getControl());
864         Text filterText = tree.getFilterControl();
865         if (filterText != null) {
866             myApplyDialogFont(filterText);
867         }
868
869         tree.getViewer().setLabelProvider(labelProvider);
870         tree.getViewer().setContentProvider(new ThemeContentProvider());
871         tree.getViewer().setComparator(new ViewerComparator() {
872             /* (non-Javadoc)
873              * @see org.eclipse.jface.viewers.ViewerComparator#category(java.lang.Object)
874              */

875             public int category(Object JavaDoc element) {
876                 if (element instanceof ThemeElementCategory) {
877                     return 0;
878                 }
879                 return 1;
880             }
881         });
882         tree.getViewer().setInput(
883                 WorkbenchPlugin.getDefault().getThemeRegistry());
884         tree.getViewer().addDoubleClickListener(new IDoubleClickListener() {
885             /*
886              * (non-Javadoc)
887              *
888              * @see org.eclipse.jface.viewers.IDoubleClickListener#doubleClick(org.eclipse.jface.viewers.DoubleClickEvent)
889              */

890             public void doubleClick(DoubleClickEvent event) {
891                 IStructuredSelection s = (IStructuredSelection) event
892                         .getSelection();
893                 Object JavaDoc element = s.getFirstElement();
894                 if (tree.getViewer().isExpandable(element)) {
895                     tree.getViewer().setExpandedState(element,
896                             !tree.getViewer().getExpandedState(element));
897                 }
898                 
899                 if (element instanceof FontDefinition) {
900                         editFont(tree.getDisplay());
901                 }
902                 else if (element instanceof ColorDefinition) {
903                         colorSelector.open();
904                 }
905             }
906         });
907         
908         restoreTreeExpansion();
909         restoreTreeSelection();
910     }
911
912     /**
913      * @param mainColumn
914      */

915     private void createPreviewControl(Composite mainColumn) {
916         Composite composite = new Composite(mainColumn, SWT.NONE);
917         GridData data = new GridData(GridData.FILL_BOTH);
918         data.heightHint = 175;
919         composite.setLayoutData(data);
920         GridLayout layout = new GridLayout(1, true);
921         layout.marginHeight = 0;
922         layout.marginWidth = 0;
923         composite.setLayout(layout);
924
925         Label label = new Label(composite, SWT.LEFT);
926         label.setText(RESOURCE_BUNDLE.getString("preview")); //$NON-NLS-1$
927
myApplyDialogFont(label);
928         previewComposite = new Composite(composite, SWT.NONE);
929         data = new GridData(GridData.FILL_BOTH);
930         previewComposite.setLayoutData(data);
931         stackLayout = new StackLayout();
932         previewComposite.setLayout(stackLayout);
933     }
934
935     /* (non-Javadoc)
936      * @see org.eclipse.jface.dialogs.IDialogPage#dispose()
937      */

938     public void dispose() {
939         super.dispose();
940
941         workbench.getThemeManager().removePropertyChangeListener(
942                 themeChangeListener);
943
944         clearPreviews();
945
946         colorRegistry.dispose();
947         fontRegistry.dispose();
948
949     }
950
951     /**
952      * Clear all previews.
953      */

954     private void clearPreviews() {
955         if (cascadingTheme != null) {
956             cascadingTheme.dispose();
957         }
958
959         for (Iterator JavaDoc i = previewSet.iterator(); i.hasNext();) {
960             IThemePreview preview = (IThemePreview) i.next();
961             try {
962                 preview.dispose();
963             } catch (RuntimeException JavaDoc e) {
964                 WorkbenchPlugin
965                         .log(
966                                 RESOURCE_BUNDLE
967                                         .getString("errorDisposePreviewLog"), StatusUtil.newStatus(IStatus.ERROR, e.getMessage(), e)); //$NON-NLS-1$
968
}
969         }
970
971         previewSet.clear();
972     }
973
974     /**
975      * Get the ancestor of the given color, if any.
976      *
977      * @param definition the descendant <code>ColorDefinition</code>.
978      * @return the ancestror <code>ColorDefinition</code>, or <code>null</code>
979      * if none.
980      */

981     private ColorDefinition getColorAncestor(ColorDefinition definition) {
982         String JavaDoc defaultsTo = definition.getDefaultsTo();
983         if (defaultsTo == null) {
984             return null;
985         }
986
987         return themeRegistry.findColor(defaultsTo);
988     }
989
990     /**
991      * Get the RGB value of the given colors ancestor, if any.
992      *
993      * @param definition the descendant <code>ColorDefinition</code>.
994      * @return the ancestror <code>RGB</code>, or <code>null</code> if none.
995      */

996     private RGB getColorAncestorValue(ColorDefinition definition) {
997         ColorDefinition ancestor = getColorAncestor(definition);
998         if (ancestor == null) {
999             return null;
1000        }
1001
1002        return getColorValue(ancestor);
1003    }
1004
1005    /**
1006     * Get the RGB value for the specified definition. Cascades through
1007     * preferenceToSet, valuesToSet and finally the registry.
1008     *
1009     * @param definition the <code>ColorDefinition</code>.
1010     * @return the <code>RGB</code> value.
1011     */

1012    private RGB getColorValue(ColorDefinition definition) {
1013        String JavaDoc id = definition.getId();
1014        RGB updatedRGB = (RGB) colorPreferencesToSet.get(id);
1015        if (updatedRGB == null) {
1016            updatedRGB = (RGB) colorValuesToSet.get(id);
1017            if (updatedRGB == null) {
1018                updatedRGB = currentTheme.getColorRegistry().getRGB(id);
1019            }
1020        }
1021        return updatedRGB;
1022    }
1023
1024    /**
1025     * @return Return the default "No preview available." preview.
1026     */

1027    private Composite getDefaultPreviewControl() {
1028        if (defaultPreviewControl == null) {
1029            defaultPreviewControl = new Composite(previewComposite, SWT.NONE);
1030            defaultPreviewControl.setLayout(new FillLayout());
1031            Label l = new Label(defaultPreviewControl, SWT.LEFT);
1032            l.setText(RESOURCE_BUNDLE.getString("noPreviewAvailable")); //$NON-NLS-1$
1033
myApplyDialogFont(l);
1034        }
1035        return defaultPreviewControl;
1036    }
1037
1038    /**
1039     * Get colors that descend from the provided color.
1040     *
1041     * @param definition the ancestor <code>ColorDefinition</code>.
1042     * @return the ColorDefinitions that have the provided definition as their
1043     * defaultsTo attribute.
1044     */

1045    private ColorDefinition[] getDescendantColors(ColorDefinition definition) {
1046        List JavaDoc list = new ArrayList JavaDoc(5);
1047        String JavaDoc id = definition.getId();
1048
1049        ColorDefinition[] colors = themeRegistry.getColors();
1050        ColorDefinition[] sorted = new ColorDefinition[colors.length];
1051        System.arraycopy(colors, 0, sorted, 0, sorted.length);
1052
1053        Arrays.sort(sorted, new IThemeRegistry.HierarchyComparator(colors));
1054
1055        for (int i = 0; i < sorted.length; i++) {
1056            if (id.equals(sorted[i].getDefaultsTo())) {
1057                list.add(sorted[i]);
1058            }
1059        }
1060
1061        return (ColorDefinition[]) list
1062                .toArray(new ColorDefinition[list.size()]);
1063    }
1064
1065    /**
1066     * @param definition
1067     * @return
1068     */

1069    private FontDefinition[] getDescendantFonts(FontDefinition definition) {
1070        List JavaDoc list = new ArrayList JavaDoc(5);
1071        String JavaDoc id = definition.getId();
1072
1073        FontDefinition[] fonts = themeRegistry.getFonts();
1074        FontDefinition[] sorted = new FontDefinition[fonts.length];
1075        System.arraycopy(fonts, 0, sorted, 0, sorted.length);
1076
1077        Arrays.sort(sorted, new IThemeRegistry.HierarchyComparator(fonts));
1078
1079        for (int i = 0; i < sorted.length; i++) {
1080            if (id.equals(sorted[i].getDefaultsTo())) {
1081                list.add(sorted[i]);
1082            }
1083        }
1084
1085        return (FontDefinition[]) list.toArray(new FontDefinition[list.size()]);
1086    }
1087
1088    /**
1089     * @param definition
1090     * @return
1091     */

1092    private FontDefinition getFontAncestor(FontDefinition definition) {
1093        String JavaDoc defaultsTo = definition.getDefaultsTo();
1094        if (defaultsTo == null) {
1095            return null;
1096        }
1097
1098        return themeRegistry.findFont(defaultsTo);
1099    }
1100
1101    /**
1102     * @param definition
1103     * @return
1104     */

1105    private FontData[] getFontAncestorValue(FontDefinition definition) {
1106        FontDefinition ancestor = getFontAncestor(definition);
1107        if (ancestor == null) {
1108            return PreferenceConverter.getDefaultFontDataArray(
1109                    getPreferenceStore(), ThemeElementHelper
1110                            .createPreferenceKey(currentTheme, definition
1111                                    .getId()));
1112        }
1113
1114        return getFontValue(ancestor);
1115    }
1116
1117    /**
1118     * @param definition
1119     * @return
1120     */

1121    protected FontData[] getFontValue(FontDefinition definition) {
1122        String JavaDoc id = definition.getId();
1123        FontData[] updatedFD = (FontData[]) fontPreferencesToSet.get(id);
1124        if (updatedFD == null) {
1125            updatedFD = (FontData[]) fontValuesToSet.get(id);
1126            if (updatedFD == null) {
1127                updatedFD = currentTheme.getFontRegistry().getFontData(id);
1128            }
1129        }
1130        return updatedFD;
1131    }
1132
1133    /**
1134     * @return
1135     */

1136    protected ColorDefinition getSelectedColorDefinition() {
1137        Object JavaDoc o = ((IStructuredSelection) tree.getViewer().getSelection())
1138                .getFirstElement();
1139        if (o instanceof ColorDefinition) {
1140            return (ColorDefinition) o;
1141        }
1142        return null;
1143    }
1144
1145    /**
1146     * @return
1147     */

1148    protected FontDefinition getSelectedFontDefinition() {
1149        Object JavaDoc o = ((IStructuredSelection) tree.getViewer().getSelection())
1150                .getFirstElement();
1151        if (o instanceof FontDefinition) {
1152            return (FontDefinition) o;
1153        }
1154        return null;
1155    }
1156
1157    /**
1158     * Hook all control listeners.
1159     */

1160    private void hookListeners() {
1161        colorSelector.addListener(new IPropertyChangeListener() {
1162
1163            /* (non-Javadoc)
1164             * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
1165             */

1166            public void propertyChange(PropertyChangeEvent event) {
1167                ColorDefinition definition = getSelectedColorDefinition();
1168
1169                RGB newRGB = (RGB) event.getNewValue();
1170                if (definition != null && newRGB != null
1171                        && !newRGB.equals(event.getOldValue())) {
1172                    setColorPreferenceValue(definition, newRGB);
1173                    setRegistryValue(definition, newRGB);
1174                }
1175
1176                updateColorControls(definition);
1177            }
1178        });
1179
1180        tree.getViewer().addSelectionChangedListener(
1181                new ISelectionChangedListener() {
1182
1183                    /* (non-Javadoc)
1184                     * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
1185                     */

1186                    public void selectionChanged(SelectionChangedEvent event) {
1187                        if (event.getSelection().isEmpty()) {
1188                            swapNoControls();
1189                            updateColorControls(null);
1190                            updateCategorySelection(null);
1191                        } else {
1192                            Object JavaDoc element = ((IStructuredSelection) event
1193                                    .getSelection()).getFirstElement();
1194                            if (element instanceof ThemeElementCategory) {
1195                                swapNoControls();
1196                                String JavaDoc description = ((ThemeElementCategory) element)
1197                                        .getDescription();
1198                                descriptionText
1199                                        .setText(description == null ? "" : description); //$NON-NLS-1$
1200
updateCategorySelection((ThemeElementCategory) element);
1201                            } else if (element instanceof ColorDefinition) {
1202                                updateColorControls((ColorDefinition) element);
1203                                swapColorControls();
1204                                updateCategorySelection(WorkbenchPlugin
1205                                        .getDefault().getThemeRegistry()
1206                                        .findCategory(
1207                                                ((ColorDefinition) element)
1208                                                        .getCategoryId()));
1209                            } else if (element instanceof FontDefinition) {
1210                                updateFontControls((FontDefinition) element);
1211                                swapFontControls();
1212                                updateCategorySelection(WorkbenchPlugin
1213                                        .getDefault().getThemeRegistry()
1214                                        .findCategory(
1215                                                ((FontDefinition) element)
1216                                                        .getCategoryId()));
1217                            }
1218                        }
1219                    }
1220                });
1221
1222        colorResetButton.addSelectionListener(new SelectionAdapter() {
1223
1224            /* (non-Javadoc)
1225             * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
1226             */

1227            public void widgetSelected(SelectionEvent e) {
1228                ColorDefinition definition = getSelectedColorDefinition();
1229                if (resetColor(definition)) {
1230                    updateColorControls(definition);
1231                }
1232            }
1233        });
1234
1235        fontResetButton.addSelectionListener(new SelectionAdapter() {
1236
1237            /* (non-Javadoc)
1238             * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
1239             */

1240            public void widgetSelected(SelectionEvent e) {
1241                FontDefinition definition = getSelectedFontDefinition();
1242                if (resetFont(definition)) {
1243                    updateFontControls(definition);
1244                }
1245            }
1246        });
1247
1248        fontChangeButton.addSelectionListener(new SelectionAdapter() {
1249            public void widgetSelected(SelectionEvent event) {
1250                Display display = event.display;
1251                editFont(display);
1252            }
1253        });
1254
1255        fontSystemButton.addSelectionListener(new SelectionAdapter() {
1256            public void widgetSelected(SelectionEvent event) {
1257                FontDefinition definition = getSelectedFontDefinition();
1258                if (definition != null) {
1259                    FontData[] defaultFontData = JFaceResources
1260                            .getDefaultFont().getFontData();
1261                    setFontPreferenceValue(definition, defaultFontData);
1262                    setRegistryValue(definition, defaultFontData);
1263
1264                    updateFontControls(definition);
1265                }
1266            }
1267        });
1268    }
1269
1270    /* (non-Javadoc)
1271     * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
1272     */

1273    public void init(IWorkbench aWorkbench) {
1274        this.workbench = (Workbench) aWorkbench;
1275        setPreferenceStore(PrefUtil.getInternalPreferenceStore());
1276
1277        final IThemeManager themeManager = aWorkbench.getThemeManager();
1278
1279        themeChangeListener = new IPropertyChangeListener() {
1280
1281            /* (non-Javadoc)
1282             * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
1283             */

1284            public void propertyChange(PropertyChangeEvent event) {
1285                if (event.getProperty().equals(
1286                        IThemeManager.CHANGE_CURRENT_THEME)) {
1287                    updateThemeInfo(themeManager);
1288                    refreshCategory();
1289                    tree.getViewer().refresh(); // refresh all the labels in the tree
1290
}
1291            }
1292        };
1293        themeManager.addPropertyChangeListener(themeChangeListener);
1294
1295        updateThemeInfo(themeManager);
1296    }
1297
1298    private void updateThemeInfo(IThemeManager manager) {
1299        clearPreviews();
1300        categoryMap.clear();
1301
1302        if (labelProvider != null) {
1303            labelProvider.dispose(); // nuke the old cache
1304
}
1305
1306        currentTheme = manager.getCurrentTheme();
1307
1308        if (colorRegistry != null) {
1309            colorRegistry.dispose();
1310        }
1311        if (fontRegistry != null) {
1312            fontRegistry.dispose();
1313        }
1314
1315        currentTheme = manager.getCurrentTheme();
1316
1317        colorRegistry = new CascadingColorRegistry(currentTheme
1318                .getColorRegistry());
1319        fontRegistry = new CascadingFontRegistry(currentTheme.getFontRegistry());
1320
1321        fontPreferencesToSet.clear();
1322        fontValuesToSet.clear();
1323
1324        colorPreferencesToSet.clear();
1325        colorValuesToSet.clear();
1326
1327        if (labelProvider != null) {
1328            labelProvider.hookListeners(); // rehook the listeners
1329
}
1330    }
1331
1332    /**
1333     * Answers whether the definition is currently set to the default value.
1334     *
1335     * @param definition the <code>ColorDefinition</code> to check.
1336     * @return Return whether the definition is currently mapped to the default
1337     * value, either in the preference store or in the local change record
1338     * of this preference page.
1339     */

1340    private boolean isDefault(ColorDefinition definition) {
1341        String JavaDoc id = definition.getId();
1342
1343        if (colorPreferencesToSet.containsKey(id)) {
1344            if (definition.getValue() != null) { // value-based color
1345
if (colorPreferencesToSet.get(id).equals(definition.getValue())) {
1346                    return true;
1347                }
1348            } else {
1349                if (colorPreferencesToSet.get(id).equals(
1350                        getColorAncestorValue(definition))) {
1351                    return true;
1352                }
1353            }
1354        } else {
1355            if (definition.getValue() != null) { // value-based color
1356
if (getPreferenceStore().isDefault(
1357                        ThemeElementHelper
1358                                .createPreferenceKey(currentTheme, id))) {
1359                    return true;
1360                }
1361            } else {
1362                // a descendant is default if it's the same value as its ancestor
1363
if (getColorValue(definition).equals(
1364                        getColorAncestorValue(definition))) {
1365                    return true;
1366                }
1367            }
1368        }
1369        return false;
1370    }
1371
1372    /**
1373     * @param definition
1374     * @return
1375     */

1376    private boolean isDefault(FontDefinition definition) {
1377        String JavaDoc id = definition.getId();
1378
1379        if (fontPreferencesToSet.containsKey(id)) {
1380            if (definition.getValue() != null) { // value-based font
1381
if (Arrays.equals((FontData[]) fontPreferencesToSet.get(id),
1382                        definition.getValue())) {
1383                    return true;
1384                }
1385            } else {
1386                FontData[] ancestor = getFontAncestorValue(definition);
1387                if (Arrays.equals((FontData[]) fontPreferencesToSet.get(id),
1388                        ancestor)) {
1389                    return true;
1390                }
1391            }
1392        } else {
1393            if (definition.getValue() != null) { // value-based font
1394
if (getPreferenceStore().isDefault(
1395                        ThemeElementHelper
1396                                .createPreferenceKey(currentTheme, id))) {
1397                    return true;
1398                }
1399            } else {
1400                FontData[] ancestor = getFontAncestorValue(definition);
1401                if (ancestor == null) {
1402                    return true;
1403                }
1404
1405                // a descendant is default if it's the same value as its ancestor
1406
if (Arrays.equals(getFontValue(definition), ancestor)) {
1407                    return true;
1408                }
1409            }
1410        }
1411        return false;
1412    }
1413
1414    /**
1415     * Apply the dialog font to the control and store
1416     * it for later so that it can be used for a later
1417     * update.
1418     * @param control
1419     */

1420    private void myApplyDialogFont(Control control) {
1421        control.setFont(JFaceResources.getDialogFont());
1422        dialogFontWidgets.add(control);
1423    }
1424
1425    /**
1426     * @see org.eclipse.jface.preference.PreferencePage#performApply()
1427     */

1428    protected void performApply() {
1429        super.performApply();
1430
1431        //Apply the default font to the dialog.
1432
Font oldFont = appliedDialogFont;
1433
1434        FontDefinition fontDefinition = themeRegistry
1435                .findFont(JFaceResources.DIALOG_FONT);
1436        if (fontDefinition == null) {
1437            return;
1438        }
1439
1440        FontData[] newData = getFontValue(fontDefinition);
1441
1442        appliedDialogFont = new Font(getControl().getDisplay(), newData);
1443
1444        updateForDialogFontChange(appliedDialogFont);
1445        getApplyButton().setFont(appliedDialogFont);
1446        getDefaultsButton().setFont(appliedDialogFont);
1447
1448        if (oldFont != null) {
1449            oldFont.dispose();
1450        }
1451    }
1452
1453    /**
1454     *
1455     */

1456    private void performColorDefaults() {
1457        ColorDefinition[] definitions = themeRegistry.getColors();
1458
1459        // apply defaults in depth-order.
1460
ColorDefinition[] definitionsCopy = new ColorDefinition[definitions.length];
1461        System
1462                .arraycopy(definitions, 0, definitionsCopy, 0,
1463                        definitions.length);
1464
1465        Arrays.sort(definitionsCopy, new IThemeRegistry.HierarchyComparator(
1466                definitions));
1467
1468        for (int i = 0; i < definitionsCopy.length; i++) {
1469            resetColor(definitionsCopy[i]);
1470        }
1471
1472        updateColorControls(getSelectedColorDefinition());
1473    }
1474
1475    /**
1476     * @return
1477     */

1478    private boolean performColorOk() {
1479        for (Iterator JavaDoc i = colorPreferencesToSet.keySet().iterator(); i
1480                .hasNext();) {
1481            String JavaDoc id = (String JavaDoc) i.next();
1482            String JavaDoc key = ThemeElementHelper.createPreferenceKey(currentTheme,
1483                    id);
1484            RGB rgb = (RGB) colorPreferencesToSet.get(id);
1485            String JavaDoc rgbString = StringConverter.asString(rgb);
1486            String JavaDoc storeString = getPreferenceStore().getString(key);
1487
1488            if (!rgbString.equals(storeString)) {
1489                getPreferenceStore().setValue(key, rgbString);
1490            }
1491        }
1492
1493        colorValuesToSet.clear();
1494        colorPreferencesToSet.clear();
1495        
1496        return true;
1497    }
1498
1499    /* (non-Javadoc)
1500     * @see org.eclipse.jface.preference.PreferencePage#performDefaults()
1501     */

1502    protected void performDefaults() {
1503        performColorDefaults();
1504        performFontDefaults();
1505    }
1506
1507    /**
1508     *
1509     */

1510    private void performFontDefaults() {
1511        FontDefinition[] definitions = themeRegistry.getFonts();
1512
1513        // apply defaults in depth-order.
1514
FontDefinition[] definitionsCopy = new FontDefinition[definitions.length];
1515        System
1516                .arraycopy(definitions, 0, definitionsCopy, 0,
1517                        definitions.length);
1518
1519        Arrays.sort(definitionsCopy, new IThemeRegistry.HierarchyComparator(
1520                definitions));
1521
1522        for (int i = 0; i < definitionsCopy.length; i++) {
1523            resetFont(definitionsCopy[i]);
1524        }
1525
1526        updateFontControls(getSelectedFontDefinition());
1527    }
1528
1529    /**
1530     * @return
1531     */

1532    private boolean performFontOk() {
1533        for (Iterator JavaDoc i = fontPreferencesToSet.keySet().iterator(); i.hasNext();) {
1534            String JavaDoc id = (String JavaDoc) i.next();
1535            String JavaDoc key = ThemeElementHelper.createPreferenceKey(currentTheme,
1536                    id);
1537            FontData[] fd = (FontData[]) fontPreferencesToSet.get(id);
1538
1539            String JavaDoc fdString = PreferenceConverter.getStoredRepresentation(fd);
1540            String JavaDoc storeString = getPreferenceStore().getString(key);
1541
1542            if (!fdString.equals(storeString)) {
1543                getPreferenceStore().setValue(key, fdString);
1544            }
1545        }
1546
1547        fontValuesToSet.clear();
1548        fontPreferencesToSet.clear();
1549        return true;
1550    }
1551
1552    /* (non-Javadoc)
1553     * @see org.eclipse.jface.preference.IPreferencePage#performOk()
1554     */

1555    public boolean performOk() {
1556        saveTreeExpansion();
1557        saveTreeSelection();
1558        boolean result = performColorOk() && performFontOk();
1559        if(result) {
1560            PrefUtil.savePrefs();
1561        }
1562        return result;
1563    }
1564
1565    /**
1566     * Refreshes the category.
1567     */

1568    private void refreshCategory() {
1569        updateColorControls(null);
1570        updateFontControls(null);
1571    }
1572
1573    /**
1574     * Resets the supplied definition to its default value.
1575     *
1576     * @param definition the <code>ColorDefinition</code> to reset.
1577     * @return whether any change was made.
1578     */

1579    private boolean resetColor(ColorDefinition definition) {
1580        if (!isDefault(definition)) {
1581
1582            RGB newRGB;
1583            if (definition.getValue() != null) {
1584                newRGB = definition.getValue();
1585            } else {
1586                newRGB = getColorAncestorValue(definition);
1587            }
1588
1589            if (newRGB != null) {
1590                setColorPreferenceValue(definition, newRGB);
1591                setRegistryValue(definition, newRGB);
1592                return true;
1593            }
1594        }
1595        return false;
1596    }
1597
1598    /**
1599     * @param definition
1600     * @return
1601     */

1602    protected boolean resetFont(FontDefinition definition) {
1603        if (!isDefault(definition)) {
1604
1605            FontData[] newFD;
1606            if (definition.getDefaultsTo() != null) {
1607                newFD = getFontAncestorValue(definition);
1608            } else {
1609                newFD = PreferenceConverter.getDefaultFontDataArray(
1610                        getPreferenceStore(), ThemeElementHelper
1611                                .createPreferenceKey(currentTheme, definition
1612                                        .getId()));
1613            }
1614
1615            if (newFD != null) {
1616                setFontPreferenceValue(definition, newFD);
1617                setRegistryValue(definition, newFD);
1618                return true;
1619            }
1620        }
1621        return false;
1622    }
1623
1624    /**
1625     * Set the value (in preferences) for the given color.
1626     *
1627     * @param definition the <code>ColorDefinition</code> to set.
1628     * @param newRGB the new <code>RGB</code> value for the definitions
1629     * identifier.
1630     */

1631    protected void setColorPreferenceValue(ColorDefinition definition,
1632            RGB newRGB) {
1633        setDescendantRegistryValues(definition, newRGB);
1634        colorPreferencesToSet.put(definition.getId(), newRGB);
1635    }
1636
1637    /**
1638     * Set the value (in registry) for the given colors children.
1639     *
1640     * @param definition the <code>ColorDefinition</code> whos children should
1641     * be set.
1642     * @param newRGB the new <code>RGB</code> value for the definitions
1643     * identifier.
1644     */

1645    private void setDescendantRegistryValues(ColorDefinition definition,
1646            RGB newRGB) {
1647        ColorDefinition[] children = getDescendantColors(definition);
1648
1649        for (int i = 0; i < children.length; i++) {
1650            if (isDefault(children[i])) {
1651                setDescendantRegistryValues(children[i], newRGB);
1652                setRegistryValue(children[i], newRGB);
1653                colorValuesToSet.put(children[i].getId(), newRGB);
1654            }
1655        }
1656    }
1657
1658    /**
1659     * @param definition
1660     * @param datas
1661     */

1662    private void setDescendantRegistryValues(FontDefinition definition,
1663            FontData[] datas) {
1664        FontDefinition[] children = getDescendantFonts(definition);
1665
1666        for (int i = 0; i < children.length; i++) {
1667            if (isDefault(children[i])) {
1668                setDescendantRegistryValues(children[i], datas);
1669                setRegistryValue(children[i], datas);
1670                fontValuesToSet.put(children[i].getId(), datas);
1671            }
1672        }
1673    }
1674
1675    /**
1676     * @param definition
1677     * @param datas
1678     */

1679    protected void setFontPreferenceValue(FontDefinition definition,
1680            FontData[] datas) {
1681        setDescendantRegistryValues(definition, datas);
1682        fontPreferencesToSet.put(definition.getId(), datas);
1683    }
1684
1685    /**
1686     * Updates the working registry.
1687     * @param definition
1688     * @param newRGB
1689     */

1690    protected void setRegistryValue(ColorDefinition definition, RGB newRGB) {
1691        colorRegistry.put(definition.getId(), newRGB);
1692    }
1693
1694    /**
1695     * @param definition
1696     * @param datas
1697     */

1698    protected void setRegistryValue(FontDefinition definition, FontData[] datas) {
1699        fontRegistry.put(definition.getId(), datas);
1700    }
1701
1702    /**
1703     * Swap in the color selection controls.
1704     */

1705    protected void swapColorControls() {
1706        controlAreaLayout.topControl = colorControls;
1707        controlArea.layout();
1708    }
1709
1710    /**
1711     * Swap in the font selection controls.
1712     */

1713    protected void swapFontControls() {
1714        controlAreaLayout.topControl = fontControls;
1715        controlArea.layout();
1716    }
1717
1718    /**
1719     * Swap in no controls (empty the control area)
1720     */

1721    protected void swapNoControls() {
1722        controlAreaLayout.topControl = null;
1723        controlArea.layout();
1724    }
1725
1726    /**
1727     * Set the color list.
1728     * @param category the category to use.
1729     */

1730    private void updateCategorySelection(ThemeElementCategory category) {
1731
1732        Composite previewControl = (Composite) previewMap.get(category);
1733        if (previewControl == null) {
1734            if (category != null) {
1735                try {
1736                    IThemePreview preview = getThemePreview(category);
1737                    if (preview != null) {
1738                        previewControl = new Composite(previewComposite,
1739                                SWT.NONE);
1740                        previewControl.setLayout(new FillLayout());
1741                        ITheme theme = getCascadingTheme();
1742                        preview.createControl(previewControl, theme);
1743                        previewSet.add(preview);
1744                    }
1745                } catch (CoreException e) {
1746                    previewControl = new Composite(previewComposite, SWT.NONE);
1747                    previewControl.setLayout(new FillLayout());
1748                    myApplyDialogFont(previewControl);
1749                    Text error = new Text(previewControl, SWT.WRAP
1750                            | SWT.READ_ONLY);
1751                    error.setText(RESOURCE_BUNDLE
1752                            .getString("errorCreatingPreview")); //$NON-NLS-1$
1753
WorkbenchPlugin
1754                            .log(
1755                                    RESOURCE_BUNDLE
1756                                            .getString("errorCreatePreviewLog"), StatusUtil.newStatus(IStatus.ERROR, e.getMessage(), e)); //$NON-NLS-1$
1757
}
1758            }
1759        }
1760        if (previewControl == null) {
1761            previewControl = getDefaultPreviewControl();
1762        }
1763        previewMap.put(category, previewControl);
1764        stackLayout.topControl = previewControl;
1765        previewComposite.layout();
1766    }
1767
1768    /**
1769     * @param category the category
1770     * @return the preview for the category, or its ancestors preview if it does not have one.
1771     */

1772    private IThemePreview getThemePreview(ThemeElementCategory category)
1773            throws CoreException {
1774        IThemePreview preview = category.createPreview();
1775        if (preview != null) {
1776            return preview;
1777        }
1778
1779        if (category.getParentId() != null) {
1780            int idx = Arrays.binarySearch(themeRegistry.getCategories(),
1781                    category.getParentId(), IThemeRegistry.ID_COMPARATOR);
1782            if (idx >= 0) {
1783                return getThemePreview(themeRegistry.getCategories()[idx]);
1784            }
1785        }
1786
1787        return null;
1788    }
1789
1790    /**
1791     * @return
1792     */

1793    private ITheme getCascadingTheme() {
1794        if (cascadingTheme == null) {
1795            cascadingTheme = new CascadingTheme(currentTheme, colorRegistry,
1796                    fontRegistry);
1797        }
1798        return cascadingTheme;
1799    }
1800
1801    /**
1802     * Update the color controls based on the supplied definition.
1803     *
1804     * @param definition The currently selected <code>ColorDefinition</code>.
1805     */

1806    protected void updateColorControls(ColorDefinition definition) {
1807        if (definition == null) {
1808            colorResetButton.setEnabled(false);
1809            colorSelector.setEnabled(false);
1810            descriptionText.setText(""); //$NON-NLS-1$
1811
return;
1812        }
1813
1814        colorSelector.setColorValue(getColorValue(definition));
1815
1816        colorResetButton.setEnabled(!isDefault(definition));
1817        colorSelector.setEnabled(true);
1818        String JavaDoc description = definition.getDescription();
1819        descriptionText.setText(description == null ? "" : description); //$NON-NLS-1$
1820
}
1821
1822    protected void updateFontControls(FontDefinition definition) {
1823        if (definition == null) {
1824            fontSystemButton.setEnabled(false);
1825            fontResetButton.setEnabled(false);
1826            fontChangeButton.setEnabled(false);
1827            descriptionText.setText(""); //$NON-NLS-1$
1828
return;
1829        }
1830
1831        fontSystemButton.setEnabled(true);
1832        fontResetButton.setEnabled(!isDefault(definition));
1833        fontChangeButton.setEnabled(true);
1834        String JavaDoc description = definition.getDescription();
1835        descriptionText.setText(description == null ? "" : description); //$NON-NLS-1$
1836
}
1837
1838    /**
1839     * Update for a change in the dialog font.
1840     * @param newFont
1841     */

1842    private void updateForDialogFontChange(Font newFont) {
1843        Iterator JavaDoc iterator = dialogFontWidgets.iterator();
1844        while (iterator.hasNext()) {
1845            ((Control) iterator.next()).setFont(newFont);
1846        }
1847
1848        //recalculate the fonts for the tree
1849
labelProvider.clearFontCacheAndUpdate();
1850    }
1851    
1852    /**
1853     * Restore the selection state of the tree.
1854     *
1855     * @since 3.1
1856     */

1857    private void restoreTreeSelection() {
1858        String JavaDoc selectedElementString = getPreferenceStore().getString(
1859                SELECTED_ELEMENT_PREF);
1860
1861        if (selectedElementString == null) {
1862            return;
1863        }
1864
1865        Object JavaDoc element = findElementFromMarker(selectedElementString);
1866        if (element == null) {
1867            return;
1868        }
1869
1870        tree.getViewer().setSelection(new StructuredSelection(element), true);
1871    }
1872
1873    /**
1874     * Save the selection state of the tree.
1875     *
1876     * @since 3.1
1877     */

1878    private void saveTreeSelection() {
1879        IStructuredSelection selection = (IStructuredSelection) tree
1880                .getViewer().getSelection();
1881        Object JavaDoc element = selection.getFirstElement();
1882        StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
1883        appendMarkerToBuffer(buffer, element);
1884        if (buffer.length() > 0) {
1885            buffer.append(((IThemeElementDefinition) element).getId());
1886        }
1887        getPreferenceStore().setValue(SELECTED_ELEMENT_PREF, buffer.toString());
1888    }
1889
1890    /**
1891     * Restore the expansion state of the tree.
1892     *
1893     * @since 3.1
1894     */

1895    private void restoreTreeExpansion() {
1896        String JavaDoc expandedElementsString = getPreferenceStore().getString(
1897                EXPANDED_ELEMENTS_PREF);
1898        if (expandedElementsString == null) {
1899            return;
1900        }
1901
1902        String JavaDoc[] expandedElementIDs = Util.getArrayFromList(expandedElementsString, EXPANDED_ELEMENTS_TOKEN);
1903        if (expandedElementIDs.length == 0) {
1904            return;
1905        }
1906
1907        List JavaDoc elements = new ArrayList JavaDoc(expandedElementIDs.length);
1908        for (int i = 0; i < expandedElementIDs.length; i++) {
1909            IThemeElementDefinition def = findElementFromMarker(expandedElementIDs[i]);
1910
1911            if (def != null) {
1912                elements.add(def);
1913            }
1914        }
1915        tree.getViewer().setExpandedElements(elements.toArray());
1916    }
1917
1918    /**
1919     * Find the theme element from the given string. It will check the first
1920     * character against the known constants and then call the appropriate
1921     * method on the theme registry. If the element does not exist or the string
1922     * is invalid <code>null</code> is returned.
1923     *
1924     * @param string the string to parse
1925     * @return the element, or <code>null</code>
1926     */

1927    private IThemeElementDefinition findElementFromMarker(String JavaDoc string) {
1928        if (string.length() < 2) {
1929            return null;
1930        }
1931
1932        char marker = string.charAt(0);
1933        String JavaDoc id = string.substring(1);
1934        IThemeElementDefinition def = null;
1935        switch (marker) {
1936        case MARKER_FONT:
1937            def = themeRegistry.findFont(id);
1938            break;
1939        case MARKER_COLOR:
1940            def = themeRegistry.findColor(id);
1941            break;
1942        case MARKER_CATEGORY:
1943            def = themeRegistry.findCategory(id);
1944            break;
1945        }
1946        return def;
1947    }
1948
1949    /**
1950     * Saves the expansion state of the tree.
1951     *
1952     * @since 3.1
1953     */

1954    private void saveTreeExpansion() {
1955        Object JavaDoc[] elements = tree.getViewer().getExpandedElements();
1956        List JavaDoc elementIds = new ArrayList JavaDoc(elements.length);
1957
1958        StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
1959        for (int i = 0; i < elements.length; i++) {
1960            Object JavaDoc object = elements[i];
1961            appendMarkerToBuffer(buffer, object);
1962
1963            if (buffer.length() != 0) {
1964                buffer.append(((IThemeElementDefinition) object).getId());
1965                elementIds.add(buffer.toString());
1966            }
1967            buffer.setLength(0);
1968        }
1969
1970        for (Iterator JavaDoc i = elementIds.iterator(); i.hasNext();) {
1971            String JavaDoc id = (String JavaDoc) i.next();
1972            buffer.append(id);
1973            if (i.hasNext()) {
1974                buffer.append(EXPANDED_ELEMENTS_TOKEN);
1975            }
1976        }
1977
1978        getPreferenceStore()
1979                .setValue(EXPANDED_ELEMENTS_PREF, buffer.toString());
1980    }
1981
1982    /**
1983     * @param buffer
1984     * @param object
1985     */

1986    private void appendMarkerToBuffer(StringBuffer JavaDoc buffer, Object JavaDoc object) {
1987        if (object instanceof FontDefinition) {
1988            buffer.append(MARKER_FONT);
1989        } else if (object instanceof ColorDefinition) {
1990            buffer.append(MARKER_COLOR);
1991        } else if (object instanceof ThemeElementCategory) {
1992            buffer.append(MARKER_CATEGORY);
1993        }
1994    }
1995
1996    /**
1997     * Edit the currently selected font.
1998     *
1999     * @param display the display to open the dialog on
2000     * @since 3.2
2001     */

2002    private void editFont(Display display) {
2003        final FontDefinition definition = getSelectedFontDefinition();
2004        if (definition != null) {
2005            final FontDialog fontDialog = new FontDialog(fontChangeButton
2006                    .getShell());
2007            fontDialog.setFontList(getFontValue(definition));
2008            final FontData data = fontDialog.open();
2009            
2010            if (data != null) {
2011                setFontPreferenceValue(definition, fontDialog.getFontList());
2012                setRegistryValue(definition, fontDialog.getFontList());
2013            }
2014
2015            updateFontControls(definition);
2016        }
2017    }
2018}
2019
Popular Tags