view dwtx/cdt/managedbuilder/ui/properties/MultiLineTextFieldEditor.d @ 110:a26bb7394581

Add two field editor from the CDT project, thanks yidabu for the port.
author Frank Benoit <benoit@tionex.de>
date Thu, 07 Aug 2008 17:37:04 +0200
parents
children
line wrap: on
line source

/**********************************************************************
 * Copyright (c) 2004 BitMethods Inc and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Common Public License v0.5
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v05.html
 *
 * Contributors:
 * BitMethods Inc - Initial API and implementation
 * Ported to the D programming language
 *     yidabu ( D Programming Language China : http://www.d-programming-language-china.org/ )
 ***********************************************************************/
module dwtx.cdt.managedbuilder.ui.properties.MultiLineTextFieldEditor;

//import org.eclipse.cdt.managedbuilder.internal.ui.ManagedBuilderUIMessages;
import dwtx.jface.preference.FieldEditor;
import dwtx.jface.util.Assert;
import dwt.DWT;
import dwt.events.DisposeEvent;
import dwt.events.DisposeListener;
import dwt.events.FocusAdapter;
import dwt.events.FocusEvent;
import dwt.events.KeyAdapter;
import dwt.events.KeyEvent;
import dwt.layout.GridData;
import dwt.widgets.Composite;
import dwt.widgets.Label;
import dwt.widgets.Text;

import dwt.dwthelper.utils;

/**
 *  MultiLineTextFieldEditor.
 *  Field editor that is same as string field editor but
 *  will have the multi line text field for user input.
 */
public class MultiLineTextFieldEditor : FieldEditor {

    alias FieldEditor.showErrorMessage showErrorMessage;
    private static final String ERROR_MESSAGE = "Multiline.error.message";  //$NON-NLS-1$
    private static final String ERROR_MESSAGE_CONST = "Please give correct input";  //$NON-NLS-1$

    /**
     * Validation strategy constant (value <code>0</code>) indicating that
     * the editor should perform validation after every key stroke.
     *
     * @see #setValidateStrategy
     */
    public static const int VALIDATE_ON_KEY_STROKE = 0;

    /**
     * Validation strategy constant (value <code>1</code>) indicating that
     * the editor should perform validation only when the text widget
     * loses focus.
     *
     * @see #setValidateStrategy
     */
    public static const int VALIDATE_ON_FOCUS_LOST = 1;

    /**
     * Text limit constant (value <code>-1</code>) indicating unlimited
     * text limit and width.
     */
    public static int UNLIMITED = -1;

    /**
     * Cached valid state.
     */
    private bool isValid_;

    /**
     * Old text value.
     */
    private String oldValue;
    private String compTitle;
    private Label title;

    /**
     * The text field, or <code>null</code> if none.
     */
    private Text textField;

    /**
     * Width of text field in characters; initially unlimited.
     */
    private int widthInChars;

    /**
     * Text limit of text field in characters; initially unlimited.
     */
    private int textLimit;

    /**
     * The error message, or <code>null</code> if none.
     */
    private String errorMessage;

    /**
     * Indicates whether the empty string is legal;
     * <code>true</code> by default.
     */
    private bool emptyStringAllowed = true;

    /**
     * The validation strategy;
     * <code>VALIDATE_ON_KEY_STROKE</code> by default.
     */
    private int validateStrategy;
    /**
     * Creates a new string field editor
     */
    protected this() {
        widthInChars = UNLIMITED;
        textLimit = UNLIMITED;
        validateStrategy = VALIDATE_ON_KEY_STROKE;
    }
    /**
     * Creates a string field editor.
     * Use the method <code>setTextLimit</code> to limit the text.
     *
     * @param name the name of the preference this field editor works on
     * @param labelText the label text of the field editor
     * @param width the width of the text input field in characters,
     *  or <code>UNLIMITED</code> for no limit
     * @param strategy either <code>VALIDATE_ON_KEY_STROKE</code> to perform
     *  on the fly checking (the default), or <code>VALIDATE_ON_FOCUS_LOST</code> to
     *  perform validation only after the text has been typed in
     * @param parent the parent of the field editor's control
     * @since 2.0
     */
    public this(
        String name,
        String labelText,
        int width,
        int strategy,
        Composite parent) {
        this();
        init(name, labelText);
        widthInChars = width;
        setValidateStrategy(strategy);
        isValid_ = false;
        //errorMessage = ManagedBuilderUIMessages.getResourceString(ERROR_MESSAGE);
        errorMessage = ERROR_MESSAGE_CONST;
        createControl(parent);
    }

