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 }