Mercurial > projects > dwt-addons
diff dwtx/jface/preference/FieldEditor.d @ 34:b3c8e32d406f
preference
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sat, 05 Apr 2008 01:45:47 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/jface/preference/FieldEditor.d Sat Apr 05 01:45:47 2008 +0200 @@ -0,0 +1,731 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 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 + * Port to the D programming language: + * Frank Benoit <benoit@tionex.de> + *******************************************************************************/ +module dwtx.jface.preference.FieldEditor; + +import dwtx.jface.preference.IPreferenceStore; +import dwtx.jface.preference.PreferencePage; + +import dwt.DWT; +import dwt.events.DisposeEvent; +import dwt.events.DisposeListener; +import dwt.graphics.FontMetrics; +import dwt.graphics.GC; +import dwt.layout.GridData; +import dwt.layout.GridLayout; +import dwt.widgets.Button; +import dwt.widgets.Composite; +import dwt.widgets.Control; +import dwt.widgets.Label; +import dwtx.core.runtime.Assert; +import dwtx.jface.dialogs.DialogPage; +import dwtx.jface.dialogs.IDialogConstants; +import dwtx.jface.resource.JFaceResources; +import dwtx.jface.util.IPropertyChangeListener; +import dwtx.jface.util.PropertyChangeEvent; + +import dwt.dwthelper.utils; + +/** + * 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 const 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 const String VALUE = "field_editor_value";//$NON-NLS-1$ + + /** + * Gap between label and control. + */ + protected static const 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 bool 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 this() { + } + + /** + * 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 this(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); + package void adjustForNumColumns_package(int numColumns){ + adjustForNumColumns(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 DWT control to + * a value different than the standard dialog font. + * </p> + */ + protected void applyFont() { + } + package void applyFont_package() { + 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() is parent, "Different parents");//$NON-NLS-1$ + } + + /** + * Clears the error message from the message line. + */ + protected void clearErrorMessage() { + if (page !is null) { + page.setErrorMessage(null); + } + } + + /** + * Clears the normal message from the message line. + */ + protected void clearMessage() { + if (page !is 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 cast(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 cast(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 DWT 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(null !is cast(GridLayout)parent.getLayout() ); + doFillIntoGrid(parent, numColumns); + } + + /** + * Informs this field editor's listener, if it has one, about a change to + * one of this field editor's bool-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, bool oldValue, + bool newValue) { + if (oldValue is newValue) { + return; + } + fireValueChanged(property, oldValue ? Boolean.TRUE : Boolean.FALSE, newValue ? Boolean.TRUE : Boolean.FALSE); + } + + /** + * 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 is 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 is null) { + label = new Label(parent, DWT.LEFT); + label.setFont(parent.getFont()); + String text = getLabelText(); + if (text !is null) { + label.setText(text); + } + label.addDisposeListener(new class 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 !is null && cast(PreferencePage)page ) { + return cast(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 bool isValid() { + return true; + } + + /** + * Initializes this field editor with the preference value from + * the preference store. + */ + public void load() { + if (preferenceStore !is null) { + isDefaultPresented = false; + doLoad(); + refreshValidState(); + } + } + + /** + * Initializes this field editor with the default preference value + * from the preference store. + */ + public void loadDefault() { + if (preferenceStore !is 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 bool 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 !is 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(bool booleanValue) { + isDefaultPresented = booleanValue; + } + package void setPresentsDefaultValue_package(bool booleanValue) { + setPresentsDefaultValue(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 !is 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 !is null) { + page.setErrorMessage(msg); + } + } + + /** + * Stores this field editor's value back into the preference store. + */ + public void store() { + if (preferenceStore is 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 = dwtx.jface.dialogs.Dialog.Dialog + .convertVerticalDLUsToPixels(fontMetrics, + IDialogConstants.BUTTON_WIDTH); + data.widthHint = Math.max(widthHint, button.computeSize(DWT.DEFAULT, + DWT.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(bool enabled, Composite parent) { + getLabelControl(parent).setEnabled(enabled); + } + +}