/*******************************************************************************
* Copyright (c) 2004 Eric Merritt 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:
* Eric Merritt
* Vlad Dumitrescu
*******************************************************************************/
package org.erlide.ui.prefs.plugin;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Map;
import org.eclipse.jface.preference.ColorSelector;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.resource.StringConverter;
import org.eclipse.jface.text.TextAttribute;
import org.eclipse.jface.text.source.SourceViewer;
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.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
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.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Scrollable;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.erlide.ui.editors.erl.ErlangSourceViewer;
import org.erlide.ui.internal.ErlideUIPlugin;
import org.erlide.ui.prefs.HighlightStyle;
import org.erlide.ui.prefs.TokenHighlight;
import org.erlide.ui.util.ColorManager;
import org.erlide.ui.util.IColorManager;
import org.erlide.ui.util.OverlayPreferenceStore;
import org.erlide.ui.util.PixelConverter;
import org.erlide.util.ErlLogger;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
/**
* The color preferences.
*
* @author Eric Merritt [cyberlync at gmail dot com]
*/
public class ColoringPreferencePage extends PreferencePage
implements IWorkbenchPreferencePage {
public static final String COLORS_QUALIFIER = "editor_colors_";
public static final String STYLE_KEY = "style";
public static final String COLOR_KEY = "color";
public static final String OLD_COLORS_QUALIFIER = "org.erlide.ui/editor/colors";
final String fErlangCategory = PreferencesMessages.ErlEditorPreferencePage_coloring_category_erlang;
ColorSelector fSyntaxForegroundColorEditor;
Label fColorEditorLabel;
Button fEnableCheckbox;
Button fBoldCheckBox;
Button fItalicCheckBox;
Button fStrikethroughCheckBox;
Button fUnderlineCheckBox;
private TreeViewer fListViewer;
private IColorManager fColorManager;
SourceViewer fPreviewViewer;
Map<TokenHighlight, HighlightStyle> fColors;
private OverlayPreferenceStore fOverlayStore;
public ColoringPreferencePage() {
fColors = Maps.newHashMap();
}
/**
* @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
*/
@Override
public void init(final IWorkbench workbench) {
fColorManager = new ColorManager();
fOverlayStore = new OverlayPreferenceStore(
ErlideUIPlugin.getDefault().getPreferenceStore(),
new OverlayPreferenceStore.OverlayKey[] {});
fOverlayStore.addKeys(createOverlayStoreKeys());
fOverlayStore.load();
fOverlayStore.start();
for (final TokenHighlight th : TokenHighlight.values()) {
fColors.put(th, null);
}
}
private OverlayPreferenceStore.OverlayKey[] createOverlayStoreKeys() {
final List<OverlayPreferenceStore.OverlayKey> overlayKeys = Lists.newArrayList();
for (final TokenHighlight item : TokenHighlight.values()) {
overlayKeys.add(new OverlayPreferenceStore.OverlayKey(
OverlayPreferenceStore.TypeDescriptor.STRING, item.getColorKey()));
overlayKeys.add(new OverlayPreferenceStore.OverlayKey(
OverlayPreferenceStore.TypeDescriptor.INT, item.getStylesKey()));
}
final OverlayPreferenceStore.OverlayKey[] keys = new OverlayPreferenceStore.OverlayKey[overlayKeys
.size()];
overlayKeys.toArray(keys);
return keys;
}
static class ColorListLabelProvider extends LabelProvider {
@Override
public String getText(final Object element) {
if (element instanceof String) {
return (String) element;
}
final String name = ((TokenHighlight) element).getDisplayName();
final char c = Character.toUpperCase(name.charAt(0));
return c + name.substring(1);
}
}
class ColorListContentProvider implements ITreeContentProvider {
@Override
public Object[] getElements(final Object inputElement) {
return new String[] { fErlangCategory
// , fEdocCategory
};
}
@Override
public void dispose() {
}
@Override
public void inputChanged(final Viewer viewer, final Object oldInput,
final Object newInput) {
}
@Override
public Object[] getChildren(final Object parentElement) {
if (parentElement instanceof String) {
final String entry = (String) parentElement;
if (fErlangCategory.equals(entry)) {
return fColors.keySet().toArray();
}
// if (fEdocCategory.equals(entry)) {
// return fListModel.subList(0, 4).toArray();
// }
}
return new Object[0];
}
@Override
public Object getParent(final Object element) {
if (element instanceof String) {
return null;
}
// final int index = fListModel.indexOf(element);
// if (index < 4) {
// return fEdocCategory;
// }
return fErlangCategory;
}
@Override
public boolean hasChildren(final Object element) {
return element instanceof String;
}
}
@Override
public void performDefaults() {
super.performDefaults();
fOverlayStore.loadDefaults();
handleSyntaxColorListSelection();
fPreviewViewer.invalidateTextPresentation();
}
@Override
public boolean performOk() {
fOverlayStore.propagate();
ErlideUIPlugin.flushInstanceScope();
return super.performOk();
}
public void storeHighlight(final IPreferenceStore store, final TokenHighlight th,
HighlightStyle style) {
if (store != null) {
store.setValue(th.getColorKey(), StringConverter.asString(style.getColor()));
store.setValue(th.getStylesKey(), style.getStyles());
}
}
@Override
public void dispose() {
fColorManager.dispose();
if (fOverlayStore != null) {
fOverlayStore.stop();
fOverlayStore = null;
}
super.dispose();
}
void handleSyntaxColorListSelection() {
final TokenHighlight item = getHighlight();
fEnableCheckbox.setEnabled(item != null);
fSyntaxForegroundColorEditor.getButton().setEnabled(item != null);
fColorEditorLabel.setEnabled(item != null);
fBoldCheckBox.setEnabled(item != null);
fItalicCheckBox.setEnabled(item != null);
fStrikethroughCheckBox.setEnabled(item != null);
fUnderlineCheckBox.setEnabled(item != null);
if (item == null) {
return;
}
final HighlightStyle style = item.getStyle(fOverlayStore);
fSyntaxForegroundColorEditor.setColorValue(style.getColor());
fBoldCheckBox.setSelection(style.hasStyle(SWT.BOLD));
fItalicCheckBox.setSelection(style.hasStyle(SWT.ITALIC));
fStrikethroughCheckBox.setSelection(style.hasStyle(TextAttribute.STRIKETHROUGH));
fUnderlineCheckBox.setSelection(style.hasStyle(TextAttribute.UNDERLINE));
// if (item instanceof SemanticHighlightingColorListItem) {
// fEnableCheckbox.setEnabled(true);
// final boolean enable = getPreferenceStore().getBoolean(
// ((SemanticHighlightingColorListItem) item).getEnableKey());
// fEnableCheckbox.setSelection(enable);
// fSyntaxForegroundColorEditor.getButton().setEnabled(enable);
// fColorEditorLabel.setEnabled(enable);
// fBoldCheckBox.setEnabled(enable);
// fItalicCheckBox.setEnabled(enable);
// fStrikethroughCheckBox.setEnabled(enable);
// fUnderlineCheckBox.setEnabled(enable);
// }
}
private Control createSyntaxPage(final Composite parent) {
final Composite colorComposite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
colorComposite.setLayout(layout);
final Link link = new Link(colorComposite, SWT.NONE);
link.setText(PreferencesMessages.ErlEditorColoringConfigurationBlock_link);
link.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
PreferencesUtil.createPreferenceDialogOn(parent.getShell(), e.text, null,
null);
}
});
final GridData gridData = new GridData(SWT.FILL, SWT.BEGINNING, true, false);
gridData.widthHint = 150;
gridData.horizontalSpan = 2;
link.setLayoutData(gridData);
addFiller(colorComposite, 1);
Label label;
label = new Label(colorComposite, SWT.LEFT);
label.setText(PreferencesMessages.ErlEditorPreferencePage_coloring_element);
label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
final Composite editorComposite = new Composite(colorComposite, SWT.NONE);
layout = new GridLayout();
layout.numColumns = 2;
layout.marginHeight = 0;
layout.marginWidth = 0;
editorComposite.setLayout(layout);
GridData gd = new GridData(SWT.FILL, SWT.BEGINNING, true, false);
editorComposite.setLayoutData(gd);
fListViewer = new TreeViewer(editorComposite, SWT.SINGLE | SWT.BORDER);
final Tree tree = fListViewer.getTree();
final GridData gdTree = new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1);
gdTree.widthHint = 100;
tree.setLayoutData(gdTree);
fListViewer.setLabelProvider(new ColorListLabelProvider());
fListViewer.setContentProvider(new ColorListContentProvider());
fListViewer.setInput(fColors);
fListViewer.setSelection(new StructuredSelection(fErlangCategory));
fListViewer.setSorter(new ViewerSorter() {
@Override
public int category(final Object element) {
// don't sort the top level categories
if (fErlangCategory.equals(element)) {
return 0;
}
// if (fEdocCategory.equals(element)) {
// return 1;
// }
// to sort semantic settings after partition based ones:
// if (element instanceof SemanticHighlightingColorListItem)
// return 1;
return 0;
}
});
gd = new GridData(SWT.BEGINNING, SWT.BEGINNING, false, true);
gd.heightHint = convertHeightInCharsToPixels(9);
int maxWidth = 0;
for (final TokenHighlight item : fColors.keySet()) {
maxWidth = Math.max(maxWidth,
convertWidthInCharsToPixels(item.getName().length()));
}
final ScrollBar vBar = ((Scrollable) fListViewer.getControl()).getVerticalBar();
if (vBar != null) {
maxWidth += vBar.getSize().x * 3; // scrollbars and tree
}
// indentation guess
gd.widthHint = maxWidth;
fListViewer.getControl().setLayoutData(gd);
fListViewer.expandAll();
final Composite stylesComposite = new Composite(editorComposite, SWT.NONE);
layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.numColumns = 2;
stylesComposite.setLayout(layout);
stylesComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
fEnableCheckbox = new Button(stylesComposite, SWT.CHECK);
fEnableCheckbox.setText(PreferencesMessages.ErlEditorPreferencePage_enable);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalAlignment = GridData.BEGINNING;
gd.horizontalSpan = 2;
fEnableCheckbox.setLayoutData(gd);
// TODO hide this until reworking the dialog
fEnableCheckbox.setVisible(false);
fColorEditorLabel = new Label(stylesComposite, SWT.LEFT);
fColorEditorLabel.setText(PreferencesMessages.ErlEditorPreferencePage_color);
gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
gd.horizontalIndent = 20;
fColorEditorLabel.setLayoutData(gd);
fSyntaxForegroundColorEditor = new ColorSelector(stylesComposite);
final Button foregroundColorButton = fSyntaxForegroundColorEditor.getButton();
gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
foregroundColorButton.setLayoutData(gd);
new Label(stylesComposite, SWT.NONE);
fBoldCheckBox = new Button(stylesComposite, SWT.CHECK);
fBoldCheckBox.setText(PreferencesMessages.ErlEditorPreferencePage_bold);
gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
gd.horizontalIndent = 20;
gd.horizontalSpan = 2;
fBoldCheckBox.setLayoutData(gd);
fItalicCheckBox = new Button(stylesComposite, SWT.CHECK);
fItalicCheckBox.setText(PreferencesMessages.ErlEditorPreferencePage_italic);
gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
gd.horizontalIndent = 20;
gd.horizontalSpan = 2;
fItalicCheckBox.setLayoutData(gd);
fStrikethroughCheckBox = new Button(stylesComposite, SWT.CHECK);
fStrikethroughCheckBox
.setText(PreferencesMessages.ErlEditorPreferencePage_strikeout);
gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
gd.horizontalIndent = 20;
gd.horizontalSpan = 2;
fStrikethroughCheckBox.setLayoutData(gd);
fUnderlineCheckBox = new Button(stylesComposite, SWT.CHECK);
fUnderlineCheckBox.setText(PreferencesMessages.ErlEditorPreferencePage_underline);
gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
gd.horizontalIndent = 20;
gd.horizontalSpan = 2;
fUnderlineCheckBox.setLayoutData(gd);
final String content = loadPreviewContentFromFile(getClass(),
"ColorSettingPreviewCode.txt"); //$NON-NLS-1$
fPreviewViewer = ErlangSourceViewer.createErlangPreviewer(colorComposite,
fColorManager, fOverlayStore, fColors, content);
final Control previewer = fPreviewViewer.getControl();
gd = new GridData(GridData.FILL_BOTH);
gd.widthHint = convertWidthInCharsToPixels(20);
gd.heightHint = convertHeightInCharsToPixels(5);
gd.grabExcessHorizontalSpace = true;
gd.grabExcessVerticalSpace = true;
previewer.setLayoutData(gd);
fListViewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(final SelectionChangedEvent event) {
handleSyntaxColorListSelection();
}
});
foregroundColorButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetDefaultSelected(final SelectionEvent e) {
// do nothing
}
@Override
public void widgetSelected(final SelectionEvent e) {
final TokenHighlight item = getHighlight();
final HighlightStyle data = item.getStyle(fOverlayStore);
if (data == null) {
return;
}
data.setColor(fSyntaxForegroundColorEditor.getColorValue());
storeHighlight(fOverlayStore, item, data);
fPreviewViewer.invalidateTextPresentation();
}
});
fBoldCheckBox.addSelectionListener(new SelectionListener() {
@Override
public void widgetDefaultSelected(final SelectionEvent e) {
// do nothing
}
@Override
public void widgetSelected(final SelectionEvent e) {
final TokenHighlight item = getHighlight();
final HighlightStyle data = item.getStyle(fOverlayStore);
if (data == null) {
return;
}
data.setStyle(SWT.BOLD, fBoldCheckBox.getSelection());
storeHighlight(fOverlayStore, item, data);
fPreviewViewer.invalidateTextPresentation();
}
});
fItalicCheckBox.addSelectionListener(new SelectionListener() {
@Override
public void widgetDefaultSelected(final SelectionEvent e) {
// do nothing
}
@Override
public void widgetSelected(final SelectionEvent e) {
final TokenHighlight item = getHighlight();
final HighlightStyle data = item.getStyle(fOverlayStore);
if (data == null) {
return;
}
data.setStyle(SWT.ITALIC, fItalicCheckBox.getSelection());
storeHighlight(fOverlayStore, item, data);
fPreviewViewer.invalidateTextPresentation();
}
});
fStrikethroughCheckBox.addSelectionListener(new SelectionListener() {
@Override
public void widgetDefaultSelected(final SelectionEvent e) {
// do nothing
}
@Override
public void widgetSelected(final SelectionEvent e) {
final TokenHighlight item = getHighlight();
final HighlightStyle data = item.getStyle(fOverlayStore);
if (data == null) {
return;
}
data.setStyle(TextAttribute.STRIKETHROUGH,
fStrikethroughCheckBox.getSelection());
storeHighlight(fOverlayStore, item, data);
fPreviewViewer.invalidateTextPresentation();
}
});
fUnderlineCheckBox.addSelectionListener(new SelectionListener() {
@Override
public void widgetDefaultSelected(final SelectionEvent e) {
// do nothing
}
@Override
public void widgetSelected(final SelectionEvent e) {
final TokenHighlight item = getHighlight();
final HighlightStyle data = item.getStyle(fOverlayStore);
if (data == null) {
return;
}
data.setStyle(TextAttribute.UNDERLINE, fUnderlineCheckBox.getSelection());
storeHighlight(fOverlayStore, item, data);
fPreviewViewer.invalidateTextPresentation();
}
});
fEnableCheckbox.addSelectionListener(new SelectionListener() {
@Override
public void widgetDefaultSelected(final SelectionEvent e) {
// do nothing
}
@Override
public void widgetSelected(final SelectionEvent e) {
fEnableCheckbox.setSelection(true);
// final TokenHighlight item = getHighlight();
// if (item instanceof SemanticHighlightingColorListItem) {
// final boolean enable = fEnableCheckbox.getSelection();
// getPreferenceStore().setValue(
// ((SemanticHighlightingColorListItem) item)
// .getEnableKey(), enable);
// fEnableCheckbox.setSelection(enable);
// fSyntaxForegroundColorEditor.getButton().setEnabled(enable);
// fColorEditorLabel.setEnabled(enable);
// fBoldCheckBox.setEnabled(enable);
// fItalicCheckBox.setEnabled(enable);
// fStrikethroughCheckBox.setEnabled(enable);
// fUnderlineCheckBox.setEnabled(enable);
// }
}
});
colorComposite.layout(false);
handleSyntaxColorListSelection();
fPreviewViewer.invalidateTextPresentation();
return colorComposite;
}
private void addFiller(final Composite composite, final int horizontalSpan) {
final PixelConverter pixelConverter = new PixelConverter(composite);
final Label filler = new Label(composite, SWT.LEFT);
final GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
gd.horizontalSpan = horizontalSpan;
gd.heightHint = pixelConverter.convertHeightInCharsToPixels(1) / 2;
filler.setLayoutData(gd);
}
public static String loadPreviewContentFromFile(final Class<?> clazz,
final String filename) {
String line;
final String separator = System.getProperty("line.separator"); //$NON-NLS-1$
final StringBuilder buffer = new StringBuilder(512);
BufferedReader reader = null;
try {
reader = new BufferedReader(
new InputStreamReader(clazz.getResourceAsStream(filename)));
while ((line = reader.readLine()) != null) {
buffer.append(line);
buffer.append(separator);
}
} catch (final IOException io) {
ErlLogger.error(io);
} finally {
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
}
}
}
return buffer.toString();
}
/**
* Returns the current highlighting color list item.
*
* @return the current highlighting color list item
*
*/
TokenHighlight getHighlight() {
if (fListViewer == null) {
return null;
}
final IStructuredSelection selection = (IStructuredSelection) fListViewer
.getSelection();
final Object element = selection.getFirstElement();
if (element == null || element instanceof String) {
return null;
}
return (TokenHighlight) element;
}
@Override
protected Control createContents(final Composite parent) {
initializeDialogUnits(parent);
return createSyntaxPage(parent);
}
}