    /**
     * Creates a string field editor.
     * Use the method <code>setTextLimit</code> to limit the text.
     *
     * @param name the name of the preference this field editor works on
     * @param labelText the label text of the field editor
     * @param width the width of the text input field in characters,
     *  or <code>UNLIMITED</code> for no limit
     * @param parent the parent of the field editor's control
     */
    public this(String name, String labelText, int width, Composite parent) {
        this(name, labelText, width, VALIDATE_ON_KEY_STROKE, parent);
        this.compTitle = labelText;
    }
    /**
     * Creates a string field editor of unlimited width.
     * Use the method <code>setTextLimit</code> to limit the text.
     *
     * @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 this(String name, String labelText, Composite parent) {
        this(name, labelText, UNLIMITED, 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 void adjustForNumColumns(int numColumns) {
        GridData gd = cast(GridData) textField.getLayoutData();
        gd.horizontalSpan = numColumns - 1;
        // We only grab excess space if we have to
        // If another field editor has more columns then
        // we assume it is setting the width.
        gd.grabExcessHorizontalSpace = gd.horizontalSpan == 1;
    }
    /**
     * Checks whether the text input field contains a valid value or not.
     *
     * @return <code>true</code> if the field value is valid,
     *   and <code>false</code> if invalid
     */
    protected bool checkState() {
        bool result = false;
        if (emptyStringAllowed)
            result = true;

        if (textField is null)
            result = false;

        String txt = textField.getText();

        if (txt is null)
            result = false;

        result = (txt.trim().length > 0) || emptyStringAllowed;

        // call hook for subclasses
        result = result && doCheckState();

        if (result)
            clearErrorMessage();
        else
            showErrorMessage(errorMessage);

        return result;
    }
    /**
     * Hook for subclasses to do specific state checks.
     * <p>
     * The default implementation of this framework method does
     * nothing and returns <code>true</code>.  Subclasses should
     * override this method to specific state checks.
     * </p>
     *
     * @return <code>true</code> if the field value is valid,
     *   and <code>false</code> if invalid
     */
    protected bool doCheckState() {
        return true;
    }
    /**
     * Fills this field editor's basic controls into the given parent.
     * <p>
     * The string field implementation of this <code>FieldEditor</code>
     * framework method contributes the text field. Subclasses may override
     * but must call <code>super.doFillIntoGrid</code>.
     * </p>
     */
    protected void doFillIntoGrid(Composite parent, int numColumns) {

        title = new Label(parent, DWT.UP);
        title.setFont(parent.getFont());
        this.compTitle = getLabelText();
        title.setText(this.compTitle);
        title.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));

        textField = getTextControl(parent);
        GridData gd = new GridData(GridData.FILL_HORIZONTAL);
        gd.widthHint = 100;
        gd.heightHint = 70;
        textField.setLayoutData(gd);

    }

    /**
     * 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 void doLoad() {
        if (textField !is null) {
            String value = getPreferenceStore().getString(getPreferenceName());
            textField.setText(value);
            oldValue = value;
        }
    }

    /**
     * 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 void doLoadDefault() {
        if (textField !is null) {
            String value =
                getPreferenceStore().getDefaultString(getPreferenceName());
            textField.setText(value);
        }
        valueChanged();
    }

    /* (non-Javadoc)
     * @see dwtx.jface.preference.FieldEditor#doStore()
     */
    protected void doStore() {
        getPreferenceStore().setValue(getPreferenceName(), textField.getText());
    }

    /**
     * Returns the error message that will be displayed when and if
     * an error occurs.
     *
     * @return the error message, or <code>null</code> if none
     */
    public String getErrorMessage() {
        return errorMessage;
    }
    /**
        * Returns the number of basic controls this field editor consists of.
        *
        * @return the number of controls
        */
    public int getNumberOfControls() {
        return 2;
    }
    /**
     * Returns the field editor's value.
     *
     * @return the current value
     */
    public String getStringValue() {
        if (textField !is null)
            return textField.getText();
        else
            return getPreferenceStore().getString(getPreferenceName());
    }

    /**
     * Returns this field editor's text control.
     *
     * @param parent the parent
     * @return the text control, or <code>null</code> if no
     * text field is created yet
     */
    protected Text getTextControl() {
        return textField;
    }

    /**
     * Returns this field editor's text control.
     * <p>
     * The control is created if it does not yet exist
     * </p>
     *
     * @param parent the parent
     * @return the text control
     */
    public Text getTextControl(Composite parent) {
        if (textField is null) {
            textField =
                new Text(
                    parent,
                    DWT.MULTI | DWT.V_SCROLL | DWT.BORDER | DWT.WRAP);
            textField.setFont(parent.getFont());
            switch (validateStrategy) {
                case VALIDATE_ON_KEY_STROKE :
                    textField.addKeyListener(new class() KeyAdapter {
                        public void keyPressed(KeyEvent e) {
                            valueChanged();
                        }
                    });

                    textField.addFocusListener(new class() FocusAdapter {
                        public void focusGained(FocusEvent e) {
                            refreshValidState();
                        }
                        public void focusLost(FocusEvent e) {
                            clearErrorMessage();
                        }
                    });
                    break;
                case VALIDATE_ON_FOCUS_LOST :
                    textField.addKeyListener(new class() KeyAdapter {
                        public void keyPressed(KeyEvent e) {
                            clearErrorMessage();
                        }
                    });
                    textField.addFocusListener(new class() FocusAdapter {
                        public void focusGained(FocusEvent e) {
                            refreshValidState();
                        }
                        public void focusLost(FocusEvent e) {
                            valueChanged();
                            clearErrorMessage();
                        }
                    });
                    break;
                default :
                    Assert.isTrue(false, "Unknown validate strategy"); //$NON-NLS-1$
            }
            textField.addDisposeListener(new class() DisposeListener {
                public void widgetDisposed(DisposeEvent event) {
                    textField = null;
                }
            });
            if (textLimit > 0) { //Only set limits above 0 - see SWT spec
                textField.setTextLimit(textLimit);
            }
        } else {
            checkParent(textField, parent);
        }
        return textField;
    }

    /**
     * Returns whether an empty string is a valid value.
     *
     * @return <code>true</code> if an empty string is a valid value, and
     *  <code>false</code> if an empty string is invalid
     * @see #setEmptyStringAllowed
     */
    public bool isEmptyStringAllowed() {
        return emptyStringAllowed;
    }

    /**
     * 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 isValid_;
    }

    /**
     * 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() {
        isValid_ = checkState();
    }

    /**
     * Sets whether the empty string is a valid value or not.
     *
     * @param b <code>true</code> if the empty string is allowed,
     *  and <code>false</code> if it is considered invalid
     */
    public void setEmptyStringAllowed(bool b) {
        emptyStringAllowed = b;
    }

    /**
     * Sets the error message that will be displayed when and if
     * an error occurs.
     *
     * @param message the error message
     */
    public void setErrorMessage(String message) {
        errorMessage = message;
    }

    /**
     * Sets the focus to this field editor.
     * <p>
     * The default implementation of this framework method
     * does nothing. Subclasses may reimplement.
     * </p>
    */
    public void setFocus() {
        if (textField !is null) {
            textField.setFocus();
        }
    }

    /**
     * Sets this field editor's value.
     *
     * @param value the new value, or <code>null</code> meaning the empty string
     */
    public void setStringValue(String value) {
        if (textField !is null) {
            if (value is null)
                value = ""; //$NON-NLS-1$
            oldValue = textField.getText();
            if (!oldValue.equals(value)) {
                textField.setText(value);
                valueChanged();
            }
        }
    }

    /**
     * Sets this text field's text limit.
     *
     * @param limit the limit on the number of character in the text
     *  input field, or <code>UNLIMITED</code> for no limit
     */
    public void setTextLimit(int limit) {
        textLimit = limit;
        if (textField !is null)
            textField.setTextLimit(limit);
    }

    /**
     * Sets the strategy for validating the text.
     * <p>
     * Calling this method has no effect after <code>createPartControl</code>
     * is called. Thus this method is really only useful for subclasses to call
     * in their constructor. However, it has public visibility for backward
     * compatibility.
     * </p>
     *
     * @param value either <code>VALIDATE_ON_KEY_STROKE</code> to perform
     *  on the fly checking (the default), or <code>VALIDATE_ON_FOCUS_LOST</code> to
     *  perform validation only after the text has been typed in
     */
    public void setValidateStrategy(int value) {
        Assert.isTrue(
            value == VALIDATE_ON_FOCUS_LOST || value == VALIDATE_ON_KEY_STROKE);
        validateStrategy = value;
    }

    /**
     * Shows the error message set via <code>setErrorMessage</code>.
     */
    public void showErrorMessage() {
        showErrorMessage(errorMessage);
    }

    /**
     * Informs this field editor's listener, if it has one, about a change
     * to the value (<code>VALUE</code> property) provided that the old and
     * new values are different.
     * <p>
     * This hook is <em>not</em> called when the text is initialized
     * (or reset to the default value) from the preference store.
     * </p>
     */
    protected void valueChanged() {
        setPresentsDefaultValue(false);
        bool oldState = isValid_;
        refreshValidState();

        if (isValid_ !is oldState)
            fireStateChanged(IS_VALID, oldState, isValid_);

        String newValue = textField.getText();
        if (!newValue.equals(oldValue)) {
            fireValueChanged(VALUE, stringcast(oldValue), stringcast(newValue));
            oldValue = newValue;
        }
    }
}