/**
* Copyright 2004-2016 Riccardo Solmi. All rights reserved.
* This file is part of the Whole Platform.
*
* The Whole Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Whole Platform is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whole.lang.e4.ui.preferences;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jface.preference.ColorSelector;
import org.eclipse.jface.preference.FontFieldEditor;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.resource.StringConverter;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
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.TableViewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.TableColumn;
import org.whole.lang.ui.PreferenceConstants;
import org.whole.lang.ui.PreferenceConstants.FontClass;
import org.whole.lang.ui.PreferenceConstants.FontSize;
import org.whole.lang.ui.PreferenceConstants.FontStyle;
import org.whole.lang.ui.util.IUIConstants;
/**
* @author Riccardo Solmi
*/
public class EditorPreferencePage extends PreferencePage {
private static final String[][] bgCategoryListModel= new String[][] {
{ "Selection", PreferenceConstants.SELECTION_CATEGORY },
{ "Matching selection", PreferenceConstants.MATCHING_SELECTION_CATEGORY },
{ "Host stage", PreferenceConstants.HOST_LANGUAGE_CATEGORY },
{ "Template stage", PreferenceConstants.TEMPLATE_LANGUAGE_CATEGORY },
};
private static final String[][] fgCategoryListModel= new String[][] {
{ "Modules", PreferenceConstants.MODULES_CATEGORY },
{ "Declarations", PreferenceConstants.DECLARATIONS_CATEGORY },
{ "Relations", PreferenceConstants.RELATIONS_CATEGORY },
{ "Keywords", PreferenceConstants.KEYWORDS_CATEGORY },
{ "Identifiers", PreferenceConstants.IDENTIFIERS_CATEGORY },
{ "Literals", PreferenceConstants.LITERALS_CATEGORY },
{ "Errors", PreferenceConstants.ERRORS_CATEGORY },
{ "Content", PreferenceConstants.CONTENT_CATEGORY },
{ "Content Dark", PreferenceConstants.CONTENT_DARK_CATEGORY },
{ "Content Light", PreferenceConstants.CONTENT_LIGHT_CATEGORY },
{ "Content Lighter", PreferenceConstants.CONTENT_LIGHTER_CATEGORY },
};
private PreferenceStoreAdapter store;
private FontFieldEditor monospaceFont;
private FontFieldEditor sanserifFont;
private FontFieldEditor serifFont;
private TableViewer bgCategoryTable;
private TableColumn bgColumn;
private ColorSelector bgColorSelector;
private TableViewer fgCategoryTable;
private TableColumn fgColumn;
private ColorSelector fgColorSelector;
private Combo classCombo;
private Combo styleCombo;
private Combo sizeCombo;
public EditorPreferencePage() {
setPreferenceStore(store = new PreferenceStoreAdapter(IUIConstants.BUNDLE_ID));
setTitle("Whole Languages");
setDescription("Colors and Fonts");
}
protected Control createContents(Composite parent) {
Label label;
GridData gd;
Composite topComposite = new Composite(parent, SWT.NONE);
topComposite.setLayout(new GridLayout(1, false));
topComposite.setFont(parent.getFont());
gd = new GridData(GridData.FILL_BOTH);
gd.horizontalSpan = 1;
topComposite.setLayoutData(gd);
Label fontsLabel = new Label(topComposite, SWT.LEFT);
fontsLabel.setText("Font category:");
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 2;
fontsLabel.setLayoutData(gd);
Composite fontComposite = new Composite(topComposite, SWT.BORDER);
GridLayout fontLayout = new GridLayout(3, false);
fontComposite.setLayout(fontLayout);
fontComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
monospaceFont = new FontFieldEditor(PreferenceConstants.MONOSPACE_FONT, "Monospace", fontComposite);
sanserifFont = new FontFieldEditor(PreferenceConstants.SANSERIF_FONT, "Sans Serif", fontComposite);
serifFont = new FontFieldEditor(PreferenceConstants.SERIF_FONT, "Serif", fontComposite);
GridLayout bgLayout = new GridLayout(2, false);
bgLayout.marginHeight=5;
bgLayout.marginWidth=10;
topComposite.setLayout(bgLayout);
Label bgLabel = new Label(topComposite, SWT.LEFT);
bgLabel.setText("Hilight category:");
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 2;
bgLabel.setLayoutData(gd);
bgCategoryTable = new TableViewer(topComposite, SWT.SINGLE | SWT.V_SCROLL | SWT.BORDER);
bgCategoryTable.setContentProvider(new ArrayContentProvider());
bgCategoryTable.setLabelProvider(new PresentationLabelProvider(bgCategoryTable));
bgCategoryTable.setComparator(new ViewerComparator());
gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING | GridData.FILL_BOTH);
gd.widthHint = convertWidthInCharsToPixels(25);
gd.heightHint = 90;//convertHeightInCharsToPixels(5);
bgCategoryTable.getControl().setLayoutData(gd);
bgColumn = new TableColumn(bgCategoryTable.getTable(), SWT.LEFT);
Composite bgStylesComposite= new Composite(topComposite, SWT.NONE);
GridLayout bgStylesLayout= new GridLayout(2, false);
bgStylesLayout.marginHeight= 0;
bgStylesLayout.marginWidth= 0;
bgStylesComposite.setLayout(bgStylesLayout);
bgStylesComposite.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));
label = new Label(bgStylesComposite, SWT.LEFT);
label.setText("Color:");
label.setLayoutData(new GridData());
bgColorSelector = new ColorSelector(bgStylesComposite);
Label fgLabel = new Label(topComposite, SWT.NONE);
fgLabel.setText("Syntax category:");
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 2;
fgLabel.setLayoutData(gd);
fgCategoryTable = new TableViewer(topComposite, SWT.SINGLE | SWT.V_SCROLL | SWT.BORDER);
fgCategoryTable.setContentProvider(new ArrayContentProvider());
fgCategoryTable.setLabelProvider(new PresentationLabelProvider(fgCategoryTable));
fgCategoryTable.setComparator(new ViewerComparator());
gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING | GridData.FILL_BOTH);
gd.widthHint = convertWidthInCharsToPixels(25);
gd.heightHint = 52;//convertHeightInCharsToPixels(4);
fgCategoryTable.getControl().setLayoutData(gd);
fgColumn = new TableColumn(fgCategoryTable.getTable(), SWT.LEFT);
Composite fgStylesComposite= new Composite(topComposite, SWT.NONE);
GridLayout fgStylesLayout= new GridLayout(2, false);
fgStylesLayout.marginHeight= 0;
fgStylesLayout.marginWidth= 0;
fgStylesComposite.setLayout(fgStylesLayout);
fgStylesComposite.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));
label = new Label(fgStylesComposite, SWT.LEFT);
label.setText("Color:");
label.setLayoutData(new GridData());
fgColorSelector = new ColorSelector(fgStylesComposite);
label = new Label(fgStylesComposite, SWT.LEFT);
label.setText("Font:");
label.setLayoutData(new GridData());
classCombo = new Combo(fgStylesComposite, SWT.DROP_DOWN | SWT.READ_ONLY);
classCombo.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
label = new Label(fgStylesComposite, SWT.LEFT);
label.setText("Style:");
label.setLayoutData(new GridData());
styleCombo = new Combo(fgStylesComposite, SWT.DROP_DOWN | SWT.READ_ONLY);
styleCombo.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
label = new Label(fgStylesComposite, SWT.LEFT);
label.setText("Size:");
label.setLayoutData(new GridData());
sizeCombo = new Combo(fgStylesComposite, SWT.DROP_DOWN | SWT.READ_ONLY);
sizeCombo.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
bgCategoryTable.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
if (!event.getSelection().isEmpty()) {
handleBgCategoryListSelection();
}
}
});
bgCategoryTable.getControl().addControlListener(new ControlAdapter() {
public void controlResized(ControlEvent e) {
bgColumn.setWidth(bgCategoryTable.getControl().getSize().x - 4);
}});
bgColorSelector.addListener(new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
RGB newRGB = (RGB)event.getNewValue();
String key = getSelectedKey(bgCategoryTable);
if (key != null && newRGB != null && !newRGB.equals(event.getOldValue())) {
store.putValue(key, StringConverter.asString(newRGB));
}
}
});
fgCategoryTable.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
if (!event.getSelection().isEmpty()) {
handleFgCategoryListSelection();
}
}
});
fgCategoryTable.getControl().addControlListener(new ControlAdapter() {
public void controlResized(ControlEvent e) {
fgColumn.setWidth(fgCategoryTable.getControl().getSize().x - 24);
}});
fgColorSelector.addListener(new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
RGB newRGB = (RGB)event.getNewValue();
String key = getSelectedKey(fgCategoryTable);
if (key != null && newRGB != null && !newRGB.equals(event.getOldValue())) {
store.putValue(key, StringConverter.asString(newRGB));
}
}
});
classCombo.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
}
public void widgetSelected(SelectionEvent e) {
String key = getSelectedKey(fgCategoryTable);
store.putValue(key + PreferenceConstants.CLASS, FontClass.nameOf(classCombo.getSelectionIndex()));
}
});
styleCombo.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
}
public void widgetSelected(SelectionEvent e) {
String key = getSelectedKey(fgCategoryTable);
store.putValue(key + PreferenceConstants.STYLE, FontStyle.nameOf(styleCombo.getSelectionIndex()));
}
});
sizeCombo.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
}
public void widgetSelected(SelectionEvent e) {
String key = getSelectedKey(fgCategoryTable);
store.putValue(key + PreferenceConstants.SIZE, FontSize.nameOf(sizeCombo.getSelectionIndex()));
}
});
initialize();
return topComposite;
}
private String getSelectedKey(TableViewer table) {
return ((String[])((IStructuredSelection)table.getSelection()).getFirstElement())[1];
}
private void handleBgCategoryListSelection() {
String key = getSelectedKey(bgCategoryTable);
RGB rgb = StringConverter.asRGB(store.getString(key));
bgColorSelector.setColorValue(rgb);
}
private void handleFgCategoryListSelection() {
String key = getSelectedKey(fgCategoryTable);
RGB rgb = StringConverter.asRGB(store.getString(key));
fgColorSelector.setColorValue(rgb);
classCombo.select(FontClass.ordinalOf(store.getString(key + PreferenceConstants.CLASS)));
styleCombo.select(FontStyle.ordinalOf(store.getString(key + PreferenceConstants.STYLE)));
sizeCombo.select(FontSize.ordinalOf(store.getString(key + PreferenceConstants.SIZE)));
}
protected void initialize() {
monospaceFont.setPage(this);
monospaceFont.setPreferenceStore(getPreferenceStore());
monospaceFont.load();
sanserifFont.setPage(this);
sanserifFont.setPreferenceStore(getPreferenceStore());
sanserifFont.load();
serifFont.setPage(this);
serifFont.setPreferenceStore(getPreferenceStore());
serifFont.load();
for (FontClass v : FontClass.values())
classCombo.add(v.name());
for (FontStyle v : FontStyle.values())
styleCombo.add(v.name());
for (FontSize v : FontSize.values())
sizeCombo.add(v.name());
bgCategoryTable.setInput(bgCategoryListModel);
bgCategoryTable.getControl().getDisplay().asyncExec(new Runnable() {
public void run() {
if (bgCategoryTable != null && !bgCategoryTable.getControl().isDisposed())
bgCategoryTable.setSelection(new StructuredSelection(new Object[] {bgCategoryListModel[0]}));
}
});
fgCategoryTable.setInput(fgCategoryListModel);
fgCategoryTable.getControl().getDisplay().asyncExec(new Runnable() {
public void run() {
if (fgCategoryTable != null && !fgCategoryTable.getControl().isDisposed())
fgCategoryTable.setSelection(new StructuredSelection(new Object[] {fgCategoryListModel[0]}));
}
});
}
protected void performDefaults() {
store.resetToDefaults();
monospaceFont.load();
sanserifFont.load();
serifFont.load();
initialize();
super.performDefaults();
}
public boolean performOk() {
monospaceFont.store();
sanserifFont.store();
serifFont.store();
store.applyChanges();
return super.performOk();
}
protected class PresentationLabelProvider extends LabelProvider {//implements IFontProvider {
private TableViewer table;
private Map<String, Image> images = new HashMap<String, Image>();
private int imageSize = -1;
private int usableImageSize = -1;
private PreferencesChangeListener listener = new PreferencesChangeListener();
private Image emptyImage;
public PresentationLabelProvider(TableViewer table) {
this.table = table;
store.addChangeListener(listener);
InstanceScope.INSTANCE.getNode(IUIConstants.BUNDLE_ID).addPreferenceChangeListener(listener);
}
public void dispose() {
InstanceScope.INSTANCE.getNode(IUIConstants.BUNDLE_ID).removePreferenceChangeListener(listener);
store.removeChangeListener(listener);
for (Image image : images.values())
image.dispose();
images.clear();
if (emptyImage != null) {
emptyImage.dispose();
emptyImage = null;
}
super.dispose();
}
public Image getImage(Object element) {
String symbolicName = ((String[]) element)[1];
String color = store.getString(symbolicName);
Image image = images.get(color);
if (image == null)
images.put(color, image = createImage(color));
return image;
}
protected Image createImage(String c) {
Display display = table.getControl().getDisplay();
Color color = new Color(display, StringConverter.asRGB(c));
GC gc = null;
try {
ensureImageSize(display);
//int size = presentationList.getControl().getFont().getFontData()[0].getHeight();
Image image = new Image(display, imageSize, imageSize);
gc = new GC(image);
gc.setBackground(table.getControl().getBackground());
gc.setForeground(table.getControl().getBackground());
gc.drawRectangle(0, 0, imageSize - 1, imageSize - 1);
gc.setForeground(table.getControl().getForeground());
gc.setBackground(color);
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);
return image;
} finally {
if (gc != null)
gc.dispose();
if (color != null)
color.dispose();
}
}
private void ensureImageSize(Display display) {
if (imageSize == -1) {
imageSize = table.getTable().getItemHeight();
usableImageSize = Math.max(1, imageSize - 4);
}
}
public String getText(Object element) {
return ((String[])element)[0];
}
protected class PreferencesChangeListener implements IChangeListener, IEclipsePreferences.IPreferenceChangeListener {
protected void handleEvent() {
fireLabelProviderChanged(new LabelProviderChangedEvent(PresentationLabelProvider.this));
}
@Override
public void handleChange(ChangeEvent event) {
handleEvent();
}
@Override
public void preferenceChange(PreferenceChangeEvent event) {
handleEvent();
}
}
}
}