-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.utils.ui.widgets;\r
-\r
-import org.eclipse.core.runtime.Assert;\r
-import org.eclipse.core.runtime.ListenerList;\r
-import org.eclipse.jface.dialogs.IInputValidator;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.custom.CCombo;\r
-import org.eclipse.swt.events.DisposeEvent;\r
-import org.eclipse.swt.events.DisposeListener;\r
-import org.eclipse.swt.events.FocusEvent;\r
-import org.eclipse.swt.events.FocusListener;\r
-import org.eclipse.swt.events.KeyEvent;\r
-import org.eclipse.swt.events.KeyListener;\r
-import org.eclipse.swt.events.ModifyEvent;\r
-import org.eclipse.swt.events.ModifyListener;\r
-import org.eclipse.swt.events.MouseEvent;\r
-import org.eclipse.swt.events.MouseListener;\r
-import org.eclipse.swt.events.MouseTrackListener;\r
-import org.eclipse.swt.graphics.Color;\r
-import org.eclipse.swt.widgets.Composite;\r
-\r
-/**\r
- * This is a TrackedTest SWT Text-widget 'decorator'.\r
- * \r
- * It implements the necessary listeners to achieve the text widget behaviour\r
- * needed by Simantics. User notification about modifications is provided via an\r
- * Action instance given by the user.\r
- * \r
- * @see org.simantics.utils.ui.widgets.TrackedTextTest\r
- * \r
- * @author Tuukka Lehtonen\r
- */\r
-public class TrackedCCombo {\r
- private static final int EDITING = 1 << 0;\r
- private static final int MODIFIED_DURING_EDITING = 1 << 1;\r
-\r
- /**\r
- * Used to tell whether or not a mouseDown has occured after a focusGained\r
- * event to be able to select the whole text field when it is pressed for\r
- * the first time while the widget holds focus.\r
- */\r
- private static final int MOUSE_DOWN_FIRST_TIME = 1 << 2;\r
- \r
- private int state;\r
-\r
- private String textBeforeEdit;\r
-\r
- private CCombo combo;\r
-\r
- private CompositeListener listener;\r
-\r
- private ListenerList modifyListeners;\r
-\r
- private IInputValidator validator;\r
-\r
- //private static Color highlightColor = new Color(null, 250, 250, 250);\r
- //private static Color inactiveColor = new Color(null, 240, 240, 240);\r
- private static Color highlightColor = new Color(null, 254, 255, 197);\r
- private static Color inactiveColor = new Color(null, 245, 246, 190);\r
- private static Color invalidInputColor = new Color(null, 255, 128, 128);\r
-\r
- /**\r
- * A composite of many UI listeners for creating the functionality of this\r
- * class.\r
- */\r
- private class CompositeListener\r
- implements ModifyListener, DisposeListener, KeyListener, MouseTrackListener,\r
- MouseListener, FocusListener\r
- {\r
- // Keyboard/editing events come in the following order:\r
- // 1. keyPressed\r
- // 2. verifyText\r
- // 3. modifyText\r
- // 4. keyReleased\r
- \r
- public void modifyText(ModifyEvent e) {\r
- //System.out.println("modifyText: " + e);\r
- if (isEditing())\r
- setModified(true);\r
-\r
- String valid = isTextValid();\r
- if (valid != null) {\r
- getWidget().setBackground(invalidInputColor);\r
- } else {\r
- if (isEditing())\r
- getWidget().setBackground(null);\r
- else\r
- getWidget().setBackground(inactiveColor);\r
- }\r
- }\r
-\r
- public void widgetDisposed(DisposeEvent e) {\r
- combo.removeModifyListener(this);\r
- }\r
-\r
- public void keyPressed(KeyEvent e) {\r
- //System.out.println("keyPressed: " + e);\r
- if (!isEditing()) {\r
- // ESC, ENTER & keypad ENTER must not start editing \r
- if (e.keyCode == SWT.ESC)\r
- return;\r
-\r
- if (e.keyCode == SWT.F2 || e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {\r
- startEdit(true);\r
- } else if (e.character != '\0') {\r
- startEdit(false);\r
- }\r
- } else {\r
- // ESC reverts any changes made during this edit\r
- if (e.keyCode == SWT.ESC) {\r
- revertEdit();\r
- }\r
- if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {\r
- applyEdit();\r
- } \r
- }\r
- }\r
-\r
- public void keyReleased(KeyEvent e) {\r
- //System.out.println("keyReleased: " + e);\r
- }\r
-\r
- public void mouseEnter(MouseEvent e) {\r
- //System.out.println("mouseEnter");\r
- if (!isEditing()) {\r
- getWidget().setBackground(highlightColor);\r
- }\r
- }\r
-\r
- public void mouseExit(MouseEvent e) {\r
- //System.out.println("mouseExit");\r
- if (!isEditing()) {\r
- getWidget().setBackground(inactiveColor);\r
- }\r
- }\r
-\r
- public void mouseHover(MouseEvent e) {\r
- //System.out.println("mouseHover");\r
- }\r
-\r
- public void mouseDoubleClick(MouseEvent e) {\r
- //System.out.println("mouseDoubleClick: " + e);\r
-// if (e.button == 1) {\r
-// getWidget().selectAll();\r
-// }\r
- }\r
-\r
- public void mouseDown(MouseEvent e) {\r
- //System.out.println("mouseDown: " + e);\r
- if (!isEditing()) {\r
- // In reality we should never get here, since focusGained\r
- // always comes before mouseDown, but let's keep this\r
- // fallback just to be safe.\r
- if (e.button == 1) {\r
- startEdit(true);\r
- }\r
- } else {\r
- if (e.button == 1 && (state & MOUSE_DOWN_FIRST_TIME) != 0) {\r
-// getWidget().selectAll();\r
- state &= ~MOUSE_DOWN_FIRST_TIME;\r
- }\r
- }\r
- }\r
-\r
- public void mouseUp(MouseEvent e) {\r
- }\r
-\r
- public void focusGained(FocusEvent e) {\r
- //System.out.println("focusGained");\r
- if (!isEditing()) {\r
- startEdit(true);\r
- }\r
- }\r
-\r
- public void focusLost(FocusEvent e) {\r
- //System.out.println("focusLost");\r
- if (isEditing()) {\r
- applyEdit();\r
- }\r
- }\r
- }\r
- \r
- public TrackedCCombo(CCombo combo) {\r
- Assert.isNotNull(combo);\r
- this.state = 0;\r
- this.combo = combo;\r
-\r
- initialize();\r
- }\r
-\r
- public TrackedCCombo(Composite parent, int style) {\r
- this.state = 0;\r
- this.combo = new CCombo(parent, style);\r
-\r
- initialize();\r
- }\r
-\r
- /**\r
- * Common initialization. Assumes that text is already created.\r
- */\r
- private void initialize() {\r
- Assert.isNotNull(combo);\r
- \r
- combo.setBackground(inactiveColor);\r
- \r
- listener = new CompositeListener();\r
- \r
- combo.addModifyListener(listener);\r
- combo.addDisposeListener(listener);\r
- combo.addKeyListener(listener);\r
- combo.addMouseTrackListener(listener);\r
- combo.addMouseListener(listener);\r
- combo.addFocusListener(listener);\r
- } \r
- \r
- private void startEdit(boolean selectAll) {\r
- if (isEditing()) {\r
- // Print some debug incase we end are in an invalid state\r
- try {\r
- throw new Exception("TrackedText: BUG: startEdit called when in editing state");\r
- } catch (Exception e) {\r
- System.out.println(e);\r
- }\r
- }\r
- //System.out.println("start edit: selectall=" + selectAll + ", text=" + text.getText() + ", caretpos=" + caretPositionBeforeEdit);\r
-\r
- // Backup text-field data for reverting purposes\r
- textBeforeEdit = combo.getText();\r
-\r
- // Signal editing state\r
- combo.setBackground(null);\r
- \r
-// if (selectAll) {\r
-// text.selectAll();\r
-// }\r
- state |= EDITING | MOUSE_DOWN_FIRST_TIME;\r
- }\r
-\r
- private void applyEdit() {\r
- try {\r
- if (isTextValid() != null) {\r
- // Just discard the edit.\r
- combo.setText(textBeforeEdit);\r
- } else if (isModified() && !combo.getText().equals(textBeforeEdit)) {\r
- //System.out.println("apply");\r
- if (modifyListeners != null) {\r
- TrackedModifyEvent event = new TrackedModifyEvent(combo, combo.getText());\r
- for (Object o : modifyListeners.getListeners()) {\r
- ((TrackedModifyListener) o).modifyText(event);\r
- }\r
- }\r
- }\r
- } finally {\r
- endEdit();\r
- }\r
- }\r
- \r
- private void endEdit() {\r
- if (!isEditing()) {\r
- // Print some debug incase we end are in an invalid state\r
- //ExceptionUtils.logError(new Exception("BUG: endEdit called when not in editing state"));\r
- System.out.println("BUG: endEdit called when not in editing state");\r
- }\r
- combo.setBackground(inactiveColor);\r
- //System.out.println("endEdit: " + text.getText() + ", caret: " + text.getCaretLocation() + ", selection: " + text.getSelection());\r
- // Always move the caret to the end of the string\r
-// text.setSelection(text.getCharCount());\r
- \r
- state &= ~(EDITING | MOUSE_DOWN_FIRST_TIME);\r
- setModified(false);\r
- }\r
-\r
- private void revertEdit() {\r
- if (!isEditing()) {\r
- // Print some debug incase we end are in an invalid state\r
- //ExceptionUtils.logError(new Exception("BUG: revertEdit called when not in editing state"));\r
- System.out.println("BUG: revertEdit called when not in editing state");\r
- }\r
- combo.setText(textBeforeEdit);\r
-// text.setSelection(caretPositionBeforeEdit);\r
- combo.setBackground(inactiveColor);\r
- state &= ~(EDITING | MOUSE_DOWN_FIRST_TIME);\r
- setModified(false);\r
- }\r
- \r
- private boolean isEditing() {\r
- return (state & EDITING) != 0;\r
- }\r
- \r
- private void setModified(boolean modified) {\r
- if (modified) {\r
- state |= MODIFIED_DURING_EDITING;\r
- } else {\r
- state &= ~MODIFIED_DURING_EDITING;\r
- }\r
- }\r
- \r
- private boolean isModified() {\r
- return (state & MODIFIED_DURING_EDITING) != 0;\r
- }\r
- \r
- public void setText(String text) {\r
- this.combo.setText(text);\r
- }\r
- \r
- public void setTextWithoutNotify(String text) {\r
- this.combo.removeModifyListener(listener);\r
- setText(text);\r
- this.combo.addModifyListener(listener);\r
- }\r
-\r
- public CCombo getWidget() {\r
- return combo;\r
- }\r
- \r
- public synchronized void addModifyListener(TrackedModifyListener listener) {\r
- if (modifyListeners == null) {\r
- modifyListeners = new ListenerList(ListenerList.IDENTITY);\r
- }\r
- modifyListeners.add(listener);\r
- }\r
- \r
- public synchronized void removeModifyListener(TrackedModifyListener listener) {\r
- if (modifyListeners == null)\r
- return;\r
- modifyListeners.remove(listener);\r
- }\r
- \r
- public void setInputValidator(IInputValidator validator) {\r
- if (validator != this.validator) {\r
- this.validator = validator;\r
- }\r
- }\r
- \r
- private String isTextValid() {\r
- if (validator != null) {\r
- return validator.isValid(getWidget().getText());\r
- }\r
- return null;\r
- }\r
-}\r
+/*******************************************************************************
+ * 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.utils.ui.widgets;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CCombo;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.MouseTrackListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * This is a TrackedTest SWT Text-widget 'decorator'.
+ *
+ * It implements the necessary listeners to achieve the text widget behaviour
+ * needed by Simantics. User notification about modifications is provided via an
+ * Action instance given by the user.
+ *
+ * @see org.simantics.utils.ui.widgets.TrackedTextTest
+ *
+ * @author Tuukka Lehtonen
+ */
+public class TrackedCCombo {
+ 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 int state;
+
+ private String textBeforeEdit;
+
+ private CCombo combo;
+
+ private CompositeListener listener;
+
+ private ListenerList modifyListeners;
+
+ private IInputValidator validator;
+
+ //private static Color highlightColor = new Color(null, 250, 250, 250);
+ //private static Color inactiveColor = new Color(null, 240, 240, 240);
+ private static Color highlightColor = new Color(null, 254, 255, 197);
+ private static Color inactiveColor = new Color(null, 245, 246, 190);
+ private static Color invalidInputColor = new Color(null, 255, 128, 128);
+
+ /**
+ * 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);
+ if (isEditing())
+ setModified(true);
+
+ String valid = isTextValid();
+ if (valid != null) {
+ getWidget().setBackground(invalidInputColor);
+ } else {
+ if (isEditing())
+ getWidget().setBackground(null);
+ else
+ getWidget().setBackground(inactiveColor);
+ }
+ }
+
+ public void widgetDisposed(DisposeEvent e) {
+ combo.removeModifyListener(this);
+ }
+
+ 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 (e.keyCode == SWT.F2 || e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {
+ startEdit(true);
+ } else if (e.character != '\0') {
+ startEdit(false);
+ }
+ } else {
+ // ESC reverts any changes made during this edit
+ if (e.keyCode == SWT.ESC) {
+ revertEdit();
+ }
+ if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {
+ applyEdit();
+ }
+ }
+ }
+
+ public void keyReleased(KeyEvent e) {
+ //System.out.println("keyReleased: " + e);
+ }
+
+ public void mouseEnter(MouseEvent e) {
+ //System.out.println("mouseEnter");
+ if (!isEditing()) {
+ getWidget().setBackground(highlightColor);
+ }
+ }
+
+ public void mouseExit(MouseEvent e) {
+ //System.out.println("mouseExit");
+ if (!isEditing()) {
+ getWidget().setBackground(inactiveColor);
+ }
+ }
+
+ public void mouseHover(MouseEvent e) {
+ //System.out.println("mouseHover");
+ }
+
+ 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()) {
+ startEdit(true);
+ }
+ }
+
+ public void focusLost(FocusEvent e) {
+ //System.out.println("focusLost");
+ if (isEditing()) {
+ applyEdit();
+ }
+ }
+ }
+
+ public TrackedCCombo(CCombo combo) {
+ Assert.isNotNull(combo);
+ this.state = 0;
+ this.combo = combo;
+
+ initialize();
+ }
+
+ public TrackedCCombo(Composite parent, int style) {
+ this.state = 0;
+ this.combo = new CCombo(parent, style);
+
+ initialize();
+ }
+
+ /**
+ * Common initialization. Assumes that text is already created.
+ */
+ private void initialize() {
+ Assert.isNotNull(combo);
+
+ combo.setBackground(inactiveColor);
+
+ listener = new CompositeListener();
+
+ combo.addModifyListener(listener);
+ combo.addDisposeListener(listener);
+ combo.addKeyListener(listener);
+ combo.addMouseTrackListener(listener);
+ combo.addMouseListener(listener);
+ combo.addFocusListener(listener);
+ }
+
+ private void startEdit(boolean selectAll) {
+ if (isEditing()) {
+ // Print some debug incase we end are in an invalid state
+ try {
+ throw new Exception("TrackedText: BUG: startEdit called when in editing state");
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+ }
+ //System.out.println("start edit: selectall=" + selectAll + ", text=" + text.getText() + ", caretpos=" + caretPositionBeforeEdit);
+
+ // Backup text-field data for reverting purposes
+ textBeforeEdit = combo.getText();
+
+ // Signal editing state
+ combo.setBackground(null);
+
+// if (selectAll) {
+// text.selectAll();
+// }
+ state |= EDITING | MOUSE_DOWN_FIRST_TIME;
+ }
+
+ private void applyEdit() {
+ try {
+ if (isTextValid() != null) {
+ // Just discard the edit.
+ combo.setText(textBeforeEdit);
+ } else if (isModified() && !combo.getText().equals(textBeforeEdit)) {
+ //System.out.println("apply");
+ if (modifyListeners != null) {
+ TrackedModifyEvent event = new TrackedModifyEvent(combo, combo.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"));
+ System.out.println("BUG: endEdit called when not in editing state");
+ }
+ combo.setBackground(inactiveColor);
+ //System.out.println("endEdit: " + text.getText() + ", caret: " + text.getCaretLocation() + ", selection: " + text.getSelection());
+ // Always move the caret to the end of the string
+// text.setSelection(text.getCharCount());
+
+ 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");
+ }
+ combo.setText(textBeforeEdit);
+// text.setSelection(caretPositionBeforeEdit);
+ combo.setBackground(inactiveColor);
+ 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 isModified() {
+ return (state & MODIFIED_DURING_EDITING) != 0;
+ }
+
+ public void setText(String text) {
+ this.combo.setText(text);
+ }
+
+ public void setTextWithoutNotify(String text) {
+ this.combo.removeModifyListener(listener);
+ setText(text);
+ this.combo.addModifyListener(listener);
+ }
+
+ public CCombo getWidget() {
+ return combo;
+ }
+
+ 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;
+ }
+}