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