/******************************************************************************* * Copyright (c) 2007, 2012 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.browsing.ui.swt.contentassist; import java.util.ArrayList; import java.util.List; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.TreeItem; import org.simantics.browsing.ui.NodeContext; import org.simantics.browsing.ui.common.modifiers.EnumeratedValue; import org.simantics.browsing.ui.common.modifiers.Enumeration; import org.simantics.browsing.ui.content.Labeler.CustomModifier; /** * @author Tuukka Lehtonen */ abstract public class AbstractContentAssistModifier implements CustomModifier { protected final Enumeration enumeration; protected final T value; protected ContentAssistTextField text; public AbstractContentAssistModifier(Enumeration enumeration, T value) { if (enumeration == null) throw new NullPointerException("null enumeration"); if (enumeration.size() == 0) throw new IllegalArgumentException(""); this.enumeration = enumeration; this.value = value; } @Override public String getValue() { if (value != null) return value.toString(); return enumeration.values().get(0).getName(); } @Override public String isValid(String label) { if (enumeration.findByName(label) == null) return "Value '" + label + "' is not among the enumerated values " + enumeration.values(); return null; } @Override public void modify(String label) { String error = isValid(label); if(error != null) throw new IllegalArgumentException(error); modifyWithValue(this.value, label); } abstract void modifyWithValue(T oldEnumValue, String enumValue); /** * Override to customize the content assist proposal objects created from * the enumerated values. * * @param value * @return */ protected NamedObject createNamedObject(EnumeratedValue value) { return new NamedObject(value.getObject(), value.getName()); } protected List> toNamedObjects(Enumeration enumeration) { List> namedObjects = new ArrayList>(); for (EnumeratedValue v : enumeration.values()) namedObjects.add(createNamedObject(v)); return namedObjects; } @Override public Object createControl(Object parentControl, Object controlItem, final int columnIndex, NodeContext context) { Composite parent = (Composite) parentControl; final TreeItem item = (TreeItem) controlItem; List> possibleValues = toNamedObjects(enumeration); EnumeratedValue enuValue = enumeration.find(value); NamedObject selectedValue = enuValue != null ? createNamedObject(enuValue) : null; text = new ContentAssistTextField(parent, selectedValue, possibleValues, SWT.NONE); Listener textListener = new Listener() { String error; @Override public void handleEvent(final Event e) { switch (e.type) { case SWT.Modify: { String newText = text.getControl().getText(); // System.out.println("VALIDATE NEW TEXT: " + newText); error = isValid(newText); if (error != null) { text.getControl().setBackground(text.getDisplay().getSystemColor(SWT.COLOR_RED)); // System.out.println("validation error: " + error); } else { text.getControl().setBackground(null); } // text.getDisplay().asyncExec(new Runnable() { // @Override // public void run() { //if (!text.getControl().isDisposed()) //text.getControl().traverse(SWT.TRAVERSE_ARROW_NEXT); //text.getControl().setSelection(text.getControl().getCaretPosition()); // } // }); break; } case SWT.Verify: // Safety check since it seems that this may happen with // virtual trees. // if (item.isDisposed()) // return; // newText = text.getControl().getText(); // String leftText = newText.substring(0, e.start); // String rightText = newText.substring(e.end, newText.length()); // GC gc = new GC(text.getControl()); // Point size = gc.textExtent(leftText + e.text + rightText); // gc.dispose(); // size = text.getControl().computeSize(size.x, SWT.DEFAULT); // Rectangle itemRect = item.getBounds(columnIndex), // rect = tree.getClientArea(); // editor.minimumWidth = Math.max(size.x, itemRect.width) + insetX * 2; // int left = itemRect.x, // right = rect.x + rect.width; // editor.minimumWidth = Math.min(editor.minimumWidth, right - left); // editor.minimumHeight = size.y + insetY * 2; // editor.layout(); break; // case SWT.FocusOut: { // System.out.println("focus out"); // String t = text.getControl().getText(); // modify(t); // // // Item may be disposed if the tree gets reset after a previous editing. // if (!item.isDisposed()) { // item.setText(columnIndex, t); // //queueSelectionRefresh(context); // } // text.dispose(); // break; // } case SWT.Traverse: { //System.out.println(AbstractContentAssistEnumerationModifier.class.getSimpleName() + " TRAVERSE: " + e.detail); switch (e.detail) { case SWT.TRAVERSE_RETURN: //System.out.println("TRAVERSE: RETURN"); INamedObject obj = text.getResult(); String txt = obj != null ? obj.getName() : text.getControl().getText(); if (txt == null || error != null) { e.doit = false; return; } modify(txt); if (!item.isDisposed()) { item.setText(columnIndex, txt); //queueSelectionRefresh(context); } // FALL THROUGH case SWT.TRAVERSE_ESCAPE: //System.out.println("TRAVERSE: ESCAPE"); text.dispose(); e.doit = false; break; default: //System.out.println("unhandled traversal: " + e.detail); break; } break; } } } }; text.getControl().addListener(SWT.Modify, textListener); // text.getControl().addListener(SWT.Verify, textListener); // text.getControl().addListener(SWT.FocusOut, textListener); text.getControl().addListener(SWT.Traverse, textListener); text.setFocus(); text.text.selectAll(); text.getDisplay().asyncExec(new Runnable() { @Override public void run() { if (!text.isDisposed()) text.openAssist(); } }); return text; } }