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);
+    }
+
+}