| /******************************************************************************* |
| * Copyright (c) 2000, 2005 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.jface.preference; |
| |
| import org.eclipse.jface.dialogs.DialogPage; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.resource.JFaceResources; |
| import org.eclipse.jface.util.Assert; |
| import org.eclipse.jface.util.IPropertyChangeListener; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.DisposeEvent; |
| import org.eclipse.swt.events.DisposeListener; |
| import org.eclipse.swt.graphics.FontMetrics; |
| import org.eclipse.swt.graphics.GC; |
| 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; |
| |
| /** |
| * Abstract base class for all field editors. |
| * <p> |
| * A field editor presents the value of a preference to the end |
| * user. The value is loaded from a preference store; if |
| * modified by the end user, the value is validated and eventually |
| * stored back to the preference store. A field editor reports |
| * an event when the value, or the validity of the value, changes. |
| * </p> |
| * <p> |
| * Field editors should be used in conjunction with a field |
| * editor preference page (<code>FieldEditorPreferencePage</code>) |
| * which coordinates everything and provides the message line |
| * which display messages emanating from the editor. |
| * </p> |
| * <p> |
| * This package contains ready-to-use field editors for various |
| * types of preferences: |
| * <ul> |
| * <li><code>BooleanFieldEditor</code> - booleans</li> |
| * <li><code>IntegerFieldEditor</code> - integers</li> |
| * <li><code>StringFieldEditor</code> - text strings</li> |
| * <li><code>RadioGroupFieldEditor</code> - enumerations</li> |
| * <li><code>ColorFieldEditor</code> - RGB colors</li> |
| * <li><code>FontFieldEditor</code> - fonts</li> |
| * <li><code>DirectoryFieldEditor</code> - directories</li> |
| * <li><code>FileFieldEditor</code> - files</li> |
| * <li><code>PathEditor</code> - paths</li> |
| * </ul> |
| * </p> |
| */ |
| public abstract class FieldEditor { |
| |
| /** |
| * Property name constant (value <code>"field_editor_is_valid"</code>) |
| * to signal a change in the validity of the value of this field editor. |
| */ |
| public static final String IS_VALID = "field_editor_is_valid";//$NON-NLS-1$ |
| |
| /** |
| * Property name constant (value <code>"field_editor_value"</code>) |
| * to signal a change in the value of this field editor. |
| */ |
| public static final String VALUE = "field_editor_value";//$NON-NLS-1$ |
| |
| /** |
| * Gap between label and control. |
| */ |
| protected static final int HORIZONTAL_GAP = 8; |
| |
| /** |
| * The preference store, or <code>null</code> if none. |
| */ |
| private IPreferenceStore preferenceStore = null; |
| |
| /** |
| * The name of the preference displayed in this field editor. |
| */ |
| private String preferenceName; |
| |
| /** |
| * Indicates whether the default value is currently displayed, |
| * initially <code>false</code>. |
| */ |
| private boolean isDefaultPresented = false; |
| |
| /** |
| * The label's text. |
| */ |
| private String labelText; |
| |
| /** |
| * The label control. |
| */ |
| private Label label; |
| |
| /** |
| * Listener, or <code>null</code> if none |
| */ |
| private IPropertyChangeListener propertyChangeListener; |
| |
| /** |
| * The page containing this field editor |
| */ |
| private DialogPage page; |
| |
| /** |
| * Creates a new field editor. |
| */ |
| protected FieldEditor() { |
| } |
| |
| /** |
| * Creates a new field editor. |
| * |
| * @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 |
| */ |
| protected FieldEditor(String name, String labelText, Composite parent) { |
| init(name, labelText); |
| createControl(parent); |
| } |
| |
| /** |
| * Adjusts the horizontal span of this field editor's basic controls. |
| * <p> |
| * Subclasses must implement this method to adjust the horizontal span |
| * of controls so they appear correct in the given number of columns. |
| * </p> |
| * <p> |
| * The number of columns will always be equal to or greater than the |
| * value returned by this editor's <code>getNumberOfControls</code> method. |
| * |
| * @param numColumns the number of columns |
| */ |
| protected abstract void adjustForNumColumns(int numColumns); |
| |
| /** |
| * Applies a font. |
| * <p> |
| * The default implementation of this framework method |
| * does nothing. Subclasses should override this method |
| * if they want to change the font of the SWT control to |
| * a value different than the standard dialog font. |
| * </p> |
| */ |
| protected void applyFont() { |
| } |
| |
| /** |
| * Checks if the given parent is the current parent of the |
| * supplied control; throws an (unchecked) exception if they |
| * are not correctly related. |
| * |
| * @param control the control |
| * @param parent the parent control |
| */ |
| protected void checkParent(Control control, Composite parent) { |
| Assert.isTrue(control.getParent() == parent, "Different parents");//$NON-NLS-1$ |
| } |
| |
| /** |
| * Clears the error message from the message line. |
| */ |
| protected void clearErrorMessage() { |
| if (page != null) |
| page.setErrorMessage(null); |
| } |
| |
| /** |
| * Clears the normal message from the message line. |
| */ |
| protected void clearMessage() { |
| if (page != null) |
| page.setMessage(null); |
| } |
| |
| /** |
| * Returns the number of pixels corresponding to the |
| * given number of horizontal dialog units. |
| * <p> |
| * Clients may call this framework method, but should not override it. |
| * </p> |
| * |
| * @param control the control being sized |
| * @param dlus the number of horizontal dialog units |
| * @return the number of pixels |
| */ |
| protected int convertHorizontalDLUsToPixels(Control control, int dlus) { |
| GC gc = new GC(control); |
| gc.setFont(control.getFont()); |
| int averageWidth = gc.getFontMetrics().getAverageCharWidth(); |
| gc.dispose(); |
| |
| double horizontalDialogUnitSize = averageWidth * 0.25; |
| |
| return (int) Math.round(dlus * horizontalDialogUnitSize); |
| } |
| |
| /** |
| * Returns the number of pixels corresponding to the |
| * given number of vertical dialog units. |
| * <p> |
| * Clients may call this framework method, but should not override it. |
| * </p> |
| * |
| * @param control the control being sized |
| * @param dlus the number of vertical dialog units |
| * @return the number of pixels |
| */ |
| protected int convertVerticalDLUsToPixels(Control control, int dlus) { |
| GC gc = new GC(control); |
| gc.setFont(control.getFont()); |
| int height = gc.getFontMetrics().getHeight(); |
| gc.dispose(); |
| |
| double verticalDialogUnitSize = height * 0.125; |
| |
| return (int) Math.round(dlus * verticalDialogUnitSize); |
| } |
| |
| /** |
| * Creates this field editor's main control containing all of its |
| * basic controls. |
| * |
| * @param parent the parent control |
| */ |
| protected void createControl(Composite parent) { |
| GridLayout layout = new GridLayout(); |
| layout.numColumns = getNumberOfControls(); |
| layout.marginWidth = 0; |
| layout.marginHeight = 0; |
| layout.horizontalSpacing = HORIZONTAL_GAP; |
| parent.setLayout(layout); |
| doFillIntoGrid(parent, layout.numColumns); |
| } |
| |
| /** |
| * Disposes the SWT resources used by this field editor. |
| */ |
| public void dispose() { |
| // nothing to dispose |
| } |
| |
| /** |
| * Fills this field editor's basic controls into the given parent. |
| * <p> |
| * Subclasses must implement this method to create the controls |
| * for this field editor. |
| * </p> |
| * |
| * @param parent the composite used as a parent for the basic controls; |
| * the parent's layout must be a <code>GridLayout</code> |
| * @param numColumns the number of columns |
| */ |
| protected abstract void doFillIntoGrid(Composite parent, int numColumns); |
| |
| /** |
| * Initializes this field editor with the preference value from |
| * the preference store. |
| * <p> |
| * Subclasses must implement this method to properly initialize |
| * the field editor. |
| * </p> |
| */ |
| protected abstract void doLoad(); |
| |
| /** |
| * Initializes this field editor with the default preference value from |
| * the preference store. |
| * <p> |
| * Subclasses must implement this method to properly initialize |
| * the field editor. |
| * </p> |
| */ |
| protected abstract void doLoadDefault(); |
| |
| /** |
| * Stores the preference value from this field editor into |
| * the preference store. |
| * <p> |
| * Subclasses must implement this method to save the entered value |
| * into the preference store. |
| * </p> |
| */ |
| protected abstract void doStore(); |
| |
| /** |
| * Fills this field editor's basic controls into the given parent. |
| * |
| * @param parent the composite used as a parent for the basic controls; |
| * the parent's layout must be a <code>GridLayout</code> |
| * @param numColumns the number of columns |
| */ |
| public void fillIntoGrid(Composite parent, int numColumns) { |
| Assert.isTrue(numColumns >= getNumberOfControls()); |
| Assert.isTrue(parent.getLayout() instanceof GridLayout); |
| doFillIntoGrid(parent, numColumns); |
| } |
| |
| /** |
| * Informs this field editor's listener, if it has one, about a change to |
| * one of this field editor's boolean-valued properties. Does nothing |
| * if the old and new values are the same. |
| * |
| * @param property the field editor property name, |
| * such as <code>VALUE</code> or <code>IS_VALID</code> |
| * @param oldValue the old value |
| * @param newValue the new value |
| */ |
| protected void fireStateChanged(String property, boolean oldValue, |
| boolean newValue) { |
| if (oldValue == newValue) |
| return; |
| fireValueChanged(property, new Boolean(oldValue), new Boolean(newValue)); |
| } |
| |
| /** |
| * Informs this field editor's listener, if it has one, about a change to |
| * one of this field editor's properties. |
| * |
| * @param property the field editor property name, |
| * such as <code>VALUE</code> or <code>IS_VALID</code> |
| * @param oldValue the old value object, or <code>null</code> |
| * @param newValue the new value, or <code>null</code> |
| */ |
| protected void fireValueChanged(String property, Object oldValue, |
| Object newValue) { |
| if (propertyChangeListener == null) |
| return; |
| propertyChangeListener.propertyChange(new PropertyChangeEvent(this, |
| property, oldValue, newValue)); |
| } |
| |
| /** |
| * Returns the symbolic font name used by this field editor. |
| * |
| * @return the symbolic font name |
| */ |
| public String getFieldEditorFontName() { |
| return JFaceResources.DIALOG_FONT; |
| } |
| |
| /** |
| * Returns the label control. |
| * |
| * @return the label control, or <code>null</code> |
| * if no label control has been created |
| */ |
| protected Label getLabelControl() { |
| return label; |
| } |
| |
| /** |
| * Returns this field editor's label component. |
| * <p> |
| * The label is created if it does not already exist |
| * </p> |
| * |
| * @param parent the parent |
| * @return the label control |
| */ |
| public Label getLabelControl(Composite parent) { |
| if (label == null) { |
| label = new Label(parent, SWT.LEFT); |
| label.setFont(parent.getFont()); |
| String text = getLabelText(); |
| if (text != null) |
| label.setText(text); |
| label.addDisposeListener(new DisposeListener() { |
| public void widgetDisposed(DisposeEvent event) { |
| label = null; |
| } |
| }); |
| } else { |
| checkParent(label, parent); |
| } |
| return label; |
| } |
| |
| /** |
| * Returns this field editor's label text. |
| * |
| * @return the label text |
| */ |
| public String getLabelText() { |
| return labelText; |
| } |
| |
| /** |
| * Returns the number of basic controls this field editor consists of. |
| * |
| * @return the number of controls |
| */ |
| public abstract int getNumberOfControls(); |
| |
| /** |
| * Returns the name of the preference this field editor operates on. |
| * |
| * @return the name of the preference |
| */ |
| public String getPreferenceName() { |
| return preferenceName; |
| } |
| |
| /** |
| * Returns the preference page in which this field editor |
| * appears. |
| * |
| * @return the preference page, or <code>null</code> if none |
| * @deprecated use #getPage() |
| */ |
| protected PreferencePage getPreferencePage() { |
| if(page != null && page instanceof PreferencePage) |
| return (PreferencePage) page; |
| return null; |
| } |
| |
| /** |
| * Return the DialogPage that the receiver is sending |
| * updates to. |
| * |
| * @return DialogPage or <code>null</code> if it |
| * has not been set. |
| * |
| * @since 3.1 |
| */ |
| protected DialogPage getPage(){ |
| return page; |
| } |
| |
| /** |
| * Returns the preference store used by this field editor. |
| * |
| * @return the preference store, or <code>null</code> if none |
| * @see #setPreferenceStore |
| */ |
| public IPreferenceStore getPreferenceStore() { |
| return preferenceStore; |
| } |
| |
| /** |
| * Initialize the field editor with the given preference name and label. |
| * |
| * @param name the name of the preference this field editor works on |
| * @param text the label text of the field editor |
| */ |
| protected void init(String name, String text) { |
| Assert.isNotNull(name); |
| Assert.isNotNull(text); |
| preferenceName = name; |
| this.labelText = text; |
| } |
| |
| /** |
| * Returns whether this field editor contains a valid value. |
| * <p> |
| * The default implementation of this framework method |
| * returns <code>true</code>. Subclasses wishing to perform |
| * validation should override both this method and |
| * <code>refreshValidState</code>. |
| * </p> |
| * |
| * @return <code>true</code> if the field value is valid, |
| * and <code>false</code> if invalid |
| * @see #refreshValidState() |
| */ |
| public boolean isValid() { |
| return true; |
| } |
| |
| /** |
| * Initializes this field editor with the preference value from |
| * the preference store. |
| */ |
| public void load() { |
| if (preferenceStore != null) { |
| isDefaultPresented = false; |
| doLoad(); |
| refreshValidState(); |
| } |
| } |
| |
| /** |
| * Initializes this field editor with the default preference value |
| * from the preference store. |
| */ |
| public void loadDefault() { |
| if (preferenceStore != null) { |
| isDefaultPresented = true; |
| doLoadDefault(); |
| refreshValidState(); |
| } |
| } |
| |
| /** |
| * Returns whether this field editor currently presents the |
| * default value for its preference. |
| * |
| * @return <code>true</code> if the default value is presented, |
| * and <code>false</code> otherwise |
| */ |
| public boolean presentsDefaultValue() { |
| return isDefaultPresented; |
| } |
| |
| /** |
| * Refreshes this field editor's valid state after a value change |
| * and fires an <code>IS_VALID</code> property change event if |
| * warranted. |
| * <p> |
| * The default implementation of this framework method does |
| * nothing. Subclasses wishing to perform validation should override |
| * both this method and <code>isValid</code>. |
| * </p> |
| * |
| * @see #isValid |
| */ |
| protected void refreshValidState() { |
| } |
| |
| /** |
| * Sets the focus to this field editor. |
| * <p> |
| * The default implementation of this framework method |
| * does nothing. Subclasses may reimplement. |
| * </p> |
| */ |
| public void setFocus() { |
| // do nothing; |
| } |
| |
| /** |
| * Sets this field editor's label text. |
| * The label is typically presented to the left of the entry field. |
| * |
| * @param text the label text |
| */ |
| public void setLabelText(String text) { |
| Assert.isNotNull(text); |
| labelText = text; |
| if (label != null) |
| label.setText(text); |
| } |
| |
| /** |
| * Sets the name of the preference this field editor operates on. |
| * <p> |
| * The ability to change this allows the same field editor object |
| * to be reused for different preferences. |
| * </p> |
| * <p> |
| * For example: <p> |
| * <pre> |
| * ... |
| * editor.setPreferenceName("font"); |
| * editor.load(); |
| * </pre> |
| * </p> |
| * |
| * @param name the name of the preference |
| */ |
| public void setPreferenceName(String name) { |
| preferenceName = name; |
| } |
| |
| /** |
| * Sets the preference page in which this field editor |
| * appears. |
| * |
| * @param preferencePage the preference page, or <code>null</code> if none |
| * @deprecated use #setPage(DialogPage) |
| */ |
| public void setPreferencePage(PreferencePage preferencePage) { |
| setPage(preferencePage); |
| } |
| |
| |
| /** |
| * Set the page to be the receiver. |
| * @param dialogPage |
| * |
| * @since 3.1 |
| */ |
| public void setPage(DialogPage dialogPage) { |
| page = dialogPage; |
| |
| } |
| |
| /** |
| * Sets the preference store used by this field editor. |
| * |
| * @param store the preference store, or <code>null</code> if none |
| * @see #getPreferenceStore |
| */ |
| public void setPreferenceStore(IPreferenceStore store) { |
| preferenceStore = store; |
| } |
| |
| /** |
| * Sets whether this field editor is presenting the default value. |
| * |
| * @param booleanValue <code>true</code> if the default value is being presented, |
| * and <code>false</code> otherwise |
| */ |
| protected void setPresentsDefaultValue(boolean booleanValue) { |
| isDefaultPresented = booleanValue; |
| } |
| |
| /** |
| * Sets or removes the property change listener for this field editor. |
| * <p> |
| * Note that field editors can support only a single listener. |
| * </p> |
| * |
| * @param listener a property change listener, or <code>null</code> |
| * to remove |
| */ |
| public void setPropertyChangeListener(IPropertyChangeListener listener) { |
| propertyChangeListener = listener; |
| } |
| |
| /** |
| * Shows the given error message in the page for this |
| * field editor if it has one. |
| * |
| * @param msg the error message |
| */ |
| protected void showErrorMessage(String msg) { |
| if (page != null) |
| page.setErrorMessage(msg); |
| } |
| |
| /** |
| * Shows the given message in the page for this |
| * field editor if it has one. |
| * |
| * @param msg the message |
| */ |
| protected void showMessage(String msg) { |
| if (page != null) |
| page.setErrorMessage(msg); |
| } |
| |
| /** |
| * Stores this field editor's value back into the preference store. |
| */ |
| public void store() { |
| if (preferenceStore == null) |
| return; |
| |
| if (isDefaultPresented) { |
| preferenceStore.setToDefault(preferenceName); |
| } else { |
| doStore(); |
| } |
| } |
| |
| /** |
| * Set the GridData on button to be one that is spaced for the |
| * current font. |
| * @param button the button the data is being set on. |
| */ |
| |
| protected void setButtonLayoutData(Button button) { |
| |
| GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL); |
| |
| // Compute and store a font metric |
| GC gc = new GC(button); |
| gc.setFont(button.getFont()); |
| FontMetrics fontMetrics = gc.getFontMetrics(); |
| gc.dispose(); |
| |
| int widthHint = org.eclipse.jface.dialogs.Dialog |
| .convertVerticalDLUsToPixels(fontMetrics, |
| IDialogConstants.BUTTON_WIDTH); |
| data.widthHint = Math.max(widthHint, button.computeSize(SWT.DEFAULT, |
| SWT.DEFAULT, true).x); |
| button.setLayoutData(data); |
| } |
| |
| /** |
| * Set whether or not the controls in the field editor |
| * are enabled. |
| * @param enabled The enabled state. |
| * @param parent The parent of the controls in the group. |
| * Used to create the controls if required. |
| */ |
| public void setEnabled(boolean enabled, Composite parent) { |
| getLabelControl(parent).setEnabled(enabled); |
| } |
| |
| } |