X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.utils.ui%2Fsrc%2Forg%2Fsimantics%2Futils%2Fui%2Fwidgets%2FTrackedCCombo.java;h=96a3a0ca7c2663f2f5373f5aa602648ec7a7b8b4;hb=f015145947a0aaf44bd11f8dab45aef96feed149;hp=8a5d38c9f0dd453a707fa25a8673f6e7f6771d4e;hpb=969bd23cab98a79ca9101af33334000879fb60c5;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/widgets/TrackedCCombo.java b/bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/widgets/TrackedCCombo.java index 8a5d38c9f..96a3a0ca7 100644 --- a/bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/widgets/TrackedCCombo.java +++ b/bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/widgets/TrackedCCombo.java @@ -1,352 +1,352 @@ -/******************************************************************************* - * 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; - } -} +/******************************************************************************* + * 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; + } +}