/*
* Copyright (c) 2012, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.tools.ui.internal.preferences;
import com.google.dart.tools.ui.DartToolsPlugin;
import com.google.dart.tools.ui.PreferenceConstants;
import com.google.dart.tools.ui.internal.text.editor.DartDocumentSetupParticipant;
import com.google.dart.tools.ui.internal.text.functions.DartColorManager;
import com.google.dart.tools.ui.internal.util.SWTUtil;
import com.google.dart.tools.ui.text.DartPartitions;
import com.google.dart.tools.ui.text.DartSourceViewerConfiguration;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.preference.PreferenceStore;
import org.eclipse.jface.resource.FontRegistry;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.text.source.SourceViewerConfiguration;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
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.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.internal.themes.ThemeElementHelper;
import org.eclipse.ui.themes.ITheme;
import org.eclipse.ui.themes.IThemeManager;
import java.util.HashMap;
import java.util.Map;
/**
* Preference page for fonts in the editor
*/
@SuppressWarnings("restriction")
public class FontPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
private static class FontSelectionComposite extends Composite {
private final String baseKey;
private final String key;
private Button smallFontsButton;
private Button mediumFontsButton;
private Button largeFontsButton;
private Button xlFontsButton;
private SourceViewer previewViewer;
private Button selectFontButton;
private Label codeFontLabel;
private Button resetButton;
private SourceViewerConfiguration sourceViewerConfiguration;
private FontData[] fontData;
private FontData[] baseData;
public FontSelectionComposite(Composite parent, int style, String baseKey, String key,
String msg) {
super(parent, style);
this.baseKey = baseKey;
this.key = key;
GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.BEGINNING).applyTo(this);
setLayout(new GridLayout(1, false));
Group fontGroup = new Group(this, SWT.NONE);
fontGroup.setText(msg);
GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.BEGINNING).applyTo(
fontGroup);
GridLayoutFactory.fillDefaults().numColumns(2).margins(8, 8).applyTo(fontGroup);
// code font
createPreviewer(fontGroup);
Composite buttons = new Composite(fontGroup, SWT.NONE);
GridLayoutFactory.fillDefaults().applyTo(buttons);
// font scaling
{
Composite scaleComposite = new Composite(buttons, SWT.NONE);
scaleComposite.setLayout(new GridLayout(4, true));
smallFontsButton = new Button(scaleComposite, SWT.TOGGLE | SWT.FLAT | SWT.CENTER);
smallFontsButton.setFont(parent.getFont()); // bootstrapping
smallFontsButton.setText(PreferencesMessages.DartBasePreferencePage_font_scale_indicator);
smallFontsButton.setFont(getSmallFont());
smallFontsButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.END, false, false));
smallFontsButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateFont(smallFontsButton.getFont());
}
});
mediumFontsButton = new Button(scaleComposite, SWT.TOGGLE | SWT.FLAT | SWT.CENTER);
mediumFontsButton.setText(PreferencesMessages.DartBasePreferencePage_font_scale_indicator);
mediumFontsButton.setFont(getMediumFont());
mediumFontsButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.END, false, false));
mediumFontsButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateFont(mediumFontsButton.getFont());
}
});
largeFontsButton = new Button(scaleComposite, SWT.TOGGLE | SWT.FLAT | SWT.CENTER);
largeFontsButton.setText(PreferencesMessages.DartBasePreferencePage_font_scale_indicator);
largeFontsButton.setFont(getLargeFont());
largeFontsButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.END, false, false));
largeFontsButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateFont(largeFontsButton.getFont());
}
});
xlFontsButton = new Button(scaleComposite, SWT.TOGGLE | SWT.FLAT | SWT.CENTER);
xlFontsButton.setText(PreferencesMessages.DartBasePreferencePage_font_scale_indicator);
xlFontsButton.setFont(getXlFont());
xlFontsButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.END, false, false));
xlFontsButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateFont(xlFontsButton.getFont());
}
});
}
codeFontLabel = new Label(buttons, SWT.NONE);
selectFontButton = new Button(buttons, SWT.PUSH);
GridDataFactory.fillDefaults().grab(false, true).applyTo(selectFontButton);
selectFontButton.setText(PreferencesMessages.DartBasePreferencePage_code_font_select_label);
selectFontButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
chooseCodeFont();
}
});
resetButton = new Button(buttons, SWT.PUSH);
GridDataFactory.fillDefaults().grab(false, true).applyTo(resetButton);
resetButton.setText(PreferencesMessages.DartBasePreferencePage_reset_button_label);
resetButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
resetFonts();
}
});
initFromPrefs();
}
boolean isFontOfSize(Font font, int size) {
return font.getFontData()[0].getHeight() == size;
}
private void chooseCodeFont() {
final FontDialog fontDialog = new FontDialog(getShell());
fontDialog.setFontList(getFontData());
final FontData data = fontDialog.open();
if (data != null) {
fontData = new FontData[] {data};
baseData = fontData;
updatePreviewFont(SWTUtil.getFont(getMediumFont().getDevice(), fontData));
}
}
private void createPreviewer(Composite parent) {
Composite previewComp = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginHeight = layout.marginWidth = 0;
previewComp.setLayout(layout);
previewComp.setLayoutData(new GridData(GridData.FILL_BOTH));
previewViewer = new SourceViewer(previewComp, null, SWT.BORDER /* | SWT.V_SCROLL | SWT.H_SCROLL */);
sourceViewerConfiguration = getSourceViewerConfiguration();
if (sourceViewerConfiguration != null) {
previewViewer.configure(sourceViewerConfiguration);
}
previewViewer.setEditable(false);
previewViewer.setDocument(getDocument());
Control control = previewViewer.getControl();
GridData controlData = new GridData(GridData.FILL_BOTH);
controlData.heightHint = 100;
control.setLayoutData(controlData);
}
private int findFontIndex(int size) {
// exact match?
for (int i = 0; i < FONT_SIZES.length; i++) {
if (FONT_SIZES[i] == size) {
return i;
}
}
// next largest?
for (int i = 0; i < FONT_SIZES.length; i++) {
if (FONT_SIZES[i] > size) {
return i;
}
}
// first
return 0;
}
private int findScaledCodeFontSize(int oldCodeFontSize, int oldBaseFontSize, int newBaseFontSize) {
int oldCodeIndex = findFontIndex(oldCodeFontSize);
int oldBaseIndex = findFontIndex(oldBaseFontSize);
int newBaseIndex = findFontIndex(newBaseFontSize);
int delta = newBaseIndex - oldBaseIndex;
int newCodeIndex = oldCodeIndex + delta;
newCodeIndex = Math.max(Math.min(newCodeIndex, FONT_SIZES.length - 1), 0);
return FONT_SIZES[newCodeIndex];
}
private FontData[] getBaseData() {
if (baseData == null) {
IThemeManager themeManager = PlatformUI.getWorkbench().getThemeManager();
ITheme theme = themeManager.getCurrentTheme();
baseData = theme.getFontRegistry().getFontData(baseKey);
}
return baseData;
}
private IDocument getDocument() {
IDocument document = new Document(SAMPLE_CODE);
new DartDocumentSetupParticipant().setup(document);
return document;
}
private Font getFont(int size) {
FontData oldData = getBaseData()[0];
FontData data = new FontData(oldData.getName(), oldData.getHeight(), oldData.getStyle());
data.height = size;
Font font = smallFontsButton.getFont(); // bootstrapped
font = new Font(font.getDevice(), data);
return font;
}
private FontData[] getFontData() {
if (fontData == null) {
IThemeManager themeManager = PlatformUI.getWorkbench().getThemeManager();
ITheme theme = themeManager.getCurrentTheme();
fontData = theme.getFontRegistry().getFontData(key);
}
return fontData;
}
private Font getLargeFont() {
return getFont(SZ_LARGE);
}
private Font getMediumFont() {
return getFont(SZ_MEDIUM);
}
private Font getSmallFont() {
return getFont(SZ_SMALL);
}
private SourceViewerConfiguration getSourceViewerConfiguration() {
return new DartSourceViewerConfiguration(
new DartColorManager(),
new PreferenceStore(),
null,
DartPartitions.DART_PARTITIONING);
}
private Font getXlFont() {
return getFont(SZ_XL);
}
private void initFromPrefs() {
getFontData();
getBaseData();
updatePreviewFont(JFaceResources.getFont(key));
selectFontButton();
setCodeFontLabel();
}
private void performOk() {
persistFont(baseKey, baseData);
persistFont(key, fontData);
if (key == EDITOR_FONT_KEY) {
persistFont(WST_FONT_KEY, baseData);
}
if (key == VIEW_FONT_KEY) {
persistFont(
"org.eclipse.debug.ui.VariableTextFont" /*IDebugUIConstants.PREF_VARIABLE_TEXT_FONT*/,
baseData);
persistFont(
"org.eclipse.debug.ui.DetailPaneFont" /*IDebugUIConstants.PREF_DETAIL_PANE_FONT*/,
baseData);
}
/*
* The following block of code adjusts fonts in dialogs. There are some issues, like much of the
* non-framework section of the page not getting changed. For now, it is commented out.
*/
// int height = fontData[0].getHeight();
// scaleFontNamed(JFaceResources.HEADER_FONT, height + 3);
// scaleFontNamed(JFaceResources.BANNER_FONT, height + 1);
// scaleFontNamed(JFaceResources.DIALOG_FONT, height);
// scaleFontNamed(JFaceResources.DEFAULT_FONT, height);
}
private void persistFont(String fontKey, FontData[] fontData) {
IPreferenceStore workbenchPrefStore = WorkbenchPlugin.getDefault().getPreferenceStore();
IThemeManager themeManager = PlatformUI.getWorkbench().getThemeManager();
ITheme theme = themeManager.getCurrentTheme();
FontRegistry registry = theme.getFontRegistry();
registry.put(fontKey, fontData);
String key = ThemeElementHelper.createPreferenceKey(theme, fontKey);
String fdString = PreferenceConverter.getStoredRepresentation(fontData);
String storeString = workbenchPrefStore.getString(key);
if (!fdString.equals(storeString)) {
workbenchPrefStore.setValue(key, fdString);
}
}
private void resetFonts() {
IThemeManager themeManager = PlatformUI.getWorkbench().getThemeManager();
ITheme theme = themeManager.getCurrentTheme();
fontData = theme.getFontRegistry().getFontData(EDITOR_DEFAULT_FONT_KEY);
baseData = theme.getFontRegistry().getFontData(BASE_DEFAULT_FONT_KEY);
selectFontButton();
updatePreviewFont(SWTUtil.getFont(getMediumFont().getDevice(), fontData));
}
@SuppressWarnings("unused")
private void scaleFontNamed(String name, int size) {
IPreferenceStore workbenchPrefStore = WorkbenchPlugin.getDefault().getPreferenceStore();
IThemeManager themeManager = PlatformUI.getWorkbench().getThemeManager();
ITheme theme = themeManager.getCurrentTheme();
FontRegistry registry = theme.getFontRegistry();
FontData[] fds = registry.getFontData(name);
FontData data = new FontData(fds[0].getName(), size, fds[0].getStyle());
registry.put(name, new FontData[] {data});
String key = ThemeElementHelper.createPreferenceKey(theme, name);
String fdString = PreferenceConverter.getStoredRepresentation(new FontData[] {data});
String storeString = workbenchPrefStore.getString(key);
if (!fdString.equals(storeString)) {
workbenchPrefStore.setValue(key, fdString);
}
}
private void selectFontButton() {
smallFontsButton.setSelection(false);
mediumFontsButton.setSelection(false);
largeFontsButton.setSelection(false);
xlFontsButton.setSelection(false);
FontData data = getBaseData()[0];
int size = data.getHeight();
if (isFontOfSize(smallFontsButton.getFont(), size)) {
smallFontsButton.setSelection(true);
} else if (isFontOfSize(mediumFontsButton.getFont(), size)) {
mediumFontsButton.setSelection(true);
} else if (isFontOfSize(largeFontsButton.getFont(), size)) {
largeFontsButton.setSelection(true);
} else if (isFontOfSize(xlFontsButton.getFont(), size)) {
xlFontsButton.setSelection(true);
}
}
private void setCodeFontLabel() {
StringBuilder label = new StringBuilder();
FontData data = getFontData()[0];
label.append(data.getName());
label.append(" ");
label.append(data.getHeight());
codeFontLabel.setText(label.toString());
codeFontLabel.getParent().getParent().layout(true, true);
}
private void updateFont(Font font) {
int oldBaseFontSize = baseData[0].getHeight();
int oldCodeFontSize = fontData[0].getHeight();
FontData[] data = baseData = font.getFontData();
int newBaseFontSize = data[0].getHeight();
int newCodeFontSize = findScaledCodeFontSize(
oldCodeFontSize,
oldBaseFontSize,
newBaseFontSize);
baseData = data;
fontData = SWTUtil.changeFontSize(fontData, newCodeFontSize);
Font newFont = SWTUtil.getFont(font.getDevice(), fontData);
selectFontButton();
updatePreviewFont(newFont);
}
private void updatePreviewFont(Font font) {
setCodeFontLabel();
previewViewer.getTextWidget().setFont(font);
}
}
private static final String SAMPLE_CODE = " void run() {\n write('Hello, world!');\n }";
public static final String FONT_PREF_PAGE_ID = "com.google.dart.tools.ui.preferences.FontPreferencePage"; //$NON-NLS-1$
public static final String EDITOR_FONT_KEY = PreferenceConstants.EDITOR_TEXT_FONT;
public static final String EDITOR_DEFAULT_FONT_KEY = "com.google.dart.tools.ui.editors.textfont.default";
public static final String EDITOR_BASE_FONT_KEY = "com.google.dart.tools.ui.editors.basefont";
public static final String BASE_DEFAULT_FONT_KEY = "com.google.dart.tools.ui.editors.basefont.default";
public static final String VIEW_FONT_KEY = PreferenceConstants.VIEW_TEXT_FONT;
public static final String VIEW_BASE_FONT_KEY = "com.google.dart.tools.ui.views.basefont";
public static final String WST_FONT_KEY = "org.eclipse.wst.sse.ui.textfont";
private static final int SZ_SMALL = 10;
private static final int SZ_MEDIUM = 11;
private static final int SZ_LARGE = 14;
private static final int SZ_XL = 18;
// Available font sizes
private static final int[] FONT_SIZES = {
8, 9, SZ_SMALL, SZ_MEDIUM, SZ_LARGE, SZ_XL, 24, 36, 48, 64, 72, 96, 144, 288};
public static Map<String, FontData> getAllFontsByName() {
// this returns nearly 150 named fonts, so is unsuitable for use directly in the UI
FontData[] allFonts = Display.getCurrent().getFontList(null, true);
Map<String, FontData> fonts = new HashMap<String, FontData>();
for (FontData data : allFonts) {
String name = data.getName();
if (fonts.get(name) == null) {
fonts.put(name, data);
}
}
return fonts;
}
private FontSelectionComposite editorComposite;
private FontSelectionComposite viewComposite;
public FontPreferencePage() {
setPreferenceStore(DartToolsPlugin.getDefault().getPreferenceStore());
// setDescription(PreferencesMessages.DartBasePreferencePage_text_font);
noDefaultAndApplyButton();
}
@Override
public IPreferenceStore getPreferenceStore() {
return new PreferenceStore();
}
@Override
public void init(IWorkbench arg0) {
}
@Override
public boolean performOk() {
editorComposite.performOk();
viewComposite.performOk();
return true;
}
@Override
protected Control createContents(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayout(new GridLayout(1, false));
editorComposite = new FontSelectionComposite(
composite,
SWT.NONE,
EDITOR_BASE_FONT_KEY,
EDITOR_FONT_KEY,
"Editors");
viewComposite = new FontSelectionComposite(
composite,
SWT.NONE,
VIEW_BASE_FONT_KEY,
VIEW_FONT_KEY,
"Views");
return composite;
}
}