Mercurial > projects > dwt-addons
comparison dwtx/jface/preference/FieldEditor.d @ 34:b3c8e32d406f
preference
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sat, 05 Apr 2008 01:45:47 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
33:f25582573129 | 34:b3c8e32d406f |
---|---|
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.FieldEditor; | |
14 | |
15 import dwtx.jface.preference.IPreferenceStore; | |
16 import dwtx.jface.preference.PreferencePage; | |
17 | |
18 import dwt.DWT; | |
19 import dwt.events.DisposeEvent; | |
20 import dwt.events.DisposeListener; | |
21 import dwt.graphics.FontMetrics; | |
22 import dwt.graphics.GC; | |
23 import dwt.layout.GridData; | |
24 import dwt.layout.GridLayout; | |
25 import dwt.widgets.Button; | |
26 import dwt.widgets.Composite; | |
27 import dwt.widgets.Control; | |
28 import dwt.widgets.Label; | |
29 import dwtx.core.runtime.Assert; | |
30 import dwtx.jface.dialogs.DialogPage; | |
31 import dwtx.jface.dialogs.IDialogConstants; | |
32 import dwtx.jface.resource.JFaceResources; | |
33 import dwtx.jface.util.IPropertyChangeListener; | |
34 import dwtx.jface.util.PropertyChangeEvent; | |
35 | |
36 import dwt.dwthelper.utils; | |
37 | |
38 /** | |
39 * Abstract base class for all field editors. | |
40 * <p> | |
41 * A field editor presents the value of a preference to the end | |
42 * user. The value is loaded from a preference store; if | |
43 * modified by the end user, the value is validated and eventually | |
44 * stored back to the preference store. A field editor reports | |
45 * an event when the value, or the validity of the value, changes. | |
46 * </p> | |
47 * <p> | |
48 * Field editors should be used in conjunction with a field | |
49 * editor preference page (<code>FieldEditorPreferencePage</code>) | |
50 * which coordinates everything and provides the message line | |
51 * which display messages emanating from the editor. | |
52 * </p> | |
53 * <p> | |
54 * This package contains ready-to-use field editors for various | |
55 * types of preferences: | |
56 * <ul> | |
57 * <li><code>BooleanFieldEditor</code> - booleans</li> | |
58 * <li><code>IntegerFieldEditor</code> - integers</li> | |
59 * <li><code>StringFieldEditor</code> - text strings</li> | |
60 * <li><code>RadioGroupFieldEditor</code> - enumerations</li> | |
61 * <li><code>ColorFieldEditor</code> - RGB colors</li> | |
62 * <li><code>FontFieldEditor</code> - fonts</li> | |
63 * <li><code>DirectoryFieldEditor</code> - directories</li> | |
64 * <li><code>FileFieldEditor</code> - files</li> | |
65 * <li><code>PathEditor</code> - paths</li> | |
66 * </ul> | |
67 * </p> | |
68 */ | |
69 public abstract class FieldEditor { | |
70 | |
71 /** | |
72 * Property name constant (value <code>"field_editor_is_valid"</code>) | |
73 * to signal a change in the validity of the value of this field editor. | |
74 */ | |
75 public static const String IS_VALID = "field_editor_is_valid";//$NON-NLS-1$ | |
76 | |
77 /** | |
78 * Property name constant (value <code>"field_editor_value"</code>) | |
79 * to signal a change in the value of this field editor. | |
80 */ | |
81 public static const String VALUE = "field_editor_value";//$NON-NLS-1$ | |
82 | |
83 /** | |
84 * Gap between label and control. | |
85 */ | |
86 protected static const int HORIZONTAL_GAP = 8; | |
87 | |
88 /** | |
89 * The preference store, or <code>null</code> if none. | |
90 */ | |
91 private IPreferenceStore preferenceStore = null; | |
92 | |
93 /** | |
94 * The name of the preference displayed in this field editor. | |
95 */ | |
96 private String preferenceName; | |
97 | |
98 /** | |
99 * Indicates whether the default value is currently displayed, | |
100 * initially <code>false</code>. | |
101 */ | |
102 private bool isDefaultPresented = false; | |
103 | |
104 /** | |
105 * The label's text. | |
106 */ | |
107 private String labelText; | |
108 | |
109 /** | |
110 * The label control. | |
111 */ | |
112 private Label label; | |
113 | |
114 /** | |
115 * Listener, or <code>null</code> if none | |
116 */ | |
117 private IPropertyChangeListener propertyChangeListener; | |
118 | |
119 /** | |
120 * The page containing this field editor | |
121 */ | |
122 private DialogPage page; | |
123 | |
124 /** | |
125 * Creates a new field editor. | |
126 */ | |
127 protected this() { | |
128 } | |
129 | |
130 /** | |
131 * Creates a new field editor. | |
132 * | |
133 * @param name the name of the preference this field editor works on | |
134 * @param labelText the label text of the field editor | |
135 * @param parent the parent of the field editor's control | |
136 */ | |
137 protected this(String name, String labelText, Composite parent) { | |
138 init(name, labelText); | |
139 createControl(parent); | |
140 } | |
141 | |
142 /** | |
143 * Adjusts the horizontal span of this field editor's basic controls. | |
144 * <p> | |
145 * Subclasses must implement this method to adjust the horizontal span | |
146 * of controls so they appear correct in the given number of columns. | |
147 * </p> | |
148 * <p> | |
149 * The number of columns will always be equal to or greater than the | |
150 * value returned by this editor's <code>getNumberOfControls</code> method. | |
151 * | |
152 * @param numColumns the number of columns | |
153 */ | |
154 protected abstract void adjustForNumColumns(int numColumns); | |
155 package void adjustForNumColumns_package(int numColumns){ | |
156 adjustForNumColumns(numColumns); | |
157 } | |
158 | |
159 /** | |
160 * Applies a font. | |
161 * <p> | |
162 * The default implementation of this framework method | |
163 * does nothing. Subclasses should override this method | |
164 * if they want to change the font of the DWT control to | |
165 * a value different than the standard dialog font. | |
166 * </p> | |
167 */ | |
168 protected void applyFont() { | |
169 } | |
170 package void applyFont_package() { | |
171 applyFont(); | |
172 } | |
173 | |
174 /** | |
175 * Checks if the given parent is the current parent of the | |
176 * supplied control; throws an (unchecked) exception if they | |
177 * are not correctly related. | |
178 * | |
179 * @param control the control | |
180 * @param parent the parent control | |
181 */ | |
182 protected void checkParent(Control control, Composite parent) { | |
183 Assert.isTrue(control.getParent() is parent, "Different parents");//$NON-NLS-1$ | |
184 } | |
185 | |
186 /** | |
187 * Clears the error message from the message line. | |
188 */ | |
189 protected void clearErrorMessage() { | |
190 if (page !is null) { | |
191 page.setErrorMessage(null); | |
192 } | |
193 } | |
194 | |
195 /** | |
196 * Clears the normal message from the message line. | |
197 */ | |
198 protected void clearMessage() { | |
199 if (page !is null) { | |
200 page.setMessage(null); | |
201 } | |
202 } | |
203 | |
204 /** | |
205 * Returns the number of pixels corresponding to the | |
206 * given number of horizontal dialog units. | |
207 * <p> | |
208 * Clients may call this framework method, but should not override it. | |
209 * </p> | |
210 * | |
211 * @param control the control being sized | |
212 * @param dlus the number of horizontal dialog units | |
213 * @return the number of pixels | |
214 */ | |
215 protected int convertHorizontalDLUsToPixels(Control control, int dlus) { | |
216 GC gc = new GC(control); | |
217 gc.setFont(control.getFont()); | |
218 int averageWidth = gc.getFontMetrics().getAverageCharWidth(); | |
219 gc.dispose(); | |
220 | |
221 double horizontalDialogUnitSize = averageWidth * 0.25; | |
222 | |
223 return cast(int) Math.round(dlus * horizontalDialogUnitSize); | |
224 } | |
225 | |
226 /** | |
227 * Returns the number of pixels corresponding to the | |
228 * given number of vertical dialog units. | |
229 * <p> | |
230 * Clients may call this framework method, but should not override it. | |
231 * </p> | |
232 * | |
233 * @param control the control being sized | |
234 * @param dlus the number of vertical dialog units | |
235 * @return the number of pixels | |
236 */ | |
237 protected int convertVerticalDLUsToPixels(Control control, int dlus) { | |
238 GC gc = new GC(control); | |
239 gc.setFont(control.getFont()); | |
240 int height = gc.getFontMetrics().getHeight(); | |
241 gc.dispose(); | |
242 | |
243 double verticalDialogUnitSize = height * 0.125; | |
244 | |
245 return cast(int) Math.round(dlus * verticalDialogUnitSize); | |
246 } | |
247 | |
248 /** | |
249 * Creates this field editor's main control containing all of its | |
250 * basic controls. | |
251 * | |
252 * @param parent the parent control | |
253 */ | |
254 protected void createControl(Composite parent) { | |
255 GridLayout layout = new GridLayout(); | |
256 layout.numColumns = getNumberOfControls(); | |
257 layout.marginWidth = 0; | |
258 layout.marginHeight = 0; | |
259 layout.horizontalSpacing = HORIZONTAL_GAP; | |
260 parent.setLayout(layout); | |
261 doFillIntoGrid(parent, layout.numColumns); | |
262 } | |
263 | |
264 /** | |
265 * Disposes the DWT resources used by this field editor. | |
266 */ | |
267 public void dispose() { | |
268 // nothing to dispose | |
269 } | |
270 | |
271 /** | |
272 * Fills this field editor's basic controls into the given parent. | |
273 * <p> | |
274 * Subclasses must implement this method to create the controls | |
275 * for this field editor. | |
276 * </p> | |
277 * | |
278 * @param parent the composite used as a parent for the basic controls; | |
279 * the parent's layout must be a <code>GridLayout</code> | |
280 * @param numColumns the number of columns | |
281 */ | |
282 protected abstract void doFillIntoGrid(Composite parent, int numColumns); | |
283 | |
284 /** | |
285 * Initializes this field editor with the preference value from | |
286 * the preference store. | |
287 * <p> | |
288 * Subclasses must implement this method to properly initialize | |
289 * the field editor. | |
290 * </p> | |
291 */ | |
292 protected abstract void doLoad(); | |
293 | |
294 /** | |
295 * Initializes this field editor with the default preference value from | |
296 * the preference store. | |
297 * <p> | |
298 * Subclasses must implement this method to properly initialize | |
299 * the field editor. | |
300 * </p> | |
301 */ | |
302 protected abstract void doLoadDefault(); | |
303 | |
304 /** | |
305 * Stores the preference value from this field editor into | |
306 * the preference store. | |
307 * <p> | |
308 * Subclasses must implement this method to save the entered value | |
309 * into the preference store. | |
310 * </p> | |
311 */ | |
312 protected abstract void doStore(); | |
313 | |
314 /** | |
315 * Fills this field editor's basic controls into the given parent. | |
316 * | |
317 * @param parent the composite used as a parent for the basic controls; | |
318 * the parent's layout must be a <code>GridLayout</code> | |
319 * @param numColumns the number of columns | |
320 */ | |
321 public void fillIntoGrid(Composite parent, int numColumns) { | |
322 Assert.isTrue(numColumns >= getNumberOfControls()); | |
323 Assert.isTrue(null !is cast(GridLayout)parent.getLayout() ); | |
324 doFillIntoGrid(parent, numColumns); | |
325 } | |
326 | |
327 /** | |
328 * Informs this field editor's listener, if it has one, about a change to | |
329 * one of this field editor's bool-valued properties. Does nothing | |
330 * if the old and new values are the same. | |
331 * | |
332 * @param property the field editor property name, | |
333 * such as <code>VALUE</code> or <code>IS_VALID</code> | |
334 * @param oldValue the old value | |
335 * @param newValue the new value | |
336 */ | |
337 protected void fireStateChanged(String property, bool oldValue, | |
338 bool newValue) { | |
339 if (oldValue is newValue) { | |
340 return; | |
341 } | |
342 fireValueChanged(property, oldValue ? Boolean.TRUE : Boolean.FALSE, newValue ? Boolean.TRUE : Boolean.FALSE); | |
343 } | |
344 | |
345 /** | |
346 * Informs this field editor's listener, if it has one, about a change to | |
347 * one of this field editor's properties. | |
348 * | |
349 * @param property the field editor property name, | |
350 * such as <code>VALUE</code> or <code>IS_VALID</code> | |
351 * @param oldValue the old value object, or <code>null</code> | |
352 * @param newValue the new value, or <code>null</code> | |
353 */ | |
354 protected void fireValueChanged(String property, Object oldValue, | |
355 Object newValue) { | |
356 if (propertyChangeListener is null) { | |
357 return; | |
358 } | |
359 propertyChangeListener.propertyChange(new PropertyChangeEvent(this, | |
360 property, oldValue, newValue)); | |
361 } | |
362 | |
363 /** | |
364 * Returns the symbolic font name used by this field editor. | |
365 * | |
366 * @return the symbolic font name | |
367 */ | |
368 public String getFieldEditorFontName() { | |
369 return JFaceResources.DIALOG_FONT; | |
370 } | |
371 | |
372 /** | |
373 * Returns the label control. | |
374 * | |
375 * @return the label control, or <code>null</code> | |
376 * if no label control has been created | |
377 */ | |
378 protected Label getLabelControl() { | |
379 return label; | |
380 } | |
381 | |
382 /** | |
383 * Returns this field editor's label component. | |
384 * <p> | |
385 * The label is created if it does not already exist | |
386 * </p> | |
387 * | |
388 * @param parent the parent | |
389 * @return the label control | |
390 */ | |
391 public Label getLabelControl(Composite parent) { | |
392 if (label is null) { | |
393 label = new Label(parent, DWT.LEFT); | |
394 label.setFont(parent.getFont()); | |
395 String text = getLabelText(); | |
396 if (text !is null) { | |
397 label.setText(text); | |
398 } | |
399 label.addDisposeListener(new class DisposeListener { | |
400 public void widgetDisposed(DisposeEvent event) { | |
401 label = null; | |
402 } | |
403 }); | |
404 } else { | |
405 checkParent(label, parent); | |
406 } | |
407 return label; | |
408 } | |
409 | |
410 /** | |
411 * Returns this field editor's label text. | |
412 * | |
413 * @return the label text | |
414 */ | |
415 public String getLabelText() { | |
416 return labelText; | |
417 } | |
418 | |
419 /** | |
420 * Returns the number of basic controls this field editor consists of. | |
421 * | |
422 * @return the number of controls | |
423 */ | |
424 public abstract int getNumberOfControls(); | |
425 | |
426 /** | |
427 * Returns the name of the preference this field editor operates on. | |
428 * | |
429 * @return the name of the preference | |
430 */ | |
431 public String getPreferenceName() { | |
432 return preferenceName; | |
433 } | |
434 | |
435 /** | |
436 * Returns the preference page in which this field editor | |
437 * appears. | |
438 * | |
439 * @return the preference page, or <code>null</code> if none | |
440 * @deprecated use #getPage() | |
441 */ | |
442 protected PreferencePage getPreferencePage() { | |
443 if(page !is null && cast(PreferencePage)page ) { | |
444 return cast(PreferencePage) page; | |
445 } | |
446 return null; | |
447 } | |
448 | |
449 /** | |
450 * Return the DialogPage that the receiver is sending | |
451 * updates to. | |
452 * | |
453 * @return DialogPage or <code>null</code> if it | |
454 * has not been set. | |
455 * | |
456 * @since 3.1 | |
457 */ | |
458 protected DialogPage getPage(){ | |
459 return page; | |
460 } | |
461 | |
462 /** | |
463 * Returns the preference store used by this field editor. | |
464 * | |
465 * @return the preference store, or <code>null</code> if none | |
466 * @see #setPreferenceStore | |
467 */ | |
468 public IPreferenceStore getPreferenceStore() { | |
469 return preferenceStore; | |
470 } | |
471 | |
472 /** | |
473 * Initialize the field editor with the given preference name and label. | |
474 * | |
475 * @param name the name of the preference this field editor works on | |
476 * @param text the label text of the field editor | |
477 */ | |
478 protected void init(String name, String text) { | |
479 Assert.isNotNull(name); | |
480 Assert.isNotNull(text); | |
481 preferenceName = name; | |
482 this.labelText = text; | |
483 } | |
484 | |
485 /** | |
486 * Returns whether this field editor contains a valid value. | |
487 * <p> | |
488 * The default implementation of this framework method | |
489 * returns <code>true</code>. Subclasses wishing to perform | |
490 * validation should override both this method and | |
491 * <code>refreshValidState</code>. | |
492 * </p> | |
493 * | |
494 * @return <code>true</code> if the field value is valid, | |
495 * and <code>false</code> if invalid | |
496 * @see #refreshValidState() | |
497 */ | |
498 public bool isValid() { | |
499 return true; | |
500 } | |
501 | |
502 /** | |
503 * Initializes this field editor with the preference value from | |
504 * the preference store. | |
505 */ | |
506 public void load() { | |
507 if (preferenceStore !is null) { | |
508 isDefaultPresented = false; | |
509 doLoad(); | |
510 refreshValidState(); | |
511 } | |
512 } | |
513 | |
514 /** | |
515 * Initializes this field editor with the default preference value | |
516 * from the preference store. | |
517 */ | |
518 public void loadDefault() { | |
519 if (preferenceStore !is null) { | |
520 isDefaultPresented = true; | |
521 doLoadDefault(); | |
522 refreshValidState(); | |
523 } | |
524 } | |
525 | |
526 /** | |
527 * Returns whether this field editor currently presents the | |
528 * default value for its preference. | |
529 * | |
530 * @return <code>true</code> if the default value is presented, | |
531 * and <code>false</code> otherwise | |
532 */ | |
533 public bool presentsDefaultValue() { | |
534 return isDefaultPresented; | |
535 } | |
536 | |
537 /** | |
538 * Refreshes this field editor's valid state after a value change | |
539 * and fires an <code>IS_VALID</code> property change event if | |
540 * warranted. | |
541 * <p> | |
542 * The default implementation of this framework method does | |
543 * nothing. Subclasses wishing to perform validation should override | |
544 * both this method and <code>isValid</code>. | |
545 * </p> | |
546 * | |
547 * @see #isValid | |
548 */ | |
549 protected void refreshValidState() { | |
550 } | |
551 | |
552 /** | |
553 * Sets the focus to this field editor. | |
554 * <p> | |
555 * The default implementation of this framework method | |
556 * does nothing. Subclasses may reimplement. | |
557 * </p> | |
558 */ | |
559 public void setFocus() { | |
560 // do nothing; | |
561 } | |
562 | |
563 /** | |
564 * Sets this field editor's label text. | |
565 * The label is typically presented to the left of the entry field. | |
566 * | |
567 * @param text the label text | |
568 */ | |
569 public void setLabelText(String text) { | |
570 Assert.isNotNull(text); | |
571 labelText = text; | |
572 if (label !is null) { | |
573 label.setText(text); | |
574 } | |
575 } | |
576 | |
577 /** | |
578 * Sets the name of the preference this field editor operates on. | |
579 * <p> | |
580 * The ability to change this allows the same field editor object | |
581 * to be reused for different preferences. | |
582 * </p> | |
583 * <p> | |
584 * For example: <p> | |
585 * <pre> | |
586 * ... | |
587 * editor.setPreferenceName("font"); | |
588 * editor.load(); | |
589 * </pre> | |
590 * </p> | |
591 * | |
592 * @param name the name of the preference | |
593 */ | |
594 public void setPreferenceName(String name) { | |
595 preferenceName = name; | |
596 } | |
597 | |
598 /** | |
599 * Sets the preference page in which this field editor | |
600 * appears. | |
601 * | |
602 * @param preferencePage the preference page, or <code>null</code> if none | |
603 * @deprecated use #setPage(DialogPage) | |
604 */ | |
605 public void setPreferencePage(PreferencePage preferencePage) { | |
606 setPage(preferencePage); | |
607 } | |
608 | |
609 | |
610 /** | |
611 * Set the page to be the receiver. | |
612 * @param dialogPage | |
613 * | |
614 * @since 3.1 | |
615 */ | |
616 public void setPage(DialogPage dialogPage) { | |
617 page = dialogPage; | |
618 | |
619 } | |
620 | |
621 /** | |
622 * Sets the preference store used by this field editor. | |
623 * | |
624 * @param store the preference store, or <code>null</code> if none | |
625 * @see #getPreferenceStore | |
626 */ | |
627 public void setPreferenceStore(IPreferenceStore store) { | |
628 preferenceStore = store; | |
629 } | |
630 | |
631 /** | |
632 * Sets whether this field editor is presenting the default value. | |
633 * | |
634 * @param booleanValue <code>true</code> if the default value is being presented, | |
635 * and <code>false</code> otherwise | |
636 */ | |
637 protected void setPresentsDefaultValue(bool booleanValue) { | |
638 isDefaultPresented = booleanValue; | |
639 } | |
640 package void setPresentsDefaultValue_package(bool booleanValue) { | |
641 setPresentsDefaultValue(booleanValue); | |
642 } | |
643 | |
644 /** | |
645 * Sets or removes the property change listener for this field editor. | |
646 * <p> | |
647 * Note that field editors can support only a single listener. | |
648 * </p> | |
649 * | |
650 * @param listener a property change listener, or <code>null</code> | |
651 * to remove | |
652 */ | |
653 public void setPropertyChangeListener(IPropertyChangeListener listener) { | |
654 propertyChangeListener = listener; | |
655 } | |
656 | |
657 /** | |
658 * Shows the given error message in the page for this | |
659 * field editor if it has one. | |
660 * | |
661 * @param msg the error message | |
662 */ | |
663 protected void showErrorMessage(String msg) { | |
664 if (page !is null) { | |
665 page.setErrorMessage(msg); | |
666 } | |
667 } | |
668 | |
669 /** | |
670 * Shows the given message in the page for this | |
671 * field editor if it has one. | |
672 * | |
673 * @param msg the message | |
674 */ | |
675 protected void showMessage(String msg) { | |
676 if (page !is null) { | |
677 page.setErrorMessage(msg); | |
678 } | |
679 } | |
680 | |
681 /** | |
682 * Stores this field editor's value back into the preference store. | |
683 */ | |
684 public void store() { | |
685 if (preferenceStore is null) { | |
686 return; | |
687 } | |
688 | |
689 if (isDefaultPresented) { | |
690 preferenceStore.setToDefault(preferenceName); | |
691 } else { | |
692 doStore(); | |
693 } | |
694 } | |
695 | |
696 /** | |
697 * Set the GridData on button to be one that is spaced for the | |
698 * current font. | |
699 * @param button the button the data is being set on. | |
700 */ | |
701 | |
702 protected void setButtonLayoutData(Button button) { | |
703 | |
704 GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL); | |
705 | |
706 // Compute and store a font metric | |
707 GC gc = new GC(button); | |
708 gc.setFont(button.getFont()); | |
709 FontMetrics fontMetrics = gc.getFontMetrics(); | |
710 gc.dispose(); | |
711 | |
712 int widthHint = dwtx.jface.dialogs.Dialog.Dialog | |
713 .convertVerticalDLUsToPixels(fontMetrics, | |
714 IDialogConstants.BUTTON_WIDTH); | |
715 data.widthHint = Math.max(widthHint, button.computeSize(DWT.DEFAULT, | |
716 DWT.DEFAULT, true).x); | |
717 button.setLayoutData(data); | |
718 } | |
719 | |
720 /** | |
721 * Set whether or not the controls in the field editor | |
722 * are enabled. | |
723 * @param enabled The enabled state. | |
724 * @param parent The parent of the controls in the group. | |
725 * Used to create the controls if required. | |
726 */ | |
727 public void setEnabled(bool enabled, Composite parent) { | |
728 getLabelControl(parent).setEnabled(enabled); | |
729 } | |
730 | |
731 } |