X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.spreadsheet.ui%2Fsrc%2Forg%2Fsimantics%2Fspreadsheet%2Fui%2FTrackedText.java;h=ef1cd6ab1d075c93dfde58c65e8f711fd9abe762;hp=168efa16e04b5d5785d5fa79847beb6d777ac2b5;hb=refs%2Fchanges%2F38%2F238%2F2;hpb=24e2b34260f219f0d1644ca7a138894980e25b14 diff --git a/bundles/org.simantics.spreadsheet.ui/src/org/simantics/spreadsheet/ui/TrackedText.java b/bundles/org.simantics.spreadsheet.ui/src/org/simantics/spreadsheet/ui/TrackedText.java index 168efa16e..ef1cd6ab1 100644 --- a/bundles/org.simantics.spreadsheet.ui/src/org/simantics/spreadsheet/ui/TrackedText.java +++ b/bundles/org.simantics.spreadsheet.ui/src/org/simantics/spreadsheet/ui/TrackedText.java @@ -1,680 +1,680 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 Association for Decentralized Information Management - * in Industry THTH ry. - * 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: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.spreadsheet.ui; - -import java.awt.Color; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ComponentEvent; -import java.awt.event.ComponentListener; -import java.awt.event.ContainerEvent; -import java.awt.event.ContainerListener; -import java.awt.event.FocusEvent; -import java.awt.event.FocusListener; -import java.awt.event.HierarchyBoundsListener; -import java.awt.event.HierarchyEvent; -import java.awt.event.HierarchyListener; -import java.awt.event.InputMethodEvent; -import java.awt.event.InputMethodListener; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.event.MouseMotionListener; -import java.awt.event.MouseWheelEvent; -import java.awt.event.MouseWheelListener; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.beans.PropertyVetoException; -import java.beans.VetoableChangeListener; - -import javax.swing.JTextField; -import javax.swing.event.AncestorEvent; -import javax.swing.event.AncestorListener; -import javax.swing.event.CaretEvent; -import javax.swing.event.CaretListener; - -import org.eclipse.core.runtime.Assert; -import org.eclipse.core.runtime.ListenerList; -import org.eclipse.jface.dialogs.IInputValidator; - -/** - * This is a TrackedTest SWT Text-widget 'decorator'. - * - * The widget has 2 main states: editing and inactive. - * - * It implements the necessary listeners to achieve the text widget behaviour - * needed by Simantics. User notification about modifications is provided via - * {@link TrackedModifyListener}. - * - * Examples: - * - *
- * // #1: create new Text internally, use TrackedModifylistener
- * TrackedText trackedText = new TrackedText(parentComposite, style); 
- * trackedText.addModifyListener(new TrackedModifyListener() {
- *     public void modifyText(TrackedModifyEvent e) {
- *         // text was modified, do something.
- *     }
- * });
- * 
- * // #2: create new Text internally, define the colors for text states.
- * TrackedText trackedText = new TrackedText(text, <instance of ITrackedColorProvider>); 
- * 
- * - * @author Tuukka Lehtonen - */ -public class TrackedText { - - private static final boolean EVENT_DEBUG = false; - - private static final int EDITING = 1 << 0; - private static final int MODIFIED_DURING_EDITING = 1 << 1; - - /** - * Used to tell whether or not a mouseDown has occured after a focusGained - * event to be able to select the whole text field when it is pressed for - * the first time while the widget holds focus. - */ - private static final int MOUSE_DOWN_FIRST_TIME = 1 << 2; - private static final int MOUSE_INSIDE_CONTROL = 1 << 3; - - private int state; - - private int caretPositionBeforeEdit; - - private String textBeforeEdit; - - private JTextField text; - - private CompositeListener listener; - - private ListenerList modifyListeners; - - private IInputValidator validator; - - private ITrackedColorProvider colorProvider; - - private class DefaultColorProvider implements ITrackedColorProvider { - - private Color editingColor = new Color(255, 255, 255); - -// private Color highlightColor = new Color(text.getDisplay(), 254, 255, 197); -// private Color inactiveColor = new Color(text.getDisplay(), 245, 246, 190); -// private Color invalidInputColor = new Color(text.getDisplay(), 255, 128, 128); - - @Override - public Color getEditingBackground() { - return editingColor; - } - - @Override - public Color getHoverBackground() { - return null; -// return highlightColor; - } - - @Override - public Color getInactiveBackground() { - return null; -// return inactiveColor; - } - - @Override - public Color getInvalidBackground() { - return null; -// return invalidInputColor; - } - - void dispose() { -// highlightColor.dispose(); -// inactiveColor.dispose(); -// invalidInputColor.dispose(); - } - }; - -// /** -// * A composite of many UI listeners for creating the functionality of this -// * class. -// */ -// private class CompositeListener -// implements ModifyListener, DisposeListener, KeyListener, MouseTrackListener, -// MouseListener, FocusListener -// { -// // Keyboard/editing events come in the following order: -// // 1. keyPressed -// // 2. verifyText -// // 3. modifyText -// // 4. keyReleased -// -// public void modifyText(ModifyEvent e) { -// //System.out.println("modifyText: " + e); -// setModified(true); -// -//// String valid = isTextValid(); -//// if (valid != null) { -//// setBackground(colorProvider.getInvalidBackground()); -//// } else { -//// if (isEditing()) -//// setBackground(colorProvider.getEditingBackground()); -//// else -//// setBackground(colorProvider.getInactiveBackground()); -//// } -// } -// -// public void widgetDisposed(DisposeEvent e) { -// getWidget().removeModifyListener(this); -// } -// -// private boolean isMultiLine() { -// return false; -//// return (text.getStyle() & SWT.MULTI) != 0; -// } -// -// private boolean hasMultiLineCommitModifier(KeyEvent e) { -// return (e.stateMask & SWT.CTRL) != 0; -// } -// -// public void keyPressed(KeyEvent e) { -// //System.out.println("keyPressed: " + e); -// if (!isEditing()) { -// // ESC, ENTER & keypad ENTER must not start editing -// if (e.keyCode == SWT.ESC) -// return; -// -// if (!isMultiLine()) { -// if (e.keyCode == SWT.F2 || e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) { -// startEdit(true); -// } else if (e.character != '\0') { -// startEdit(false); -// } -// } else { -// // In multi-line mode, TAB must not start editing! -// if (e.keyCode == SWT.F2) { -// startEdit(true); -// } else if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) { -// if (hasMultiLineCommitModifier(e)) { -// e.doit = false; -// } else { -// startEdit(false); -// } -// } else if (e.keyCode == SWT.TAB) { -// text.traverse(((e.stateMask & SWT.SHIFT) != 0) ? SWT.TRAVERSE_TAB_PREVIOUS : SWT.TRAVERSE_TAB_NEXT); -// e.doit = false; -// } else if (e.character != '\0') { -// startEdit(false); -// } -// } -// } else { -// // ESC reverts any changes made during this edit -// if (e.keyCode == SWT.ESC) { -// revertEdit(); -// } -// if (!isMultiLine()) { -// if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) { -// applyEdit(); -// } -// } else { -// if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) { -// if (hasMultiLineCommitModifier(e)) { -// applyEdit(); -// e.doit = false; -// } -// } -// } -// } -// } -// -// public void keyReleased(KeyEvent e) { -// //System.out.println("keyReleased: " + e); -// } -// -// public void mouseEnter(MouseEvent e) { -// //System.out.println("mouseEnter"); -// if (!isEditing()) { -// setBackground(colorProvider.getHoverBackground()); -// } -// setMouseInsideControl(true); -// } -// -// public void mouseExit(MouseEvent e) { -// //System.out.println("mouseExit"); -// if (!isEditing()) { -// setBackground(colorProvider.getInactiveBackground()); -// } -// setMouseInsideControl(false); -// } -// -// public void mouseHover(MouseEvent e) { -// //System.out.println("mouseHover"); -// setMouseInsideControl(true); -// } -// -// public void mouseDoubleClick(MouseEvent e) { -// //System.out.println("mouseDoubleClick: " + e); -// if (e.button == 1) { -// getWidget().selectAll(); -// } -// } -// -// public void mouseDown(MouseEvent e) { -// //System.out.println("mouseDown: " + e); -// if (!isEditing()) { -// // In reality we should never get here, since focusGained -// // always comes before mouseDown, but let's keep this -// // fallback just to be safe. -// if (e.button == 1) { -// startEdit(true); -// } -// } else { -// if (e.button == 1 && (state & MOUSE_DOWN_FIRST_TIME) != 0) { -// getWidget().selectAll(); -// state &= ~MOUSE_DOWN_FIRST_TIME; -// } -// } -// } -// -// public void mouseUp(MouseEvent e) { -// } -// -// public void focusGained(FocusEvent e) { -// //System.out.println("focusGained"); -// if (!isEditing()) { -// if (!isMultiLine()) { -// // Always start edit on single line texts when focus is gained -// startEdit(true); -// } -// } -// } -// -// public void focusLost(FocusEvent e) { -// //System.out.println("focusLost"); -// if (isEditing()) { -// applyEdit(); -// } -// } -// } - - public TrackedText(JTextField text) { - Assert.isNotNull(text); - this.state = 0; - this.text = text; - this.colorProvider = new DefaultColorProvider(); - - initialize(); - } - - public TrackedText(JTextField text, ITrackedColorProvider colorProvider) { - Assert.isNotNull(text, "text must not be null"); - Assert.isNotNull(colorProvider, "colorProvider must not be null"); - this.state = 0; - this.text = text; - this.colorProvider = colorProvider; - - initialize(); - } - - private class CompositeListener implements ActionListener, CaretListener, AncestorListener, ComponentListener, ContainerListener, FocusListener, HierarchyBoundsListener, HierarchyListener, - InputMethodListener, KeyListener, MouseListener, MouseMotionListener, MouseWheelListener, PropertyChangeListener, VetoableChangeListener { - - @Override - public void actionPerformed(ActionEvent arg0) { - if(EVENT_DEBUG) System.out.println("actionPerformed " + arg0); - } - - @Override - public void caretUpdate(CaretEvent arg0) { - if(EVENT_DEBUG) System.out.println("caretUpdate " + arg0); - } - - @Override - public void ancestorAdded(AncestorEvent arg0) { - if(EVENT_DEBUG) System.out.println("ancestorAdded " + arg0); - } - - @Override - public void ancestorMoved(AncestorEvent arg0) { - if(EVENT_DEBUG) System.out.println("ancestorMoved " + arg0); - } - - @Override - public void ancestorRemoved(AncestorEvent arg0) { - if(EVENT_DEBUG) System.out.println("ancestorRemoved " + arg0); - } - - @Override - public void componentHidden(ComponentEvent arg0) { - if(EVENT_DEBUG) System.out.println("componentHidden " + arg0); - } - - @Override - public void componentMoved(ComponentEvent arg0) { - if(EVENT_DEBUG) System.out.println("componentMoved " + arg0); - } - - @Override - public void componentResized(ComponentEvent arg0) { - if(EVENT_DEBUG) System.out.println("componentResized " + arg0); - } - - @Override - public void componentShown(ComponentEvent arg0) { - if(EVENT_DEBUG) System.out.println("componentShown " + arg0); - } - - @Override - public void componentAdded(ContainerEvent arg0) { - if(EVENT_DEBUG) System.out.println("componentAdded " + arg0); - } - - @Override - public void componentRemoved(ContainerEvent arg0) { - if(EVENT_DEBUG) System.out.println("componentRemoved " + arg0); - } - - @Override - public void focusGained(FocusEvent arg0) { - if(EVENT_DEBUG) System.out.println("focusGained " + arg0); - if(!isEditing()) - startEdit(false); - } - - @Override - public void focusLost(FocusEvent arg0) { - if(EVENT_DEBUG) System.out.println("focusLost " + arg0); - } - - @Override - public void ancestorMoved(HierarchyEvent arg0) { - if(EVENT_DEBUG) System.out.println("ancestorMoved " + arg0); - } - - @Override - public void ancestorResized(HierarchyEvent arg0) { - if(EVENT_DEBUG) System.out.println("ancestorResized " + arg0); - } - - @Override - public void hierarchyChanged(HierarchyEvent arg0) { - if(EVENT_DEBUG) System.out.println("hierarchyChanged " + arg0); - } - - @Override - public void caretPositionChanged(InputMethodEvent arg0) { - if(EVENT_DEBUG) System.out.println("caretPositionChanged " + arg0); - } - - @Override - public void inputMethodTextChanged(InputMethodEvent arg0) { - if(EVENT_DEBUG) System.out.println("inputMethodTextChanged " + arg0); - } - - @Override - public void keyPressed(KeyEvent arg0) { - if(EVENT_DEBUG) System.out.println("keyPressed " + arg0); - if(arg0.getKeyCode() == KeyEvent.VK_ESCAPE) { - revertEdit(); - } - if(arg0.getKeyCode() == KeyEvent.VK_ENTER) { - applyEdit(); - } - } - - @Override - public void keyReleased(KeyEvent arg0) { - if(EVENT_DEBUG) System.out.println("keyReleased " + arg0); - setModified(true); - if(!isEditing()) - startEdit(false); - } - - @Override - public void keyTyped(KeyEvent arg0) { - if(EVENT_DEBUG) System.out.println("keyTyped " + arg0); - } - - @Override - public void mouseClicked(MouseEvent arg0) { - if(EVENT_DEBUG) System.out.println("mouseClicked " + arg0); - } - - @Override - public void mouseEntered(MouseEvent arg0) { - if(EVENT_DEBUG) System.out.println("mouseEntered " + arg0); - } - - @Override - public void mouseExited(MouseEvent arg0) { - if(EVENT_DEBUG) System.out.println("mouseExited " + arg0); - } - - @Override - public void mousePressed(MouseEvent arg0) { - if(EVENT_DEBUG) System.out.println("mousePressed " + arg0); - } - - @Override - public void mouseReleased(MouseEvent arg0) { - if(EVENT_DEBUG) System.out.println("mouseReleased " + arg0); - } - - @Override - public void mouseDragged(MouseEvent arg0) { - if(EVENT_DEBUG) System.out.println("mouseDragged " + arg0); - } - - @Override - public void mouseMoved(MouseEvent arg0) { - if(EVENT_DEBUG) System.out.println("mouseMoved " + arg0); - } - - @Override - public void mouseWheelMoved(MouseWheelEvent arg0) { - if(EVENT_DEBUG) System.out.println("mouseWheelMoved " + arg0); - } - - @Override - public void propertyChange(PropertyChangeEvent arg0) { - if(EVENT_DEBUG) System.out.println("propertyChange " + arg0); - } - - @Override - public void vetoableChange(PropertyChangeEvent arg0) throws PropertyVetoException { - if(EVENT_DEBUG) System.out.println("vetoableChange " + arg0); - } - - }; - - /** - * Common initialization. Assumes that text is already created. - */ - private void initialize() { - Assert.isNotNull(text); - -// text.setBackground(colorProvider.getInactiveBackground()); -// text.setDoubleClickEnabled(false); - - listener = new CompositeListener(); - - text.addActionListener(listener); - text.addCaretListener(listener); - text.addAncestorListener(listener); - text.addComponentListener(listener); - text.addContainerListener(listener); - text.addFocusListener(listener); - text.addHierarchyBoundsListener(listener); - text.addHierarchyListener(listener); - text.addInputMethodListener(listener); - text.addKeyListener(listener); - text.addMouseListener(listener); - text.addMouseMotionListener(listener); - text.addMouseWheelListener(listener); - text.addPropertyChangeListener(listener); - text.addVetoableChangeListener(listener); - - } - - private void startEdit(boolean selectAll) { - if (isEditing()) { - // Print some debug incase we end are in an invalid state - System.out.println("TrackedText: BUG: startEdit called when in editing state"); - } - //System.out.println("start edit: selectall=" + selectAll + ", text=" + text.getText() + ", caretpos=" + caretPositionBeforeEdit); - - // Backup text-field data for reverting purposes - caretPositionBeforeEdit = text.getCaretPosition(); - textBeforeEdit = text.getText(); - - // Signal editing state - setBackground(colorProvider.getEditingBackground()); - - if (selectAll) { - text.selectAll(); - } - state |= EDITING | MOUSE_DOWN_FIRST_TIME; - } - - private void applyEdit() { - try { - if (isTextValid() != null) { - text.setText(textBeforeEdit); - } else if (isModified() && !text.getText().equals(textBeforeEdit)) { - //System.out.println("apply"); - if (modifyListeners != null) { - TrackedModifyEvent event = new TrackedModifyEvent(text, text.getText()); - for (Object o : modifyListeners.getListeners()) { - ((TrackedModifyListener) o).modifyText(event); - } - } - } - } finally { - endEdit(); - } - } - - private void endEdit() { - if (!isEditing()) { - // Print some debug incase we end are in an invalid state - //ExceptionUtils.logError(new Exception("BUG: endEdit called when not in editing state")); - } - setBackground(isMouseInsideControl() ? colorProvider.getHoverBackground() : colorProvider.getInactiveBackground()); - //System.out.println("endEdit: " + text.getText() + ", caret: " + text.getCaretLocation() + ", selection: " + text.getSelection()); - // Always move the caret to the end of the string - text.setCaretPosition(text.getText().length()); - state &= ~(EDITING | MOUSE_DOWN_FIRST_TIME); - setModified(false); - } - - private void revertEdit() { - if (!isEditing()) { - // Print some debug incase we end are in an invalid state - //ExceptionUtils.logError(new Exception("BUG: revertEdit called when not in editing state")); - System.out.println("BUG: revertEdit called when not in editing state"); - } - text.setText(textBeforeEdit); - text.setCaretPosition(caretPositionBeforeEdit); - setBackground(isMouseInsideControl() ? colorProvider.getHoverBackground() : colorProvider.getInactiveBackground()); - state &= ~(EDITING | MOUSE_DOWN_FIRST_TIME); - setModified(false); - } - - private boolean isEditing() { - return (state & EDITING) != 0; - } - - private void setModified(boolean modified) { - if (modified) { - state |= MODIFIED_DURING_EDITING; - } else { - state &= ~MODIFIED_DURING_EDITING; - } - } - - private boolean isMouseInsideControl() { - return (state & MOUSE_INSIDE_CONTROL) != 0; - } - - private void setMouseInsideControl(boolean inside) { - if (inside) - state |= MOUSE_INSIDE_CONTROL; - else - state &= ~MOUSE_INSIDE_CONTROL; - } - - private boolean isModified() { - return (state & MODIFIED_DURING_EDITING) != 0; - } - - public void setEditable(boolean editable) { - if (editable) { - text.setEditable(true); - setBackground(isMouseInsideControl() ? colorProvider.getHoverBackground() : colorProvider.getInactiveBackground()); - } else { - text.setEditable(false); - text.setBackground(null); - } - } - - public void setText(String text) { - this.text.setText(text); - } - - public void setTextWithoutNotify(String text) { -// this.text.removeModifyListener(listener); - setText(text); -// this.text.addModifyListener(listener); - } - - public JTextField getWidget() { - return text; - } - - public synchronized void addModifyListener(TrackedModifyListener listener) { - if (modifyListeners == null) { - modifyListeners = new ListenerList(ListenerList.IDENTITY); - } - modifyListeners.add(listener); - } - - public synchronized void removeModifyListener(TrackedModifyListener listener) { - if (modifyListeners == null) - return; - modifyListeners.remove(listener); - } - - public void setInputValidator(IInputValidator validator) { - if (validator != this.validator) { - this.validator = validator; - } - } - - private String isTextValid() { - if (validator != null) { - return validator.isValid(getWidget().getText()); - } - return null; - } - - public void setColorProvider(ITrackedColorProvider provider) { - Assert.isNotNull(provider); - this.colorProvider = provider; - } - - private void setBackground(Color background) { - if (!text.isEditable()) { - // Do not alter background when the widget is not editable. - return; - } - text.setBackground(background); - } - -} +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * 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: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.spreadsheet.ui; + +import java.awt.Color; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.ContainerEvent; +import java.awt.event.ContainerListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.HierarchyBoundsListener; +import java.awt.event.HierarchyEvent; +import java.awt.event.HierarchyListener; +import java.awt.event.InputMethodEvent; +import java.awt.event.InputMethodListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyVetoException; +import java.beans.VetoableChangeListener; + +import javax.swing.JTextField; +import javax.swing.event.AncestorEvent; +import javax.swing.event.AncestorListener; +import javax.swing.event.CaretEvent; +import javax.swing.event.CaretListener; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.ListenerList; +import org.eclipse.jface.dialogs.IInputValidator; + +/** + * This is a TrackedTest SWT Text-widget 'decorator'. + * + * The widget has 2 main states: editing and inactive. + * + * It implements the necessary listeners to achieve the text widget behaviour + * needed by Simantics. User notification about modifications is provided via + * {@link TrackedModifyListener}. + * + * Examples: + * + *
+ * // #1: create new Text internally, use TrackedModifylistener
+ * TrackedText trackedText = new TrackedText(parentComposite, style); 
+ * trackedText.addModifyListener(new TrackedModifyListener() {
+ *     public void modifyText(TrackedModifyEvent e) {
+ *         // text was modified, do something.
+ *     }
+ * });
+ * 
+ * // #2: create new Text internally, define the colors for text states.
+ * TrackedText trackedText = new TrackedText(text, <instance of ITrackedColorProvider>); 
+ * 
+ * + * @author Tuukka Lehtonen + */ +public class TrackedText { + + private static final boolean EVENT_DEBUG = false; + + private static final int EDITING = 1 << 0; + private static final int MODIFIED_DURING_EDITING = 1 << 1; + + /** + * Used to tell whether or not a mouseDown has occured after a focusGained + * event to be able to select the whole text field when it is pressed for + * the first time while the widget holds focus. + */ + private static final int MOUSE_DOWN_FIRST_TIME = 1 << 2; + private static final int MOUSE_INSIDE_CONTROL = 1 << 3; + + private int state; + + private int caretPositionBeforeEdit; + + private String textBeforeEdit; + + private JTextField text; + + private CompositeListener listener; + + private ListenerList modifyListeners; + + private IInputValidator validator; + + private ITrackedColorProvider colorProvider; + + private class DefaultColorProvider implements ITrackedColorProvider { + + private Color editingColor = new Color(255, 255, 255); + +// private Color highlightColor = new Color(text.getDisplay(), 254, 255, 197); +// private Color inactiveColor = new Color(text.getDisplay(), 245, 246, 190); +// private Color invalidInputColor = new Color(text.getDisplay(), 255, 128, 128); + + @Override + public Color getEditingBackground() { + return editingColor; + } + + @Override + public Color getHoverBackground() { + return null; +// return highlightColor; + } + + @Override + public Color getInactiveBackground() { + return null; +// return inactiveColor; + } + + @Override + public Color getInvalidBackground() { + return null; +// return invalidInputColor; + } + + void dispose() { +// highlightColor.dispose(); +// inactiveColor.dispose(); +// invalidInputColor.dispose(); + } + }; + +// /** +// * A composite of many UI listeners for creating the functionality of this +// * class. +// */ +// private class CompositeListener +// implements ModifyListener, DisposeListener, KeyListener, MouseTrackListener, +// MouseListener, FocusListener +// { +// // Keyboard/editing events come in the following order: +// // 1. keyPressed +// // 2. verifyText +// // 3. modifyText +// // 4. keyReleased +// +// public void modifyText(ModifyEvent e) { +// //System.out.println("modifyText: " + e); +// setModified(true); +// +//// String valid = isTextValid(); +//// if (valid != null) { +//// setBackground(colorProvider.getInvalidBackground()); +//// } else { +//// if (isEditing()) +//// setBackground(colorProvider.getEditingBackground()); +//// else +//// setBackground(colorProvider.getInactiveBackground()); +//// } +// } +// +// public void widgetDisposed(DisposeEvent e) { +// getWidget().removeModifyListener(this); +// } +// +// private boolean isMultiLine() { +// return false; +//// return (text.getStyle() & SWT.MULTI) != 0; +// } +// +// private boolean hasMultiLineCommitModifier(KeyEvent e) { +// return (e.stateMask & SWT.CTRL) != 0; +// } +// +// public void keyPressed(KeyEvent e) { +// //System.out.println("keyPressed: " + e); +// if (!isEditing()) { +// // ESC, ENTER & keypad ENTER must not start editing +// if (e.keyCode == SWT.ESC) +// return; +// +// if (!isMultiLine()) { +// if (e.keyCode == SWT.F2 || e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) { +// startEdit(true); +// } else if (e.character != '\0') { +// startEdit(false); +// } +// } else { +// // In multi-line mode, TAB must not start editing! +// if (e.keyCode == SWT.F2) { +// startEdit(true); +// } else if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) { +// if (hasMultiLineCommitModifier(e)) { +// e.doit = false; +// } else { +// startEdit(false); +// } +// } else if (e.keyCode == SWT.TAB) { +// text.traverse(((e.stateMask & SWT.SHIFT) != 0) ? SWT.TRAVERSE_TAB_PREVIOUS : SWT.TRAVERSE_TAB_NEXT); +// e.doit = false; +// } else if (e.character != '\0') { +// startEdit(false); +// } +// } +// } else { +// // ESC reverts any changes made during this edit +// if (e.keyCode == SWT.ESC) { +// revertEdit(); +// } +// if (!isMultiLine()) { +// if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) { +// applyEdit(); +// } +// } else { +// if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) { +// if (hasMultiLineCommitModifier(e)) { +// applyEdit(); +// e.doit = false; +// } +// } +// } +// } +// } +// +// public void keyReleased(KeyEvent e) { +// //System.out.println("keyReleased: " + e); +// } +// +// public void mouseEnter(MouseEvent e) { +// //System.out.println("mouseEnter"); +// if (!isEditing()) { +// setBackground(colorProvider.getHoverBackground()); +// } +// setMouseInsideControl(true); +// } +// +// public void mouseExit(MouseEvent e) { +// //System.out.println("mouseExit"); +// if (!isEditing()) { +// setBackground(colorProvider.getInactiveBackground()); +// } +// setMouseInsideControl(false); +// } +// +// public void mouseHover(MouseEvent e) { +// //System.out.println("mouseHover"); +// setMouseInsideControl(true); +// } +// +// public void mouseDoubleClick(MouseEvent e) { +// //System.out.println("mouseDoubleClick: " + e); +// if (e.button == 1) { +// getWidget().selectAll(); +// } +// } +// +// public void mouseDown(MouseEvent e) { +// //System.out.println("mouseDown: " + e); +// if (!isEditing()) { +// // In reality we should never get here, since focusGained +// // always comes before mouseDown, but let's keep this +// // fallback just to be safe. +// if (e.button == 1) { +// startEdit(true); +// } +// } else { +// if (e.button == 1 && (state & MOUSE_DOWN_FIRST_TIME) != 0) { +// getWidget().selectAll(); +// state &= ~MOUSE_DOWN_FIRST_TIME; +// } +// } +// } +// +// public void mouseUp(MouseEvent e) { +// } +// +// public void focusGained(FocusEvent e) { +// //System.out.println("focusGained"); +// if (!isEditing()) { +// if (!isMultiLine()) { +// // Always start edit on single line texts when focus is gained +// startEdit(true); +// } +// } +// } +// +// public void focusLost(FocusEvent e) { +// //System.out.println("focusLost"); +// if (isEditing()) { +// applyEdit(); +// } +// } +// } + + public TrackedText(JTextField text) { + Assert.isNotNull(text); + this.state = 0; + this.text = text; + this.colorProvider = new DefaultColorProvider(); + + initialize(); + } + + public TrackedText(JTextField text, ITrackedColorProvider colorProvider) { + Assert.isNotNull(text, "text must not be null"); + Assert.isNotNull(colorProvider, "colorProvider must not be null"); + this.state = 0; + this.text = text; + this.colorProvider = colorProvider; + + initialize(); + } + + private class CompositeListener implements ActionListener, CaretListener, AncestorListener, ComponentListener, ContainerListener, FocusListener, HierarchyBoundsListener, HierarchyListener, + InputMethodListener, KeyListener, MouseListener, MouseMotionListener, MouseWheelListener, PropertyChangeListener, VetoableChangeListener { + + @Override + public void actionPerformed(ActionEvent arg0) { + if(EVENT_DEBUG) System.out.println("actionPerformed " + arg0); + } + + @Override + public void caretUpdate(CaretEvent arg0) { + if(EVENT_DEBUG) System.out.println("caretUpdate " + arg0); + } + + @Override + public void ancestorAdded(AncestorEvent arg0) { + if(EVENT_DEBUG) System.out.println("ancestorAdded " + arg0); + } + + @Override + public void ancestorMoved(AncestorEvent arg0) { + if(EVENT_DEBUG) System.out.println("ancestorMoved " + arg0); + } + + @Override + public void ancestorRemoved(AncestorEvent arg0) { + if(EVENT_DEBUG) System.out.println("ancestorRemoved " + arg0); + } + + @Override + public void componentHidden(ComponentEvent arg0) { + if(EVENT_DEBUG) System.out.println("componentHidden " + arg0); + } + + @Override + public void componentMoved(ComponentEvent arg0) { + if(EVENT_DEBUG) System.out.println("componentMoved " + arg0); + } + + @Override + public void componentResized(ComponentEvent arg0) { + if(EVENT_DEBUG) System.out.println("componentResized " + arg0); + } + + @Override + public void componentShown(ComponentEvent arg0) { + if(EVENT_DEBUG) System.out.println("componentShown " + arg0); + } + + @Override + public void componentAdded(ContainerEvent arg0) { + if(EVENT_DEBUG) System.out.println("componentAdded " + arg0); + } + + @Override + public void componentRemoved(ContainerEvent arg0) { + if(EVENT_DEBUG) System.out.println("componentRemoved " + arg0); + } + + @Override + public void focusGained(FocusEvent arg0) { + if(EVENT_DEBUG) System.out.println("focusGained " + arg0); + if(!isEditing()) + startEdit(false); + } + + @Override + public void focusLost(FocusEvent arg0) { + if(EVENT_DEBUG) System.out.println("focusLost " + arg0); + } + + @Override + public void ancestorMoved(HierarchyEvent arg0) { + if(EVENT_DEBUG) System.out.println("ancestorMoved " + arg0); + } + + @Override + public void ancestorResized(HierarchyEvent arg0) { + if(EVENT_DEBUG) System.out.println("ancestorResized " + arg0); + } + + @Override + public void hierarchyChanged(HierarchyEvent arg0) { + if(EVENT_DEBUG) System.out.println("hierarchyChanged " + arg0); + } + + @Override + public void caretPositionChanged(InputMethodEvent arg0) { + if(EVENT_DEBUG) System.out.println("caretPositionChanged " + arg0); + } + + @Override + public void inputMethodTextChanged(InputMethodEvent arg0) { + if(EVENT_DEBUG) System.out.println("inputMethodTextChanged " + arg0); + } + + @Override + public void keyPressed(KeyEvent arg0) { + if(EVENT_DEBUG) System.out.println("keyPressed " + arg0); + if(arg0.getKeyCode() == KeyEvent.VK_ESCAPE) { + revertEdit(); + } + if(arg0.getKeyCode() == KeyEvent.VK_ENTER) { + applyEdit(); + } + } + + @Override + public void keyReleased(KeyEvent arg0) { + if(EVENT_DEBUG) System.out.println("keyReleased " + arg0); + setModified(true); + if(!isEditing()) + startEdit(false); + } + + @Override + public void keyTyped(KeyEvent arg0) { + if(EVENT_DEBUG) System.out.println("keyTyped " + arg0); + } + + @Override + public void mouseClicked(MouseEvent arg0) { + if(EVENT_DEBUG) System.out.println("mouseClicked " + arg0); + } + + @Override + public void mouseEntered(MouseEvent arg0) { + if(EVENT_DEBUG) System.out.println("mouseEntered " + arg0); + } + + @Override + public void mouseExited(MouseEvent arg0) { + if(EVENT_DEBUG) System.out.println("mouseExited " + arg0); + } + + @Override + public void mousePressed(MouseEvent arg0) { + if(EVENT_DEBUG) System.out.println("mousePressed " + arg0); + } + + @Override + public void mouseReleased(MouseEvent arg0) { + if(EVENT_DEBUG) System.out.println("mouseReleased " + arg0); + } + + @Override + public void mouseDragged(MouseEvent arg0) { + if(EVENT_DEBUG) System.out.println("mouseDragged " + arg0); + } + + @Override + public void mouseMoved(MouseEvent arg0) { + if(EVENT_DEBUG) System.out.println("mouseMoved " + arg0); + } + + @Override + public void mouseWheelMoved(MouseWheelEvent arg0) { + if(EVENT_DEBUG) System.out.println("mouseWheelMoved " + arg0); + } + + @Override + public void propertyChange(PropertyChangeEvent arg0) { + if(EVENT_DEBUG) System.out.println("propertyChange " + arg0); + } + + @Override + public void vetoableChange(PropertyChangeEvent arg0) throws PropertyVetoException { + if(EVENT_DEBUG) System.out.println("vetoableChange " + arg0); + } + + }; + + /** + * Common initialization. Assumes that text is already created. + */ + private void initialize() { + Assert.isNotNull(text); + +// text.setBackground(colorProvider.getInactiveBackground()); +// text.setDoubleClickEnabled(false); + + listener = new CompositeListener(); + + text.addActionListener(listener); + text.addCaretListener(listener); + text.addAncestorListener(listener); + text.addComponentListener(listener); + text.addContainerListener(listener); + text.addFocusListener(listener); + text.addHierarchyBoundsListener(listener); + text.addHierarchyListener(listener); + text.addInputMethodListener(listener); + text.addKeyListener(listener); + text.addMouseListener(listener); + text.addMouseMotionListener(listener); + text.addMouseWheelListener(listener); + text.addPropertyChangeListener(listener); + text.addVetoableChangeListener(listener); + + } + + private void startEdit(boolean selectAll) { + if (isEditing()) { + // Print some debug incase we end are in an invalid state + System.out.println("TrackedText: BUG: startEdit called when in editing state"); + } + //System.out.println("start edit: selectall=" + selectAll + ", text=" + text.getText() + ", caretpos=" + caretPositionBeforeEdit); + + // Backup text-field data for reverting purposes + caretPositionBeforeEdit = text.getCaretPosition(); + textBeforeEdit = text.getText(); + + // Signal editing state + setBackground(colorProvider.getEditingBackground()); + + if (selectAll) { + text.selectAll(); + } + state |= EDITING | MOUSE_DOWN_FIRST_TIME; + } + + private void applyEdit() { + try { + if (isTextValid() != null) { + text.setText(textBeforeEdit); + } else if (isModified() && !text.getText().equals(textBeforeEdit)) { + //System.out.println("apply"); + if (modifyListeners != null) { + TrackedModifyEvent event = new TrackedModifyEvent(text, text.getText()); + for (Object o : modifyListeners.getListeners()) { + ((TrackedModifyListener) o).modifyText(event); + } + } + } + } finally { + endEdit(); + } + } + + private void endEdit() { + if (!isEditing()) { + // Print some debug incase we end are in an invalid state + //ExceptionUtils.logError(new Exception("BUG: endEdit called when not in editing state")); + } + setBackground(isMouseInsideControl() ? colorProvider.getHoverBackground() : colorProvider.getInactiveBackground()); + //System.out.println("endEdit: " + text.getText() + ", caret: " + text.getCaretLocation() + ", selection: " + text.getSelection()); + // Always move the caret to the end of the string + text.setCaretPosition(text.getText().length()); + state &= ~(EDITING | MOUSE_DOWN_FIRST_TIME); + setModified(false); + } + + private void revertEdit() { + if (!isEditing()) { + // Print some debug incase we end are in an invalid state + //ExceptionUtils.logError(new Exception("BUG: revertEdit called when not in editing state")); + System.out.println("BUG: revertEdit called when not in editing state"); + } + text.setText(textBeforeEdit); + text.setCaretPosition(caretPositionBeforeEdit); + setBackground(isMouseInsideControl() ? colorProvider.getHoverBackground() : colorProvider.getInactiveBackground()); + state &= ~(EDITING | MOUSE_DOWN_FIRST_TIME); + setModified(false); + } + + private boolean isEditing() { + return (state & EDITING) != 0; + } + + private void setModified(boolean modified) { + if (modified) { + state |= MODIFIED_DURING_EDITING; + } else { + state &= ~MODIFIED_DURING_EDITING; + } + } + + private boolean isMouseInsideControl() { + return (state & MOUSE_INSIDE_CONTROL) != 0; + } + + private void setMouseInsideControl(boolean inside) { + if (inside) + state |= MOUSE_INSIDE_CONTROL; + else + state &= ~MOUSE_INSIDE_CONTROL; + } + + private boolean isModified() { + return (state & MODIFIED_DURING_EDITING) != 0; + } + + public void setEditable(boolean editable) { + if (editable) { + text.setEditable(true); + setBackground(isMouseInsideControl() ? colorProvider.getHoverBackground() : colorProvider.getInactiveBackground()); + } else { + text.setEditable(false); + text.setBackground(null); + } + } + + public void setText(String text) { + this.text.setText(text); + } + + public void setTextWithoutNotify(String text) { +// this.text.removeModifyListener(listener); + setText(text); +// this.text.addModifyListener(listener); + } + + public JTextField getWidget() { + return text; + } + + public synchronized void addModifyListener(TrackedModifyListener listener) { + if (modifyListeners == null) { + modifyListeners = new ListenerList(ListenerList.IDENTITY); + } + modifyListeners.add(listener); + } + + public synchronized void removeModifyListener(TrackedModifyListener listener) { + if (modifyListeners == null) + return; + modifyListeners.remove(listener); + } + + public void setInputValidator(IInputValidator validator) { + if (validator != this.validator) { + this.validator = validator; + } + } + + private String isTextValid() { + if (validator != null) { + return validator.isValid(getWidget().getText()); + } + return null; + } + + public void setColorProvider(ITrackedColorProvider provider) { + Assert.isNotNull(provider); + this.colorProvider = provider; + } + + private void setBackground(Color background) { + if (!text.isEditable()) { + // Do not alter background when the widget is not editable. + return; + } + text.setBackground(background); + } + +}