package io.sloeber.ui; /******************************************************************************* * Copyright (c) 2004 BitMethods Inc 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: * BitMethods Inc - Initial API and implementation *******************************************************************************/ import org.eclipse.jface.preference.FieldEditor; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; /** * MultiLineTextFieldEditor. Field editor that is same as string field editor * but will have the multi line text field for user input. */ public class MultiLineTextFieldEditor extends FieldEditor { /** * Text limit constant (value <code>-1</code>) indicating unlimited text * limit and width. */ public static int UNLIMITED = -1; /** * Cached valid state. */ private boolean isValid; /** * Old text value. */ private String oldValue; private String compTitle; private Label title; /** * The text field, or <code>null</code> if none. */ protected Text textField; /** * Text limit of text field in characters; initially unlimited. */ private int textLimit = UNLIMITED; /** * Indicates whether the empty string is legal; <code>true</code> by * default. */ private boolean emptyStringAllowed = true; /** * Creates a new string field editor */ protected MultiLineTextFieldEditor() { } /** * 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 * @since 2.0 */ public MultiLineTextFieldEditor(String name, String labelText, Composite parent) { init(name, labelText); this.isValid = false; 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 */ @Override protected void adjustForNumColumns(int numColumns) { GridData gd = (GridData) this.textField.getLayoutData(); // grab all the space we can gd.horizontalSpan = numColumns; gd.grabExcessHorizontalSpace = true; gd.grabExcessVerticalSpace = true; } /** * 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 boolean checkState() { String txt = this.textField.getText(); if (txt == null) return false; return (txt.trim().length() > 0) || this.emptyStringAllowed; } /** * 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> */ @Override protected void doFillIntoGrid(Composite parent, int numColumns) { this.title = new Label(parent, SWT.UP); this.title.setFont(parent.getFont()); this.compTitle = getLabelText(); this.title.setText(this.compTitle); this.title.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING)); this.textField = getTextControl(parent); GridData gd = new GridData(GridData.FILL_BOTH); this.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> */ @Override protected void doLoad() { if (this.textField != null) { String value = getPreferenceStore().getString(getPreferenceName()); this.textField.setText(value); this.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> */ @Override protected void doLoadDefault() { if (this.textField != null) { String value = getPreferenceStore().getDefaultString(getPreferenceName()); this.textField.setText(value); } valueChanged(); } /* * (non-Javadoc) * * @see org.eclipse.jface.preference.FieldEditor#doStore() */ @Override protected void doStore() { getPreferenceStore().setValue(getPreferenceName(), this.textField.getText()); } /** * Returns the field editor's value. * * @return the current value */ public String getStringValue() { if (this.textField != null) return this.textField.getText(); 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 this.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 (this.textField == null) { this.textField = new Text(parent, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER | SWT.WRAP); this.textField.setFont(parent.getFont()); this.textField.addDisposeListener(new DisposeListener() { @Override public void widgetDisposed(DisposeEvent event) { MultiLineTextFieldEditor.this.textField = null; } }); if (this.textLimit > 0) { // Only set limits above 0 - see SWT spec this.textField.setTextLimit(this.textLimit); } } else { checkParent(this.textField, parent); } return this.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 boolean isEmptyStringAllowed() { return this.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 */ @Override public boolean isValid() { return this.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 */ @Override protected void refreshValidState() { this.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(boolean b) { this.emptyStringAllowed = b; } /** * Sets the focus to this field editor. * <p> * The default implementation of this framework method does nothing. * Subclasses may reimplement. * </p> */ @Override public void setFocus() { if (this.textField != null) { this.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) { String safeValue = value; if (value == null) safeValue = ""; //$NON-NLS-1$ if (this.textField != null) { this.oldValue = this.textField.getText(); if (!this.oldValue.equals(safeValue)) { this.textField.setText(safeValue); 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) { this.textLimit = limit; if (this.textField != null) this.textField.setTextLimit(limit); } /** * 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); boolean oldState = this.isValid; refreshValidState(); if (this.isValid != oldState) fireStateChanged(IS_VALID, oldState, this.isValid); String newValue = this.textField.getText(); if (!newValue.equals(this.oldValue)) { fireValueChanged(VALUE, this.oldValue, newValue); this.oldValue = newValue; } } @Override public int getNumberOfControls() { return 2; } }