Merge commit '0b471805f017da83d715a0d8409f53bdd009d31e'
[simantics/platform.git] / bundles / org.simantics.browsing.ui.nattable / src / org / simantics / browsing / ui / nattable / KeyToSelectionAdapter.java
1 package org.simantics.browsing.ui.nattable;\r
2 \r
3 import java.util.Collection;\r
4 import java.util.List;\r
5 import java.util.regex.Pattern;\r
6 \r
7 import org.eclipse.jface.viewers.IStructuredSelection;\r
8 import org.eclipse.nebula.widgets.nattable.NatTable;\r
9 import org.eclipse.swt.events.KeyAdapter;\r
10 import org.eclipse.swt.events.KeyEvent;\r
11 import org.simantics.browsing.ui.GraphExplorer;\r
12 import org.simantics.utils.ui.AdaptionUtils;\r
13 \r
14 /**\r
15  * Selects tree items based on pressed key events.<p>\r
16  * \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 NatTableGraphExplorer          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 = (NatTableGraphExplorer)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          NatTable tree = explorer.getControl();\r
59          columns = explorer.getColumns().length;\r
60          \r
61          IStructuredSelection sel = (IStructuredSelection)explorer.getWidgetSelection();\r
62          Collection<RowSelectionItem> selected = AdaptionUtils.adaptToCollection(sel, RowSelectionItem.class);\r
63          \r
64           \r
65          TreeNode item = find(tree, selected);\r
66          \r
67          if (item == null && matcher.length() > 1) {\r
68                  matcher = matcher.substring(matcher.length()-1);\r
69                  item = find(tree, selected);\r
70          }\r
71          \r
72          if (item != null) {\r
73                  explorer.select(item);\r
74                  explorer.show(item);\r
75                  } \r
76          // without this the default handling would take over.\r
77          e.doit = false;\r
78     }\r
79     \r
80     private TreeNode previous = null;\r
81     private boolean foundPrev = false;\r
82     \r
83         private TreeNode find(NatTable tree, Collection<RowSelectionItem> selected) {\r
84                 TreeNode item = null;\r
85 \r
86                 List<TreeNode> items = explorer.getItems();\r
87                 \r
88                 if (selected.size() == 0) {\r
89                         previous = null;\r
90                         foundPrev = true;\r
91                         item = findItem(items);\r
92 \r
93                 } else {\r
94                         previous = selected.iterator().next().item;\r
95                         foundPrev = false;\r
96                         item = findItem(items);\r
97                         if (item == null) {\r
98                                 previous = null;\r
99                                 foundPrev = true;\r
100                                 item = findItem(items);\r
101                         }\r
102                 }\r
103                 return item;\r
104         }\r
105     \r
106     private TreeNode findItem(List<TreeNode> items) {\r
107         for (int i = 0; i < items.size(); i++) {\r
108                 TreeNode item = items.get(i);\r
109                 if (item != previous) {\r
110                         if (foundPrev && matches(item, columns, matcher))\r
111                                 return item;\r
112                         \r
113                 } else {\r
114                         foundPrev = true;\r
115                 }\r
116         }\r
117         return null;\r
118     }\r
119     \r
120     \r
121     /**\r
122      * \r
123      * @param item\r
124      * @param depth Depth of the item in the tree.\r
125      * @param columns Number of columns.\r
126      * @param string Matching string.\r
127      * @return\r
128      */\r
129     protected boolean matches(TreeNode item, int columns, String matcher) {\r
130         for (int c = 0; c < columns; c++) {     \r
131                         if (matchesColumn(item, c, matcher)) {\r
132                                 return true;\r
133                         }\r
134                 }\r
135         return false;\r
136     }\r
137     \r
138     /**\r
139      * \r
140      * @param item\r
141      * @param column\r
142      * @param matcher\r
143      * @return\r
144      */\r
145     protected boolean matchesColumn(TreeNode item, int column, String matcher) {\r
146         String text = item.getValueString(column);\r
147                 if (text.toLowerCase().startsWith(matcher)) {\r
148                         return true;\r
149                 }\r
150                 return false;\r
151     }\r
152 \r
153 }\r