/******************************************************************************* * Copyright (c) 2007 IBM Corporation. * 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: * Matthew Kaplan (mmk@us.ibm.com) - initial API and implementation *******************************************************************************/ package org.eclipse.imp.preferences.fields; import org.eclipse.imp.preferences.IPreferencesService; import org.eclipse.imp.preferences.PreferencesTab; import org.eclipse.jface.dialogs.IDialogConstants; 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.core.runtime.Assert; import org.eclipse.swt.SWT; 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.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.FontDialog; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; /** * A field editor for font selection. * Based on ComboFieldEditor with accommodations made for font Control * @author rfuhrer@watson.ibm.com */ public class FontFieldEditor extends ChangeButtonFieldEditor { private static final String DEFAULT_FONT_DESCRIPTOR= new FontData("courier", 12, SWT.NORMAL).toString(); /** * The change font button, or <code>null</code> if none * (before creation and after disposal). */ private Button changeFontButton = null; /** * The text for the change font button, or <code>null</code> * if missing. */ private String changeButtonText; /** * The text for the preview, or <code>null</code> if no preview is desired */ private String previewText; /** * Font data for the chosen font button, or <code>null</code> if none. */ private FontData[] chosenFont; /** * The label that displays the selected font, or <code>null</code> if none. */ private Label valueControl; /** * The previewer, or <code>null</code> if none. */ private DefaultPreviewer previewer; /** * Internal font previewer implementation. */ private static class DefaultPreviewer { private Text text; private String string; private Font font; /** * Constructor for the previewer. * @param s * @param parent */ public DefaultPreviewer(String s, Composite parent) { string = s; text = new Text(parent, SWT.READ_ONLY | SWT.BORDER | SWT.WRAP); text.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { if (font != null) { font.dispose(); } } }); if (string != null) { text.setText(string); } } /** * @return the control the previewer is using */ public Control getControl() { return text; } /** * Set the font to display with * @param fontData */ public void setFont(FontData[] fontData) { if (font != null) { font.dispose(); } font = new Font(text.getDisplay(), fontData); text.setFont(font); text.getParent().layout(); } /** * @return the preferred height of the previewer. */ public int getPreferredHeight() { if (font != null) { return font.getFontData()[0].getHeight() * 3; } else { return 40; } } /** * @return the preferred height of the previewer. */ public int getPreferredWidth() { if (font != null) { return font.getFontData()[0].getHeight() * 15; } else { return 120; } } } /** * Creates a new font field editor */ protected FontFieldEditor() { } /** * Creates a font field editor with an optional preview area. * * @param name the name of the preference this field editor works on * @param labelText the label text of the field editor * @param previewAreaText the text used for the preview window. If it is * <code>null</code> there will be no preview area, * @param parent the parent of the field editor's control */ public FontFieldEditor(String name, String labelText, String previewAreaText, Composite parent) { init(name, labelText); previewText = previewAreaText; changeButtonText = JFaceResources.getString("openChange"); //$NON-NLS-1$ createControl(parent); } /** * Creates a font field editor without a preview. * * @param name the name of the preference this field editor works on * @param labelText the label text of the field editor * @param parent the parent of the field editor's control */ public FontFieldEditor(String name, String labelText, Composite parent) { this(name, labelText, null, parent); } /* (non-Javadoc) * Method declared on FieldEditor. */ protected void adjustForNumColumns(int numColumns) { GridData data = new GridData(); if (valueControl.getLayoutData() != null) { data = (GridData) valueControl.getLayoutData(); } data.horizontalSpan = numColumns - getNumberOfControls() + 1; valueControl.setLayoutData(data); } /* (non-Javadoc) * Method declared on FieldEditor. */ protected void applyFont() { if (chosenFont != null && previewer != null) { previewer.setFont(chosenFont); } } /* (non-Javadoc) * Method declared on FieldEditor. */ protected void doFillIntoGrid(Composite parent, int numColumns) { getLabelControl(parent); valueControl = getValueControl(parent); GridData gd = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL); gd.horizontalSpan = numColumns - getNumberOfControls() + 1; valueControl.setLayoutData(gd); if (previewText != null) { previewer = new DefaultPreviewer(previewText, parent); gd = new GridData(GridData.FILL_HORIZONTAL); gd.heightHint = previewer.getPreferredHeight(); gd.widthHint = previewer.getPreferredWidth(); previewer.getControl().setLayoutData(gd); } changeFontButton = getChangeControl(); gd = new GridData(); int widthHint = convertHorizontalDLUsToPixels(changeFontButton, IDialogConstants.BUTTON_WIDTH); gd.widthHint = Math.max(widthHint, changeFontButton.computeSize( SWT.DEFAULT, SWT.DEFAULT, true).x); changeFontButton.setLayoutData(gd); } @Override protected void doSetToolTip() { if (toolTipText != null) { getValueControl(parent).setToolTipText(toolTipText); } } /* (non-Javadoc) * Method declared on FieldEditor. */ protected void doLoad() { if (changeFontButton == null) { return; } updateFont(PreferenceConverter.basicGetFontData(preferencesService.getStringPreference(getPreferenceName()))); } /* (non-Javadoc) * Method declared on FieldEditor. */ protected void doLoadDefault() { if (changeFontButton == null) { return; } String fontPref= preferencesService.getStringPreference(IPreferencesService.DEFAULT_LEVEL, getPreferenceName()); updateFont(PreferenceConverter.basicGetFontData(fontPref)); } /* (non-Javadoc) * Method declared on FieldEditor. */ protected void doStore() { if (chosenFont != null) { fieldModified = false; levelFromWhichLoaded = preferencesLevel; setInherited(false); String encodedFont= PreferenceConverter.getStoredRepresentation(chosenFont); preferencesService.setStringPreference("instance", getPreferenceName(), encodedFont); } } @Override public Composite getHolder() { return getChangeControl().getParent(); } /** * Returns the change button for this field editor. * * @param parent The Composite to create the button in if required. * @return the change button */ public Button getChangeControl() { if (changeFontButton == null) { changeFontButton = new Button(parent, SWT.PUSH); if (changeButtonText != null) { changeFontButton.setText(changeButtonText); } changeFontButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { FontDialog fontDialog = new FontDialog(changeFontButton .getShell()); if (chosenFont != null) { fontDialog.setFontList(chosenFont); } FontData font = fontDialog.open(); if (font != null) { FontData[] oldFont = chosenFont; if (oldFont == null) { oldFont = JFaceResources.getDefaultFont().getFontData(); } setPresentsDefaultValue(false); FontData[] newData = new FontData[1]; newData[0] = font; updateFont(newData); fireValueChanged(VALUE, oldFont[0], font); } } }); changeFontButton.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent event) { changeFontButton = null; } }); changeFontButton.setFont(parent.getFont()); setButtonLayoutData(changeFontButton); } else { checkParent(changeFontButton, parent); } return changeFontButton; } /* (non-Javadoc) * Method declared on FieldEditor. */ public int getNumberOfControls() { if (previewer == null) { return 3; } return 4; } /** * Returns the preferred preview height. * * @return the height, or <code>-1</code> if no previewer * is installed */ public int getPreferredPreviewHeight() { if (previewer == null) { return -1; } return previewer.getPreferredHeight(); } /** * Returns the preview control for this field editor. * * @return the preview control */ public Control getPreviewControl() { if (previewer == null) { return null; } return previewer.getControl(); } /** * Returns the value control for this field editor. The value control * displays the currently selected font name. * @param parent The Composite to create the viewer in if required * @return the value control */ protected Label getValueControl(Composite parent) { if (valueControl == null) { valueControl = new Label(parent, SWT.LEFT); valueControl.setFont(parent.getFont()); valueControl.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent event) { valueControl = null; } }); } else { checkParent(valueControl, parent); } return valueControl; } /** * Sets the text of the change button. * * @param text the new text */ public void setChangeButtonText(String text) { Assert.isNotNull(text); changeButtonText = text; if (changeFontButton != null) { changeFontButton.setText(text); } } /** * Updates the change font button and the previewer to reflect the * newly selected font. * @param font The FontData[] to update with. */ private void updateFont(FontData font[]) { FontData[] bestFont = JFaceResources.getFontRegistry().filterData( font, valueControl.getDisplay()); //if we have nothing valid do as best we can if (bestFont == null) { bestFont = getDefaultFontData(); } //Now cache this value in the receiver this.chosenFont = bestFont; if (valueControl != null) { valueControl.setText(StringConverter.asString(chosenFont[0])); } if (previewer != null) { previewer.setFont(bestFont); } setInherited(false); valueChanged(); } /** * Store the default preference for the field * being edited */ protected void setToDefault() { String defaultFontStr= PreferenceConverter.getStoredRepresentation(getDefaultFontData()); preferencesService.setStringPreference(IPreferencesService.DEFAULT_LEVEL, getPreferenceName(), defaultFontStr); } /** * Get the system default font data. * @return FontData[] */ private FontData[] getDefaultFontData() { return valueControl.getDisplay().getSystemFont().getFontData(); } public FontData[] getSelectedFont() { return chosenFont; } /* * @see FieldEditor.setEnabled(boolean,Composite). */ public void setEnabled(boolean enabled, Composite parent) { super.setEnabled(enabled, parent); getChangeControl().setEnabled(enabled); getValueControl(parent).setEnabled(enabled); } /* * Note: The specialValue may be one that is used as a default or * one that signifies no meaningful value selected. It is assumed * here NOT to occur in entryNamesAndValues, and it is added to * the head of the array of names and values used here to create * the combo box entries. */ public FontFieldEditor( PreferencePage page, PreferencesTab tab, IPreferencesService service, String level, String name, String labelText, Composite parent) { init(name, labelText); // Assert.isTrue(checkArray(entryNamesAndValues)); previewText = "The quick brown fox jumped over the lazy dog"; changeButtonText = JFaceResources.getString("openChange"); //$NON-NLS-1$ preferencesService = service; preferencesLevel = level; this.parent = parent; prefPage = page; setPage(prefPage); prefTab = tab; createControl(parent); } @Override protected void doLoadLevel(String level) { if (valueControl != null) { String value = preferencesService.getStringPreference(level, getPreferenceName()); updateFont(PreferenceConverter.basicGetFontData(value)); } } @Override protected String doLoadWithInheritance() { String levelLoaded = null; String[] levels = IPreferencesService.levels; // If we're loading with inheritance for some field that is // not attached to a preferences level then assume that we // should just search from the bottom up int startingLevelIdx = (preferencesLevel == null) ? 0 : PREFS_LEVELS_AS_LIST.indexOf(preferencesLevel); int levelAtWhichFound = -1; String encodedFontValue = null; // Search up levels starting from the level of this field for (int level = startingLevelIdx; level < levels.length; level++) { encodedFontValue = preferencesService.getRawStringPreference(levels[level], getPreferenceName()); if (encodedFontValue != null) { levelAtWhichFound = level; levelLoaded = levels[levelAtWhichFound]; break; } } if (encodedFontValue == null) { encodedFontValue= DEFAULT_FONT_DESCRIPTOR; } // TODO should this be calling updateFont() instead of the following? levelFromWhichLoaded = levelLoaded; setInherited(startingLevelIdx != levelAtWhichFound); setPresentsDefaultValue(IPreferencesService.DEFAULT_LEVEL.equals(levelFromWhichLoaded)); fieldModified = true; // valueChanged(); // should not be called when field set from preference store previousValue = chosenFont; // not clear whether this needs to be done on initial load from store chosenFont = PreferenceConverter.basicGetFontData(encodedFontValue); if (valueControl != null) { valueControl.setText(StringConverter.asString(chosenFont[0])); } if (previewer != null) { previewer.setFont(chosenFont); } return levelLoaded; } @Override protected boolean valueChanged() { // copied from ComboFieldEditor return valueChanged(false); } protected boolean valueChanged(boolean assertChanged) { // Check for change in value boolean valueChanged = assertChanged || inheritanceChanged(); if (!valueChanged) { if ((chosenFont != null && previousValue == null) || (chosenFont == null && previousValue != null)) { valueChanged = true; } if (chosenFont != null && previousValue != null) { if (!chosenFont.equals(previousValue)) { valueChanged = true; } } } if (valueChanged) { fireValueChanged(VALUE, previousValue, chosenFont); fieldModified = true; previousValue = chosenFont; setModifiedMarkOnLabel(); } return valueChanged; } /** * Set the value of this field directly, from outside of * the field, without loading a value from the preferences * service. * * Intended for use by external clients of the field. * * In addition to setting the value of the field this method * also sets several attributes to appropriately characterize * a field that has been set in this way. * * @param newValue */ public void setFieldValueFromOutside(FontData[] newValue) { previousValue = chosenFont; setInherited(false); setPresentsDefaultValue(false); levelFromWhichLoaded = null; updateFont(newValue); } }