Mercurial > projects > dwt-addons
annotate dwtx/jface/dialogs/ProgressMonitorDialog.d @ 43:ea8ff534f622
Fix override and super aliases
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Fri, 11 Apr 2008 01:24:25 +0200 |
parents | 1451821c3e00 |
children | 46a6e0e6ccd4 |
rev | line source |
---|---|
23 | 1 /******************************************************************************* |
2 * Copyright (c) 2000, 2007 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.dialogs.ProgressMonitorDialog; | |
14 | |
15 import dwtx.jface.dialogs.IconAndMessageDialog; | |
16 import dwtx.jface.dialogs.IDialogConstants; | |
17 import dwtx.jface.dialogs.ProgressIndicator; | |
18 | |
19 // import java.lang.reflect.InvocationTargetException; | |
20 | |
21 import dwt.DWT; | |
22 import dwt.graphics.Cursor; | |
23 import dwt.graphics.Image; | |
24 import dwt.graphics.Point; | |
25 import dwt.layout.GridData; | |
26 import dwt.widgets.Button; | |
27 import dwt.widgets.Composite; | |
28 import dwt.widgets.Control; | |
29 import dwt.widgets.Event; | |
30 import dwt.widgets.Label; | |
31 import dwt.widgets.Listener; | |
32 import dwt.widgets.Shell; | |
33 import dwtx.core.runtime.IProgressMonitor; | |
34 import dwtx.core.runtime.IProgressMonitorWithBlocking; | |
35 import dwtx.core.runtime.IStatus; | |
36 import dwtx.jface.operation.IRunnableContext; | |
37 import dwtx.jface.operation.IRunnableWithProgress; | |
38 import dwtx.jface.operation.ModalContext; | |
39 import dwtx.jface.resource.JFaceResources; | |
40 | |
41 import dwt.dwthelper.utils; | |
42 import dwt.dwthelper.Runnable; | |
43 | |
44 /** | |
45 * A modal dialog that displays progress during a long running operation. | |
46 * <p> | |
47 * This concrete dialog class can be instantiated as is, or further subclassed | |
48 * as required. | |
49 * </p> | |
50 * <p> | |
51 * Typical usage is: | |
52 * | |
53 * <pre> | |
54 * | |
55 * | |
56 * try { | |
57 * IRunnableWithProgress op = ...; | |
58 * new ProgressMonitorDialog(activeShell).run(true, true, op); | |
59 * } catch (InvocationTargetException e) { | |
60 * // handle exception | |
61 * } catch (InterruptedException e) { | |
62 * // handle cancelation | |
63 * } | |
64 * | |
65 * | |
66 * </pre> | |
67 * | |
68 * </p> | |
69 * <p> | |
70 * Note that the ProgressMonitorDialog is not intended to be used with multiple | |
71 * runnables - this dialog should be discarded after completion of one | |
72 * IRunnableWithProgress and a new one instantiated for use by a second or | |
73 * sebsequent IRunnableWithProgress to ensure proper initialization. | |
74 * </p> | |
75 * <p> | |
76 * Note that not forking the process will result in it running in the UI which | |
77 * may starve the UI. The most obvious symptom of this problem is non | |
78 * responsiveness of the cancel button. If you are running within the UI Thread | |
79 * you should do the bulk of your work in another Thread to prevent starvation. | |
80 * It is recommended that fork is set to true in most cases. | |
81 * </p> | |
82 */ | |
83 public class ProgressMonitorDialog : IconAndMessageDialog, | |
84 IRunnableContext { | |
85 /** | |
86 * Name to use for task when normal task name is empty string. | |
87 */ | |
88 private static String DEFAULT_TASKNAME; | |
89 | |
90 static this() { | |
91 DEFAULT_TASKNAME = JFaceResources | |
92 .getString("ProgressMonitorDialog.message"); //$NON-NLS-1$ | |
93 } | |
94 /** | |
95 * Constants for label and monitor size | |
96 */ | |
97 private static int LABEL_DLUS = 21; | |
98 | |
99 private static int BAR_DLUS = 9; | |
100 | |
101 /** | |
102 * The progress indicator control. | |
103 */ | |
104 protected ProgressIndicator progressIndicator; | |
105 | |
106 /** | |
107 * The label control for the task. Kept for backwards compatibility. | |
108 */ | |
109 protected Label taskLabel; | |
110 | |
111 /** | |
112 * The label control for the subtask. | |
113 */ | |
114 protected Label subTaskLabel; | |
115 | |
116 /** | |
117 * The Cancel button control. | |
118 */ | |
119 protected Button cancel; | |
120 | |
121 /** | |
122 * Indicates whether the Cancel button is to be shown. | |
123 */ | |
124 protected bool operationCancelableState = false; | |
125 | |
126 /** | |
127 * Indicates whether the Cancel button is to be enabled. | |
128 */ | |
129 protected bool enableCancelButton; | |
130 | |
131 /** | |
132 * The progress monitor. | |
133 */ | |
134 private ProgressMonitor progressMonitor; | |
135 | |
136 /** | |
137 * The name of the current task (used by ProgressMonitor). | |
138 */ | |
139 private String task; | |
140 | |
141 /** | |
142 * The nesting depth of currently running runnables. | |
143 */ | |
144 private int nestingDepth; | |
145 | |
146 /** | |
147 * The cursor used in the cancel button; | |
148 */ | |
149 protected Cursor arrowCursor; | |
150 | |
151 /** | |
152 * The cursor used in the shell; | |
153 */ | |
154 private Cursor waitCursor; | |
155 | |
156 /** | |
157 * Flag indicating whether to open or merely create the dialog before run. | |
158 */ | |
159 private bool openOnRun = true; | |
160 | |
161 /** | |
162 * Internal progress monitor implementation. | |
163 */ | |
164 private class ProgressMonitor : IProgressMonitorWithBlocking { | |
165 private String fSubTask = "";//$NON-NLS-1$ | |
166 | |
167 private bool fIsCanceled; | |
168 | |
169 /** | |
170 * is the process forked | |
171 */ | |
172 protected bool forked = false; | |
173 | |
174 /** | |
175 * is locked | |
176 */ | |
177 protected bool locked = false; | |
178 | |
179 public void beginTask(String name, int totalWork) { | |
180 if (progressIndicator.isDisposed()) { | |
181 return; | |
182 } | |
183 if (name is null) { | |
184 task = "";//$NON-NLS-1$ | |
185 } else { | |
186 task = name; | |
187 } | |
188 String s = task; | |
189 if (s.length <= 0) { | |
190 s = DEFAULT_TASKNAME; | |
191 } | |
192 setMessage(s, false); | |
193 if (!forked) { | |
194 update(); | |
195 } | |
196 if (totalWork is UNKNOWN) { | |
197 progressIndicator.beginAnimatedTask(); | |
198 } else { | |
199 progressIndicator.beginTask(totalWork); | |
200 } | |
201 } | |
202 | |
203 public void done() { | |
204 if (!progressIndicator.isDisposed()) { | |
205 progressIndicator.sendRemainingWork(); | |
206 progressIndicator.done(); | |
207 } | |
208 } | |
209 | |
210 public void setTaskName(String name) { | |
211 if (name is null) { | |
212 task = "";//$NON-NLS-1$ | |
213 } else { | |
214 task = name; | |
215 } | |
216 String s = task; | |
217 if (s.length <= 0) { | |
218 s = DEFAULT_TASKNAME; | |
219 } | |
220 setMessage(s, false); | |
221 if (!forked) { | |
222 update(); | |
223 } | |
224 } | |
225 | |
226 public bool isCanceled() { | |
227 return fIsCanceled; | |
228 } | |
229 | |
230 public void setCanceled(bool b) { | |
231 fIsCanceled = b; | |
232 if (locked) { | |
233 clearBlocked(); | |
234 } | |
235 } | |
236 | |
237 public void subTask(String name) { | |
238 if (subTaskLabel.isDisposed()) { | |
239 return; | |
240 } | |
241 if (name is null) { | |
242 fSubTask = "";//$NON-NLS-1$ | |
243 } else { | |
244 fSubTask = name; | |
245 } | |
246 subTaskLabel.setText(shortenText(fSubTask, subTaskLabel)); | |
247 if (!forked) { | |
248 subTaskLabel.update(); | |
249 } | |
250 } | |
251 | |
252 public void worked(int work) { | |
253 internalWorked(work); | |
254 } | |
255 | |
256 public void internalWorked(double work) { | |
257 if (!progressIndicator.isDisposed()) { | |
258 progressIndicator.worked(work); | |
259 } | |
260 } | |
261 | |
262 /* | |
263 * (non-Javadoc) | |
264 * | |
265 * @see dwtx.core.runtime.IProgressMonitorWithBlocking#clearBlocked() | |
266 */ | |
267 public void clearBlocked() { | |
268 locked = false; | |
269 updateForClearBlocked(); | |
270 } | |
271 | |
272 /* | |
273 * (non-Javadoc) | |
274 * | |
275 * @see dwtx.core.runtime.IProgressMonitorWithBlocking#setBlocked(dwtx.core.runtime.IStatus) | |
276 */ | |
277 public void setBlocked(IStatus reason) { | |
278 locked = true; | |
279 updateForSetBlocked(reason); | |
280 } | |
281 } | |
282 | |
283 /** | |
284 * Clear blocked state from the receiver. | |
285 */ | |
286 protected void updateForClearBlocked() { | |
287 setMessage(task, true); | |
288 imageLabel.setImage(getImage()); | |
289 } | |
290 | |
291 /** | |
292 * Set blocked state from the receiver. | |
293 * | |
294 * @param reason | |
295 * IStatus that gives the details | |
296 */ | |
297 protected void updateForSetBlocked(IStatus reason) { | |
298 setMessage(reason.getMessage(), true); | |
299 imageLabel.setImage(getImage()); | |
300 } | |
301 | |
302 /** | |
303 * Creates a progress monitor dialog under the given shell. The dialog has a | |
304 * standard title and no image. <code>open</code> is non-blocking. | |
305 * | |
306 * @param parent | |
307 * the parent shell, or <code>null</code> to create a top-level | |
308 * shell | |
309 */ | |
310 public this(Shell parent) { | |
311 progressMonitor = new ProgressMonitor(); | |
312 super(parent); | |
313 setShellStyle(getDefaultOrientation() | DWT.BORDER | DWT.TITLE | |
314 | DWT.APPLICATION_MODAL); // no | |
315 // close | |
316 // button | |
317 setBlockOnOpen(false); | |
318 } | |
319 | |
320 /** | |
321 * Enables the cancel button (asynchronously). | |
322 * | |
323 * @param b | |
324 * The state to set the button to. | |
325 */ | |
326 private void asyncSetOperationCancelButtonEnabled(bool b) { | |
327 if (getShell() !is null) { | |
328 getShell().getDisplay().asyncExec(new class Runnable { | |
329 bool b_; | |
330 this(){ b_=b; } | |
331 public void run() { | |
332 setOperationCancelButtonEnabled(b); | |
333 } | |
334 }); | |
335 } | |
336 } | |
337 | |
338 /** | |
339 * The cancel button has been pressed. | |
340 * | |
341 * @since 3.0 | |
342 */ | |
43
ea8ff534f622
Fix override and super aliases
Frank Benoit <benoit@tionex.de>
parents:
23
diff
changeset
|
343 protected override void cancelPressed() { |
23 | 344 // NOTE: this was previously done from a listener installed on the |
345 // cancel button. On GTK, the listener installed by | |
346 // Dialog.createButton is called first and this was throwing an | |
347 // exception because the cancel button was already disposed | |
348 cancel.setEnabled(false); | |
349 progressMonitor.setCanceled(true); | |
350 super.cancelPressed(); | |
351 } | |
352 | |
353 /* | |
354 * (non-Javadoc) Method declared on Window. | |
355 */ | |
356 /** | |
357 * The <code>ProgressMonitorDialog</code> implementation of this method | |
358 * only closes the dialog if there are no currently running runnables. | |
359 */ | |
43
ea8ff534f622
Fix override and super aliases
Frank Benoit <benoit@tionex.de>
parents:
23
diff
changeset
|
360 public override bool close() { |
23 | 361 if (getNestingDepth() <= 0) { |
362 clearCursors(); | |
363 return super.close(); | |
364 } | |
365 return false; | |
366 } | |
367 | |
368 /** | |
369 * Clear the cursors in the dialog. | |
370 * | |
371 * @since 3.0 | |
372 */ | |
373 protected void clearCursors() { | |
374 if (cancel !is null && !cancel.isDisposed()) { | |
375 cancel.setCursor(null); | |
376 } | |
377 Shell shell = getShell(); | |
378 if (shell !is null && !shell.isDisposed()) { | |
379 shell.setCursor(null); | |
380 } | |
381 if (arrowCursor !is null) { | |
382 arrowCursor.dispose(); | |
383 } | |
384 if (waitCursor !is null) { | |
385 waitCursor.dispose(); | |
386 } | |
387 arrowCursor = null; | |
388 waitCursor = null; | |
389 } | |
390 | |
391 /* | |
392 * (non-Javadoc) Method declared in Window. | |
393 */ | |
43
ea8ff534f622
Fix override and super aliases
Frank Benoit <benoit@tionex.de>
parents:
23
diff
changeset
|
394 protected override void configureShell(Shell shell) { |
23 | 395 super.configureShell(shell); |
396 shell.setText(JFaceResources.getString("ProgressMonitorDialog.title")); //$NON-NLS-1$ | |
397 if (waitCursor is null) { | |
398 waitCursor = new Cursor(shell.getDisplay(), DWT.CURSOR_WAIT); | |
399 } | |
400 shell.setCursor(waitCursor); | |
401 // Add a listener to set the message properly when the dialog becomes | |
402 // visible | |
403 shell.addListener(DWT.Show, new class Listener { | |
404 Shell shell_; | |
405 this(){ shell_=shell; } | |
406 public void handleEvent(Event event) { | |
407 // We need to async the message update since the Show precedes | |
408 // visibility | |
409 shell_.getDisplay().asyncExec(new class Runnable { | |
410 public void run() { | |
411 setMessage(message, true); | |
412 } | |
413 }); | |
414 } | |
415 }); | |
416 } | |
417 | |
418 /* | |
419 * (non-Javadoc) Method declared on Dialog. | |
420 */ | |
43
ea8ff534f622
Fix override and super aliases
Frank Benoit <benoit@tionex.de>
parents:
23
diff
changeset
|
421 protected override void createButtonsForButtonBar(Composite parent) { |
23 | 422 // cancel button |
423 createCancelButton(parent); | |
424 } | |
425 | |
426 /** | |
427 * Creates the cancel button. | |
428 * | |
429 * @param parent | |
430 * the parent composite | |
431 * @since 3.0 | |
432 */ | |
433 protected void createCancelButton(Composite parent) { | |
434 cancel = createButton(parent, IDialogConstants.CANCEL_ID, | |
435 IDialogConstants.CANCEL_LABEL, true); | |
436 if (arrowCursor is null) { | |
437 arrowCursor = new Cursor(cancel.getDisplay(), DWT.CURSOR_ARROW); | |
438 } | |
439 cancel.setCursor(arrowCursor); | |
440 setOperationCancelButtonEnabled(enableCancelButton); | |
441 } | |
442 | |
443 /* | |
444 * (non-Javadoc) Method declared on Dialog. | |
445 */ | |
43
ea8ff534f622
Fix override and super aliases
Frank Benoit <benoit@tionex.de>
parents:
23
diff
changeset
|
446 protected override Control createDialogArea(Composite parent) { |
23 | 447 setMessage(DEFAULT_TASKNAME, false); |
448 createMessageArea(parent); | |
449 // Only set for backwards compatibility | |
450 taskLabel = messageLabel; | |
451 // progress indicator | |
452 progressIndicator = new ProgressIndicator(parent); | |
453 GridData gd = new GridData(); | |
454 gd.heightHint = convertVerticalDLUsToPixels(BAR_DLUS); | |
455 gd.horizontalAlignment = GridData.FILL; | |
456 gd.grabExcessHorizontalSpace = true; | |
457 gd.horizontalSpan = 2; | |
458 progressIndicator.setLayoutData(gd); | |
459 // label showing current task | |
460 subTaskLabel = new Label(parent, DWT.LEFT | DWT.WRAP); | |
461 gd = new GridData(GridData.FILL_HORIZONTAL); | |
462 gd.heightHint = convertVerticalDLUsToPixels(LABEL_DLUS); | |
463 gd.horizontalSpan = 2; | |
464 subTaskLabel.setLayoutData(gd); | |
465 subTaskLabel.setFont(parent.getFont()); | |
466 return parent; | |
467 } | |
468 | |
469 /* | |
470 * (non-Javadoc) | |
471 * | |
472 * @see dwtx.jface.window.Window#getInitialSize() | |
473 */ | |
43
ea8ff534f622
Fix override and super aliases
Frank Benoit <benoit@tionex.de>
parents:
23
diff
changeset
|
474 protected override Point getInitialSize() { |
23 | 475 Point calculatedSize = super.getInitialSize(); |
476 if (calculatedSize.x < 450) { | |
477 calculatedSize.x = 450; | |
478 } | |
479 return calculatedSize; | |
480 } | |
481 | |
482 /** | |
483 * Returns the progress monitor to use for operations run in this progress | |
484 * dialog. | |
485 * | |
486 * @return the progress monitor | |
487 */ | |
488 public IProgressMonitor getProgressMonitor() { | |
489 return progressMonitor; | |
490 } | |
491 | |
492 /** | |
493 * This implementation of IRunnableContext#run(bool, bool, | |
494 * IRunnableWithProgress) runs the given <code>IRunnableWithProgress</code> | |
495 * using the progress monitor for this progress dialog and blocks until the | |
496 * runnable has been run, regardless of the value of <code>fork</code>. | |
497 * The dialog is opened before the runnable is run, and closed after it | |
498 * completes. It is recommended that <code>fork</code> is set to true in | |
499 * most cases. If <code>fork</code> is set to <code>false</code>, the | |
500 * runnable will run in the UI thread and it is the runnable's | |
501 * responsibility to call <code>Display.readAndDispatch()</code> to ensure | |
502 * UI responsiveness. | |
503 */ | |
504 public void run(bool fork, bool cancelable, | |
505 IRunnableWithProgress runnable) { | |
506 setCancelable(cancelable); | |
507 try { | |
508 aboutToRun(); | |
509 // Let the progress monitor know if they need to update in UI Thread | |
510 progressMonitor.forked = fork; | |
511 ModalContext.run(runnable, fork, getProgressMonitor(), getShell() | |
512 .getDisplay()); | |
513 } finally { | |
514 finishedRun(); | |
515 } | |
516 } | |
517 | |
518 /** | |
519 * Returns whether the dialog should be opened before the operation is run. | |
520 * Defaults to <code>true</code> | |
521 * | |
522 * @return <code>true</code> to open the dialog before run, | |
523 * <code>false</code> to only create the dialog, but not open it | |
524 * @since 3.0 | |
525 */ | |
526 public bool getOpenOnRun() { | |
527 return openOnRun; | |
528 } | |
529 | |
530 /** | |
531 * Sets whether the dialog should be opened before the operation is run. | |
532 * NOTE: Setting this to false and not forking a process may starve any | |
533 * asyncExec that tries to open the dialog later. | |
534 * | |
535 * @param openOnRun | |
536 * <code>true</code> to open the dialog before run, | |
537 * <code>false</code> to only create the dialog, but not open | |
538 * it | |
539 * @since 3.0 | |
540 */ | |
541 public void setOpenOnRun(bool openOnRun) { | |
542 this.openOnRun = openOnRun; | |
543 } | |
544 | |
545 /** | |
546 * Returns the nesting depth of running operations. | |
547 * | |
548 * @return the nesting depth of running operations | |
549 * @since 3.0 | |
550 */ | |
551 protected int getNestingDepth() { | |
552 return nestingDepth; | |
553 } | |
554 | |
555 /** | |
556 * Increments the nesting depth of running operations. | |
557 * | |
558 * @since 3.0 | |
559 */ | |
560 protected void incrementNestingDepth() { | |
561 nestingDepth++; | |
562 } | |
563 | |
564 /** | |
565 * Decrements the nesting depth of running operations. | |
566 * | |
567 * @since 3.0 | |
568 * | |
569 */ | |
570 protected void decrementNestingDepth() { | |
571 nestingDepth--; | |
572 } | |
573 | |
574 /** | |
575 * Called just before the operation is run. Default behaviour is to open or | |
576 * create the dialog, based on the setting of <code>getOpenOnRun</code>, | |
577 * and increment the nesting depth. | |
578 * | |
579 * @since 3.0 | |
580 */ | |
581 protected void aboutToRun() { | |
582 if (getOpenOnRun()) { | |
583 open(); | |
584 } else { | |
585 create(); | |
586 } | |
587 incrementNestingDepth(); | |
588 } | |
589 | |
590 /** | |
591 * Called just after the operation is run. Default behaviour is to decrement | |
592 * the nesting depth, and close the dialog. | |
593 * | |
594 * @since 3.0 | |
595 */ | |
596 protected void finishedRun() { | |
597 decrementNestingDepth(); | |
598 close(); | |
599 } | |
600 | |
601 /** | |
602 * Sets whether the progress dialog is cancelable or not. | |
603 * | |
604 * @param cancelable | |
605 * <code>true</code> if the end user can cancel this progress | |
606 * dialog, and <code>false</code> if it cannot be canceled | |
607 */ | |
608 public void setCancelable(bool cancelable) { | |
609 if (cancel is null) { | |
610 enableCancelButton = cancelable; | |
611 } else { | |
612 asyncSetOperationCancelButtonEnabled(cancelable); | |
613 } | |
614 } | |
615 | |
616 /** | |
617 * Helper to enable/disable Cancel button for this dialog. | |
618 * | |
619 * @param b | |
620 * <code>true</code> to enable the cancel button, and | |
621 * <code>false</code> to disable it | |
622 * @since 3.0 | |
623 */ | |
624 protected void setOperationCancelButtonEnabled(bool b) { | |
625 operationCancelableState = b; | |
626 cancel.setEnabled(b); | |
627 } | |
628 | |
629 /* | |
630 * (non-Javadoc) | |
631 * | |
632 * @see dwtx.jface.dialogs.IconAndMessageDialog#getImage() | |
633 */ | |
43
ea8ff534f622
Fix override and super aliases
Frank Benoit <benoit@tionex.de>
parents:
23
diff
changeset
|
634 protected override Image getImage() { |
23 | 635 return getInfoImage(); |
636 } | |
637 | |
638 /** | |
639 * Set the message in the message label. | |
640 * | |
641 * @param messageString | |
642 * The string for the new message. | |
643 * @param force | |
644 * If force is true then always set the message text. | |
645 */ | |
646 private void setMessage(String messageString, bool force) { | |
647 // must not set null text in a label | |
648 message = messageString is null ? "" : messageString; //$NON-NLS-1$ | |
649 if (messageLabel is null || messageLabel.isDisposed()) { | |
650 return; | |
651 } | |
652 if (force || messageLabel.isVisible()) { | |
653 messageLabel.setToolTipText(message); | |
654 messageLabel.setText(shortenText(message, messageLabel)); | |
655 } | |
656 } | |
657 | |
658 /** | |
659 * Update the message label. Required if the monitor is forked. | |
660 */ | |
661 private void update() { | |
662 if (messageLabel is null || messageLabel.isDisposed()) { | |
663 return; | |
664 } | |
665 messageLabel.update(); | |
666 } | |
667 | |
668 /* | |
669 * (non-Javadoc) | |
670 * | |
671 * @see dwtx.jface.window.Window#open() | |
672 */ | |
43
ea8ff534f622
Fix override and super aliases
Frank Benoit <benoit@tionex.de>
parents:
23
diff
changeset
|
673 public override int open() { |
23 | 674 // Check to be sure it is not already done. If it is just return OK. |
675 if (!getOpenOnRun()) { | |
676 if (getNestingDepth() is 0) { | |
677 return OK; | |
678 } | |
679 } | |
680 int result = super.open(); | |
681 // update message label just in case beginTask() has been invoked already | |
682 if (task is null || task.length is 0) | |
683 setMessage(DEFAULT_TASKNAME, true); | |
684 else | |
685 setMessage(task, true); | |
686 return result; | |
687 } | |
688 } |