1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package net.sf.commonclipse.preferences;
18
19 import org.eclipse.jface.preference.FieldEditor;
20 import org.eclipse.jface.resource.JFaceResources;
21 import org.eclipse.swt.SWT;
22 import org.eclipse.swt.events.DisposeEvent;
23 import org.eclipse.swt.events.DisposeListener;
24 import org.eclipse.swt.events.FocusAdapter;
25 import org.eclipse.swt.events.FocusEvent;
26 import org.eclipse.swt.events.KeyAdapter;
27 import org.eclipse.swt.events.KeyEvent;
28 import org.eclipse.swt.events.SelectionEvent;
29 import org.eclipse.swt.events.SelectionListener;
30 import org.eclipse.swt.graphics.GC;
31 import org.eclipse.swt.graphics.Point;
32 import org.eclipse.swt.layout.GridData;
33 import org.eclipse.swt.widgets.Combo;
34 import org.eclipse.swt.widgets.Composite;
35
36
37 /***
38 * Implementation identical to StringFieldEditor but using a combo instead of a Text field.
39 * @author fgiust
40 * @version $Revision: 1.4 $ ($Author: fgiust $)
41 */
42 public class ComboFieldEditor extends FieldEditor
43 {
44
45 /***
46 * Text limit constant (value <code>-1</code>) indicating unlimited text limit and width.
47 */
48 public static final int UNLIMITED = -1;
49
50 /***
51 * The text field, or <code>null</code> if none.
52 */
53 Combo textField;
54
55 /***
56 * predefined values to be shown in list.
57 */
58 private String[] predefinedValues;
59
60 /***
61 * Cached valid state.
62 */
63 private boolean isValid;
64
65 /***
66 * Old text value.
67 */
68 private String oldValue;
69
70 /***
71 * Width of text field in characters; initially unlimited.
72 */
73 private int widthInChars = UNLIMITED;
74
75 /***
76 * Text limit of text field in characters; initially unlimited.
77 */
78 private int textLimit = UNLIMITED;
79
80 /***
81 * The error message, or <code>null</code> if none.
82 */
83 private String errorMessage;
84
85 /***
86 * Indicates whether the empty string is legal; <code>true</code> by default.
87 */
88 private boolean emptyStringAllowed = true;
89
90 /***
91 * Creates a new string field editor.
92 */
93 protected ComboFieldEditor()
94 {
95 }
96
97 /***
98 * Creates a string field editor. Use the method <code>setTextLimit</code> to limit the text.
99 * @param name the name of the preference this field editor works on
100 * @param labelText the label text of the field editor
101 * @param width the width of the text input field in characters, or <code>UNLIMITED</code> for no limit
102 * @param parent the parent of the field editor's control
103 */
104 public ComboFieldEditor(String name, String labelText, int width, Composite parent)
105 {
106 init(name, labelText);
107 this.widthInChars = width;
108 this.isValid = false;
109 this.errorMessage = JFaceResources.getString("StringFieldEditor.errorMessage");
110 createControl(parent);
111 }
112
113 /***
114 * Creates a string field editor of unlimited width. Use the method <code>setTextLimit</code> to limit the text.
115 * @param name the name of the preference this field editor works on
116 * @param labelText the label text of the field editor
117 * @param parent the parent of the field editor's control
118 */
119 public ComboFieldEditor(String name, String labelText, Composite parent)
120 {
121 this(name, labelText, UNLIMITED, parent);
122 }
123
124 /***
125 * Checks whether the text input field contains a valid value or not.
126 * @return <code>true</code> if the field value is valid, and <code>false</code> if invalid
127 */
128 protected boolean checkState()
129 {
130 boolean result = false;
131 if (this.emptyStringAllowed)
132 {
133 result = true;
134 }
135
136 if (this.textField == null)
137 {
138 result = false;
139 }
140
141 String txt = this.textField.getText();
142
143 if (txt == null)
144 {
145 result = false;
146 }
147
148 result = (txt.trim().length() > 0) || this.emptyStringAllowed;
149
150
151 result = result && doCheckState();
152
153 if (result)
154 {
155 clearErrorMessage();
156 }
157 else
158 {
159 showErrorMessage(this.errorMessage);
160 }
161
162 return result;
163 }
164
165 /***
166 * @see org.eclipse.jface.preference.FieldEditor#doLoad()
167 */
168 protected void doLoad()
169 {
170 if (this.textField != null)
171 {
172
173 addDefaultOptions();
174 String value = getPreferenceStore().getString(getPreferenceName());
175 this.textField.setText(value);
176 this.oldValue = value;
177
178 }
179 }
180
181 /***
182 * @see org.eclipse.jface.preference.FieldEditor#doLoadDefault()
183 */
184 protected void doLoadDefault()
185 {
186 if (this.textField != null)
187 {
188 addDefaultOptions();
189 String value = getPreferenceStore().getDefaultString(getPreferenceName());
190 this.textField.setText(value);
191
192 }
193 valueChanged();
194 }
195
196 /***
197 * @see org.eclipse.jface.preference.FieldEditor#doStore()
198 */
199 protected void doStore()
200 {
201 getPreferenceStore().setValue(getPreferenceName(), this.textField.getText());
202 }
203
204 /***
205 * Returns the error message that will be displayed when and if an error occurs.
206 * @return the error message, or <code>null</code> if none
207 */
208 public String getErrorMessage()
209 {
210 return this.errorMessage;
211 }
212
213 /***
214 * @see org.eclipse.jface.preference.FieldEditor#getNumberOfControls()
215 */
216 public int getNumberOfControls()
217 {
218 return 2;
219 }
220
221 /***
222 * Returns the field editor's value.
223 * @return the current value
224 */
225 public String getStringValue()
226 {
227 if (this.textField != null)
228 {
229 return this.textField.getText();
230 }
231 return getPreferenceStore().getString(getPreferenceName());
232 }
233
234 /***
235 * Returns this field editor's text control.
236 * @return the text control, or <code>null</code> if no text field is created yet
237 */
238 protected Combo getTextControl()
239 {
240 return this.textField;
241 }
242
243 /***
244 * Returns this field editor's text control.
245 * <p>
246 * The control is created if it does not yet exist
247 * </p>
248 * @param parent the parent
249 * @return the text control
250 */
251 public Combo getTextControl(Composite parent)
252 {
253 if (this.textField == null)
254 {
255 this.textField = new Combo(parent, SWT.SINGLE | SWT.BORDER);
256
257 this.textField.setFont(parent.getFont());
258
259 this.textField.addKeyListener(new KeyAdapter()
260 {
261
262 public void keyReleased(KeyEvent e)
263 {
264 valueChanged();
265 }
266 });
267 this.textField.addSelectionListener(new SelectionListener()
268 {
269
270 public void widgetSelected(SelectionEvent e)
271 {
272 valueChanged();
273 }
274
275 public void widgetDefaultSelected(SelectionEvent e)
276 {
277 valueChanged();
278 }
279
280 });
281 this.textField.addFocusListener(new FocusAdapter()
282 {
283
284 public void focusGained(FocusEvent e)
285 {
286 refreshValidState();
287 }
288
289 public void focusLost(FocusEvent e)
290 {
291 valueChanged();
292 clearErrorMessage();
293 }
294 });
295
296 this.textField.addDisposeListener(new DisposeListener()
297 {
298
299 public void widgetDisposed(DisposeEvent event)
300 {
301 ComboFieldEditor.this.textField = null;
302 }
303 });
304 if (this.textLimit > 0)
305 {
306 this.textField.setTextLimit(this.textLimit);
307 }
308 }
309 else
310 {
311 checkParent(this.textField, parent);
312 }
313 return this.textField;
314 }
315
316 /***
317 * Returns whether an empty string is a valid value.
318 * @return <code>true</code> if an empty string is a valid value, and <code>false</code> if an empty string is
319 * invalid
320 * @see #setEmptyStringAllowed
321 */
322 public boolean isEmptyStringAllowed()
323 {
324 return this.emptyStringAllowed;
325 }
326
327 /***
328 * @see org.eclipse.jface.preference.FieldEditor # isValid()
329 */
330 public boolean isValid()
331 {
332 return this.isValid;
333 }
334
335 /***
336 * @see org.eclipse.jface.preference.FieldEditor#refreshValidState()
337 */
338 protected void refreshValidState()
339 {
340 this.isValid = checkState();
341 }
342
343 /***
344 * Sets whether the empty string is a valid value or not.
345 * @param b <code>true</code> if the empty string is allowed, and <code>false</code> if it is considered invalid
346 */
347 public void setEmptyStringAllowed(boolean b)
348 {
349 this.emptyStringAllowed = b;
350 }
351
352 /***
353 * Sets the error message that will be displayed when and if an error occurs.
354 * @param message the error message
355 */
356 public void setErrorMessage(String message)
357 {
358 this.errorMessage = message;
359 }
360
361 /***
362 * @see org.eclipse.jface.preference.FieldEditor#setFocus()
363 */
364 public void setFocus()
365 {
366 if (this.textField != null)
367 {
368 this.textField.setFocus();
369 }
370 }
371
372 /***
373 * Sets this field editor's value.
374 * @param value the new value, or <code>null</code> meaning the empty string
375 */
376 public void setStringValue(String value)
377 {
378 if (this.textField != null)
379 {
380 String newValue = value;
381 if (newValue == null)
382 {
383 newValue = "";
384 }
385
386 this.oldValue = this.textField.getText();
387
388 if (!this.oldValue.equals(newValue))
389 {
390 this.textField.setText(newValue);
391
392 valueChanged();
393 }
394 }
395 }
396
397 /***
398 * Sets this text field's text limit.
399 * @param limit the limit on the number of character in the text input field, or <code>UNLIMITED</code> for no
400 * limit
401 */
402 public void setTextLimit(int limit)
403 {
404 this.textLimit = limit;
405 if (this.textField != null)
406 {
407 this.textField.setTextLimit(limit);
408 }
409 }
410
411 /***
412 * Shows the error message set via <code>setErrorMessage</code>.
413 */
414 public void showErrorMessage()
415 {
416 showErrorMessage(this.errorMessage);
417 }
418
419 /***
420 * Informs this field editor's listener, if it has one, about a change to the value (<code>VALUE</code> property)
421 * provided that the old and new values are different.
422 * <p>
423 * This hook is <em>not</em> called when the text is initialized (or reset to the default value) from the
424 * preference store.
425 * </p>
426 */
427 protected void valueChanged()
428 {
429 setPresentsDefaultValue(false);
430 boolean oldState = this.isValid;
431 refreshValidState();
432
433 if (this.isValid != oldState)
434 {
435 fireStateChanged(IS_VALID, oldState, this.isValid);
436 }
437
438 String newValue = this.textField.getText();
439 if (!newValue.equals(this.oldValue))
440 {
441 fireValueChanged(VALUE, this.oldValue, newValue);
442 this.oldValue = newValue;
443 }
444 }
445
446 /***
447 * @see org.eclipse.jface.preference.FieldEditor#setEnabled(boolean,Composite).
448 */
449 public void setEnabled(boolean enabled, Composite parent)
450 {
451 super.setEnabled(enabled, parent);
452 getTextControl(parent).setEnabled(enabled);
453 }
454
455 /***
456 * Hook for subclasses to do specific state checks.
457 * <p>
458 * The default implementation of this framework method does nothing and returns <code>true</code>. Subclasses
459 * should override this method to specific state checks.
460 * </p>
461 * @return <code>true</code> if the field value is valid, and <code>false</code> if invalid
462 */
463 protected boolean doCheckState()
464 {
465 return true;
466 }
467
468 /***
469 * @see org.eclipse.jface.preference.FieldEditor#adjustForNumColumns(int)
470 */
471 protected void adjustForNumColumns(int numColumns)
472 {
473 GridData gd = (GridData) this.textField.getLayoutData();
474 gd.horizontalSpan = numColumns - 1;
475
476
477
478 gd.grabExcessHorizontalSpace = gd.horizontalSpan == 1;
479 }
480
481 /***
482 * @see org.eclipse.jface.preference.FieldEditor#doFillIntoGrid(Composite, int)
483 */
484 protected void doFillIntoGrid(Composite parent, int numColumns)
485 {
486 getLabelControl(parent);
487
488 this.textField = getTextControl(parent);
489 GridData gd = new GridData();
490 gd.horizontalSpan = numColumns - 1;
491 if (this.widthInChars != UNLIMITED)
492 {
493 GC gc = new GC(this.textField);
494 try
495 {
496 Point extent = gc.textExtent("X");
497 gd.widthHint = this.widthInChars * extent.x;
498 }
499 finally
500 {
501 gc.dispose();
502 }
503 }
504 else
505 {
506 gd.horizontalAlignment = GridData.FILL;
507 gd.grabExcessHorizontalSpace = true;
508 }
509 this.textField.setLayoutData(gd);
510 }
511
512 /***
513 * Sets a list of predefined values that must be shown in the combo.
514 * @param strings array of Strings added to the combo
515 */
516 public void setPredefinedValues(String[] strings)
517 {
518 this.predefinedValues = strings;
519 }
520
521 /***
522 * Adds predefined options to the combo.
523 */
524 private void addDefaultOptions()
525 {
526 if (this.textField != null && this.predefinedValues != null)
527 {
528 this.textField.setItems(this.predefinedValues);
529 }
530 }
531
532 /***
533 * @see org.eclipse.jface.preference.FieldEditor#clearErrorMessage()
534 */
535 protected void clearErrorMessage()
536 {
537 super.clearErrorMessage();
538 }
539
540 }