001: /*******************************************************************************
002: * Copyright (c) 2004, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM - Initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal.progress;
011:
012: import org.eclipse.core.runtime.IProgressMonitor;
013: import org.eclipse.core.runtime.IProgressMonitorWithBlocking;
014: import org.eclipse.core.runtime.IStatus;
015: import org.eclipse.core.runtime.Status;
016: import org.eclipse.core.runtime.jobs.IJobChangeEvent;
017: import org.eclipse.core.runtime.jobs.IJobChangeListener;
018: import org.eclipse.core.runtime.jobs.Job;
019: import org.eclipse.core.runtime.jobs.JobChangeAdapter;
020: import org.eclipse.jface.dialogs.IDialogConstants;
021: import org.eclipse.swt.SWT;
022: import org.eclipse.swt.custom.BusyIndicator;
023: import org.eclipse.swt.events.SelectionAdapter;
024: import org.eclipse.swt.events.SelectionEvent;
025: import org.eclipse.swt.graphics.Rectangle;
026: import org.eclipse.swt.widgets.Button;
027: import org.eclipse.swt.widgets.Composite;
028: import org.eclipse.swt.widgets.Control;
029: import org.eclipse.swt.widgets.Display;
030: import org.eclipse.swt.widgets.Shell;
031: import org.eclipse.ui.PlatformUI;
032: import org.eclipse.ui.progress.IProgressConstants;
033: import org.eclipse.ui.progress.WorkbenchJob;
034:
035: /**
036: * The ProgressMonitorFocusJobDialog is a dialog that shows progress for a
037: * particular job in a modal dialog so as to give a user accustomed to a modal
038: * UI a more familiar feel.
039: */
040: class ProgressMonitorFocusJobDialog extends ProgressMonitorJobsDialog {
041: Job job;
042:
043: /**
044: * Create a new instance of the receiver with progress reported on the job.
045: *
046: * @param parentShell
047: * The shell this is parented from.
048: */
049: public ProgressMonitorFocusJobDialog(Shell parentShell) {
050: super (parentShell == null ? ProgressManagerUtil
051: .getNonModalShell() : parentShell);
052: setShellStyle(getDefaultOrientation() | SWT.BORDER | SWT.TITLE
053: | SWT.RESIZE | SWT.MAX | SWT.MODELESS);
054: setCancelable(true);
055: enableDetailsButton = true;
056: }
057:
058: /*
059: * (non-Javadoc)
060: *
061: * @see org.eclipse.jface.dialogs.ProgressMonitorDialog#cancelPressed()
062: */
063: protected void cancelPressed() {
064: job.cancel();
065: super .cancelPressed();
066: }
067:
068: /*
069: * (non-Javadoc)
070: *
071: * @see org.eclipse.jface.dialogs.ProgressMonitorDialog#configureShell(org.eclipse.swt.widgets.Shell)
072: */
073: protected void configureShell(Shell shell) {
074: super .configureShell(shell);
075: shell.setText(job.getName());
076:
077: }
078:
079: /*
080: * (non-Javadoc)
081: *
082: * @see org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)
083: */
084: protected void createButtonsForButtonBar(Composite parent) {
085: Button runInWorkspace = createButton(
086: parent,
087: IDialogConstants.CLOSE_ID,
088: ProgressMessages.ProgressMonitorFocusJobDialog_RunInBackgroundButton,
089: true);
090: runInWorkspace.addSelectionListener(new SelectionAdapter() {
091: /*
092: * (non-Javadoc)
093: *
094: * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
095: */
096: public void widgetSelected(SelectionEvent e) {
097: Rectangle shellPosition = getShell().getBounds();
098: job.setProperty(IProgressConstants.PROPERTY_IN_DIALOG,
099: Boolean.FALSE);
100: finishedRun();
101: ProgressManagerUtil.animateDown(shellPosition);
102: }
103: });
104: runInWorkspace.setCursor(arrowCursor);
105:
106: cancel = createButton(parent, IDialogConstants.CANCEL_ID,
107: IDialogConstants.CANCEL_LABEL, false);
108: cancel.setCursor(arrowCursor);
109:
110: createDetailsButton(parent);
111: }
112:
113: /**
114: * Returns a listener that will close the dialog when the job completes.
115: *
116: * @return IJobChangeListener
117: */
118: private IJobChangeListener createCloseListener() {
119: return new JobChangeAdapter() {
120: /*
121: * (non-Javadoc)
122: *
123: * @see org.eclipse.core.runtime.jobs.IJobChangeListener#done(org.eclipse.core.runtime.jobs.IJobChangeEvent)
124: */
125: public void done(IJobChangeEvent event) {
126: // first of all, make sure this listener is removed
127: event.getJob().removeJobChangeListener(this );
128: if (!PlatformUI.isWorkbenchRunning()) {
129: return;
130: }
131: // nothing to do if the dialog is already closed
132: if (getShell() == null) {
133: return;
134: }
135: WorkbenchJob closeJob = new WorkbenchJob(
136: ProgressMessages.ProgressMonitorFocusJobDialog_CLoseDialogJob) {
137: /*
138: * (non-Javadoc)
139: *
140: * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
141: */
142: public IStatus runInUIThread(
143: IProgressMonitor monitor) {
144: Shell currentShell = getShell();
145: if (currentShell == null
146: || currentShell.isDisposed()) {
147: return Status.CANCEL_STATUS;
148: }
149: finishedRun();
150: return Status.OK_STATUS;
151: }
152: };
153: closeJob.setSystem(true);
154: closeJob.schedule();
155: }
156: };
157: }
158:
159: /**
160: * Return the ProgressMonitorWithBlocking for the receiver.
161: *
162: * @return IProgressMonitorWithBlocking
163: */
164: private IProgressMonitorWithBlocking getBlockingProgressMonitor() {
165: return new IProgressMonitorWithBlocking() {
166: /*
167: * (non-Javadoc)
168: *
169: * @see org.eclipse.core.runtime.IProgressMonitor#beginTask(java.lang.String,
170: * int)
171: */
172: public void beginTask(String name, int totalWork) {
173: final String finalName = name;
174: final int finalWork = totalWork;
175: runAsync(new Runnable() {
176: /*
177: * (non-Javadoc)
178: *
179: * @see java.lang.Runnable#run()
180: */
181: public void run() {
182: getProgressMonitor().beginTask(finalName,
183: finalWork);
184: }
185: });
186: }
187:
188: /*
189: * (non-Javadoc)
190: *
191: * @see org.eclipse.core.runtime.IProgressMonitorWithBlocking#clearBlocked()
192: */
193: public void clearBlocked() {
194: runAsync(new Runnable() {
195: /*
196: * (non-Javadoc)
197: *
198: * @see java.lang.Runnable#run()
199: */
200: public void run() {
201: ((IProgressMonitorWithBlocking) getProgressMonitor())
202: .clearBlocked();
203: }
204: });
205: }
206:
207: /*
208: * (non-Javadoc)
209: *
210: * @see org.eclipse.core.runtime.IProgressMonitor#done()
211: */
212: public void done() {
213: runAsync(new Runnable() {
214: /*
215: * (non-Javadoc)
216: *
217: * @see java.lang.Runnable#run()
218: */
219: public void run() {
220: getProgressMonitor().done();
221: }
222: });
223: }
224:
225: /*
226: * (non-Javadoc)
227: *
228: * @see org.eclipse.core.runtime.IProgressMonitor#internalWorked(double)
229: */
230: public void internalWorked(double work) {
231: final double finalWork = work;
232: runAsync(new Runnable() {
233: /*
234: * (non-Javadoc)
235: *
236: * @see java.lang.Runnable#run()
237: */
238: public void run() {
239: getProgressMonitor().internalWorked(finalWork);
240: }
241: });
242: }
243:
244: /*
245: * (non-Javadoc)
246: *
247: * @see org.eclipse.core.runtime.IProgressMonitor#isCanceled()
248: */
249: public boolean isCanceled() {
250: return getProgressMonitor().isCanceled();
251: }
252:
253: /**
254: * Run the runnable as an asyncExec if we are already open.
255: *
256: * @param runnable
257: */
258: private void runAsync(final Runnable runnable) {
259:
260: if (alreadyClosed) {
261: return;
262: }
263: Shell currentShell = getShell();
264:
265: Display display;
266: if (currentShell == null) {
267: display = Display.getDefault();
268: } else {
269: if (currentShell.isDisposed())// Don't bother if it has
270: // been closed
271: return;
272: display = currentShell.getDisplay();
273: }
274:
275: display.asyncExec(new Runnable() {
276: /*
277: * (non-Javadoc)
278: *
279: * @see java.lang.Runnable#run()
280: */
281: public void run() {
282: if (alreadyClosed) {
283: return;// Check again as the async may come too
284: // late
285: }
286: Shell shell = getShell();
287: if (shell != null && shell.isDisposed())
288: return;
289:
290: runnable.run();
291: }
292: });
293: }
294:
295: /*
296: * (non-Javadoc)
297: *
298: * @see org.eclipse.core.runtime.IProgressMonitorWithBlocking#setBlocked(org.eclipse.core.runtime.IStatus)
299: */
300: public void setBlocked(IStatus reason) {
301: final IStatus finalReason = reason;
302: runAsync(new Runnable() {
303: /*
304: * (non-Javadoc)
305: *
306: * @see java.lang.Runnable#run()
307: */
308: public void run() {
309: ((IProgressMonitorWithBlocking) getProgressMonitor())
310: .setBlocked(finalReason);
311: }
312: });
313: }
314:
315: /*
316: * (non-Javadoc)
317: *
318: * @see org.eclipse.core.runtime.IProgressMonitor#setCanceled(boolean)
319: */
320: public void setCanceled(boolean value) {
321: // Just a listener - doesn't matter.
322: }
323:
324: /*
325: * (non-Javadoc)
326: *
327: * @see org.eclipse.core.runtime.IProgressMonitor#setTaskName(java.lang.String)
328: */
329: public void setTaskName(String name) {
330: final String finalName = name;
331: runAsync(new Runnable() {
332: /*
333: * (non-Javadoc)
334: *
335: * @see java.lang.Runnable#run()
336: */
337: public void run() {
338: getProgressMonitor().setTaskName(finalName);
339: }
340: });
341: }
342:
343: /*
344: * (non-Javadoc)
345: *
346: * @see org.eclipse.core.runtime.IProgressMonitor#subTask(java.lang.String)
347: */
348: public void subTask(String name) {
349: final String finalName = name;
350: runAsync(new Runnable() {
351: /*
352: * (non-Javadoc)
353: *
354: * @see java.lang.Runnable#run()
355: */
356: public void run() {
357: getProgressMonitor().subTask(finalName);
358: }
359: });
360: }
361:
362: /*
363: * (non-Javadoc)
364: *
365: * @see org.eclipse.core.runtime.IProgressMonitor#worked(int)
366: */
367: public void worked(int work) {
368: internalWorked(work);
369: }
370: };
371: }
372:
373: /*
374: * (non-Javadoc)
375: *
376: * @see org.eclipse.jface.window.Window#open()
377: */
378: public int open() {
379: int result = super .open();
380:
381: // add a listener that will close the dialog when the job completes.
382: IJobChangeListener listener = createCloseListener();
383: job.addJobChangeListener(listener);
384: if (job.getState() == Job.NONE) {
385: // if the job completed before we had a chance to add
386: // the listener, just remove the listener and return
387: job.removeJobChangeListener(listener);
388: finishedRun();
389: cleanUpFinishedJob();
390: }
391:
392: return result;
393: }
394:
395: /**
396: * Opens this dialog for the duration that the given job is running.
397: *
398: * @param jobToWatch
399: * @param originatingShell
400: * The shell this request was created from. Do not block on this
401: * shell.
402: */
403: public void show(Job jobToWatch, final Shell originatingShell) {
404: job = jobToWatch;
405: // after the dialog is opened we can get access to its monitor
406: job.setProperty(IProgressConstants.PROPERTY_IN_DIALOG,
407: Boolean.TRUE);
408:
409: ProgressManager.getInstance().progressFor(job)
410: .addProgressListener(getBlockingProgressMonitor());
411:
412: setOpenOnRun(false);
413: aboutToRun();
414: // start with a quick busy indicator. Lock the UI as we
415: // want to preserve modality
416: BusyIndicator.showWhile(PlatformUI.getWorkbench().getDisplay(),
417: new Runnable() {
418: public void run() {
419: try {
420: Thread
421: .sleep(ProgressManagerUtil.SHORT_OPERATION_TIME);
422: } catch (InterruptedException e) {
423: // Do not log as this is a common operation from the
424: // lock listener
425: }
426: }
427: });
428:
429: WorkbenchJob openJob = new WorkbenchJob(
430: ProgressMessages.ProgressMonitorFocusJobDialog_UserDialogJob) {
431: /*
432: * (non-Javadoc)
433: *
434: * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
435: */
436: public IStatus runInUIThread(IProgressMonitor monitor) {
437:
438: // if the job is done at this point, we don't need the dialog
439: if (job.getState() == Job.NONE) {
440: finishedRun();
441: cleanUpFinishedJob();
442: return Status.CANCEL_STATUS;
443: }
444:
445: // now open the progress dialog if nothing else is
446: if (!ProgressManagerUtil.safeToOpen(
447: ProgressMonitorFocusJobDialog.this ,
448: originatingShell)) {
449: return Status.CANCEL_STATUS;
450: }
451:
452: // Do not bother if the parent is disposed
453: if (getParentShell() != null
454: && getParentShell().isDisposed()) {
455: return Status.CANCEL_STATUS;
456: }
457:
458: open();
459:
460: return Status.OK_STATUS;
461: }
462: };
463: openJob.setSystem(true);
464: openJob.schedule();
465:
466: }
467:
468: /**
469: * The job finished before we did anything so clean up the finished
470: * reference.
471: */
472: private void cleanUpFinishedJob() {
473: ProgressManager.getInstance().checkForStaleness(job);
474: }
475:
476: /*
477: * (non-Javadoc)
478: *
479: * @see org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog#createDialogArea(org.eclipse.swt.widgets.Composite)
480: */
481: protected Control createDialogArea(Composite parent) {
482: Control area = super .createDialogArea(parent);
483: // Give the job info as the initial details
484: getProgressMonitor().setTaskName(
485: ProgressManager.getInstance().getJobInfo(this.job)
486: .getDisplayString());
487: return area;
488: }
489: }
|