Mercurial > projects > dwt-addons
diff dwtx/jface/viewers/TextCellEditor.d @ 10:b6c35faf97c8
Viewers
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Mon, 31 Mar 2008 00:47:19 +0200 |
parents | |
children | ea8ff534f622 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/jface/viewers/TextCellEditor.d Mon Mar 31 00:47:19 2008 +0200 @@ -0,0 +1,485 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 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.viewers.TextCellEditor; + +import dwtx.jface.viewers.CellEditor; + +import dwt.DWT; +import dwt.events.FocusAdapter; +import dwt.events.FocusEvent; +import dwt.events.KeyAdapter; +import dwt.events.KeyEvent; +import dwt.events.ModifyEvent; +import dwt.events.ModifyListener; +import dwt.events.MouseAdapter; +import dwt.events.MouseEvent; +import dwt.events.SelectionAdapter; +import dwt.events.SelectionEvent; +import dwt.events.TraverseEvent; +import dwt.events.TraverseListener; +import dwt.widgets.Composite; +import dwt.widgets.Control; +import dwt.widgets.Text; +import dwtx.core.runtime.Assert; + +import dwt.dwthelper.utils; +import tango.text.convert.Format; + +/** + * A cell editor that manages a text entry field. + * The cell editor's value is the text string itself. + * <p> + * This class may be instantiated; it is not intended to be subclassed. + * </p> + */ +public class TextCellEditor : CellEditor { + + /** + * The text control; initially <code>null</code>. + */ + protected Text text; + + private ModifyListener modifyListener; + + /** + * State information for updating action enablement + */ + private bool isSelection = false; + + private bool isDeleteable = false; + + private bool isSelectable = false; + + /** + * Default TextCellEditor style + * specify no borders on text widget as cell outline in table already + * provides the look of a border. + */ + private static const int defaultStyle = DWT.SINGLE; + + /** + * Creates a new text string cell editor with no control + * The cell editor value is the string itself, which is initially the empty + * string. Initially, the cell editor has no cell validator. + * + * @since 2.1 + */ + public this() { + setStyle(defaultStyle); + } + + /** + * Creates a new text string cell editor parented under the given control. + * The cell editor value is the string itself, which is initially the empty string. + * Initially, the cell editor has no cell validator. + * + * @param parent the parent control + */ + public this(Composite parent) { + this(parent, defaultStyle); + } + + /** + * Creates a new text string cell editor parented under the given control. + * The cell editor value is the string itself, which is initially the empty string. + * Initially, the cell editor has no cell validator. + * + * @param parent the parent control + * @param style the style bits + * @since 2.1 + */ + public this(Composite parent, int style) { + super(parent, style); + } + + /** + * Checks to see if the "deletable" state (can delete/ + * nothing to delete) has changed and if so fire an + * enablement changed notification. + */ + private void checkDeleteable() { + bool oldIsDeleteable = isDeleteable; + isDeleteable = isDeleteEnabled(); + if (oldIsDeleteable !is isDeleteable) { + fireEnablementChanged(DELETE); + } + } + + /** + * Checks to see if the "selectable" state (can select) + * has changed and if so fire an enablement changed notification. + */ + private void checkSelectable() { + bool oldIsSelectable = isSelectable; + isSelectable = isSelectAllEnabled(); + if (oldIsSelectable !is isSelectable) { + fireEnablementChanged(SELECT_ALL); + } + } + + /** + * Checks to see if the selection state (selection / + * no selection) has changed and if so fire an + * enablement changed notification. + */ + private void checkSelection() { + bool oldIsSelection = isSelection; + isSelection = text.getSelectionCount() > 0; + if (oldIsSelection !is isSelection) { + fireEnablementChanged(COPY); + fireEnablementChanged(CUT); + } + } + + /* (non-Javadoc) + * Method declared on CellEditor. + */ + protected Control createControl(Composite parent) { + text = new Text(parent, getStyle()); + text.addSelectionListener(new class SelectionAdapter { + public void widgetDefaultSelected(SelectionEvent e) { + handleDefaultSelection(e); + } + }); + text.addKeyListener(new class KeyAdapter { + // hook key pressed - see PR 14201 + public void keyPressed(KeyEvent e) { + keyReleaseOccured(e); + + // as a result of processing the above call, clients may have + // disposed this cell editor + if ((getControl() is null) || getControl().isDisposed()) { + return; + } + checkSelection(); // see explanation below + checkDeleteable(); + checkSelectable(); + } + }); + text.addTraverseListener(new class TraverseListener { + public void keyTraversed(TraverseEvent e) { + if (e.detail is DWT.TRAVERSE_ESCAPE + || e.detail is DWT.TRAVERSE_RETURN) { + e.doit = false; + } + } + }); + // We really want a selection listener but it is not supported so we + // use a key listener and a mouse listener to know when selection changes + // may have occurred + text.addMouseListener(new class MouseAdapter { + public void mouseUp(MouseEvent e) { + checkSelection(); + checkDeleteable(); + checkSelectable(); + } + }); + text.addFocusListener(new class FocusAdapter { + public void focusLost(FocusEvent e) { + this.outer.focusLost(); + } + }); + text.setFont(parent.getFont()); + text.setBackground(parent.getBackground()); + text.setText("");//$NON-NLS-1$ + text.addModifyListener(getModifyListener()); + return text; + } + + /** + * The <code>TextCellEditor</code> implementation of + * this <code>CellEditor</code> framework method returns + * the text string. + * + * @return the text string + */ + protected Object doGetValue() { + return new ArrayWrapperString(text.getText()); + } + + /* (non-Javadoc) + * Method declared on CellEditor. + */ + protected void doSetFocus() { + if (text !is null) { + text.selectAll(); + text.setFocus(); + checkSelection(); + checkDeleteable(); + checkSelectable(); + } + } + + /** + * The <code>TextCellEditor</code> implementation of + * this <code>CellEditor</code> framework method accepts + * a text string (type <code>String</code>). + * + * @param value a text string (type <code>String</code>) + */ + protected void doSetValue(Object value) { + Assert.isTrue(text !is null && ( cast(ArrayWrapperString)value )); + text.removeModifyListener(getModifyListener()); + text.setText((cast(ArrayWrapperString)value).array); + text.addModifyListener(getModifyListener()); + } + + /** + * Processes a modify event that occurred in this text cell editor. + * This framework method performs validation and sets the error message + * accordingly, and then reports a change via <code>fireEditorValueChanged</code>. + * Subclasses should call this method at appropriate times. Subclasses + * may extend or reimplement. + * + * @param e the DWT modify event + */ + protected void editOccured(ModifyEvent e) { + String value = text.getText(); + if (value is null) { + value = "";//$NON-NLS-1$ + } + Object typedValue = new ArrayWrapperString(value); + bool oldValidState = isValueValid(); + bool newValidState = isCorrect(typedValue); + if (typedValue is null && newValidState) { + Assert.isTrue(false, + "Validator isn't limiting the cell editor's type range");//$NON-NLS-1$ + } + if (!newValidState) { + // try to insert the current value into the error message. + setErrorMessage(Format(getErrorMessage(), value )); + } + valueChanged(oldValidState, newValidState); + } + + /** + * Since a text editor field is scrollable we don't + * set a minimumSize. + */ + public LayoutData getLayoutData() { + return new LayoutData(); + } + + /** + * Return the modify listener. + */ + private ModifyListener getModifyListener() { + if (modifyListener is null) { + modifyListener = new class ModifyListener { + public void modifyText(ModifyEvent e) { + editOccured(e); + } + }; + } + return modifyListener; + } + + /** + * Handles a default selection event from the text control by applying the editor + * value and deactivating this cell editor. + * + * @param event the selection event + * + * @since 3.0 + */ + protected void handleDefaultSelection(SelectionEvent event) { + // same with enter-key handling code in keyReleaseOccured(e); + fireApplyEditorValue(); + deactivate(); + } + + /** + * The <code>TextCellEditor</code> implementation of this + * <code>CellEditor</code> method returns <code>true</code> if + * the current selection is not empty. + */ + public bool isCopyEnabled() { + if (text is null || text.isDisposed()) { + return false; + } + return text.getSelectionCount() > 0; + } + + /** + * The <code>TextCellEditor</code> implementation of this + * <code>CellEditor</code> method returns <code>true</code> if + * the current selection is not empty. + */ + public bool isCutEnabled() { + if (text is null || text.isDisposed()) { + return false; + } + return text.getSelectionCount() > 0; + } + + /** + * The <code>TextCellEditor</code> implementation of this + * <code>CellEditor</code> method returns <code>true</code> + * if there is a selection or if the caret is not positioned + * at the end of the text. + */ + public bool isDeleteEnabled() { + if (text is null || text.isDisposed()) { + return false; + } + return text.getSelectionCount() > 0 + || text.getCaretPosition() < text.getCharCount(); + } + + /** + * The <code>TextCellEditor</code> implementation of this + * <code>CellEditor</code> method always returns <code>true</code>. + */ + public bool isPasteEnabled() { + if (text is null || text.isDisposed()) { + return false; + } + return true; + } + + /** + * Check if save all is enabled + * @return true if it is + */ + public bool isSaveAllEnabled() { + if (text is null || text.isDisposed()) { + return false; + } + return true; + } + + /** + * Returns <code>true</code> if this cell editor is + * able to perform the select all action. + * <p> + * This default implementation always returns + * <code>false</code>. + * </p> + * <p> + * Subclasses may override + * </p> + * @return <code>true</code> if select all is possible, + * <code>false</code> otherwise + */ + public bool isSelectAllEnabled() { + if (text is null || text.isDisposed()) { + return false; + } + return text.getCharCount() > 0; + } + + /** + * Processes a key release event that occurred in this cell editor. + * <p> + * The <code>TextCellEditor</code> implementation of this framework method + * ignores when the RETURN key is pressed since this is handled in + * <code>handleDefaultSelection</code>. + * An exception is made for Ctrl+Enter for multi-line texts, since + * a default selection event is not sent in this case. + * </p> + * + * @param keyEvent the key event + */ + protected void keyReleaseOccured(KeyEvent keyEvent) { + if (keyEvent.character is '\r') { // Return key + // Enter is handled in handleDefaultSelection. + // Do not apply the editor value in response to an Enter key event + // since this can be received from the IME when the intent is -not- + // to apply the value. + // See bug 39074 [CellEditors] [DBCS] canna input mode fires bogus event from Text Control + // + // An exception is made for Ctrl+Enter for multi-line texts, since + // a default selection event is not sent in this case. + if (text !is null && !text.isDisposed() + && (text.getStyle() & DWT.MULTI) !is 0) { + if ((keyEvent.stateMask & DWT.CTRL) !is 0) { + super.keyReleaseOccured(keyEvent); + } + } + return; + } + super.keyReleaseOccured(keyEvent); + } + + /** + * The <code>TextCellEditor</code> implementation of this + * <code>CellEditor</code> method copies the + * current selection to the clipboard. + */ + public void performCopy() { + text.copy(); + } + + /** + * The <code>TextCellEditor</code> implementation of this + * <code>CellEditor</code> method cuts the + * current selection to the clipboard. + */ + public void performCut() { + text.cut(); + checkSelection(); + checkDeleteable(); + checkSelectable(); + } + + /** + * The <code>TextCellEditor</code> implementation of this + * <code>CellEditor</code> method deletes the + * current selection or, if there is no selection, + * the character next character from the current position. + */ + public void performDelete() { + if (text.getSelectionCount() > 0) { + // remove the contents of the current selection + text.insert(""); //$NON-NLS-1$ + } else { + // remove the next character + int pos = text.getCaretPosition(); + if (pos < text.getCharCount()) { + text.setSelection(pos, pos + 1); + text.insert(""); //$NON-NLS-1$ + } + } + checkSelection(); + checkDeleteable(); + checkSelectable(); + } + + /** + * The <code>TextCellEditor</code> implementation of this + * <code>CellEditor</code> method pastes the + * the clipboard contents over the current selection. + */ + public void performPaste() { + text.paste(); + checkSelection(); + checkDeleteable(); + checkSelectable(); + } + + /** + * The <code>TextCellEditor</code> implementation of this + * <code>CellEditor</code> method selects all of the + * current text. + */ + public void performSelectAll() { + text.selectAll(); + checkSelection(); + checkDeleteable(); + } + + bool dependsOnExternalFocusListener() { + return this.classinfo !is TextCellEditor.classinfo; + } +}