]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/KeyToSelectionAdapter.java
Merge remote-tracking branch 'origin/svn' commit 'ccc1271c9d6657fb9dcf4cf3cb115fa0c8c...
[simantics/platform.git] / bundles / org.simantics.browsing.ui.swt / src / org / simantics / browsing / ui / swt / KeyToSelectionAdapter.java
1 package org.simantics.browsing.ui.swt;\r
2 \r
3 import java.util.regex.Pattern;\r
4 \r
5 import org.eclipse.swt.events.KeyAdapter;\r
6 import org.eclipse.swt.events.KeyEvent;\r
7 import org.eclipse.swt.widgets.Tree;\r
8 import org.eclipse.swt.widgets.TreeItem;\r
9 import org.simantics.browsing.ui.GraphExplorer;\r
10 \r
11 /**\r
12  * Selects tree items based on pressed key events.<p>\r
13  * \r
14  * The default implementation of SWT.Tree (Windows?) uses only the the first column when matching the items.<p>\r
15  * \r
16  * This implementation checks all columns. Override <pre>matches(), matchesColumn()</pre> for customized behavior.<p>\r
17  * \r
18  * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
19  *\r
20  */\r
21 public class KeyToSelectionAdapter extends KeyAdapter {\r
22 \r
23         private static final int KEY_INPUT_DELAY = 500;\r
24         \r
25     private final GraphExplorer          explorer;\r
26 \r
27     private String matcher = "";\r
28     private int prevEvent = 0;\r
29     private int columns = 0;\r
30         \r
31     protected Pattern alphaNum;\r
32     \r
33     /**\r
34      * @param contextProvider\r
35      * @param explorer\r
36      */\r
37     public KeyToSelectionAdapter(GraphExplorer explorer) {\r
38         assert explorer != null;\r
39 \r
40         this.explorer = explorer;\r
41         this.alphaNum = Pattern.compile("\\p{Alnum}");\r
42     }\r
43 \r
44     @Override\r
45     public void keyPressed(KeyEvent e) {\r
46         if (explorer.isDisposed())\r
47             return;\r
48 \r
49          \r
50          if (!alphaNum.matcher(Character.toString(e.character)).matches())\r
51                  return;\r
52          // concatenate / replace matcher.\r
53          if ((e.time - prevEvent) > KEY_INPUT_DELAY )\r
54                  matcher = "";\r
55          prevEvent = e.time;\r
56          matcher = matcher += Character.toString(e.character);\r
57 \r
58          TreeItem item = null;\r
59          Tree tree = explorer.getControl();\r
60          columns = tree.getColumnCount();\r
61          TreeItem[] selected = tree.getSelection();\r
62         \r
63          item = find(tree, selected);\r
64          \r
65          if (item == null && matcher.length() > 1) {\r
66                  matcher = matcher.substring(matcher.length()-1);\r
67                  item = find(tree, selected);\r
68          }\r
69          \r
70          if (item != null) {\r
71                          tree.select(item);\r
72                          tree.showItem(item);\r
73                         \r
74                  } \r
75          // without this the default handling would take over.\r
76          e.doit = false;\r
77     }\r
78     \r
79     private TreeItem previous = null;\r
80     private boolean foundPrev = false;\r
81     \r
82         private TreeItem find(Tree tree, TreeItem[] selected) {\r
83                 TreeItem item = null;\r
84 \r
85                 TreeItem items[] = tree.getItems();\r
86                 if (selected.length == 0) {\r
87                         previous = null;\r
88                         foundPrev = true;\r
89                         item = findItem(items, 0);\r
90 \r
91                 } else {\r
92                         previous = selected[0];\r
93                         foundPrev = false;\r
94                         item = findItem(items, 0);\r
95                         if (item == null) {\r
96                                 previous = null;\r
97                                 foundPrev = true;\r
98                                 item = findItem(items, 0);\r
99                         }\r
100                 }\r
101                 return item;\r
102         }\r
103     \r
104     private TreeItem findItem(TreeItem items[], int depth) {\r
105         for (int i = 0; i < items.length; i++) {\r
106                 TreeItem item = items[i];\r
107                 if (item != previous) {\r
108                         if (foundPrev && matches(item, depth, columns, matcher))\r
109                                 return item;\r
110                         \r
111                 } else {\r
112                         foundPrev = true;\r
113                 }\r
114                 TreeItem childItem = findItem(item.getItems(),depth+1); \r
115                 if (childItem != null)\r
116                         return childItem;\r
117         }\r
118         return null;\r
119     }\r
120     \r
121     \r
122     /**\r
123      * \r
124      * @param item\r
125      * @param depth Depth of the item in the tree.\r
126      * @param columns Number of columns.\r
127      * @param string Matching string.\r
128      * @return\r
129      */\r
130     protected boolean matches(TreeItem item, int depth, int columns, String matcher) {\r
131         for (int c = 0; c < columns; c++) {     \r
132                         if (matchesColumn(item, c, matcher)) {\r
133                                 return true;\r
134                         }\r
135                 }\r
136         return false;\r
137     }\r
138     \r
139     /**\r
140      * \r
141      * @param item\r
142      * @param column\r
143      * @param matcher\r
144      * @return\r
145      */\r
146     protected boolean matchesColumn(TreeItem item, int column, String matcher) {\r
147         String text = item.getText(column);\r
148                 if (text.toLowerCase().startsWith(matcher)) {\r
149                         return true;\r
150                 }\r
151                 return false;\r
152     }\r
153 \r
154 \r
155 }\r