1
2
3
4
5
6
7
8
9
10
11 package de.jaret.util.ui;
12
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.StringTokenizer;
18
19 import org.eclipse.jface.viewers.IContentProvider;
20 import org.eclipse.jface.viewers.ILabelProvider;
21 import org.eclipse.jface.viewers.IStructuredContentProvider;
22 import org.eclipse.swt.SWT;
23 import org.eclipse.swt.custom.JaretStyledText;
24 import org.eclipse.swt.custom.StyleRange;
25 import org.eclipse.swt.events.FocusEvent;
26 import org.eclipse.swt.events.FocusListener;
27 import org.eclipse.swt.events.KeyEvent;
28 import org.eclipse.swt.events.KeyListener;
29 import org.eclipse.swt.events.ModifyEvent;
30 import org.eclipse.swt.events.ModifyListener;
31 import org.eclipse.swt.events.VerifyEvent;
32 import org.eclipse.swt.events.VerifyListener;
33 import org.eclipse.swt.layout.GridData;
34 import org.eclipse.swt.layout.GridLayout;
35 import org.eclipse.swt.widgets.Composite;
36 import org.eclipse.swt.widgets.Display;
37
38 import de.jaret.util.misc.MiscUtil;
39 import de.jaret.util.ui.model.IMutableContentProvider;
40
41
42
43
44
45 public class CsvListEditor extends Composite implements FocusListener, VerifyListener, KeyListener, ModifyListener {
46
47 private ILabelProvider _srcLabelProvider;
48 private ILabelProvider _destLabelProvider;
49 private IMutableContentProvider _destContentProvider;
50 private IStructuredContentProvider _srcContentProvider;
51
52 private String _separator = ",";
53 private Map _labelMap = new HashMap();
54 private List _labelList = new ArrayList();
55 private boolean _caseSensitive = false;
56 private boolean _contentParsable = true;
57
58 JaretStyledText _text;
59
60 public CsvListEditor(Composite parent, int style) {
61 super(parent, style);
62
63 _srcLabelProvider = new DefaultLabelProvider();
64 _destLabelProvider = _srcLabelProvider;
65
66 createControls();
67 }
68
69 private void updateText() {
70 StringBuffer buf = new StringBuffer();
71 Object[] dest = _destContentProvider.getElements(null);
72 for (int i = 0; i < dest.length; i++) {
73 String label = _destLabelProvider.getText(dest[i]);
74 buf.append(label);
75 if (i < dest.length - 1) {
76 buf.append(_separator);
77 }
78 }
79 _text.setText(buf.toString());
80 _contentParsable = true;
81 }
82
83
84
85
86
87
88 private boolean updateDest() {
89 String input = _text.getText().trim();
90
91 if (input.endsWith(_separator)) {
92 input = input.substring(0, input.length() - 1);
93 }
94 StringTokenizer tokenizer = new StringTokenizer(input, _separator, true);
95 boolean success = true;
96 List objects = new ArrayList();
97
98 while (tokenizer.hasMoreTokens()) {
99 String token = tokenizer.nextToken();
100 if (!token.equals(_separator)) {
101 token = token.trim();
102 if (!_caseSensitive) {
103 token = token.toLowerCase();
104 }
105 Object o = _labelMap.get(token);
106 if (o == null) {
107 success = false;
108 break;
109 } else {
110 objects.add(o);
111 }
112 }
113 }
114 if (success) {
115
116 _destContentProvider.clear();
117 for (int i = 0; i < objects.size(); i++) {
118 _destContentProvider.addToDest(objects.get(i));
119 }
120 }
121 _contentParsable = success;
122 return success;
123 }
124
125 private void createControls() {
126 GridLayout gridLayout = new GridLayout();
127 gridLayout.numColumns = 1;
128 this.setLayout(gridLayout);
129
130 GridData gd = new GridData(GridData.FILL_HORIZONTAL);
131 _text = new JaretStyledText(this, SWT.SINGLE | SWT.BORDER);
132 _text.setLayoutData(gd);
133 _text.addFocusListener(this);
134
135 _text.addModifyListener(this);
136 }
137
138
139
140
141
142
143
144
145 private boolean checkLabelUniqueness(IStructuredContentProvider cp, ILabelProvider lp) {
146 boolean result = true;
147 Map labels = new HashMap();
148 Object[] elements = cp.getElements(null);
149 for (int i = 0; i < elements.length; i++) {
150 String label = lp.getText(elements[i]).trim();
151 if (!_caseSensitive) {
152 label = label.toLowerCase();
153 }
154 if (labels.get(label) != null) {
155 result = false;
156 break;
157 } else {
158 labels.put(label, "x");
159 }
160 }
161 return result;
162 }
163
164 private void fillLabelMap() {
165 Object[] elements = _srcContentProvider.getElements(null);
166 for (int i = 0; i < elements.length; i++) {
167 String label = _srcLabelProvider.getText(elements[i]).trim();
168 if (!_caseSensitive) {
169 label = label.toLowerCase();
170 }
171 _labelMap.put(label, elements[i]);
172 _labelList.add(label);
173 }
174 }
175
176 public void setSrcLabelProvider(ILabelProvider labelProvider) {
177 _srcLabelProvider = labelProvider;
178 }
179
180 public void setDestLabelProvider(ILabelProvider labelProvider) {
181 _destLabelProvider = labelProvider;
182 }
183
184
185
186
187 public IMutableContentProvider getDestContentProvider() {
188 return _destContentProvider;
189 }
190
191
192
193
194 public void setDestContentProvider(IMutableContentProvider destContentProvider) {
195 _destContentProvider = destContentProvider;
196 updateText();
197 }
198
199 public void updateX() {
200 updateText();
201 updateDest2(false);
202 }
203
204
205
206
207 public IContentProvider getSrcContentProvider() {
208 return _srcContentProvider;
209 }
210
211
212
213
214 public void setSrcContentProvider(IStructuredContentProvider srcContentProvider) {
215 _srcContentProvider = srcContentProvider;
216 if (!checkLabelUniqueness(_srcContentProvider, _srcLabelProvider)) {
217 throw new RuntimeException("SrcLabels must form a unique key");
218 }
219 fillLabelMap();
220 }
221
222
223
224
225 public ILabelProvider getDestLabelProvider() {
226 return _destLabelProvider;
227 }
228
229
230
231
232 public ILabelProvider getSrcLabelProvider() {
233 return _srcLabelProvider;
234 }
235
236
237
238
239
240
241 public void focusGained(FocusEvent arg0) {
242 }
243
244
245
246
247
248
249 public void focusLost(FocusEvent arg0) {
250 boolean success = updateDest();
251 if (!success) {
252 _text.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
253 } else {
254 _text.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
255 _text.removeModifyListener(this);
256 updateText();
257 updateDest2(false);
258 _text.addModifyListener(this);
259 }
260 }
261
262 private void resetStyle() {
263 _text.setStyleRanges(new StyleRange[] {});
264 }
265
266 private boolean updateDest2(boolean updateDest) {
267 String input = MiscUtil.rightTrim(_text.getText());
268
269 if (input.endsWith(_separator)) {
270 input = input.substring(0, input.length() - 1);
271 }
272 boolean success = true;
273 char separator = _separator.charAt(0);
274 List objects = new ArrayList();
275 List styleRanges = new ArrayList();
276 int pos = 0;
277
278 while (pos < input.length()) {
279 int beginToken = -1;
280 int endToken = -1;
281
282
283 while (pos < input.length() && Character.isWhitespace(input.charAt(pos))) {
284 pos++;
285 }
286 beginToken = pos;
287
288 while (pos < input.length() && input.charAt(pos) != separator) {
289 pos++;
290 }
291 if (beginToken == endToken) {
292
293 break;
294 }
295 endToken = pos;
296 String token = input.substring(beginToken, endToken);
297
298 pos++;
299
300
301 token = token.trim();
302 if (!_caseSensitive) {
303 token = token.toLowerCase();
304 }
305 Object o = _labelMap.get(token);
306 if (o == null) {
307 success = false;
308 } else {
309 objects.add(o);
310
311 styleRanges.add(new StyleRange(beginToken, endToken - beginToken, _text.getForeground(), _text
312 .getBackground(), SWT.BOLD));
313 }
314 }
315
316
317
318 _contentParsable = success;
319 StyleRange srs[] = new StyleRange[styleRanges.size()];
320 for (int i = 0; i < styleRanges.size(); i++) {
321 StyleRange sr = (StyleRange) styleRanges.get(i);
322 srs[i] = sr;
323 }
324 _text.setStyleRanges(srs);
325 return success;
326 }
327
328
329
330
331 public boolean isCaseSensitive() {
332 return _caseSensitive;
333 }
334
335
336
337
338 public void setCaseSensitive(boolean caseSensitive) {
339 _caseSensitive = caseSensitive;
340 }
341
342
343
344
345 public String getSeparator() {
346 return _separator;
347 }
348
349
350
351
352 public void setSeparator(String separator) {
353 _separator = separator;
354 }
355
356
357
358
359 public boolean isContentParsable() {
360 return _contentParsable;
361 }
362
363 private String possibleLabel(String prefix) {
364 if (!_caseSensitive) {
365 prefix = prefix.toLowerCase();
366 }
367 if (prefix.length() == 0) {
368 return "";
369 }
370
371 Object o = _labelMap.get(prefix);
372 if (o != null) {
373 return prefix;
374 }
375 for (int i = 0; i < _labelList.size(); i++) {
376 String label = (String) _labelList.get(i);
377 if (label.startsWith(prefix)) {
378 return label;
379 }
380 }
381 return "";
382 }
383
384
385
386
387
388
389 public void verifyText(VerifyEvent ve) {
390
391
392
393 }
394
395
396
397
398
399 private String getPrefix(String text, int pos) {
400 if (text.length() < 1) {
401 return "";
402 }
403 int end = pos;
404 while (pos > 0 && !text.substring(pos - 1, pos).equals(_separator)) {
405 pos--;
406 }
407 String prefix = text.substring(pos, end);
408 return MiscUtil.leftTrim(prefix);
409 }
410
411
412
413
414
415
416 public void keyPressed(KeyEvent e) {
417
418
419 }
420
421
422
423
424
425
426 public void keyReleased(KeyEvent arg0) {
427 }
428
429
430
431
432
433
434 private boolean ignoreNext = false;
435
436 public void modifyText(ModifyEvent arg0) {
437 updateDest2(false);
438
439 int pos = _text.getCaretOffset();
440 if (ignoreNext) {
441 ignoreNext = false;
442 return;
443 }
444 System.out.println("modify " + _text.getText());
445 String prefix = getPrefix(_text.getText(), pos);
446
447 String label = possibleLabel(prefix);
448
449 if (label.length() > 0) {
450 String rest = label.substring(prefix.length());
451 System.out.println("Rest:" + rest);
452 _text.removeModifyListener(this);
453 ignoreNext = true;
454 _text.insert(rest);
455 _text.setSelection(pos, pos + rest.length());
456 _text.setCaretOffsetJaret(pos);
457 _text.addModifyListener(this);
458 }
459 }
460
461
462
463
464
465
466 public void setToolTipText(String toolTip) {
467 super.setToolTipText(toolTip);
468 _text.setToolTipText(toolTip);
469 }
470 }