1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2012 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.browsing.ui.swt.contentassist;
\r
14 import java.util.ArrayList;
\r
15 import java.util.List;
\r
17 import org.eclipse.swt.SWT;
\r
18 import org.eclipse.swt.widgets.Composite;
\r
19 import org.eclipse.swt.widgets.Event;
\r
20 import org.eclipse.swt.widgets.Listener;
\r
21 import org.eclipse.swt.widgets.TreeItem;
\r
22 import org.simantics.browsing.ui.NodeContext;
\r
23 import org.simantics.browsing.ui.common.modifiers.EnumeratedValue;
\r
24 import org.simantics.browsing.ui.common.modifiers.Enumeration;
\r
25 import org.simantics.browsing.ui.content.Labeler.CustomModifier;
\r
28 * @author Tuukka Lehtonen
\r
30 public class AbstractContentAssistEnumerationModifier<T> implements CustomModifier {
\r
32 protected final Enumeration<T> enumeration;
\r
33 protected final EnumeratedValue<T> value;
\r
35 protected ContentAssistTextField text;
\r
37 public AbstractContentAssistEnumerationModifier(Enumeration<T> enumeration, T value) {
\r
38 this(enumeration, enumeration.find(value));
\r
41 public AbstractContentAssistEnumerationModifier(Enumeration<T> enumeration, EnumeratedValue<T> value) {
\r
42 if (enumeration == null)
\r
43 throw new NullPointerException("null enumeration");
\r
44 if (enumeration.size() == 0)
\r
45 throw new IllegalArgumentException("");
\r
47 this.enumeration = enumeration;
\r
52 public String getValue() {
\r
54 return value.getName();
\r
55 return enumeration.values().get(0).getName();
\r
59 public String isValid(String label) {
\r
60 if (enumeration.findByName(label) == null)
\r
61 return "Value '" + label + "' is not among the enumerated values " + enumeration.values();
\r
66 public void modify(String label) {
\r
67 EnumeratedValue<T> value = enumeration.findByName(label);
\r
69 throw new IllegalArgumentException("Cannot modify enumeration with value '" + label + "', not among the enumerated values " + enumeration.values());
\r
70 modifyWithValue(this.value, value);
\r
73 protected void modifyWithValue(EnumeratedValue<T> oldEnumValue, EnumeratedValue<T> enumValue) {
\r
74 T oldObject = oldEnumValue != null ? oldEnumValue.getObject() : null;
\r
75 T newObject = enumValue != null ? enumValue.getObject() : null;
\r
76 modifyWithObject(oldObject, newObject, EnumeratedValue.isInvalid(oldEnumValue));
\r
80 * At least implement this if you don't override
\r
81 * {@link #modifyWithValue(EnumeratedValue, EnumeratedValue)}.
\r
83 * @param oldEnumObject
\r
86 protected void modifyWithObject(T oldEnumObject, T enumObject, boolean force) {
\r
90 * Override to customize the content assist proposal objects created from
\r
91 * the enumerated values.
\r
96 protected NamedObject<T> createNamedObject(EnumeratedValue<T> value) {
\r
97 return new NamedObject<T>(value.getObject(), value.getName());
\r
100 protected List<NamedObject<T>> toNamedObjects(Enumeration<T> enumeration) {
\r
101 List<NamedObject<T>> namedObjects = new ArrayList<NamedObject<T>>();
\r
102 for (EnumeratedValue<T> v : enumeration.values())
\r
103 namedObjects.add(createNamedObject(v));
\r
104 return namedObjects;
\r
108 public Object createControl(Object parentControl, Object controlItem, final int columnIndex, NodeContext context) {
\r
109 Composite parent = (Composite) parentControl;
\r
110 final TreeItem item = (TreeItem) controlItem;
\r
112 List<NamedObject<T>> possibleValues = toNamedObjects(enumeration);
\r
113 NamedObject<T> selectedValue = value != null ? createNamedObject(value) : null;
\r
115 text = new ContentAssistTextField(parent, selectedValue, possibleValues, SWT.NONE);
\r
117 Listener textListener = new Listener() {
\r
121 public void handleEvent(final Event e) {
\r
124 String newText = text.getControl().getText();
\r
125 // System.out.println("VALIDATE NEW TEXT: " + newText);
\r
126 error = isValid(newText);
\r
127 if (error != null) {
\r
128 text.getControl().setBackground(text.getDisplay().getSystemColor(SWT.COLOR_RED));
\r
129 // System.out.println("validation error: " + error);
\r
131 text.getControl().setBackground(null);
\r
133 // text.getDisplay().asyncExec(new Runnable() {
\r
135 // public void run() {
\r
136 //if (!text.getControl().isDisposed())
\r
137 //text.getControl().traverse(SWT.TRAVERSE_ARROW_NEXT);
\r
138 //text.getControl().setSelection(text.getControl().getCaretPosition());
\r
144 // Safety check since it seems that this may happen with
\r
146 // if (item.isDisposed())
\r
149 // newText = text.getControl().getText();
\r
150 // String leftText = newText.substring(0, e.start);
\r
151 // String rightText = newText.substring(e.end, newText.length());
\r
152 // GC gc = new GC(text.getControl());
\r
153 // Point size = gc.textExtent(leftText + e.text + rightText);
\r
155 // size = text.getControl().computeSize(size.x, SWT.DEFAULT);
\r
156 // Rectangle itemRect = item.getBounds(columnIndex),
\r
157 // rect = tree.getClientArea();
\r
158 // editor.minimumWidth = Math.max(size.x, itemRect.width) + insetX * 2;
\r
159 // int left = itemRect.x,
\r
160 // right = rect.x + rect.width;
\r
161 // editor.minimumWidth = Math.min(editor.minimumWidth, right - left);
\r
162 // editor.minimumHeight = size.y + insetY * 2;
\r
163 // editor.layout();
\r
165 // case SWT.FocusOut: {
\r
166 // System.out.println("focus out");
\r
167 // String t = text.getControl().getText();
\r
170 // // Item may be disposed if the tree gets reset after a previous editing.
\r
171 // if (!item.isDisposed()) {
\r
172 // item.setText(columnIndex, t);
\r
173 // //queueSelectionRefresh(context);
\r
178 case SWT.Traverse: {
\r
179 //System.out.println(AbstractContentAssistEnumerationModifier.class.getSimpleName() + " TRAVERSE: " + e.detail);
\r
180 switch (e.detail) {
\r
181 case SWT.TRAVERSE_RETURN:
\r
182 //System.out.println("TRAVERSE: RETURN");
\r
183 INamedObject obj = text.getResult();
\r
184 String txt = obj != null ? obj.getName() : text.getControl().getText();
\r
185 if (txt == null || error != null) {
\r
190 if (!item.isDisposed()) {
\r
191 item.setText(columnIndex, txt);
\r
192 //queueSelectionRefresh(context);
\r
195 case SWT.TRAVERSE_ESCAPE:
\r
196 //System.out.println("TRAVERSE: ESCAPE");
\r
201 //System.out.println("unhandled traversal: " + e.detail);
\r
209 text.getControl().addListener(SWT.Modify, textListener);
\r
210 // text.getControl().addListener(SWT.Verify, textListener);
\r
211 // text.getControl().addListener(SWT.FocusOut, textListener);
\r
212 text.getControl().addListener(SWT.Traverse, textListener);
\r
215 text.text.selectAll();
\r
216 text.getDisplay().asyncExec(new Runnable() {
\r
218 public void run() {
\r
219 if (!text.isDisposed())
\r