comparison org.eclipse.jface/src/org/eclipse/jface/dialogs/Dialog.d @ 12:bc29606a740c

Added dwt-addons in original directory structure of eclipse.org
author Frank Benoit <benoit@tionex.de>
date Sat, 14 Mar 2009 18:23:29 +0100
parents
children 12b890a6392a
comparison
equal deleted inserted replaced
11:43904fec5dca 12:bc29606a740c
1 /*******************************************************************************
2 * Copyright (c) 2000, 2008 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 * Remy Chi Jian Suen <remy.suen@gmail.com> - Bug 218553 [JFace] mis-spelling of their in applyDialogFont(...)
11 * Port to the D programming language:
12 * Frank Benoit <benoit@tionex.de>
13 *******************************************************************************/
14 module org.eclipse.jface.dialogs.Dialog;
15
16 import org.eclipse.jface.dialogs.IDialogBlockedHandler;
17 import org.eclipse.jface.dialogs.IDialogSettings;
18 import org.eclipse.jface.dialogs.IDialogConstants;
19 // import tango.util.Arrays;
20
21 import org.eclipse.swt.SWT;
22 import org.eclipse.swt.events.SelectionAdapter;
23 import org.eclipse.swt.events.SelectionEvent;
24 import org.eclipse.swt.graphics.Font;
25 import org.eclipse.swt.graphics.FontData;
26 import org.eclipse.swt.graphics.FontMetrics;
27 import org.eclipse.swt.graphics.GC;
28 import org.eclipse.swt.graphics.Image;
29 import org.eclipse.swt.graphics.Point;
30 import org.eclipse.swt.layout.FormData;
31 import org.eclipse.swt.layout.GridData;
32 import org.eclipse.swt.layout.GridLayout;
33 import org.eclipse.swt.widgets.Button;
34 import org.eclipse.swt.widgets.Composite;
35 import org.eclipse.swt.widgets.Control;
36 import org.eclipse.swt.widgets.Display;
37 import org.eclipse.swt.widgets.Shell;
38 import org.eclipse.core.runtime.IProgressMonitor;
39 import org.eclipse.core.runtime.IStatus;
40 import org.eclipse.core.runtime.Status;
41 import org.eclipse.jface.resource.JFaceResources;
42 import org.eclipse.jface.util.Policy;
43 import org.eclipse.jface.window.IShellProvider;
44 import org.eclipse.jface.window.SameShellProvider;
45 import org.eclipse.jface.window.Window;
46
47 import java.lang.all;
48 import java.util.Arrays;
49 import java.util.Collection;
50 import java.util.Set;
51
52 /**
53 * A dialog is a specialized window used for narrow-focused communication with
54 * the user.
55 * <p>
56 * Dialogs are usually modal. Consequently, it is generally bad practice to open
57 * a dialog without a parent. A modal dialog without a parent is not prevented
58 * from disappearing behind the application's other windows, making it very
59 * confusing for the user.
60 * </p>
61 * <p>
62 * If there is more than one modal dialog is open the second one should be
63 * parented off of the shell of the first one otherwise it is possible that the
64 * OS will give focus to the first dialog potentially blocking the UI.
65 * </p>
66 */
67 public abstract class Dialog : Window {
68 /**
69 * Image registry key for error image (value
70 * <code>"dialog_error_image"</code>).
71 *
72 * @deprecated use
73 * org.eclipse.swt.widgets.Display.getSystemImage(SWT.ICON_ERROR)
74 */
75 public static const String DLG_IMG_ERROR = "dialog_error_image"; //$NON-NLS-1$
76
77 /**
78 * Image registry key for info image (value <code>"dialog_info_image"</code>).
79 *
80 * @deprecated use
81 * org.eclipse.swt.widgets.Display.getSystemImage(SWT.ICON_INFORMATION)
82 */
83 public static const String DLG_IMG_INFO = "dialog_info_imageg"; //$NON-NLS-1$
84
85 /**
86 * Image registry key for question image (value
87 * <code>"dialog_question_image"</code>).
88 *
89 * @deprecated org.eclipse.swt.widgets.Display.getSystemImage(SWT.ICON_QUESTION)
90 */
91 public static const String DLG_IMG_QUESTION = "dialog_question_image"; //$NON-NLS-1$
92
93 /**
94 * Image registry key for warning image (value
95 * <code>"dialog_warning_image"</code>).
96 *
97 * @deprecated use
98 * org.eclipse.swt.widgets.Display.getSystemImage(SWT.ICON_WARNING)
99 */
100 public static const String DLG_IMG_WARNING = "dialog_warning_image"; //$NON-NLS-1$
101
102 /**
103 * Image registry key for info message image (value
104 * <code>"dialog_messasge_info_image"</code>).
105 *
106 * @since 2.0
107 */
108 public static const String DLG_IMG_MESSAGE_INFO = "dialog_messasge_info_image"; //$NON-NLS-1$
109
110 /**
111 * Image registry key for info message image (value
112 * <code>"dialog_messasge_warning_image"</code>).
113 *
114 * @since 2.0
115 */
116 public static const String DLG_IMG_MESSAGE_WARNING = "dialog_messasge_warning_image"; //$NON-NLS-1$
117
118 /**
119 * Image registry key for info message image (value
120 * <code>"dialog_message_error_image"</code>).
121 *
122 * @since 2.0
123 */
124 public static const String DLG_IMG_MESSAGE_ERROR = "dialog_message_error_image"; //$NON-NLS-1$
125
126 /**
127 * Image registry key for help image (value
128 * <code>"dialog_help_image"</code>).
129 *
130 * @since 3.2
131 */
132 public static const String DLG_IMG_HELP = "dialog_help_image"; //$NON-NLS-1$
133
134 /**
135 * The ellipsis is the string that is used to represent shortened text.
136 *
137 * @since 3.0
138 */
139 public static const String ELLIPSIS = "..."; //$NON-NLS-1$
140
141 /**
142 * The dialog settings key name for stored dialog x location.
143 *
144 * @since 3.2
145 */
146 private static const String DIALOG_ORIGIN_X = "DIALOG_X_ORIGIN"; //$NON-NLS-1$
147
148 /**
149 * The dialog settings key name for stored dialog y location.
150 *
151 * @since 3.2
152 */
153 private static const String DIALOG_ORIGIN_Y = "DIALOG_Y_ORIGIN"; //$NON-NLS-1$
154
155 /**
156 * The dialog settings key name for stored dialog width.
157 *
158 * @since 3.2
159 */
160 private static const String DIALOG_WIDTH = "DIALOG_WIDTH"; //$NON-NLS-1$
161
162 /**
163 * The dialog settings key name for stored dialog height.
164 *
165 * @since 3.2
166 */
167 private static const String DIALOG_HEIGHT = "DIALOG_HEIGHT"; //$NON-NLS-1$
168
169 /**
170 * The dialog settings key name for the font used when the dialog
171 * height and width was stored.
172 *
173 *@since 3.2
174 */
175 private static const String DIALOG_FONT_DATA = "DIALOG_FONT_NAME"; //$NON-NLS-1$
176
177 /**
178 * A value that can be used for stored dialog width or height that
179 * indicates that the default bounds should be used.
180 *
181 * @since 3.2
182 */
183 public static const int DIALOG_DEFAULT_BOUNDS = -1;
184
185 /**
186 * Constants that can be used for specifying the strategy for persisting
187 * dialog bounds. These constants represent bit masks that can be used
188 * together.
189 *
190 *@since 3.2
191 */
192
193 /**
194 * Persist the last location of the dialog.
195 * @since 3.2
196 */
197 public static const int DIALOG_PERSISTLOCATION = 0x0001;
198 /**
199 * Persist the last known size of the dialog.
200 * @since 3.2
201 */
202 public static const int DIALOG_PERSISTSIZE = 0x0002;
203
204 /**
205 * The dialog area; <code>null</code> until dialog is layed out.
206 */
207 protected Control dialogArea;
208
209 /**
210 * The button bar; <code>null</code> until dialog is layed out.
211 */
212 public Control buttonBar;
213
214 /**
215 * Collection of buttons created by the <code>createButton</code> method.
216 */
217 private Button[int] buttons;
218
219 /**
220 * Font metrics to use for determining pixel sizes.
221 */
222 private FontMetrics fontMetrics;
223
224 /**
225 * Number of horizontal dialog units per character, value <code>4</code>.
226 */
227 private static const int HORIZONTAL_DIALOG_UNIT_PER_CHAR = 4;
228
229 /**
230 * Number of vertical dialog units per character, value <code>8</code>.
231 */
232 private static const int VERTICAL_DIALOG_UNITS_PER_CHAR = 8;
233
234 /**
235 * Returns the number of pixels corresponding to the height of the given
236 * number of characters.
237 * <p>
238 * The required <code>FontMetrics</code> parameter may be created in the
239 * following way: <code>
240 * GC gc = new GC(control);
241 * gc.setFont(control.getFont());
242 * fontMetrics = gc.getFontMetrics();
243 * gc.dispose();
244 * </code>
245 * </p>
246 *
247 * @param fontMetrics
248 * used in performing the conversion
249 * @param chars
250 * the number of characters
251 * @return the number of pixels
252 * @since 2.0
253 */
254 public static int convertHeightInCharsToPixels(FontMetrics fontMetrics,
255 int chars) {
256 return fontMetrics.getHeight() * chars;
257 }
258
259 /**
260 * Returns the number of pixels corresponding to the given number of
261 * horizontal dialog units.
262 * <p>
263 * The required <code>FontMetrics</code> parameter may be created in the
264 * following way: <code>
265 * GC gc = new GC(control);
266 * gc.setFont(control.getFont());
267 * fontMetrics = gc.getFontMetrics();
268 * gc.dispose();
269 * </code>
270 * </p>
271 *
272 * @param fontMetrics
273 * used in performing the conversion
274 * @param dlus
275 * the number of horizontal dialog units
276 * @return the number of pixels
277 * @since 2.0
278 */
279 public static int convertHorizontalDLUsToPixels(FontMetrics fontMetrics,
280 int dlus) {
281 // round to the nearest pixel
282 return (fontMetrics.getAverageCharWidth() * dlus + HORIZONTAL_DIALOG_UNIT_PER_CHAR / 2)
283 / HORIZONTAL_DIALOG_UNIT_PER_CHAR;
284 }
285
286 /**
287 * Returns the number of pixels corresponding to the given number of
288 * vertical dialog units.
289 * <p>
290 * The required <code>FontMetrics</code> parameter may be created in the
291 * following way: <code>
292 * GC gc = new GC(control);
293 * gc.setFont(control.getFont());
294 * fontMetrics = gc.getFontMetrics();
295 * gc.dispose();
296 * </code>
297 * </p>
298 *
299 * @param fontMetrics
300 * used in performing the conversion
301 * @param dlus
302 * the number of vertical dialog units
303 * @return the number of pixels
304 * @since 2.0
305 */
306 public static int convertVerticalDLUsToPixels(FontMetrics fontMetrics,
307 int dlus) {
308 // round to the nearest pixel
309 return (fontMetrics.getHeight() * dlus + VERTICAL_DIALOG_UNITS_PER_CHAR / 2)
310 / VERTICAL_DIALOG_UNITS_PER_CHAR;
311 }
312
313 /**
314 * Returns the number of pixels corresponding to the width of the given
315 * number of characters.
316 * <p>
317 * The required <code>FontMetrics</code> parameter may be created in the
318 * following way: <code>
319 * GC gc = new GC(control);
320 * gc.setFont(control.getFont());
321 * fontMetrics = gc.getFontMetrics();
322 * gc.dispose();
323 * </code>
324 * </p>
325 *
326 * @param fontMetrics
327 * used in performing the conversion
328 * @param chars
329 * the number of characters
330 * @return the number of pixels
331 * @since 2.0
332 */
333 public static int convertWidthInCharsToPixels(FontMetrics fontMetrics,
334 int chars) {
335 return fontMetrics.getAverageCharWidth() * chars;
336 }
337
338 /**
339 * Shortens the given text <code>textValue</code> so that its width in
340 * pixels does not exceed the width of the given control. Overrides
341 * characters in the center of the original string with an ellipsis ("...")
342 * if necessary. If a <code>null</code> value is given, <code>null</code>
343 * is returned.
344 *
345 * @param textValue
346 * the original string or <code>null</code>
347 * @param control
348 * the control the string will be displayed on
349 * @return the string to display, or <code>null</code> if null was passed
350 * in
351 *
352 * @since 3.0
353 */
354 public static String shortenText(String textValue, Control control) {
355 if (textValue is null) {
356 return null;
357 }
358 GC gc = new GC(control);
359 int maxWidth = control.getBounds().width - 5;
360 int maxExtent = gc.textExtent(textValue).x;
361 if (maxExtent < maxWidth) {
362 gc.dispose();
363 return textValue;
364 }
365 int length = textValue.length;
366 int charsToClip = cast(int) Math.round(0.95f*length * (1 - (cast(float)maxWidth/maxExtent)));
367 int pivot = length / 2;
368 int start = pivot - (charsToClip/2);
369 int end = pivot + (charsToClip/2) + 1;
370 while (start >= 0 && end < length) {
371 String s1 = textValue.substring(0, start);
372 String s2 = textValue.substring(end, length);
373 String s = s1 ~ ELLIPSIS ~ s2;
374 int l = gc.textExtent(s).x;
375 if (l < maxWidth) {
376 gc.dispose();
377 return s;
378 }
379 start--;
380 end++;
381 }
382 gc.dispose();
383 return textValue;
384 }
385
386 /**
387 * Create a default instance of the blocked handler which does not do
388 * anything.
389 */
390 private static IDialogBlockedHandler blockedHandler_;
391 public static IDialogBlockedHandler blockedHandler(){
392 static_this_blockedhandler();
393 return blockedHandler_;
394 }
395 public static IDialogBlockedHandler blockedHandler( IDialogBlockedHandler b ){
396 static_this_blockedhandler();
397 return ( blockedHandler_ = b );
398 }
399 private static bool static_this_blockedhandler_completed = false;
400 private static void static_this_blockedhandler(){
401 if( static_this_blockedhandler_completed ){
402 return;
403 }
404 synchronized{
405 if( static_this_blockedhandler_completed ){
406 return;
407 }
408 blockedHandler_ = new class IDialogBlockedHandler {
409 /*
410 * (non-Javadoc)
411 *
412 * @see org.eclipse.jface.dialogs.IDialogBlockedHandler#clearBlocked()
413 */
414 public void clearBlocked() {
415 // No default behaviour
416 }
417
418 /*
419 * (non-Javadoc)
420 *
421 * @see org.eclipse.jface.dialogs.IDialogBlockedHandler#showBlocked(org.eclipse.core.runtime.IProgressMonitor,
422 * org.eclipse.core.runtime.IStatus, java.lang.String)
423 */
424 public void showBlocked(IProgressMonitor blocking,
425 IStatus blockingStatus, String blockedName) {
426 // No default behaviour
427 }
428
429 /*
430 * (non-Javadoc)
431 *
432 * @see org.eclipse.jface.dialogs.IDialogBlockedHandler#showBlocked(org.eclipse.swt.widgets.Shell,
433 * org.eclipse.core.runtime.IProgressMonitor,
434 * org.eclipse.core.runtime.IStatus, java.lang.String)
435 */
436 public void showBlocked(Shell parentShell, IProgressMonitor blocking,
437 IStatus blockingStatus, String blockedName) {
438 // No default behaviour
439 }
440 };
441 static_this_blockedhandler_completed = true;
442 }
443 }
444
445 /**
446 * Creates a dialog instance. Note that the window will have no visual
447 * representation (no widgets) until it is told to open. By default,
448 * <code>open</code> blocks for dialogs.
449 *
450 * @param parentShell
451 * the parent shell, or <code>null</code> to create a top-level
452 * shell
453 */
454 protected this(Shell parentShell) {
455 this(new SameShellProvider(parentShell));
456 if (parentShell is null && Policy.DEBUG_DIALOG_NO_PARENT) {
457 Policy.getLog().log(
458 new Status(IStatus.INFO, Policy.JFACE, IStatus.INFO, this
459 .classinfo.name
460 ~ " created with no shell",//$NON-NLS-1$
461 new Exception( null, null )));
462 }
463 }
464
465 /**
466 * Creates a dialog with the given parent.
467 *
468 * @param parentShell
469 * object that returns the current parent shell
470 *
471 * @since 3.1
472 */
473 protected this(IShellProvider parentShell) {
474 super(parentShell);
475 if (isResizable()) {
476 setShellStyle(SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | SWT.MAX | SWT.RESIZE
477 | getDefaultOrientation());
478 } else {
479 setShellStyle(SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL
480 | getDefaultOrientation());
481 }
482 setBlockOnOpen(true);
483 }
484
485 /**
486 * Notifies that this dialog's button with the given id has been pressed.
487 * <p>
488 * The <code>Dialog</code> implementation of this framework method calls
489 * <code>okPressed</code> if the ok button is the pressed, and
490 * <code>cancelPressed</code> if the cancel button is the pressed. All
491 * other button presses are ignored. Subclasses may override to handle other
492 * buttons, but should call <code>super.buttonPressed</code> if the
493 * default handling of the ok and cancel buttons is desired.
494 * </p>
495 *
496 * @param buttonId
497 * the id of the button that was pressed (see
498 * <code>IDialogConstants.*_ID</code> constants)
499 */
500 protected void buttonPressed(int buttonId) {
501 if (IDialogConstants.OK_ID is buttonId) {
502 okPressed();
503 } else if (IDialogConstants.CANCEL_ID is buttonId) {
504 cancelPressed();
505 }
506 }
507
508 /**
509 * Notifies that the cancel button of this dialog has been pressed.
510 * <p>
511 * The <code>Dialog</code> implementation of this framework method sets
512 * this dialog's return code to <code>Window.CANCEL</code> and closes the
513 * dialog. Subclasses may override if desired.
514 * </p>
515 */
516 protected void cancelPressed() {
517 setReturnCode(CANCEL);
518 close();
519 }
520
521 /**
522 * Returns the number of pixels corresponding to the height of the given
523 * number of characters.
524 * <p>
525 * This method may only be called after <code>initializeDialogUnits</code>
526 * has been called.
527 * </p>
528 * <p>
529 * Clients may call this framework method, but should not override it.
530 * </p>
531 *
532 * @param chars
533 * the number of characters
534 * @return the number of pixels
535 */
536 protected int convertHeightInCharsToPixels(int chars) {
537 // test for failure to initialize for backward compatibility
538 if (fontMetrics is null) {
539 return 0;
540 }
541 return convertHeightInCharsToPixels(fontMetrics, chars);
542 }
543
544 /**
545 * Returns the number of pixels corresponding to the given number of
546 * horizontal dialog units.
547 * <p>
548 * This method may only be called after <code>initializeDialogUnits</code>
549 * has been called.
550 * </p>
551 * <p>
552 * Clients may call this framework method, but should not override it.
553 * </p>
554 *
555 * @param dlus
556 * the number of horizontal dialog units
557 * @return the number of pixels
558 */
559 protected int convertHorizontalDLUsToPixels(int dlus) {
560 // test for failure to initialize for backward compatibility
561 if (fontMetrics is null) {
562 return 0;
563 }
564 return convertHorizontalDLUsToPixels(fontMetrics, dlus);
565 }
566
567 /**
568 * Returns the number of pixels corresponding to the given number of
569 * vertical dialog units.
570 * <p>
571 * This method may only be called after <code>initializeDialogUnits</code>
572 * has been called.
573 * </p>
574 * <p>
575 * Clients may call this framework method, but should not override it.
576 * </p>
577 *
578 * @param dlus
579 * the number of vertical dialog units
580 * @return the number of pixels
581 */
582 protected int convertVerticalDLUsToPixels(int dlus) {
583 // test for failure to initialize for backward compatibility
584 if (fontMetrics is null) {
585 return 0;
586 }
587 return convertVerticalDLUsToPixels(fontMetrics, dlus);
588 }
589
590 /**
591 * Returns the number of pixels corresponding to the width of the given
592 * number of characters.
593 * <p>
594 * This method may only be called after <code>initializeDialogUnits</code>
595 * has been called.
596 * </p>
597 * <p>
598 * Clients may call this framework method, but should not override it.
599 * </p>
600 *
601 * @param chars
602 * the number of characters
603 * @return the number of pixels
604 */
605 protected int convertWidthInCharsToPixels(int chars) {
606 // test for failure to initialize for backward compatibility
607 if (fontMetrics is null) {
608 return 0;
609 }
610 return convertWidthInCharsToPixels(fontMetrics, chars);
611 }
612
613 /**
614 * Creates a new button with the given id.
615 * <p>
616 * The <code>Dialog</code> implementation of this framework method creates
617 * a standard push button, registers it for selection events including
618 * button presses, and registers default buttons with its shell. The button
619 * id is stored as the button's client data. If the button id is
620 * <code>IDialogConstants.CANCEL_ID</code>, the new button will be
621 * accessible from <code>getCancelButton()</code>. If the button id is
622 * <code>IDialogConstants.OK_ID</code>, the new button will be accesible
623 * from <code>getOKButton()</code>. Note that the parent's layout is
624 * assumed to be a <code>GridLayout</code> and the number of columns in
625 * this layout is incremented. Subclasses may override.
626 * </p>
627 *
628 * @param parent
629 * the parent composite
630 * @param id
631 * the id of the button (see <code>IDialogConstants.*_ID</code>
632 * constants for standard dialog button ids)
633 * @param label
634 * the label from the button
635 * @param defaultButton
636 * <code>true</code> if the button is to be the default button,
637 * and <code>false</code> otherwise
638 *
639 * @return the new button
640 *
641 * @see #getCancelButton
642 * @see #getOKButton()
643 */
644 protected Button createButton(Composite parent, int id, String label,
645 bool defaultButton) {
646 // increment the number of columns in the button bar
647 (cast(GridLayout) parent.getLayout()).numColumns++;
648 Button button = new Button(parent, SWT.PUSH);
649 button.setText(label);
650 button.setFont(JFaceResources.getDialogFont());
651 button.setData(new ValueWrapperInt(id));
652 button.addSelectionListener(new class SelectionAdapter {
653 public void widgetSelected(SelectionEvent event) {
654 buttonPressed((cast(ValueWrapperInt) event.widget.getData()).value);
655 }
656 });
657 if (defaultButton) {
658 Shell shell = parent.getShell();
659 if (shell !is null) {
660 shell.setDefaultButton(button);
661 }
662 }
663 buttons[id] = button;
664 setButtonLayoutData(button);
665 return button;
666 }
667
668 /**
669 * Creates and returns the contents of this dialog's button bar.
670 * <p>
671 * The <code>Dialog</code> implementation of this framework method lays
672 * out a button bar and calls the <code>createButtonsForButtonBar</code>
673 * framework method to populate it. Subclasses may override.
674 * </p>
675 * <p>
676 * The returned control's layout data must be an instance of
677 * <code>GridData</code>.
678 * </p>
679 *
680 * @param parent
681 * the parent composite to contain the button bar
682 * @return the button bar control
683 */
684 protected Control createButtonBar(Composite parent) {
685 Composite composite = new Composite(parent, SWT.NONE);
686 // create a layout with spacing and margins appropriate for the font
687 // size.
688 GridLayout layout = new GridLayout();
689 layout.numColumns = 0; // this is incremented by createButton
690 layout.makeColumnsEqualWidth = true;
691 layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
692 layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
693 layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
694 layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
695 composite.setLayout(layout);
696 GridData data = new GridData(GridData.HORIZONTAL_ALIGN_END
697 | GridData.VERTICAL_ALIGN_CENTER);
698 composite.setLayoutData(data);
699 composite.setFont(parent.getFont());
700
701 // Add the buttons to the button bar.
702 createButtonsForButtonBar(composite);
703 return composite;
704 }
705
706 /**
707 * Adds buttons to this dialog's button bar.
708 * <p>
709 * The <code>Dialog</code> implementation of this framework method adds
710 * standard ok and cancel buttons using the <code>createButton</code>
711 * framework method. These standard buttons will be accessible from
712 * <code>getCancelButton</code>, and <code>getOKButton</code>.
713 * Subclasses may override.
714 * </p>
715 *
716 * @param parent
717 * the button bar composite
718 */
719 protected void createButtonsForButtonBar(Composite parent) {
720 // create OK and Cancel buttons by default
721 createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL,
722 true);
723 createButton(parent, IDialogConstants.CANCEL_ID,
724 IDialogConstants.CANCEL_LABEL, false);
725 }
726
727 /*
728 * @see Window.initializeBounds()
729 */
730 protected override void initializeBounds() {
731 String platform = SWT.getPlatform();
732 if ("carbon".equals(platform)) { //$NON-NLS-1$
733 // On Mac OS X the default button must be the right-most button
734 Shell shell = getShell();
735 if (shell !is null) {
736 Button defaultButton = shell.getDefaultButton();
737 if (defaultButton !is null
738 && isContained(buttonBar, defaultButton)) {
739 defaultButton.moveBelow(null);
740 }
741 }
742 }
743
744 super.initializeBounds();
745 }
746
747 /**
748 * Returns true if the given Control is a direct or indirect child of
749 * container.
750 *
751 * @param container
752 * the potential parent
753 * @param control
754 * @return bool <code>true</code> if control is a child of container
755 */
756 private bool isContained(Control container, Control control) {
757 Composite parent;
758 while ((parent = control.getParent()) !is null) {
759 if (parent is container) {
760 return true;
761 }
762 control = parent;
763 }
764 return false;
765 }
766
767 /**
768 * The <code>Dialog</code> implementation of this <code>Window</code>
769 * method creates and lays out the top level composite for the dialog, and
770 * determines the appropriate horizontal and vertical dialog units based on
771 * the font size. It then calls the <code>createDialogArea</code> and
772 * <code>createButtonBar</code> methods to create the dialog area and
773 * button bar, respectively. Overriding <code>createDialogArea</code> and
774 * <code>createButtonBar</code> are recommended rather than overriding
775 * this method.
776 */
777 protected override Control createContents(Composite parent) {
778 // create the top level composite for the dialog
779 Composite composite = new Composite(parent, 0);
780 GridLayout layout = new GridLayout();
781 layout.marginHeight = 0;
782 layout.marginWidth = 0;
783 layout.verticalSpacing = 0;
784 composite.setLayout(layout);
785 composite.setLayoutData(new GridData(GridData.FILL_BOTH));
786 applyDialogFont(composite);
787 // initialize the dialog units
788 initializeDialogUnits(composite);
789 // create the dialog area and button bar
790 dialogArea = createDialogArea(composite);
791 buttonBar = createButtonBar(composite);
792
793 return composite;
794 }
795
796 /**
797 * Creates and returns the contents of the upper part of this dialog (above
798 * the button bar).
799 * <p>
800 * The <code>Dialog</code> implementation of this framework method creates
801 * and returns a new <code>Composite</code> with standard margins and
802 * spacing.
803 * </p>
804 * <p>
805 * The returned control's layout data must be an instance of
806 * <code>GridData</code>. This method must not modify the parent's
807 * layout.
808 * </p>
809 * <p>
810 * Subclasses must override this method but may call <code>super</code> as
811 * in the following example:
812 * </p>
813 *
814 * <pre>
815 * Composite composite = (Composite) super.createDialogArea(parent);
816 * //add controls to composite as necessary
817 * return composite;
818 * </pre>
819 *
820 * @param parent
821 * the parent composite to contain the dialog area
822 * @return the dialog area control
823 */
824 protected Control createDialogArea(Composite parent) {
825 // create a composite with standard margins and spacing
826 Composite composite = new Composite(parent, SWT.NONE);
827 GridLayout layout = new GridLayout();
828 layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
829 layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
830 layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
831 layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
832 composite.setLayout(layout);
833 composite.setLayoutData(new GridData(GridData.FILL_BOTH));
834 applyDialogFont(composite);
835 return composite;
836 }
837
838 /**
839 * Returns the button created by the method <code>createButton</code> for
840 * the specified ID as defined on <code>IDialogConstants</code>. If
841 * <code>createButton</code> was never called with this ID, or if
842 * <code>createButton</code> is overridden, this method will return
843 * <code>null</code>.
844 *
845 * @param id
846 * the id of the button to look for
847 *
848 * @return the button for the ID or <code>null</code>
849 *
850 * @see #createButton(Composite, int, String, bool)
851 * @since 2.0
852 */
853 protected Button getButton(int id) {
854 if( auto btn = id in buttons ){
855 return *btn;
856 }
857 return null;
858 }
859
860 /**
861 * Returns the button bar control.
862 * <p>
863 * Clients may call this framework method, but should not override it.
864 * </p>
865 *
866 * @return the button bar, or <code>null</code> if the button bar has not
867 * been created yet
868 */
869 protected Control getButtonBar() {
870 return buttonBar;
871 }
872
873 /**
874 * Returns the button created when <code>createButton</code> is called
875 * with an ID of <code>IDialogConstants.CANCEL_ID</code>. If
876 * <code>createButton</code> was never called with this parameter, or if
877 * <code>createButton</code> is overridden, <code>getCancelButton</code>
878 * will return <code>null</code>.
879 *
880 * @return the cancel button or <code>null</code>
881 *
882 * @see #createButton(Composite, int, String, bool)
883 * @since 2.0
884 * @deprecated Use <code>getButton(IDialogConstants.CANCEL_ID)</code>
885 * instead. This method will be removed soon.
886 */
887 protected Button getCancelButton() {
888 return getButton(IDialogConstants.CANCEL_ID);
889 }
890
891 /**
892 * Returns the dialog area control.
893 * <p>
894 * Clients may call this framework method, but should not override it.
895 * </p>
896 *
897 * @return the dialog area, or <code>null</code> if the dialog area has
898 * not been created yet
899 */
900 protected Control getDialogArea() {
901 return dialogArea;
902 }
903
904 /**
905 * Returns the standard dialog image with the given key. Note that these
906 * images are managed by the dialog framework, and must not be disposed by
907 * another party.
908 *
909 * @param key
910 * one of the <code>Dialog.DLG_IMG_* </code> constants
911 * @return the standard dialog image
912 *
913 * NOTE: Dialog does not use the following images in the registry
914 * DLG_IMG_ERROR DLG_IMG_INFO DLG_IMG_QUESTION DLG_IMG_WARNING
915 *
916 * They are now coming directly from SWT, see ImageRegistry. For backwards
917 * compatibility they are still supported, however new code should use SWT
918 * for these.
919 *
920 * @see Display#getSystemImage(int)
921 */
922 public static Image getImage(String key) {
923 return JFaceResources.getImageRegistry().get(key);
924 }
925
926 /**
927 * Returns the button created when <code>createButton</code> is called
928 * with an ID of <code>IDialogConstants.OK_ID</code>. If
929 * <code>createButton</code> was never called with this parameter, or if
930 * <code>createButton</code> is overridden, <code>getOKButton</code>
931 * will return <code>null</code>.
932 *
933 * @return the OK button or <code>null</code>
934 *
935 * @see #createButton(Composite, int, String, bool)
936 * @since 2.0
937 * @deprecated Use <code>getButton(IDialogConstants.OK_ID)</code> instead.
938 * This method will be removed soon.
939 */
940 protected Button getOKButton() {
941 return getButton(IDialogConstants.OK_ID);
942 }
943
944 /**
945 * Initializes the computation of horizontal and vertical dialog units based
946 * on the size of current font.
947 * <p>
948 * This method must be called before any of the dialog unit based conversion
949 * methods are called.
950 * </p>
951 *
952 * @param control
953 * a control from which to obtain the current font
954 */
955 protected void initializeDialogUnits(Control control) {
956 // Compute and store a font metric
957 GC gc = new GC(control);
958 gc.setFont(JFaceResources.getDialogFont());
959 fontMetrics = gc.getFontMetrics();
960 gc.dispose();
961 }
962
963 /**
964 * Notifies that the ok button of this dialog has been pressed.
965 * <p>
966 * The <code>Dialog</code> implementation of this framework method sets
967 * this dialog's return code to <code>Window.OK</code> and closes the
968 * dialog. Subclasses may override.
969 * </p>
970 */
971 protected void okPressed() {
972 setReturnCode(OK);
973 close();
974 }
975
976 /**
977 * Set the layout data of the button to a GridData with appropriate heights
978 * and widths.
979 *
980 * @param button
981 */
982 protected void setButtonLayoutData(Button button) {
983 GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
984 int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
985 Point minSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
986 data.widthHint = Math.max(widthHint, minSize.x);
987 button.setLayoutData(data);
988 }
989
990 /**
991 * Set the layout data of the button to a FormData with appropriate heights
992 * and widths.
993 *
994 * @param button
995 */
996 protected void setButtonLayoutFormData(Button button) {
997 FormData data = new FormData();
998 int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
999 Point minSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
1000 data.width = Math.max(widthHint, minSize.x);
1001 button.setLayoutData(data);
1002 }
1003
1004 /**
1005 * @see org.eclipse.jface.window.Window#close()
1006 */
1007 public override bool close() {
1008 if (getShell() !is null && !getShell().isDisposed()) {
1009 saveDialogBounds(getShell());
1010 }
1011
1012 bool returnValue = super.close();
1013 if (returnValue) {
1014 buttons = null;
1015 buttonBar = null;
1016 dialogArea = null;
1017 }
1018 return returnValue;
1019 }
1020
1021 /**
1022 * Applies the dialog font to all controls that currently have the default
1023 * font.
1024 *
1025 * @param control
1026 * the control to apply the font to. Font will also be applied to
1027 * its children. If the control is <code>null</code> nothing
1028 * happens.
1029 */
1030 public static void applyDialogFont(Control control) {
1031 if (control is null || dialogFontIsDefault()) {
1032 return;
1033 }
1034 Font dialogFont = JFaceResources.getDialogFont();
1035 applyDialogFont(control, dialogFont);
1036 }
1037
1038 /**
1039 * Sets the dialog font on the control and any of its children if their font
1040 * is not otherwise set.
1041 *
1042 * @param control
1043 * the control to apply the font to. Font will also be applied to
1044 * its children.
1045 * @param dialogFont
1046 * the dialog font to set
1047 */
1048 private static void applyDialogFont(Control control, Font dialogFont) {
1049 if (hasDefaultFont(control)) {
1050 control.setFont(dialogFont);
1051 }
1052 if ( auto comp = cast(Composite)control ) {
1053 Control[] children = comp.getChildren();
1054 for (int i = 0; i < children.length; i++) {
1055 applyDialogFont(children[i], dialogFont);
1056 }
1057 }
1058 }
1059
1060 /**
1061 * Return whether or not this control has the same font as it's default.
1062 *
1063 * @param control
1064 * Control
1065 * @return bool
1066 */
1067 private static bool hasDefaultFont(Control control) {
1068 FontData[] controlFontData = control.getFont().getFontData();
1069 FontData[] defaultFontData = getDefaultFont(control).getFontData();
1070 if (controlFontData.length is defaultFontData.length) {
1071 for (int i = 0; i < controlFontData.length; i++) {
1072 if (controlFontData[i].opEquals(defaultFontData[i])) {
1073 continue;
1074 }
1075 return false;
1076 }
1077 return true;
1078 }
1079 return false;
1080 }
1081
1082 /**
1083 * Get the default font for this type of control.
1084 *
1085 * @param control
1086 * @return the default font
1087 */
1088 private static Font getDefaultFont(Control control) {
1089 String fontName = "DEFAULT_FONT_" ~ control.classinfo.name; //$NON-NLS-1$
1090 if (JFaceResources.getFontRegistry().hasValueFor(fontName)) {
1091 return JFaceResources.getFontRegistry().get(fontName);
1092 }
1093 Font cached = control.getFont();
1094 control.setFont(null);
1095 Font defaultFont = control.getFont();
1096 control.setFont(cached);
1097 JFaceResources.getFontRegistry().put(fontName,
1098 defaultFont.getFontData());
1099 return defaultFont;
1100 }
1101
1102 /**
1103 * Return whether or not the dialog font is currently the same as the
1104 * default font.
1105 *
1106 * @return bool if the two are the same
1107 */
1108 protected static bool dialogFontIsDefault() {
1109 FontData[] dialogFontData = JFaceResources.getFontRegistry()
1110 .getFontData(JFaceResources.DIALOG_FONT);
1111 FontData[] defaultFontData = JFaceResources.getFontRegistry()
1112 .getFontData(JFaceResources.DEFAULT_FONT);
1113 return ArrayEquals(dialogFontData, defaultFontData);
1114 }
1115
1116 /*
1117 * (non-Javadoc)
1118 *
1119 * @see org.eclipse.jface.window.Window#create()
1120 */
1121 public override void create() {
1122 super.create();
1123 applyDialogFont(buttonBar);
1124 }
1125
1126 /**
1127 * Get the IDialogBlockedHandler to be used by WizardDialogs and
1128 * ModalContexts.
1129 *
1130 * @return Returns the blockedHandler.
1131 */
1132 public static IDialogBlockedHandler getBlockedHandler() {
1133 return blockedHandler;
1134 }
1135
1136 /**
1137 * Set the IDialogBlockedHandler to be used by WizardDialogs and
1138 * ModalContexts.
1139 *
1140 * @param blockedHandler
1141 * The blockedHandler for the dialogs.
1142 */
1143 public static void setBlockedHandler(IDialogBlockedHandler blockedHandler) {
1144 Dialog.blockedHandler = blockedHandler;
1145 }
1146
1147 /**
1148 * Gets the dialog settings that should be used for remembering the bounds of
1149 * of the dialog, according to the dialog bounds strategy.
1150 *
1151 * @return settings the dialog settings used to store the dialog's location
1152 * and/or size, or <code>null</code> if the dialog's bounds should
1153 * never be stored.
1154 *
1155 * @since 3.2
1156 * @see Dialog#getDialogBoundsStrategy()
1157 */
1158 protected IDialogSettings getDialogBoundsSettings() {
1159 return null;
1160 }
1161
1162 /**
1163 * Get the integer constant that describes the strategy for persisting the
1164 * dialog bounds. This strategy is ignored if the implementer does not also
1165 * specify the dialog settings for storing the bounds in
1166 * Dialog.getDialogBoundsSettings().
1167 *
1168 * @return the constant describing the strategy for persisting the dialog
1169 * bounds.
1170 *
1171 * @since 3.2
1172 * @see Dialog#DIALOG_PERSISTLOCATION
1173 * @see Dialog#DIALOG_PERSISTSIZE
1174 * @see Dialog#getDialogBoundsSettings()
1175 */
1176 protected int getDialogBoundsStrategy() {
1177 return DIALOG_PERSISTLOCATION | DIALOG_PERSISTSIZE;
1178 }
1179
1180 /**
1181 * Saves the bounds of the shell in the appropriate dialog settings. The
1182 * bounds are recorded relative to the parent shell, if there is one, or
1183 * display coordinates if there is no parent shell.
1184 *
1185 * @param shell
1186 * The shell whose bounds are to be stored
1187 *
1188 * @since 3.2
1189 */
1190 private void saveDialogBounds(Shell shell) {
1191 IDialogSettings settings = getDialogBoundsSettings();
1192 if (settings !is null) {
1193 Point shellLocation = shell.getLocation();
1194 Point shellSize = shell.getSize();
1195 Shell parent = getParentShell();
1196 if (parent !is null) {
1197 Point parentLocation = parent.getLocation();
1198 shellLocation.x -= parentLocation.x;
1199 shellLocation.y -= parentLocation.y;
1200 }
1201 int strategy = getDialogBoundsStrategy();
1202 if ((strategy & DIALOG_PERSISTLOCATION) !is 0) {
1203 settings.put(DIALOG_ORIGIN_X, shellLocation.x);
1204 settings.put(DIALOG_ORIGIN_Y, shellLocation.y);
1205 }
1206 if ((strategy & DIALOG_PERSISTSIZE) !is 0) {
1207 settings.put(DIALOG_WIDTH, shellSize.x);
1208 settings.put(DIALOG_HEIGHT, shellSize.y);
1209 FontData [] fontDatas = JFaceResources.getDialogFont().getFontData();
1210 if (fontDatas.length > 0) {
1211 settings.put(DIALOG_FONT_DATA, fontDatas[0].toString());
1212 }
1213 }
1214 }
1215 }
1216
1217 /**
1218 * Returns the initial size to use for the shell. Overridden
1219 * to check whether a size has been stored in dialog settings.
1220 * If a size has been stored, it is returned.
1221 *
1222 * @return the initial size of the shell
1223 *
1224 * @since 3.2
1225 * @see #getDialogBoundsSettings()
1226 * @see #getDialogBoundsStrategy()
1227 */
1228 protected override Point getInitialSize() {
1229 Point result = super.getInitialSize();
1230
1231 // Check the dialog settings for a stored size.
1232 if ((getDialogBoundsStrategy() & DIALOG_PERSISTSIZE)!is 0) {
1233 IDialogSettings settings = getDialogBoundsSettings();
1234 if (settings !is null) {
1235 // Check that the dialog font matches the font used
1236 // when the bounds was stored. If the font has changed,
1237 // we do not honor the stored settings.
1238 // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=132821
1239 bool useStoredBounds = true;
1240 String previousDialogFontData = settings.get(DIALOG_FONT_DATA);
1241 // There is a previously stored font, so we will check it.
1242 // Note that if we haven't stored the font before, then we will
1243 // use the stored bounds. This allows restoring of dialog bounds
1244 // that were stored before we started storing the fontdata.
1245 if (previousDialogFontData !is null && previousDialogFontData.length > 0) {
1246 FontData [] fontDatas = JFaceResources.getDialogFont().getFontData();
1247 if (fontDatas.length > 0) {
1248 String currentDialogFontData = fontDatas[0].toString();
1249 useStoredBounds = currentDialogFontData.equalsIgnoreCase(previousDialogFontData);
1250 }
1251 }
1252 if (useStoredBounds) {
1253 try {
1254 // Get the stored width and height.
1255 int width = settings.getInt(DIALOG_WIDTH);
1256 if (width !is DIALOG_DEFAULT_BOUNDS) {
1257 result.x = width;
1258 }
1259 int height = settings.getInt(DIALOG_HEIGHT);
1260 if (height !is DIALOG_DEFAULT_BOUNDS) {
1261 result.y = height;
1262 }
1263
1264 } catch (NumberFormatException e) {
1265 }
1266 }
1267 }
1268 }
1269 // No attempt is made to constrain the bounds. The default
1270 // constraining behavior in Window will be used.
1271 return result;
1272 }
1273
1274 /**
1275 * Returns the initial location to use for the shell. Overridden
1276 * to check whether the bounds of the dialog have been stored in
1277 * dialog settings. If a location has been stored, it is returned.
1278 *
1279 * @param initialSize
1280 * the initial size of the shell, as returned by
1281 * <code>getInitialSize</code>.
1282 * @return the initial location of the shell
1283 *
1284 * @since 3.2
1285 * @see #getDialogBoundsSettings()
1286 * @see #getDialogBoundsStrategy()
1287 */
1288 protected override Point getInitialLocation(Point initialSize) {
1289 Point result = super.getInitialLocation(initialSize);
1290 if ((getDialogBoundsStrategy() & DIALOG_PERSISTLOCATION)!is 0) {
1291 IDialogSettings settings = getDialogBoundsSettings();
1292 if (settings !is null) {
1293 try {
1294 int x = settings.getInt(DIALOG_ORIGIN_X);
1295 int y = settings.getInt(DIALOG_ORIGIN_Y);
1296 result = new Point(x, y);
1297 // The coordinates were stored relative to the parent shell.
1298 // Convert to display coordinates.
1299 Shell parent = getParentShell();
1300 if (parent !is null) {
1301 Point parentLocation = parent.getLocation();
1302 result.x += parentLocation.x;
1303 result.y += parentLocation.y;
1304 }
1305 } catch (NumberFormatException e) {
1306 }
1307 }
1308 }
1309 // No attempt is made to constrain the bounds. The default
1310 // constraining behavior in Window will be used.
1311 return result;
1312 }
1313
1314 /**
1315 * Returns a bool indicating whether the dialog should be
1316 * considered resizable when the shell style is initially
1317 * set.
1318 *
1319 * This method is used to ensure that all style
1320 * bits appropriate for resizable dialogs are added to the
1321 * shell style. Individual dialogs may always set the shell
1322 * style to ensure that a dialog is resizable, but using this
1323 * method ensures that resizable dialogs will be created with
1324 * the same set of style bits.
1325 *
1326 * Style bits will never be removed based on the return value
1327 * of this method. For example, if a dialog returns
1328 * <code>false</code>, but also sets a style bit for a
1329 * SWT.RESIZE border, the style bit will be honored.
1330 *
1331 * @return a bool indicating whether the dialog is
1332 * resizable and should have the default style bits for
1333 * resizable dialogs
1334 *
1335 * @since 3.4
1336 */
1337 protected bool isResizable() {
1338 return false;
1339 }
1340 }