blob: d635403df77f2609a6d64f4a881315997e4419ac [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.internal.themes;
import com.ibm.icu.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.preference.ColorSelector;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.StringConverter;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.IFontProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.LabelProviderChangedEvent;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FontDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.FilteredTree;
import org.eclipse.ui.dialogs.PatternFilter;
import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
import org.eclipse.ui.internal.Workbench;
import org.eclipse.ui.internal.WorkbenchMessages;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.internal.misc.StatusUtil;
import org.eclipse.ui.internal.util.PrefUtil;
import org.eclipse.ui.internal.util.Util;
import org.eclipse.ui.themes.ITheme;
import org.eclipse.ui.themes.IThemeManager;
import org.eclipse.ui.themes.IThemePreview;
/**
* Preference page for management of system colors, gradients and fonts.
*
* @since 3.0
*/
public final class ColorsAndFontsPreferencePage extends PreferencePage
implements IWorkbenchPreferencePage {
private static final String SELECTED_ELEMENT_PREF = "ColorsAndFontsPreferencePage.selectedElement"; //$NON-NLS-1$
/**
* The preference that stores the expanded state.
*/
private static final String EXPANDED_ELEMENTS_PREF = "ColorsAndFontsPreferencePage.expandedCategories"; //$NON-NLS-1$
/**
* The token that seperates expanded elements in EXPANDED_ELEMENTS_PREF.
*/
private static final String EXPANDED_ELEMENTS_TOKEN = "\t"; //$NON-NLS-1$
/**
* Marks category tokens in EXPANDED_ELEMENTS_PREF and SELECTED_ELEMENT_PREF.
*/
private static final char MARKER_CATEGORY = 'T';
/**
* Marks color tokens in EXPANDED_ELEMENTS_PREF and SELECTED_ELEMENT_PREF.
*/
private static final char MARKER_COLOR = 'C';
/**
* Marks font tokens in EXPANDED_ELEMENTS_PREF and SELECTED_ELEMENT_PREF.
*/
private static final char MARKER_FONT = 'F';
private class ThemeContentProvider implements ITreeContentProvider {
private IThemeRegistry registry;
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
*/
public Object[] getChildren(Object parentElement) {
if (parentElement instanceof ThemeElementCategory) {
String categoryId = ((ThemeElementCategory) parentElement)
.getId();
Object[] defintions = (Object[]) categoryMap.get(categoryId);
if (defintions == null) {
defintions = getCategoryChildren(categoryId);
categoryMap.put(categoryId, defintions);
}
return defintions;
}
ArrayList list = new ArrayList();
IHierarchalThemeElementDefinition def = (IHierarchalThemeElementDefinition) parentElement;
String id = def.getId();
IHierarchalThemeElementDefinition[] defs;
if (def instanceof ColorDefinition) {
defs = registry.getColors();
} else {
defs = registry.getFonts();
}
for (int i = 0; i < defs.length; i++) {
if (id.equals(defs[i].getDefaultsTo())
&& ColorsAndFontsPreferencePage.equals(
((ICategorizedThemeElementDefinition) def)
.getCategoryId(),
((ICategorizedThemeElementDefinition) defs[i])
.getCategoryId())) {
list.add(defs[i]);
}
}
return list.toArray();
}
private Object[] getCategoryChildren(String categoryId) {
ArrayList list = new ArrayList();
if (categoryId != null) {
ThemeElementCategory[] categories = registry.getCategories();
for (int i = 0; i < categories.length; i++) {
if (categoryId.equals(categories[i].getParentId())) {
Set bindings = themeRegistry
.getPresentationsBindingsFor(categories[i]);
if (bindings == null
|| bindings.contains(workbench
.getPresentationId())) {
list.add(categories[i]);
}
}
}
}
{
ColorDefinition[] colorDefinitions = themeRegistry
.getColorsFor(currentTheme.getId());
for (int i = 0; i < colorDefinitions.length; i++) {
if (!colorDefinitions[i].isEditable()) {
continue;
}
String catId = colorDefinitions[i].getCategoryId();
if ((catId == null && categoryId == null)
|| (catId != null && categoryId != null && categoryId
.equals(catId))) {
if (colorDefinitions[i].getDefaultsTo() != null
&& parentIsInSameCategory(colorDefinitions[i])) {
continue;
}
list.add(colorDefinitions[i]);
}
}
}
{
FontDefinition[] fontDefinitions = themeRegistry
.getFontsFor(currentTheme.getId());
for (int i = 0; i < fontDefinitions.length; i++) {
if (!fontDefinitions[i].isEditable()) {
continue;
}
String catId = fontDefinitions[i].getCategoryId();
if ((catId == null && categoryId == null)
|| (catId != null && categoryId != null && categoryId
.equals(catId))) {
if (fontDefinitions[i].getDefaultsTo() != null
&& parentIsInSameCategory(fontDefinitions[i])) {
continue;
}
list.add(fontDefinitions[i]);
}
}
}
return list.toArray(new Object[list.size()]);
}
/**
* @param definition
* @return
*/
private boolean parentIsInSameCategory(ColorDefinition definition) {
String defaultsTo = definition.getDefaultsTo();
ColorDefinition[] defs = registry.getColors();
for (int i = 0; i < defs.length; i++) {
if (defs[i].getId().equals(defaultsTo)
&& ColorsAndFontsPreferencePage.equals(defs[i]
.getCategoryId(), definition.getCategoryId())) {
return true;
}
}
return false;
}
/**
* @param definition
* @return
*/
private boolean parentIsInSameCategory(FontDefinition definition) {
String defaultsTo = definition.getDefaultsTo();
FontDefinition[] defs = registry.getFonts();
for (int i = 0; i < defs.length; i++) {
if (defs[i].getId().equals(defaultsTo)
&& ColorsAndFontsPreferencePage.equals(defs[i]
.getCategoryId(), definition.getCategoryId())) {
return true;
}
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
*/
public Object getParent(Object element) {
return null;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
*/
public boolean hasChildren(Object element) {
if (element instanceof ThemeElementCategory) {
return true;
}
IHierarchalThemeElementDefinition def = (IHierarchalThemeElementDefinition) element;
String id = def.getId();
IHierarchalThemeElementDefinition[] defs;
if (def instanceof ColorDefinition) {
defs = registry.getColors();
} else {
defs = registry.getFonts();
}
for (int i = 0; i < defs.length; i++) {
if (id.equals(defs[i].getDefaultsTo())
&& ColorsAndFontsPreferencePage.equals(
((ICategorizedThemeElementDefinition) def)
.getCategoryId(),
((ICategorizedThemeElementDefinition) defs[i])
.getCategoryId())) {
return true;
}
}
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
*/
public Object[] getElements(Object inputElement) {
ArrayList list = new ArrayList();
Object[] uncatChildren = getCategoryChildren(null);
list.addAll(Arrays.asList(uncatChildren));
ThemeElementCategory[] categories = ((IThemeRegistry) inputElement)
.getCategories();
for (int i = 0; i < categories.length; i++) {
if (categories[i].getParentId() == null) {
Set bindings = themeRegistry
.getPresentationsBindingsFor(categories[i]);
if (bindings == null
|| bindings.contains(workbench.getPresentationId())) {
list.add(categories[i]);
}
}
}
return list.toArray(new Object[list.size()]);
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IContentProvider#dispose()
*/
public void dispose() {
categoryMap.clear();
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
*/
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
categoryMap.clear();
registry = (IThemeRegistry) newInput;
}
}
private class PresentationLabelProvider extends LabelProvider implements
IFontProvider {
private HashMap fonts = new HashMap();
private HashMap images = new HashMap();
private int imageSize = -1;
private int usableImageSize = -1;
private IPropertyChangeListener listener = new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
fireLabelProviderChanged(new LabelProviderChangedEvent(
PresentationLabelProvider.this));
}
};
private Image emptyImage;
/**
*
*/
public PresentationLabelProvider() {
hookListeners();
}
/**
* Hook the listeners onto the various registries.
*/
public void hookListeners() {
colorRegistry.addListener(listener);
fontRegistry.addListener(listener);
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
*/
public void dispose() {
super.dispose();
colorRegistry.removeListener(listener);
fontRegistry.removeListener(listener);
for (Iterator i = images.values().iterator(); i.hasNext();) {
((Image) i.next()).dispose();
}
images.clear();
if (emptyImage != null) {
emptyImage.dispose();
emptyImage = null;
}
//clear the fonts. Has a side effect of firing a label property change
clearFontCache();
}
/**
* Clears and disposes all fonts and fires a label changed event.
*/
public void clearFontCache() {
for (Iterator i = fonts.values().iterator(); i.hasNext();) {
((Font) i.next()).dispose();
}
fonts.clear();
fireLabelProviderChanged(new LabelProviderChangedEvent(
PresentationLabelProvider.this));
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IFontProvider#getFont(java.lang.Object)
*/
public Font getFont(Object element) {
Display display = tree.getDisplay();
if (element instanceof FontDefinition) {
int parentHeight = tree.getViewer().getControl().getFont()
.getFontData()[0].getHeight();
Font baseFont = fontRegistry.get(((FontDefinition) element)
.getId());
Font font = (Font) fonts.get(baseFont);
if (font == null) {
FontData[] data = baseFont.getFontData();
for (int i = 0; i < data.length; i++) {
data[i].setHeight(parentHeight);
}
font = new Font(display, data);
fonts.put(baseFont, font);
}
return font;
}
return JFaceResources.getDialogFont();
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ILabelProvider#getImage(java.lang.Object)
*/
public Image getImage(Object element) {
if (element instanceof ColorDefinition) {
Color c = colorRegistry
.get(((ColorDefinition) element).getId());
Image image = (Image) images.get(c);
if (image == null) {
Display display = tree.getDisplay();
ensureImageSize(display);
//int size = presentationList.getControl().getFont().getFontData()[0].getHeight();
image = new Image(display, imageSize, imageSize);
GC gc = new GC(image);
gc.setBackground(tree.getViewer().getControl()
.getBackground());
gc.setForeground(tree.getViewer().getControl()
.getBackground());
gc.drawRectangle(0, 0, imageSize - 1, imageSize - 1);
gc.setForeground(tree.getViewer().getControl()
.getForeground());
gc.setBackground(c);
int offset = (imageSize - usableImageSize) / 2;
gc.drawRectangle(offset, offset, usableImageSize - offset,
usableImageSize - offset);
gc.fillRectangle(offset + 1, offset + 1, usableImageSize
- offset - 1, usableImageSize - offset - 1);
gc.dispose();
images.put(c, image);
}
return image;
} else if (element instanceof FontDefinition) {
return workbench.getSharedImages().getImage(
IWorkbenchGraphicConstants.IMG_OBJ_FONT);
} else {
return workbench.getSharedImages().getImage(
IWorkbenchGraphicConstants.IMG_OBJ_THEME_CATEGORY);
}
}
/**
* @param display
* @return
*/
private void ensureImageSize(Display display) {
if (imageSize == -1) {
imageSize = tree.getViewer().getTree().getItemHeight();
usableImageSize = Math.max(1, imageSize - 4);
}
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object)
*/
public String getText(Object element) {
if (element instanceof IHierarchalThemeElementDefinition) {
IHierarchalThemeElementDefinition themeElement = (IHierarchalThemeElementDefinition) element;
if (themeElement
.getDefaultsTo() != null) {
String myCategory = ((ICategorizedThemeElementDefinition) themeElement)
.getCategoryId();
ICategorizedThemeElementDefinition def;
if (element instanceof ColorDefinition) {
def = themeRegistry
.findColor(themeElement
.getDefaultsTo());
} else {
def = themeRegistry
.findFont(themeElement
.getDefaultsTo());
}
if (!ColorsAndFontsPreferencePage.equals(def
.getCategoryId(), myCategory)) {
if (isDefault(themeElement)) {
return MessageFormat
.format(
RESOURCE_BUNDLE
.getString("defaultFormat_default"), new Object[] { themeElement.getName(), def.getName() }); //$NON-NLS-1$
}
return MessageFormat
.format(
RESOURCE_BUNDLE
.getString("defaultFormat_override"), new Object[] { themeElement.getName(), def.getName() }); //$NON-NLS-1$
}
}
}
return ((IThemeElementDefinition) element).getName();
}
/**
* Return whether the element is set to default.
*
* @param def the definition
* @return whether the element is set to default
* @since 3.2
*/
private boolean isDefault(IThemeElementDefinition def) {
if (def instanceof FontDefinition) {
return ColorsAndFontsPreferencePage.this.isDefault((FontDefinition)def);
} else if (def instanceof ColorDefinition) {
return ColorsAndFontsPreferencePage.this.isDefault((ColorDefinition)def);
}
return false;
}
}
/**
* The translation bundle in which to look up internationalized text.
*/
private final static ResourceBundle RESOURCE_BUNDLE = ResourceBundle
.getBundle(ColorsAndFontsPreferencePage.class.getName());
/**
* Map to precalculate category color lists.
*/
private Map categoryMap = new HashMap(7);
private Font appliedDialogFont;
/**
* The composite containing all color-specific controls.
*/
private Composite colorControls;
/**
* Map of defintion id->RGB objects that map to changes expressed in this
* UI session. These changes should be made in preferences and the
* registry.
*/
private Map colorPreferencesToSet = new HashMap(7);
private CascadingColorRegistry colorRegistry;
private Button colorResetButton;
private ColorSelector colorSelector;
/**
* Map of defintion id->RGB objects that map to changes expressed in this
* UI session. These changes should be made in the registry.
*/
private Map colorValuesToSet = new HashMap(7);
/**
* The composite that contains the font or color controls (or none).
*/
private Composite controlArea;
/**
* The layout for the controlArea.
*/
private StackLayout controlAreaLayout;
/**
* The composite to use when no preview is available.
*/
private Composite defaultPreviewControl;
private Text descriptionText;
private List dialogFontWidgets = new ArrayList();
private Button fontChangeButton;
/**
* The composite containing all font-specific controls.
*/
private Composite fontControls;
private Map fontPreferencesToSet = new HashMap(7);
private CascadingFontRegistry fontRegistry;
private Button fontResetButton;
private Button fontSystemButton;
/**
* Map of defintion id->FontData[] objects that map to changes expressed in
* this UI session. These changes should be made in preferences and the
* registry.
*/
private Map fontValuesToSet = new HashMap(7);
/**
* The list of fonts and colors.
*/
//private TreeViewer presentationList;
/**
* The composite that is parent to all previews.
*/
private Composite previewComposite;
/**
* A mapping from PresentationCategory->Composite for the created previews.
*/
private Map previewMap = new HashMap(7);
/**
* Set containing all IPresentationPreviews created.
*/
private Set previewSet = new HashSet(7);
/**
* The layout for the previewComposite.
*/
private StackLayout stackLayout;
private final IThemeRegistry themeRegistry;
private ITheme currentTheme;
private PresentationLabelProvider labelProvider;
private CascadingTheme cascadingTheme;
private IPropertyChangeListener themeChangeListener;
private Workbench workbench;
private FilteredTree tree;
/**
* Create a new instance of the receiver.
*/
public ColorsAndFontsPreferencePage() {
themeRegistry = WorkbenchPlugin.getDefault().getThemeRegistry();
//no-op
}
/**
* @param string
* @param string2
* @return
*/
private static boolean equals(String string, String string2) {
if ((string == null && string2 == null)) {
return true;
}
if (string == null || string2 == null) {
return false;
}
if (string.equals(string2)) {
return true;
}
return false;
}
/**
* Create a button for the preference page.
* @param parent
* @param label
*/
private Button createButton(Composite parent, String label) {
Button button = new Button(parent, SWT.PUSH | SWT.CENTER);
button.setText(label);
myApplyDialogFont(button);
setButtonLayoutData(button);
button.setEnabled(false);
return button;
}
/**
* Create the color selection control.
*/
private void createColorControl() {
Composite composite = new Composite(colorControls, SWT.NONE);
GridLayout layout = new GridLayout(2, false);
layout.marginHeight = 0;
layout.marginWidth = 0;
composite.setLayout(layout);
colorSelector = new ColorSelector(composite);
colorSelector.getButton().setLayoutData(new GridData());
myApplyDialogFont(colorSelector.getButton());
colorSelector.setEnabled(false);
colorResetButton = createButton(composite, RESOURCE_BUNDLE
.getString("reset")); //$NON-NLS-1$
}
/* (non-Javadoc)
* @see org.eclipse.jface.preference.PreferencePage#createContents(org.eclipse.swt.widgets.Composite)
*/
protected Control createContents(Composite parent) {
PlatformUI.getWorkbench().getHelpSystem().setHelp(parent,
IWorkbenchHelpContextIds.FONTS_PREFERENCE_PAGE);
parent.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
if (appliedDialogFont != null) {
appliedDialogFont.dispose();
}
}
});
Composite mainColumn = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginWidth = 0;
layout.marginHeight = 0;
mainColumn.setFont(parent.getFont());
mainColumn.setLayout(layout);
GridData data = new GridData(GridData.BEGINNING);
Label label = new Label(mainColumn, SWT.LEFT);
label.setText(RESOURCE_BUNDLE.getString("colorsAndFonts")); //$NON-NLS-1$
myApplyDialogFont(label);
label.setLayoutData(data);
Composite controlRow = new Composite(mainColumn, SWT.NONE);
layout = new GridLayout();
layout.numColumns = 2;
layout.marginHeight = 0;
layout.marginWidth = 0;
controlRow.setLayout(layout);
data = new GridData(GridData.FILL_HORIZONTAL);
controlRow.setLayoutData(data);
createTree(controlRow);
Composite controlColumn = new Composite(controlRow, SWT.NONE);
data = new GridData(GridData.FILL_VERTICAL);
controlColumn.setLayoutData(data);
layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
controlColumn.setLayout(layout);
controlArea = new Composite(controlColumn, SWT.NONE);
controlAreaLayout = new StackLayout();
controlArea.setLayout(controlAreaLayout);
colorControls = new Composite(controlArea, SWT.NONE);
colorControls.setLayout(new FillLayout());
createColorControl();
fontControls = new Composite(controlArea, SWT.NONE);
fontControls.setLayout(new FillLayout());
createFontControl();
createDescriptionControl(mainColumn);
createPreviewControl(mainColumn);
hookListeners();
return mainColumn;
}
/**
* Create the text box that will contain the current color/font description
* text (if any).
*
* @param parent the parent <code>Composite</code>.
*/
private void createDescriptionControl(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginWidth = 0;
layout.marginHeight = 0;
composite.setLayout(layout);
GridData data = new GridData(GridData.FILL_BOTH);
data.heightHint = convertHeightInCharsToPixels(5);
composite.setLayoutData(data);
Label label = new Label(composite, SWT.LEFT);
label.setText(RESOURCE_BUNDLE.getString("description")); //$NON-NLS-1$
myApplyDialogFont(label);
descriptionText = new Text(composite, SWT.H_SCROLL | SWT.V_SCROLL
| SWT.READ_ONLY | SWT.BORDER | SWT.WRAP);
data = new GridData(GridData.FILL_BOTH);
descriptionText.setLayoutData(data);
myApplyDialogFont(descriptionText);
}
private void createFontControl() {
Composite composite = new Composite(fontControls, SWT.NONE);
GridLayout layout = new GridLayout(1, false);
layout.marginHeight = 0;
layout.marginWidth = 0;
composite.setLayout(layout);
fontSystemButton = createButton(composite, WorkbenchMessages.FontsPreference_useSystemFont);
fontChangeButton = createButton(composite, JFaceResources
.getString("openChange")); //$NON-NLS-1$
fontResetButton = createButton(composite, RESOURCE_BUNDLE
.getString("reset")); //$NON-NLS-1$
}
/**
* Create the <code>ListViewer</code> that will contain all color
* definitions as defined in the extension point.
*
* @param parent the parent <code>Composite</code>.
*/
private void createTree(Composite parent) {
labelProvider = new PresentationLabelProvider();
// create a new tree with a custom pattern matcher that will allow
// non-category elements to be returned in the event that their children
// do not
tree = new FilteredTree(parent, SWT.SINGLE | SWT.H_SCROLL
| SWT.V_SCROLL | SWT.BORDER, new PatternFilter() {
/* (non-Javadoc)
* @see org.eclipse.ui.dialogs.PatternFilter#isParentMatch(org.eclipse.jface.viewers.Viewer, java.lang.Object)
*/
protected boolean isParentMatch(Viewer viewer, Object element) {
Object[] children = ((ITreeContentProvider) ((AbstractTreeViewer) viewer)
.getContentProvider()).getChildren(element);
if (children.length > 0
&& element instanceof ThemeElementCategory) {
return filter(viewer, element, children).length > 0;
}
return false;
}
});
GridData data = new GridData(GridData.FILL_HORIZONTAL
| GridData.VERTICAL_ALIGN_FILL);
data.heightHint = Math.max(175, convertHeightInCharsToPixels(10));
tree.setLayoutData(data);
myApplyDialogFont(tree.getViewer().getControl());
Text filterText = tree.getFilterControl();
if (filterText != null) {
myApplyDialogFont(filterText);
}
tree.getViewer().setLabelProvider(labelProvider);
tree.getViewer().setContentProvider(new ThemeContentProvider());
tree.getViewer().setComparator(new ViewerComparator() {
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ViewerComparator#category(java.lang.Object)
*/
public int category(Object element) {
if (element instanceof ThemeElementCategory) {
return 0;
}
return 1;
}
});
tree.getViewer().setInput(
WorkbenchPlugin.getDefault().getThemeRegistry());
tree.getViewer().addDoubleClickListener(new IDoubleClickListener() {
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.IDoubleClickListener#doubleClick(org.eclipse.jface.viewers.DoubleClickEvent)
*/
public void doubleClick(DoubleClickEvent event) {
IStructuredSelection s = (IStructuredSelection) event
.getSelection();
Object element = s.getFirstElement();
if (tree.getViewer().isExpandable(element)) {
tree.getViewer().setExpandedState(element,
!tree.getViewer().getExpandedState(element));
}
if (element instanceof FontDefinition) {
editFont(tree.getDisplay());
}
else if (element instanceof ColorDefinition) {
colorSelector.open();
}
}
});
restoreTreeExpansion();
restoreTreeSelection();
}
/**
* @param mainColumn
*/
private void createPreviewControl(Composite mainColumn) {
Composite composite = new Composite(mainColumn, SWT.NONE);
GridData data = new GridData(GridData.FILL_BOTH);
data.heightHint = 175;
composite.setLayoutData(data);
GridLayout layout = new GridLayout(1, true);
layout.marginHeight = 0;
layout.marginWidth = 0;
composite.setLayout(layout);
Label label = new Label(composite, SWT.LEFT);
label.setText(RESOURCE_BUNDLE.getString("preview")); //$NON-NLS-1$
myApplyDialogFont(label);
previewComposite = new Composite(composite, SWT.NONE);
data = new GridData(GridData.FILL_BOTH);
previewComposite.setLayoutData(data);
stackLayout = new StackLayout();
previewComposite.setLayout(stackLayout);
}
/* (non-Javadoc)
* @see org.eclipse.jface.dialogs.IDialogPage#dispose()
*/
public void dispose() {
super.dispose();
workbench.getThemeManager().removePropertyChangeListener(
themeChangeListener);
clearPreviews();
colorRegistry.dispose();
fontRegistry.dispose();
}
/**
* Clear all previews.
*/
private void clearPreviews() {
if (cascadingTheme != null) {
cascadingTheme.dispose();
}
for (Iterator i = previewSet.iterator(); i.hasNext();) {
IThemePreview preview = (IThemePreview) i.next();
try {
preview.dispose();
} catch (RuntimeException e) {
WorkbenchPlugin
.log(
RESOURCE_BUNDLE
.getString("errorDisposePreviewLog"), StatusUtil.newStatus(IStatus.ERROR, e.getMessage(), e)); //$NON-NLS-1$
}
}
previewSet.clear();
}
/**
* Get the ancestor of the given color, if any.
*
* @param definition the descendant <code>ColorDefinition</code>.
* @return the ancestror <code>ColorDefinition</code>, or <code>null</code>
* if none.
*/
private ColorDefinition getColorAncestor(ColorDefinition definition) {
String defaultsTo = definition.getDefaultsTo();
if (defaultsTo == null) {
return null;
}
return themeRegistry.findColor(defaultsTo);
}
/**
* Get the RGB value of the given colors ancestor, if any.
*
* @param definition the descendant <code>ColorDefinition</code>.
* @return the ancestror <code>RGB</code>, or <code>null</code> if none.
*/
private RGB getColorAncestorValue(ColorDefinition definition) {
ColorDefinition ancestor = getColorAncestor(definition);
if (ancestor == null) {
return null;
}
return getColorValue(ancestor);
}
/**
* Get the RGB value for the specified definition. Cascades through
* preferenceToSet, valuesToSet and finally the registry.
*
* @param definition the <code>ColorDefinition</code>.
* @return the <code>RGB</code> value.
*/
private RGB getColorValue(ColorDefinition definition) {
String id = definition.getId();
RGB updatedRGB = (RGB) colorPreferencesToSet.get(id);
if (updatedRGB == null) {
updatedRGB = (RGB) colorValuesToSet.get(id);
if (updatedRGB == null) {
updatedRGB = currentTheme.getColorRegistry().getRGB(id);
}
}
return updatedRGB;
}
/**
* @return Return the default "No preview available." preview.
*/
private Composite getDefaultPreviewControl() {
if (defaultPreviewControl == null) {
defaultPreviewControl = new Composite(previewComposite, SWT.NONE);
defaultPreviewControl.setLayout(new FillLayout());
Label l = new Label(defaultPreviewControl, SWT.LEFT);
l.setText(RESOURCE_BUNDLE.getString("noPreviewAvailable")); //$NON-NLS-1$
myApplyDialogFont(l);
}
return defaultPreviewControl;
}
/**
* Get colors that descend from the provided color.
*
* @param definition the ancestor <code>ColorDefinition</code>.
* @return the ColorDefinitions that have the provided definition as their
* defaultsTo attribute.
*/
private ColorDefinition[] getDescendantColors(ColorDefinition definition) {
List list = new ArrayList(5);
String id = definition.getId();
ColorDefinition[] colors = themeRegistry.getColors();
ColorDefinition[] sorted = new ColorDefinition[colors.length];
System.arraycopy(colors, 0, sorted, 0, sorted.length);
Arrays.sort(sorted, new IThemeRegistry.HierarchyComparator(colors));
for (int i = 0; i < sorted.length; i++) {
if (id.equals(sorted[i].getDefaultsTo())) {
list.add(sorted[i]);
}
}
return (ColorDefinition[]) list
.toArray(new ColorDefinition[list.size()]);
}
/**
* @param definition
* @return
*/
private FontDefinition[] getDescendantFonts(FontDefinition definition) {
List list = new ArrayList(5);
String id = definition.getId();
FontDefinition[] fonts = themeRegistry.getFonts();
FontDefinition[] sorted = new FontDefinition[fonts.length];
System.arraycopy(fonts, 0, sorted, 0, sorted.length);
Arrays.sort(sorted, new IThemeRegistry.HierarchyComparator(fonts));
for (int i = 0; i < sorted.length; i++) {
if (id.equals(sorted[i].getDefaultsTo())) {
list.add(sorted[i]);
}
}
return (FontDefinition[]) list.toArray(new FontDefinition[list.size()]);
}
/**
* @param definition
* @return
*/
private FontDefinition getFontAncestor(FontDefinition definition) {
String defaultsTo = definition.getDefaultsTo();
if (defaultsTo == null) {
return null;
}
return themeRegistry.findFont(defaultsTo);
}
/**
* @param definition
* @return
*/
private FontData[] getFontAncestorValue(FontDefinition definition) {
FontDefinition ancestor = getFontAncestor(definition);
if (ancestor == null) {
return PreferenceConverter.getDefaultFontDataArray(
getPreferenceStore(), ThemeElementHelper
.createPreferenceKey(currentTheme, definition
.getId()));
}
return getFontValue(ancestor);
}
/**
* @param definition
* @return
*/
protected FontData[] getFontValue(FontDefinition definition) {
String id = definition.getId();
FontData[] updatedFD = (FontData[]) fontPreferencesToSet.get(id);
if (updatedFD == null) {
updatedFD = (FontData[]) fontValuesToSet.get(id);
if (updatedFD == null) {
updatedFD = currentTheme.getFontRegistry().getFontData(id);
}
}
return updatedFD;
}
/**
* @return
*/
protected ColorDefinition getSelectedColorDefinition() {
Object o = ((IStructuredSelection) tree.getViewer().getSelection())
.getFirstElement();
if (o instanceof ColorDefinition) {
return (ColorDefinition) o;
}
return null;
}
/**
* @return
*/
protected FontDefinition getSelectedFontDefinition() {
Object o = ((IStructuredSelection) tree.getViewer().getSelection())
.getFirstElement();
if (o instanceof FontDefinition) {
return (FontDefinition) o;
}
return null;
}
/**
* Hook all control listeners.
*/
private void hookListeners() {
colorSelector.addListener(new IPropertyChangeListener() {
/* (non-Javadoc)
* @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent event) {
ColorDefinition definition = getSelectedColorDefinition();
RGB newRGB = (RGB) event.getNewValue();
if (definition != null && newRGB != null
&& !newRGB.equals(event.getOldValue())) {
setColorPreferenceValue(definition, newRGB);
setRegistryValue(definition, newRGB);
}
updateColorControls(definition);
}
});
tree.getViewer().addSelectionChangedListener(
new ISelectionChangedListener() {
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
*/
public void selectionChanged(SelectionChangedEvent event) {
if (event.getSelection().isEmpty()) {
swapNoControls();
updateColorControls(null);
updateCategorySelection(null);
} else {
Object element = ((IStructuredSelection) event
.getSelection()).getFirstElement();
if (element instanceof ThemeElementCategory) {
swapNoControls();
String description = ((ThemeElementCategory) element)
.getDescription();
descriptionText
.setText(description == null ? "" : description); //$NON-NLS-1$
updateCategorySelection((ThemeElementCategory) element);
} else if (element instanceof ColorDefinition) {
updateColorControls((ColorDefinition) element);
swapColorControls();
updateCategorySelection(WorkbenchPlugin
.getDefault().getThemeRegistry()
.findCategory(
((ColorDefinition) element)
.getCategoryId()));
} else if (element instanceof FontDefinition) {
updateFontControls((FontDefinition) element);
swapFontControls();
updateCategorySelection(WorkbenchPlugin
.getDefault().getThemeRegistry()
.findCategory(
((FontDefinition) element)
.getCategoryId()));
}
}
}
});
colorResetButton.addSelectionListener(new SelectionAdapter() {
/* (non-Javadoc)
* @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
*/
public void widgetSelected(SelectionEvent e) {
ColorDefinition definition = getSelectedColorDefinition();
if (resetColor(definition)) {
updateColorControls(definition);
}
}
});
fontResetButton.addSelectionListener(new SelectionAdapter() {
/* (non-Javadoc)
* @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
*/
public void widgetSelected(SelectionEvent e) {
FontDefinition definition = getSelectedFontDefinition();
if (resetFont(definition)) {
updateFontControls(definition);
}
}
});
fontChangeButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
Display display = event.display;
editFont(display);
}
});
fontSystemButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
FontDefinition definition = getSelectedFontDefinition();
if (definition != null) {
FontData[] defaultFontData = JFaceResources
.getDefaultFont().getFontData();
setFontPreferenceValue(definition, defaultFontData);
setRegistryValue(definition, defaultFontData);
updateFontControls(definition);
}
}
});
}
/* (non-Javadoc)
* @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
*/
public void init(IWorkbench aWorkbench) {
this.workbench = (Workbench) aWorkbench;
setPreferenceStore(PrefUtil.getInternalPreferenceStore());
final IThemeManager themeManager = aWorkbench.getThemeManager();
themeChangeListener = new IPropertyChangeListener() {
/* (non-Javadoc)
* @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent event) {
if (event.getProperty().equals(
IThemeManager.CHANGE_CURRENT_THEME)) {
updateThemeInfo(themeManager);
refreshCategory();
}
}
};
themeManager.addPropertyChangeListener(themeChangeListener);
updateThemeInfo(themeManager);
}
private void updateThemeInfo(IThemeManager manager) {
clearPreviews();
categoryMap.clear();
if (labelProvider != null) {
labelProvider.dispose(); // nuke the old cache
}
if (colorRegistry != null) {
colorRegistry.dispose();
}
if (fontRegistry != null) {
fontRegistry.dispose();
}
currentTheme = manager.getCurrentTheme();
colorRegistry = new CascadingColorRegistry(currentTheme
.getColorRegistry());
fontRegistry = new CascadingFontRegistry(currentTheme.getFontRegistry());
fontPreferencesToSet.clear();
fontValuesToSet.clear();
colorPreferencesToSet.clear();
colorValuesToSet.clear();
if (labelProvider != null) {
labelProvider.hookListeners(); // rehook the listeners
}
}
/**
* Answers whether the definition is currently set to the default value.
*
* @param definition the <code>ColorDefinition</code> to check.
* @return Return whether the definition is currently mapped to the default
* value, either in the preference store or in the local change record
* of this preference page.
*/
private boolean isDefault(ColorDefinition definition) {
String id = definition.getId();
if (colorPreferencesToSet.containsKey(id)) {
if (definition.getValue() != null) { // value-based color
if (colorPreferencesToSet.get(id).equals(definition.getValue())) {
return true;
}
} else {
if (colorPreferencesToSet.get(id).equals(
getColorAncestorValue(definition))) {
return true;
}
}
} else {
if (definition.getValue() != null) { // value-based color
if (getPreferenceStore().isDefault(
ThemeElementHelper
.createPreferenceKey(currentTheme, id))) {
return true;
}
} else {
// a descendant is default if it's the same value as its ancestor
if (getColorValue(definition).equals(
getColorAncestorValue(definition))) {
return true;
}
}
}
return false;
}
/**
* @param definition
* @return
*/
private boolean isDefault(FontDefinition definition) {
String id = definition.getId();
if (fontPreferencesToSet.containsKey(id)) {
if (definition.getValue() != null) { // value-based font
if (Arrays.equals((FontData[]) fontPreferencesToSet.get(id),
definition.getValue())) {
return true;
}
} else {
FontData[] ancestor = getFontAncestorValue(definition);
if (Arrays.equals((FontData[]) fontPreferencesToSet.get(id),
ancestor)) {
return true;
}
}
} else {
if (definition.getValue() != null) { // value-based font
if (getPreferenceStore().isDefault(
ThemeElementHelper
.createPreferenceKey(currentTheme, id))) {
return true;
}
} else {
FontData[] ancestor = getFontAncestorValue(definition);
if (ancestor == null) {
return true;
}
// a descendant is default if it's the same value as its ancestor
if (Arrays.equals(getFontValue(definition), ancestor)) {
return true;
}
}
}
return false;
}
/**
* Apply the dialog font to the control and store
* it for later so that it can be used for a later
* update.
* @param control
*/
private void myApplyDialogFont(Control control) {
control.setFont(JFaceResources.getDialogFont());
dialogFontWidgets.add(control);
}
/**
* @see org.eclipse.jface.preference.PreferencePage#performApply()
*/
protected void performApply() {
super.performApply();
//Apply the default font to the dialog.
Font oldFont = appliedDialogFont;
FontDefinition fontDefinition = themeRegistry
.findFont(JFaceResources.DIALOG_FONT);
if (fontDefinition == null) {
return;
}
FontData[] newData = getFontValue(fontDefinition);
appliedDialogFont = new Font(getControl().getDisplay(), newData);
updateForDialogFontChange(appliedDialogFont);
getApplyButton().setFont(appliedDialogFont);
getDefaultsButton().setFont(appliedDialogFont);
if (oldFont != null) {
oldFont.dispose();
}
}
/**
*
*/
private void performColorDefaults() {
ColorDefinition[] definitions = themeRegistry.getColors();
// apply defaults in depth-order.
ColorDefinition[] definitionsCopy = new ColorDefinition[definitions.length];
System
.arraycopy(definitions, 0, definitionsCopy, 0,
definitions.length);
Arrays.sort(definitionsCopy, new IThemeRegistry.HierarchyComparator(
definitions));
for (int i = 0; i < definitionsCopy.length; i++) {
resetColor(definitionsCopy[i]);
}
updateColorControls(getSelectedColorDefinition());
}
/**
* @return
*/
private boolean performColorOk() {
for (Iterator i = colorPreferencesToSet.keySet().iterator(); i
.hasNext();) {
String id = (String) i.next();
String key = ThemeElementHelper.createPreferenceKey(currentTheme,
id);
RGB rgb = (RGB) colorPreferencesToSet.get(id);
String rgbString = StringConverter.asString(rgb);
String storeString = getPreferenceStore().getString(key);
if (!rgbString.equals(storeString)) {
getPreferenceStore().setValue(key, rgbString);
}
}
colorValuesToSet.clear();
colorPreferencesToSet.clear();
return true;
}
/* (non-Javadoc)
* @see org.eclipse.jface.preference.PreferencePage#performDefaults()
*/
protected void performDefaults() {
performColorDefaults();
performFontDefaults();
}
/**
*
*/
private void performFontDefaults() {
FontDefinition[] definitions = themeRegistry.getFonts();
// apply defaults in depth-order.
FontDefinition[] definitionsCopy = new FontDefinition[definitions.length];
System
.arraycopy(definitions, 0, definitionsCopy, 0,
definitions.length);
Arrays.sort(definitionsCopy, new IThemeRegistry.HierarchyComparator(
definitions));
for (int i = 0; i < definitionsCopy.length; i++) {
resetFont(definitionsCopy[i]);
}
updateFontControls(getSelectedFontDefinition());
}
/**
* @return
*/
private boolean performFontOk() {
for (Iterator i = fontPreferencesToSet.keySet().iterator(); i.hasNext();) {
String id = (String) i.next();
String key = ThemeElementHelper.createPreferenceKey(currentTheme,
id);
FontData[] fd = (FontData[]) fontPreferencesToSet.get(id);
String fdString = PreferenceConverter.getStoredRepresentation(fd);
String storeString = getPreferenceStore().getString(key);
if (!fdString.equals(storeString)) {
getPreferenceStore().setValue(key, fdString);
}
}
fontValuesToSet.clear();
fontPreferencesToSet.clear();
return true;
}
/* (non-Javadoc)
* @see org.eclipse.jface.preference.IPreferencePage#performOk()
*/
public boolean performOk() {
saveTreeExpansion();
saveTreeSelection();
boolean result = performColorOk() && performFontOk();
if(result) {
PrefUtil.savePrefs();
}
return result;
}
/**
* Refreshes the category.
*/
private void refreshCategory() {
updateColorControls(null);
updateFontControls(null);
}
/**
* Resets the supplied definition to its default value.
*
* @param definition the <code>ColorDefinition</code> to reset.
* @return whether any change was made.
*/
private boolean resetColor(ColorDefinition definition) {
if (!isDefault(definition)) {
RGB newRGB;
if (definition.getValue() != null) {
newRGB = definition.getValue();
} else {
newRGB = getColorAncestorValue(definition);
}
if (newRGB != null) {
setColorPreferenceValue(definition, newRGB);
setRegistryValue(definition, newRGB);
return true;
}
}
return false;
}
/**
* @param definition
* @return
*/
protected boolean resetFont(FontDefinition definition) {
if (!isDefault(definition)) {
FontData[] newFD;
if (definition.getDefaultsTo() != null) {
newFD = getFontAncestorValue(definition);
} else {
newFD = PreferenceConverter.getDefaultFontDataArray(
getPreferenceStore(), ThemeElementHelper
.createPreferenceKey(currentTheme, definition
.getId()));
}
if (newFD != null) {
setFontPreferenceValue(definition, newFD);
setRegistryValue(definition, newFD);
return true;
}
}
return false;
}
/**
* Set the value (in preferences) for the given color.
*
* @param definition the <code>ColorDefinition</code> to set.
* @param newRGB the new <code>RGB</code> value for the definitions
* identifier.
*/
protected void setColorPreferenceValue(ColorDefinition definition,
RGB newRGB) {
setDescendantRegistryValues(definition, newRGB);
colorPreferencesToSet.put(definition.getId(), newRGB);
}
/**
* Set the value (in registry) for the given colors children.
*
* @param definition the <code>ColorDefinition</code> whos children should
* be set.
* @param newRGB the new <code>RGB</code> value for the definitions
* identifier.
*/
private void setDescendantRegistryValues(ColorDefinition definition,
RGB newRGB) {
ColorDefinition[] children = getDescendantColors(definition);
for (int i = 0; i < children.length; i++) {
if (isDefault(children[i])) {
setDescendantRegistryValues(children[i], newRGB);
setRegistryValue(children[i], newRGB);
colorValuesToSet.put(children[i].getId(), newRGB);
}
}
}
/**
* @param definition
* @param datas
*/
private void setDescendantRegistryValues(FontDefinition definition,
FontData[] datas) {
FontDefinition[] children = getDescendantFonts(definition);
for (int i = 0; i < children.length; i++) {
if (isDefault(children[i])) {
setDescendantRegistryValues(children[i], datas);
setRegistryValue(children[i], datas);
fontValuesToSet.put(children[i].getId(), datas);
}
}
}
/**
* @param definition
* @param datas
*/
protected void setFontPreferenceValue(FontDefinition definition,
FontData[] datas) {
setDescendantRegistryValues(definition, datas);
fontPreferencesToSet.put(definition.getId(), datas);
}
/**
* Updates the working registry.
* @param definition
* @param newRGB
*/
protected void setRegistryValue(ColorDefinition definition, RGB newRGB) {
colorRegistry.put(definition.getId(), newRGB);
}
/**
* @param definition
* @param datas
*/
protected void setRegistryValue(FontDefinition definition, FontData[] datas) {
fontRegistry.put(definition.getId(), datas);
}
/**
* Swap in the color selection controls.
*/
protected void swapColorControls() {
controlAreaLayout.topControl = colorControls;
controlArea.layout();
}
/**
* Swap in the font selection controls.
*/
protected void swapFontControls() {
controlAreaLayout.topControl = fontControls;
controlArea.layout();
}
/**
* Swap in no controls (empty the control area)
*/
protected void swapNoControls() {
controlAreaLayout.topControl = null;
controlArea.layout();
}
/**
* Set the color list.
* @param category the category to use.
*/
private void updateCategorySelection(ThemeElementCategory category) {
Composite previewControl = (Composite) previewMap.get(category);
if (previewControl == null) {
if (category != null) {
try {
IThemePreview preview = getThemePreview(category);
if (preview != null) {
previewControl = new Composite(previewComposite,
SWT.NONE);
previewControl.setLayout(new FillLayout());
ITheme theme = getCascadingTheme();
preview.createControl(previewControl, theme);
previewSet.add(preview);
}
} catch (CoreException e) {
previewControl = new Composite(previewComposite, SWT.NONE);
previewControl.setLayout(new FillLayout());
myApplyDialogFont(previewControl);
Text error = new Text(previewControl, SWT.WRAP
| SWT.READ_ONLY);
error.setText(RESOURCE_BUNDLE
.getString("errorCreatingPreview")); //$NON-NLS-1$
WorkbenchPlugin
.log(
RESOURCE_BUNDLE
.getString("errorCreatePreviewLog"), StatusUtil.newStatus(IStatus.ERROR, e.getMessage(), e)); //$NON-NLS-1$
}
}
}
if (previewControl == null) {
previewControl = getDefaultPreviewControl();
}
previewMap.put(category, previewControl);
stackLayout.topControl = previewControl;
previewComposite.layout();
}
/**
* @param category the category
* @return the preview for the category, or its ancestors preview if it does not have one.
*/
private IThemePreview getThemePreview(ThemeElementCategory category)
throws CoreException {
IThemePreview preview = category.createPreview();
if (preview != null) {
return preview;
}
if (category.getParentId() != null) {
int idx = Arrays.binarySearch(themeRegistry.getCategories(),
category.getParentId(), IThemeRegistry.ID_COMPARATOR);
if (idx >= 0) {
return getThemePreview(themeRegistry.getCategories()[idx]);
}
}
return null;
}
/**
* @return
*/
private ITheme getCascadingTheme() {
if (cascadingTheme == null) {
cascadingTheme = new CascadingTheme(currentTheme, colorRegistry,
fontRegistry);
}
return cascadingTheme;
}
/**
* Update the color controls based on the supplied definition.
*
* @param definition The currently selected <code>ColorDefinition</code>.
*/
protected void updateColorControls(ColorDefinition definition) {
if (definition == null) {
colorResetButton.setEnabled(false);
colorSelector.setEnabled(false);
descriptionText.setText(""); //$NON-NLS-1$
return;
}
colorSelector.setColorValue(getColorValue(definition));
colorResetButton.setEnabled(!isDefault(definition));
colorSelector.setEnabled(true);
String description = definition.getDescription();
descriptionText.setText(description == null ? "" : description); //$NON-NLS-1$
}
protected void updateFontControls(FontDefinition definition) {
if (definition == null) {
fontSystemButton.setEnabled(false);
fontResetButton.setEnabled(false);
fontChangeButton.setEnabled(false);
descriptionText.setText(""); //$NON-NLS-1$
return;
}
fontSystemButton.setEnabled(true);
fontResetButton.setEnabled(!isDefault(definition));
fontChangeButton.setEnabled(true);
String description = definition.getDescription();
descriptionText.setText(description == null ? "" : description); //$NON-NLS-1$
}
/**
* Update for a change in the dialog font.
* @param newFont
*/
private void updateForDialogFontChange(Font newFont) {
Iterator iterator = dialogFontWidgets.iterator();
while (iterator.hasNext()) {
((Control) iterator.next()).setFont(newFont);
}
//recalculate the fonts for the tree
labelProvider.clearFontCache();
}
/**
* Restore the selection state of the tree.
*
* @since 3.1
*/
private void restoreTreeSelection() {
String selectedElementString = getPreferenceStore().getString(
SELECTED_ELEMENT_PREF);
if (selectedElementString == null) {
return;
}
Object element = findElementFromMarker(selectedElementString);
if (element == null) {
return;
}
tree.getViewer().setSelection(new StructuredSelection(element), true);
}
/**
* Save the selection state of the tree.
*
* @since 3.1
*/
private void saveTreeSelection() {
IStructuredSelection selection = (IStructuredSelection) tree
.getViewer().getSelection();
Object element = selection.getFirstElement();
StringBuffer buffer = new StringBuffer();
appendMarkerToBuffer(buffer, element);
if (buffer.length() > 0) {
buffer.append(((IThemeElementDefinition) element).getId());
}
getPreferenceStore().setValue(SELECTED_ELEMENT_PREF, buffer.toString());
}
/**
* Restore the expansion state of the tree.
*
* @since 3.1
*/
private void restoreTreeExpansion() {
String expandedElementsString = getPreferenceStore().getString(
EXPANDED_ELEMENTS_PREF);
if (expandedElementsString == null) {
return;
}
String[] expandedElementIDs = Util.getArrayFromList(expandedElementsString, EXPANDED_ELEMENTS_TOKEN);
if (expandedElementIDs.length == 0) {
return;
}
List elements = new ArrayList(expandedElementIDs.length);
for (int i = 0; i < expandedElementIDs.length; i++) {
IThemeElementDefinition def = findElementFromMarker(expandedElementIDs[i]);
if (def != null) {
elements.add(def);
}
}
tree.getViewer().setExpandedElements(elements.toArray());
}
/**
* Find the theme element from the given string. It will check the first
* character against the known constants and then call the appropriate
* method on the theme registry. If the element does not exist or the string
* is invalid <code>null</code> is returned.
*
* @param string the string to parse
* @return the element, or <code>null</code>
*/
private IThemeElementDefinition findElementFromMarker(String string) {
if (string.length() < 2) {
return null;
}
char marker = string.charAt(0);
String id = string.substring(1);
IThemeElementDefinition def = null;
switch (marker) {
case MARKER_FONT:
def = themeRegistry.findFont(id);
break;
case MARKER_COLOR:
def = themeRegistry.findColor(id);
break;
case MARKER_CATEGORY:
def = themeRegistry.findCategory(id);
break;
}
return def;
}
/**
* Saves the expansion state of the tree.
*
* @since 3.1
*/
private void saveTreeExpansion() {
Object[] elements = tree.getViewer().getExpandedElements();
List elementIds = new ArrayList(elements.length);
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < elements.length; i++) {
Object object = elements[i];
appendMarkerToBuffer(buffer, object);
if (buffer.length() != 0) {
buffer.append(((IThemeElementDefinition) object).getId());
elementIds.add(buffer.toString());
}
buffer.setLength(0);
}
for (Iterator i = elementIds.iterator(); i.hasNext();) {
String id = (String) i.next();
buffer.append(id);
if (i.hasNext()) {
buffer.append(EXPANDED_ELEMENTS_TOKEN);
}
}
getPreferenceStore()
.setValue(EXPANDED_ELEMENTS_PREF, buffer.toString());
}
/**
* @param buffer
* @param object
*/
private void appendMarkerToBuffer(StringBuffer buffer, Object object) {
if (object instanceof FontDefinition) {
buffer.append(MARKER_FONT);
} else if (object instanceof ColorDefinition) {
buffer.append(MARKER_COLOR);
} else if (object instanceof ThemeElementCategory) {
buffer.append(MARKER_CATEGORY);
}
}
/**
* Edit the currently selected font.
*
* @param display the display to open the dialog on
* @since 3.2
*/
private void editFont(Display display) {
final FontDefinition definition = getSelectedFontDefinition();
if (definition != null) {
final FontDialog fontDialog = new FontDialog(fontChangeButton
.getShell());
fontDialog.setFontList(getFontValue(definition));
final FontData data = fontDialog.open();
if (data != null) {
setFontPreferenceValue(definition, fontDialog.getFontList());
setRegistryValue(definition, fontDialog.getFontList());
}
updateFontControls(definition);
}
}
}