]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/ComboBoxCellEditor2.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.browsing.ui.swt / src / org / simantics / browsing / ui / swt / ComboBoxCellEditor2.java
index 9c96fcc53c7c08a11ffa80a0c11d6b672bede703..b2eaa7c8492292732a6ca182fa62e40688e35fad 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2013 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.browsing.ui.swt;\r
-\r
-import java.text.MessageFormat;\r
-import java.util.regex.Pattern;\r
-\r
-import org.eclipse.core.runtime.Assert;\r
-import org.eclipse.jface.viewers.CellEditor;\r
-import org.eclipse.jface.viewers.ComboBoxCellEditor;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.events.FocusAdapter;\r
-import org.eclipse.swt.events.FocusEvent;\r
-import org.eclipse.swt.events.KeyAdapter;\r
-import org.eclipse.swt.events.KeyEvent;\r
-import org.eclipse.swt.events.SelectionAdapter;\r
-import org.eclipse.swt.events.SelectionEvent;\r
-import org.eclipse.swt.events.TraverseEvent;\r
-import org.eclipse.swt.events.TraverseListener;\r
-import org.eclipse.swt.graphics.GC;\r
-import org.eclipse.swt.widgets.Combo;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Control;\r
-\r
-/**\r
- * Similar to org.eclipse.jface.viewers.ComboBoxCellEditor, but: <br>\r
- *   Uses Combo instead of CCombo <br>\r
- *   Set value when combo item is selected, does not wait for CR Key / Focus lost to apply the value.<br>\r
- *   In ReadOnly mode uses alphanum keys to preselect items.<br>\r
- * \r
- * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
- *\r
- */\r
-public class ComboBoxCellEditor2 extends CellEditor {\r
-       private static final int KEY_INPUT_DELAY = 500;\r
-       \r
-       /**\r
-        * The list of items to present in the combo box.\r
-        */\r
-       private String[] items;\r
-\r
-       /**\r
-        * The zero-based index of the selected item.\r
-        */\r
-       int selection;\r
-\r
-       /**\r
-        * The custom combo box control.\r
-        */\r
-       Combo comboBox;\r
-\r
-       /**\r
-        * Default ComboBoxCellEditor style\r
-        */\r
-       private static final int defaultStyle = SWT.NONE;\r
-\r
-       /**\r
-        * Creates a new cell editor with no control and no st of choices.\r
-        * Initially, the cell editor has no cell validator.\r
-        *\r
-        * @since 2.1\r
-        * @see CellEditor#setStyle\r
-        * @see CellEditor#create\r
-        * @see ComboBoxCellEditor#setItems\r
-        * @see CellEditor#dispose\r
-        */\r
-       public ComboBoxCellEditor2() {\r
-               setStyle(defaultStyle);\r
-       }\r
-\r
-       /**\r
-        * Creates a new cell editor with a combo containing the given list of\r
-        * choices and parented under the given control. The cell editor value is\r
-        * the zero-based index of the selected item. Initially, the cell editor has\r
-        * no cell validator and the first item in the list is selected.\r
-        *\r
-        * @param parent\r
-        *            the parent control\r
-        * @param items\r
-        *            the list of strings for the combo box\r
-        */\r
-       public ComboBoxCellEditor2(Composite parent, String[] items) {\r
-               this(parent, items, defaultStyle);\r
-       }\r
-\r
-       /**\r
-        * Creates a new cell editor with a combo containing the given list of\r
-        * choices and parented under the given control. The cell editor value is\r
-        * the zero-based index of the selected item. Initially, the cell editor has\r
-        * no cell validator and the first item in the list is selected.\r
-        *\r
-        * @param parent\r
-        *            the parent control\r
-        * @param items\r
-        *            the list of strings for the combo box\r
-        * @param style\r
-        *            the style bits\r
-        * @since 2.1\r
-        */\r
-       public ComboBoxCellEditor2(Composite parent, String[] items, int style) {\r
-               super(parent, style);\r
-               setItems(items);\r
-       }\r
-\r
-       /**\r
-        * Returns the list of choices for the combo box\r
-        *\r
-        * @return the list of choices for the combo box\r
-        */\r
-       public String[] getItems() {\r
-               return this.items;\r
-       }\r
-\r
-       /**\r
-        * Sets the list of choices for the combo box\r
-        *\r
-        * @param items\r
-        *            the list of choices for the combo box\r
-        */\r
-       public void setItems(String[] items) {\r
-               Assert.isNotNull(items);\r
-               this.items = items;\r
-               populateComboBoxItems();\r
-       }\r
-\r
-       /*\r
-        * (non-Javadoc) Method declared on CellEditor.\r
-        */\r
-       protected Control createControl(Composite parent) {\r
-\r
-               comboBox = new Combo(parent, getStyle());\r
-               comboBox.setFont(parent.getFont());\r
-\r
-               populateComboBoxItems();\r
-\r
-               if ((getStyle() & SWT.READ_ONLY) > 0) {\r
-                       comboBox.addKeyListener(new AutoCompleteAdapter(comboBox));\r
-               }\r
-               \r
-               comboBox.addKeyListener(new KeyAdapter() {\r
-                       // hook key pressed - see PR 14201\r
-                       public void keyPressed(KeyEvent e) {\r
-                               keyReleaseOccured(e);\r
-                       }\r
-               });\r
-\r
-               comboBox.addSelectionListener(new SelectionAdapter() {\r
-                       public void widgetDefaultSelected(SelectionEvent event) {\r
-                               applyEditorValueAndDeactivate();\r
-                       }\r
-\r
-                       public void widgetSelected(SelectionEvent event) {\r
-                               selection = comboBox.getSelectionIndex();\r
-                               if (!comboBox.getListVisible()) {\r
-                                       /*\r
-                                        * There seems to be no reliable way to detect if selection was done with\r
-                                        * mouse or with arrow keys. The problem is that we want to close the editor,\r
-                                        * if selection was changed with mouse, but keep it open if it was done with\r
-                                        * arrow keys.\r
-                                        */\r
-                                       // close the editor if list is visible. (Mouse selection hides the list)\r
-                                       // Note that this prevents proper selections with arrow keys with hidden list. \r
-                                       applyEditorValueAndDeactivate();\r
-                               }\r
-                               \r
-                       }\r
-               });\r
-               \r
-               comboBox.addTraverseListener(new TraverseListener() {\r
-                       public void keyTraversed(TraverseEvent e) {\r
-                               if (e.detail == SWT.TRAVERSE_ESCAPE\r
-                            || e.detail == SWT.TRAVERSE_RETURN) {\r
-                                       e.doit = false;\r
-                               }\r
-                       }\r
-               });\r
-\r
-               comboBox.addFocusListener(new FocusAdapter() {\r
-                       public void focusLost(FocusEvent e) {\r
-                               ComboBoxCellEditor2.this.focusLost();\r
-                       }\r
-               });\r
-\r
-               return comboBox;\r
-       }\r
-\r
-       /**\r
-        * The <code>ComboBoxCellEditor</code> implementation of this\r
-        * <code>CellEditor</code> framework method returns the zero-based index\r
-        * of the current selection.\r
-        *\r
-        * @return the zero-based index of the current selection wrapped as an\r
-        *         <code>Integer</code>\r
-        */\r
-       protected Object doGetValue() {\r
-               return new Integer(selection);\r
-       }\r
-\r
-       /*\r
-        * (non-Javadoc) Method declared on CellEditor.\r
-        */\r
-       protected void doSetFocus() {\r
-               comboBox.setFocus();\r
-       }\r
-\r
-       /**\r
-        * The <code>ComboBoxCellEditor</code> implementation of this\r
-        * <code>CellEditor</code> framework method sets the minimum width of the\r
-        * cell. The minimum width is 10 characters if <code>comboBox</code> is\r
-        * not <code>null</code> or <code>disposed</code> else it is 60 pixels\r
-        * to make sure the arrow button and some text is visible. The list of\r
-        * CCombo will be wide enough to show its longest item.\r
-        */\r
-       public LayoutData getLayoutData() {\r
-               LayoutData layoutData = super.getLayoutData();\r
-               if ((comboBox == null) || comboBox.isDisposed()) {\r
-                       layoutData.minimumWidth = 60;\r
-               } else {\r
-                       // make the comboBox 10 characters wide\r
-                       GC gc = new GC(comboBox);\r
-                       layoutData.minimumWidth = (gc.getFontMetrics()\r
-                                       .getAverageCharWidth() * 10) + 10;\r
-                       gc.dispose();\r
-               }\r
-               return layoutData;\r
-       }\r
-\r
-       /**\r
-        * The <code>ComboBoxCellEditor</code> implementation of this\r
-        * <code>CellEditor</code> framework method accepts a zero-based index of\r
-        * a selection.\r
-        *\r
-        * @param value\r
-        *            the zero-based index of the selection wrapped as an\r
-        *            <code>Integer</code>\r
-        */\r
-       protected void doSetValue(Object value) {\r
-               Assert.isTrue(comboBox != null && (value instanceof Integer));\r
-               selection = ((Integer) value).intValue();\r
-               comboBox.select(selection);\r
-       }\r
-\r
-       /**\r
-        * Updates the list of choices for the combo box for the current control.\r
-        */\r
-       private void populateComboBoxItems() {\r
-               if (comboBox != null && items != null) {\r
-                       comboBox.removeAll();\r
-                       for (int i = 0; i < items.length; i++) {\r
-                               comboBox.add(items[i], i);\r
-                       }\r
-\r
-                       setValueValid(true);\r
-                       selection = 0;\r
-               }\r
-       }\r
-\r
-       /**\r
-        * Applies the currently selected value and deactivates the cell editor\r
-        */\r
-       void applyEditorValueAndDeactivate() {\r
-               // must set the selection before getting value\r
-               selection = comboBox.getSelectionIndex();\r
-               Object newValue = doGetValue();\r
-               markDirty();\r
-               boolean isValid = isCorrect(newValue);\r
-               setValueValid(isValid);\r
-\r
-               if (!isValid) {\r
-                       // Only format if the 'index' is valid\r
-                       if (items.length > 0 && selection >= 0 && selection < items.length) {\r
-                               // try to insert the current value into the error message.\r
-                               setErrorMessage(MessageFormat.format(getErrorMessage(),\r
-                                               new Object[] { items[selection] }));\r
-                       } else {\r
-                               // Since we don't have a valid index, assume we're using an\r
-                               // 'edit'\r
-                               // combo so format using its text value\r
-                               setErrorMessage(MessageFormat.format(getErrorMessage(),\r
-                                               new Object[] { comboBox.getText() }));\r
-                       }\r
-               }\r
-\r
-               fireApplyEditorValue();\r
-               deactivate();\r
-       }\r
-\r
-       /*\r
-        * (non-Javadoc)\r
-        *\r
-        * @see org.eclipse.jface.viewers.CellEditor#focusLost()\r
-        */\r
-       protected void focusLost() {\r
-               if (isActivated()) {\r
-                       applyEditorValueAndDeactivate();\r
-               }\r
-       }\r
-\r
-       /*\r
-        * (non-Javadoc)\r
-        *\r
-        * @see org.eclipse.jface.viewers.CellEditor#keyReleaseOccured(org.eclipse.swt.events.KeyEvent)\r
-        */\r
-       protected void keyReleaseOccured(KeyEvent keyEvent) {\r
-               if (keyEvent.character == '\u001b') { // Escape character\r
-                       fireCancelEditor();\r
-               } else if (keyEvent.character == '\t') { // tab key\r
-                       applyEditorValueAndDeactivate();\r
-               }\r
-       }\r
-       \r
-       protected int getDoubleClickTimeout() {\r
-               // while we would want to allow double click closing the editor (Closing implementation is in org.eclipse.jface.viewers.ColumnViewerEditor)\r
-               // using the double click detection prevents opening the combo, if the cell selection and edit commands are done "too fast". \r
-               //\r
-               // Hence, in order to use the double click mechanism so that is does not annoy users, the default ColumnViewerEditor must be overridden. \r
-               \r
-               return 0;\r
-       }\r
-       \r
-       private class AutoCompleteAdapter extends KeyAdapter {\r
-               private Combo combo;\r
-               private String matcher = "";\r
-           private int prevEvent = 0;\r
-           private int prevIndex = -1;\r
-           private int toBeSelected = -1;\r
-           protected Pattern alphaNum;\r
-               \r
-           public AutoCompleteAdapter(Combo combo) {\r
-               this.combo = combo;\r
-               alphaNum = Pattern.compile("\\p{Alnum}");\r
-           }\r
-           \r
-               @Override\r
-               public void keyPressed(KeyEvent e) {\r
-                       if (combo.isDisposed())\r
-                               return;\r
-                       if (e.keyCode == SWT.CR) {\r
-                               if (prevIndex != -1) {\r
-                                       combo.select(toBeSelected);\r
-                               }       \r
-                       }\r
-                       if (!alphaNum.matcher(Character.toString(e.character)).matches())\r
-                        return;\r
-                        if ((e.time - prevEvent) > KEY_INPUT_DELAY )\r
-                        matcher = "";\r
-                prevEvent = e.time;\r
-                matcher = matcher += Character.toString(e.character);\r
-                int index = findMatching();\r
-                \r
-                if (index != -1) {\r
-                        combo.setText(combo.getItem(index));\r
-                        toBeSelected = index;\r
-                }\r
-                prevIndex = index;\r
-                e.doit = false;\r
-               }\r
-               \r
-               public int findMatching() {\r
-                       int index = -1;\r
-                       if (prevIndex == -1)\r
-                        index = getMatchingIndex(matcher);\r
-                else {\r
-                        index = getMatchingIndex(matcher,prevIndex);\r
-                        if (index == -1) {\r
-                                index = getMatchingIndex(matcher);\r
-                        }\r
-                        if (index == -1) {\r
-                                matcher = matcher.substring(matcher.length()-1);\r
-                                index = getMatchingIndex(matcher,prevIndex);\r
-                                if (index == -1) {\r
-                                        index = getMatchingIndex(matcher);\r
-                                }\r
-                        }\r
-                }\r
-                       return index;\r
-               }\r
-               \r
-               public int getMatchingIndex(String prefix) {\r
-                       for (int i = 0; i < combo.getItemCount(); i++) {\r
-                        if (combo.getItem(i).toLowerCase().trim().startsWith(matcher)) {\r
-                                return i;\r
-                        }\r
-                }\r
-                       return -1;\r
-               }\r
-               \r
-               public int getMatchingIndex(String prefix, int firstIndex) {\r
-                       for (int i = firstIndex+1; i < combo.getItemCount(); i++) {\r
-                        if (combo.getItem(i).toLowerCase().trim().startsWith(matcher)) {\r
-                                return i;\r
-                        }\r
-                }\r
-                       return -1;\r
-               }\r
-       }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2013 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;
+
+import java.text.MessageFormat;
+import java.util.regex.Pattern;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ComboBoxCellEditor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.TraverseEvent;
+import org.eclipse.swt.events.TraverseListener;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * Similar to org.eclipse.jface.viewers.ComboBoxCellEditor, but: <br>
+ *   Uses Combo instead of CCombo <br>
+ *   Set value when combo item is selected, does not wait for CR Key / Focus lost to apply the value.<br>
+ *   In ReadOnly mode uses alphanum keys to preselect items.<br>
+ * 
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
+ *
+ */
+public class ComboBoxCellEditor2 extends CellEditor {
+       private static final int KEY_INPUT_DELAY = 500;
+       
+       /**
+        * The list of items to present in the combo box.
+        */
+       private String[] items;
+
+       /**
+        * The zero-based index of the selected item.
+        */
+       int selection;
+
+       /**
+        * The custom combo box control.
+        */
+       Combo comboBox;
+
+       /**
+        * Default ComboBoxCellEditor style
+        */
+       private static final int defaultStyle = SWT.NONE;
+
+       /**
+        * Creates a new cell editor with no control and no st of choices.
+        * Initially, the cell editor has no cell validator.
+        *
+        * @since 2.1
+        * @see CellEditor#setStyle
+        * @see CellEditor#create
+        * @see ComboBoxCellEditor#setItems
+        * @see CellEditor#dispose
+        */
+       public ComboBoxCellEditor2() {
+               setStyle(defaultStyle);
+       }
+
+       /**
+        * Creates a new cell editor with a combo containing the given list of
+        * choices and parented under the given control. The cell editor value is
+        * the zero-based index of the selected item. Initially, the cell editor has
+        * no cell validator and the first item in the list is selected.
+        *
+        * @param parent
+        *            the parent control
+        * @param items
+        *            the list of strings for the combo box
+        */
+       public ComboBoxCellEditor2(Composite parent, String[] items) {
+               this(parent, items, defaultStyle);
+       }
+
+       /**
+        * Creates a new cell editor with a combo containing the given list of
+        * choices and parented under the given control. The cell editor value is
+        * the zero-based index of the selected item. Initially, the cell editor has
+        * no cell validator and the first item in the list is selected.
+        *
+        * @param parent
+        *            the parent control
+        * @param items
+        *            the list of strings for the combo box
+        * @param style
+        *            the style bits
+        * @since 2.1
+        */
+       public ComboBoxCellEditor2(Composite parent, String[] items, int style) {
+               super(parent, style);
+               setItems(items);
+       }
+
+       /**
+        * Returns the list of choices for the combo box
+        *
+        * @return the list of choices for the combo box
+        */
+       public String[] getItems() {
+               return this.items;
+       }
+
+       /**
+        * Sets the list of choices for the combo box
+        *
+        * @param items
+        *            the list of choices for the combo box
+        */
+       public void setItems(String[] items) {
+               Assert.isNotNull(items);
+               this.items = items;
+               populateComboBoxItems();
+       }
+
+       /*
+        * (non-Javadoc) Method declared on CellEditor.
+        */
+       protected Control createControl(Composite parent) {
+
+               comboBox = new Combo(parent, getStyle());
+               comboBox.setFont(parent.getFont());
+
+               populateComboBoxItems();
+
+               if ((getStyle() & SWT.READ_ONLY) > 0) {
+                       comboBox.addKeyListener(new AutoCompleteAdapter(comboBox));
+               }
+               
+               comboBox.addKeyListener(new KeyAdapter() {
+                       // hook key pressed - see PR 14201
+                       public void keyPressed(KeyEvent e) {
+                               keyReleaseOccured(e);
+                       }
+               });
+
+               comboBox.addSelectionListener(new SelectionAdapter() {
+                       public void widgetDefaultSelected(SelectionEvent event) {
+                               applyEditorValueAndDeactivate();
+                       }
+
+                       public void widgetSelected(SelectionEvent event) {
+                               selection = comboBox.getSelectionIndex();
+                               if (!comboBox.getListVisible()) {
+                                       /*
+                                        * There seems to be no reliable way to detect if selection was done with
+                                        * mouse or with arrow keys. The problem is that we want to close the editor,
+                                        * if selection was changed with mouse, but keep it open if it was done with
+                                        * arrow keys.
+                                        */
+                                       // close the editor if list is visible. (Mouse selection hides the list)
+                                       // Note that this prevents proper selections with arrow keys with hidden list. 
+                                       applyEditorValueAndDeactivate();
+                               }
+                               
+                       }
+               });
+               
+               comboBox.addTraverseListener(new TraverseListener() {
+                       public void keyTraversed(TraverseEvent e) {
+                               if (e.detail == SWT.TRAVERSE_ESCAPE
+                            || e.detail == SWT.TRAVERSE_RETURN) {
+                                       e.doit = false;
+                               }
+                       }
+               });
+
+               comboBox.addFocusListener(new FocusAdapter() {
+                       public void focusLost(FocusEvent e) {
+                               ComboBoxCellEditor2.this.focusLost();
+                       }
+               });
+
+               return comboBox;
+       }
+
+       /**
+        * The <code>ComboBoxCellEditor</code> implementation of this
+        * <code>CellEditor</code> framework method returns the zero-based index
+        * of the current selection.
+        *
+        * @return the zero-based index of the current selection wrapped as an
+        *         <code>Integer</code>
+        */
+       protected Object doGetValue() {
+               return new Integer(selection);
+       }
+
+       /*
+        * (non-Javadoc) Method declared on CellEditor.
+        */
+       protected void doSetFocus() {
+               comboBox.setFocus();
+       }
+
+       /**
+        * The <code>ComboBoxCellEditor</code> implementation of this
+        * <code>CellEditor</code> framework method sets the minimum width of the
+        * cell. The minimum width is 10 characters if <code>comboBox</code> is
+        * not <code>null</code> or <code>disposed</code> else it is 60 pixels
+        * to make sure the arrow button and some text is visible. The list of
+        * CCombo will be wide enough to show its longest item.
+        */
+       public LayoutData getLayoutData() {
+               LayoutData layoutData = super.getLayoutData();
+               if ((comboBox == null) || comboBox.isDisposed()) {
+                       layoutData.minimumWidth = 60;
+               } else {
+                       // make the comboBox 10 characters wide
+                       GC gc = new GC(comboBox);
+                       layoutData.minimumWidth = (gc.getFontMetrics()
+                                       .getAverageCharWidth() * 10) + 10;
+                       gc.dispose();
+               }
+               return layoutData;
+       }
+
+       /**
+        * The <code>ComboBoxCellEditor</code> implementation of this
+        * <code>CellEditor</code> framework method accepts a zero-based index of
+        * a selection.
+        *
+        * @param value
+        *            the zero-based index of the selection wrapped as an
+        *            <code>Integer</code>
+        */
+       protected void doSetValue(Object value) {
+               Assert.isTrue(comboBox != null && (value instanceof Integer));
+               selection = ((Integer) value).intValue();
+               comboBox.select(selection);
+       }
+
+       /**
+        * Updates the list of choices for the combo box for the current control.
+        */
+       private void populateComboBoxItems() {
+               if (comboBox != null && items != null) {
+                       comboBox.removeAll();
+                       for (int i = 0; i < items.length; i++) {
+                               comboBox.add(items[i], i);
+                       }
+
+                       setValueValid(true);
+                       selection = 0;
+               }
+       }
+
+       /**
+        * Applies the currently selected value and deactivates the cell editor
+        */
+       void applyEditorValueAndDeactivate() {
+               // must set the selection before getting value
+               selection = comboBox.getSelectionIndex();
+               Object newValue = doGetValue();
+               markDirty();
+               boolean isValid = isCorrect(newValue);
+               setValueValid(isValid);
+
+               if (!isValid) {
+                       // Only format if the 'index' is valid
+                       if (items.length > 0 && selection >= 0 && selection < items.length) {
+                               // try to insert the current value into the error message.
+                               setErrorMessage(MessageFormat.format(getErrorMessage(),
+                                               new Object[] { items[selection] }));
+                       } else {
+                               // Since we don't have a valid index, assume we're using an
+                               // 'edit'
+                               // combo so format using its text value
+                               setErrorMessage(MessageFormat.format(getErrorMessage(),
+                                               new Object[] { comboBox.getText() }));
+                       }
+               }
+
+               fireApplyEditorValue();
+               deactivate();
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see org.eclipse.jface.viewers.CellEditor#focusLost()
+        */
+       protected void focusLost() {
+               if (isActivated()) {
+                       applyEditorValueAndDeactivate();
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see org.eclipse.jface.viewers.CellEditor#keyReleaseOccured(org.eclipse.swt.events.KeyEvent)
+        */
+       protected void keyReleaseOccured(KeyEvent keyEvent) {
+               if (keyEvent.character == '\u001b') { // Escape character
+                       fireCancelEditor();
+               } else if (keyEvent.character == '\t') { // tab key
+                       applyEditorValueAndDeactivate();
+               }
+       }
+       
+       protected int getDoubleClickTimeout() {
+               // while we would want to allow double click closing the editor (Closing implementation is in org.eclipse.jface.viewers.ColumnViewerEditor)
+               // using the double click detection prevents opening the combo, if the cell selection and edit commands are done "too fast". 
+               //
+               // Hence, in order to use the double click mechanism so that is does not annoy users, the default ColumnViewerEditor must be overridden. 
+               
+               return 0;
+       }
+       
+       private class AutoCompleteAdapter extends KeyAdapter {
+               private Combo combo;
+               private String matcher = "";
+           private int prevEvent = 0;
+           private int prevIndex = -1;
+           private int toBeSelected = -1;
+           protected Pattern alphaNum;
+               
+           public AutoCompleteAdapter(Combo combo) {
+               this.combo = combo;
+               alphaNum = Pattern.compile("\\p{Alnum}");
+           }
+           
+               @Override
+               public void keyPressed(KeyEvent e) {
+                       if (combo.isDisposed())
+                               return;
+                       if (e.keyCode == SWT.CR) {
+                               if (prevIndex != -1) {
+                                       combo.select(toBeSelected);
+                               }       
+                       }
+                       if (!alphaNum.matcher(Character.toString(e.character)).matches())
+                        return;
+                        if ((e.time - prevEvent) > KEY_INPUT_DELAY )
+                        matcher = "";
+                prevEvent = e.time;
+                matcher = matcher += Character.toString(e.character);
+                int index = findMatching();
+                
+                if (index != -1) {
+                        combo.setText(combo.getItem(index));
+                        toBeSelected = index;
+                }
+                prevIndex = index;
+                e.doit = false;
+               }
+               
+               public int findMatching() {
+                       int index = -1;
+                       if (prevIndex == -1)
+                        index = getMatchingIndex(matcher);
+                else {
+                        index = getMatchingIndex(matcher,prevIndex);
+                        if (index == -1) {
+                                index = getMatchingIndex(matcher);
+                        }
+                        if (index == -1) {
+                                matcher = matcher.substring(matcher.length()-1);
+                                index = getMatchingIndex(matcher,prevIndex);
+                                if (index == -1) {
+                                        index = getMatchingIndex(matcher);
+                                }
+                        }
+                }
+                       return index;
+               }
+               
+               public int getMatchingIndex(String prefix) {
+                       for (int i = 0; i < combo.getItemCount(); i++) {
+                        if (combo.getItem(i).toLowerCase().trim().startsWith(matcher)) {
+                                return i;
+                        }
+                }
+                       return -1;
+               }
+               
+               public int getMatchingIndex(String prefix, int firstIndex) {
+                       for (int i = firstIndex+1; i < combo.getItemCount(); i++) {
+                        if (combo.getItem(i).toLowerCase().trim().startsWith(matcher)) {
+                                return i;
+                        }
+                }
+                       return -1;
+               }
+       }
+
+}