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 java.lang.reflect.InvocationTargetException;
013:
014: import org.eclipse.core.runtime.IProgressMonitor;
015: import org.eclipse.core.runtime.IProgressMonitorWithBlocking;
016: import org.eclipse.core.runtime.IStatus;
017: import org.eclipse.jface.dialogs.IDialogConstants;
018: import org.eclipse.jface.dialogs.ProgressMonitorDialog;
019: import org.eclipse.jface.operation.IRunnableWithProgress;
020: import org.eclipse.jface.viewers.Viewer;
021: import org.eclipse.jface.viewers.ViewerComparator;
022: import org.eclipse.swt.SWT;
023: import org.eclipse.swt.events.SelectionAdapter;
024: import org.eclipse.swt.events.SelectionEvent;
025: import org.eclipse.swt.graphics.Cursor;
026: import org.eclipse.swt.graphics.Point;
027: import org.eclipse.swt.layout.GridData;
028: import org.eclipse.swt.layout.GridLayout;
029: import org.eclipse.swt.widgets.Button;
030: import org.eclipse.swt.widgets.Composite;
031: import org.eclipse.swt.widgets.Control;
032: import org.eclipse.swt.widgets.Label;
033: import org.eclipse.swt.widgets.Shell;
034: import org.eclipse.ui.PlatformUI;
035: import org.eclipse.ui.internal.misc.Policy;
036:
037: /**
038: * The ProgressMonitorJobsDialog is the progress monitor dialog used by the
039: * progress service to allow locks to show the current jobs.
040: */
041: public class ProgressMonitorJobsDialog extends ProgressMonitorDialog {
042: private DetailedProgressViewer viewer;
043:
044: /**
045: * The height of the viewer. Set when the details button is selected.
046: */
047: private int viewerHeight = -1;
048:
049: Composite viewerComposite;
050:
051: private Button detailsButton;
052:
053: private long watchTime = -1;
054:
055: protected boolean alreadyClosed = false;
056:
057: private IProgressMonitor wrapperedMonitor;
058:
059: //Cache initial enablement in case the enablement state is set
060: //before the button is created
061: protected boolean enableDetailsButton = false;
062:
063: /**
064: * Create a new instance of the receiver.
065: *
066: * @param parent
067: */
068: public ProgressMonitorJobsDialog(Shell parent) {
069: super (parent);
070: }
071:
072: /*
073: * (non-Javadoc)
074: *
075: * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
076: */
077: protected Control createDialogArea(Composite parent) {
078: Composite top = (Composite) super .createDialogArea(parent);
079: viewerComposite = new Composite(parent, SWT.NONE);
080: GridLayout layout = new GridLayout();
081: layout.marginHeight = 0;
082: layout.marginWidth = 0;
083: viewerComposite.setLayout(layout);
084: GridData viewerData = new GridData(GridData.FILL_BOTH);
085: viewerData.horizontalSpan = 2;
086: viewerData.heightHint = 0;
087: viewerComposite.setLayoutData(viewerData);
088: return top;
089: }
090:
091: /**
092: * The details button has been selected. Open or close the progress viewer
093: * as appropriate.
094: *
095: */
096: void handleDetailsButtonSelect() {
097: Shell shell = getShell();
098: Point shellSize = shell.getSize();
099: Composite composite = (Composite) getDialogArea();
100: if (viewer != null) {
101: viewer.getControl().dispose();
102: viewer = null;
103: composite.layout();
104: shell.setSize(shellSize.x, shellSize.y - viewerHeight);
105: detailsButton
106: .setText(ProgressMessages.ProgressMonitorJobsDialog_DetailsTitle);
107: } else {
108: //Abort if there are no jobs visible
109: if (ProgressManager.getInstance().getRootElements(
110: Policy.DEBUG_SHOW_ALL_JOBS).length == 0) {
111: detailsButton.setEnabled(false);
112: return;
113: }
114:
115: viewer = new DetailedProgressViewer(viewerComposite,
116: SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL
117: | SWT.BORDER);
118: viewer.setComparator(new ViewerComparator() {
119: /*
120: * (non-Javadoc)
121: *
122: * @see org.eclipse.jface.viewers.ViewerComparator#compare(org.eclipse.jface.viewers.Viewer,
123: * java.lang.Object, java.lang.Object)
124: */
125: public int compare(Viewer testViewer, Object e1,
126: Object e2) {
127: return ((Comparable) e1).compareTo(e2);
128: }
129: });
130:
131: viewer
132: .setContentProvider(new ProgressViewerContentProvider(
133: viewer, true, false) {
134: public Object[] getElements(Object inputElement) {
135: return super .getElements(inputElement);
136: }
137: });
138:
139: viewer.setLabelProvider(new ProgressLabelProvider());
140: viewer.setInput(this );
141: GridData viewerData = new GridData(GridData.FILL_BOTH);
142: viewer.getControl().setLayoutData(viewerData);
143: GridData viewerCompositeData = (GridData) viewerComposite
144: .getLayoutData();
145: viewerCompositeData.heightHint = convertHeightInCharsToPixels(10);
146: viewerComposite.layout(true);
147: viewer.getControl().setVisible(true);
148: viewerHeight = viewerComposite.computeTrim(0, 0, 0,
149: viewerCompositeData.heightHint).height;
150: detailsButton
151: .setText(ProgressMessages.ProgressMonitorJobsDialog_HideTitle);
152: shell.setSize(shellSize.x, shellSize.y + viewerHeight);
153: }
154: }
155:
156: /*
157: * (non-Javadoc)
158: *
159: * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)
160: */
161: protected void createButtonsForButtonBar(Composite parent) {
162: super .createButtonsForButtonBar(parent);
163: createDetailsButton(parent);
164: }
165:
166: /**
167: * Create a spacer label to get the layout to not bunch the widgets.
168: *
169: * @param parent
170: * The parent of the new button.
171: */
172: protected void createSpacer(Composite parent) {
173: //Make a label to force the spacing
174: Label spacer = new Label(parent, SWT.NONE);
175: spacer.setLayoutData(new GridData(GridData.FILL_HORIZONTAL
176: | GridData.GRAB_HORIZONTAL));
177: }
178:
179: /**
180: * Create the details button for the receiver.
181: *
182: * @param parent
183: * The parent of the new button.
184: */
185: protected void createDetailsButton(Composite parent) {
186: detailsButton = createButton(
187: parent,
188: IDialogConstants.DETAILS_ID,
189: ProgressMessages.ProgressMonitorJobsDialog_DetailsTitle,
190: false);
191: detailsButton.addSelectionListener(new SelectionAdapter() {
192: /*
193: * (non-Javadoc)
194: *
195: * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
196: */
197: public void widgetSelected(SelectionEvent e) {
198: handleDetailsButtonSelect();
199: }
200: });
201: detailsButton.setCursor(arrowCursor);
202: detailsButton.setEnabled(enableDetailsButton);
203: }
204:
205: /*
206: * (non-Javadoc)
207: *
208: * @see org.eclipse.jface.dialogs.IconAndMessageDialog#createButtonBar(org.eclipse.swt.widgets.Composite)
209: */
210: protected Control createButtonBar(Composite parent) {
211: Composite composite = new Composite(parent, SWT.NONE);
212: // create a layout with spacing and margins appropriate for the font
213: // size.
214: GridLayout layout = new GridLayout();
215: layout.numColumns = 1; // this is incremented by createButton
216: layout.makeColumnsEqualWidth = false;
217: layout.marginWidth = 0;
218: layout.marginHeight = 0;
219: layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
220: layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
221: composite.setLayout(layout);
222: GridData data = new GridData(GridData.FILL_HORIZONTAL);
223: data.horizontalSpan = 2;
224: data.horizontalAlignment = GridData.END;
225: data.grabExcessHorizontalSpace = true;
226: composite.setLayoutData(data);
227: composite.setFont(parent.getFont());
228: // Add the buttons to the button bar.
229: if (arrowCursor == null) {
230: arrowCursor = new Cursor(parent.getDisplay(),
231: SWT.CURSOR_ARROW);
232: }
233: createButtonsForButtonBar(composite);
234: return composite;
235: }
236:
237: /*
238: * (non-Javadoc)
239: *
240: * @see org.eclipse.jface.dialogs.ProgressMonitorDialog#clearCursors()
241: */
242: protected void clearCursors() {
243: if (detailsButton != null && !detailsButton.isDisposed()) {
244: detailsButton.setCursor(null);
245: }
246: super .clearCursors();
247: }
248:
249: /*
250: * (non-Javadoc)
251: *
252: * @see org.eclipse.jface.dialogs.ProgressMonitorDialog#updateForSetBlocked(org.eclipse.core.runtime.IStatus)
253: */
254: protected void updateForSetBlocked(IStatus reason) {
255: if (alreadyClosed)
256: return;
257:
258: super .updateForSetBlocked(reason);
259: enableDetails(true);
260: if (viewer == null) {
261: handleDetailsButtonSelect();
262: }
263: }
264:
265: /*
266: * (non-Javadoc)
267: *
268: * @see org.eclipse.jface.dialogs.ProgressMonitorDialog#run(boolean,
269: * boolean, org.eclipse.jface.operation.IRunnableWithProgress)
270: */
271: public void run(boolean fork, boolean cancelable,
272: IRunnableWithProgress runnable)
273: throws InvocationTargetException, InterruptedException {
274: //if it is run in the UI Thread don't do anything.
275: if (!fork) {
276: enableDetails(false);
277: }
278: super .run(fork, cancelable, runnable);
279: }
280:
281: /**
282: * Set the enable state of the details button now or when it will be
283: * created.
284: *
285: * @param enableState
286: * a boolean to indicate the preferred' state
287: */
288: protected void enableDetails(boolean enableState) {
289: if (detailsButton == null) {
290: enableDetailsButton = enableState;
291: } else {
292: detailsButton.setEnabled(enableState);
293: }
294: }
295:
296: /**
297: * Start watching the ticks. When the long operation time has
298: * passed open the dialog.
299: */
300: public void watchTicks() {
301: watchTime = System.currentTimeMillis();
302: }
303:
304: /**
305: * Create a monitor for the receiver that wrappers the superclasses monitor.
306: *
307: */
308: public void createWrapperedMonitor() {
309: wrapperedMonitor = new IProgressMonitorWithBlocking() {
310:
311: IProgressMonitor super Monitor = ProgressMonitorJobsDialog.super
312: .getProgressMonitor();
313:
314: /*
315: * (non-Javadoc)
316: *
317: * @see org.eclipse.core.runtime.IProgressMonitor#beginTask(java.lang.String,
318: * int)
319: */
320: public void beginTask(String name, int totalWork) {
321: super Monitor.beginTask(name, totalWork);
322: checkTicking();
323: }
324:
325: /**
326: * Check if we have ticked in the last 800ms.
327: */
328: private void checkTicking() {
329: if (watchTime < 0) {
330: return;
331: }
332: if ((System.currentTimeMillis() - watchTime) > ProgressManager
333: .getInstance().getLongOperationTime()) {
334: watchTime = -1;
335: openDialog();
336: }
337: }
338:
339: /**
340: * Open the dialog in the ui Thread
341: */
342: private void openDialog() {
343: if (!PlatformUI.isWorkbenchRunning()) {
344: return;
345: }
346:
347: PlatformUI.getWorkbench().getDisplay().syncExec(
348: new Runnable() {
349: /* (non-Javadoc)
350: * @see java.lang.Runnable#run()
351: */
352: public void run() {
353: //Reset the watch if it is not safe to open
354: if (!ProgressManagerUtil.safeToOpen(
355: ProgressMonitorJobsDialog.this ,
356: null)) {
357: watchTicks();
358: return;
359: }
360:
361: if (!alreadyClosed) {
362: open();
363: }
364: }
365: });
366: }
367:
368: /*
369: * (non-Javadoc)
370: *
371: * @see org.eclipse.core.runtime.IProgressMonitor#done()
372: */
373: public void done() {
374: super Monitor.done();
375: checkTicking();
376: }
377:
378: /*
379: * (non-Javadoc)
380: *
381: * @see org.eclipse.core.runtime.IProgressMonitor#internalWorked(double)
382: */
383: public void internalWorked(double work) {
384: super Monitor.internalWorked(work);
385: checkTicking();
386: }
387:
388: /*
389: * (non-Javadoc)
390: *
391: * @see org.eclipse.core.runtime.IProgressMonitor#isCanceled()
392: */
393: public boolean isCanceled() {
394: return super Monitor.isCanceled();
395: }
396:
397: /*
398: * (non-Javadoc)
399: *
400: * @see org.eclipse.core.runtime.IProgressMonitor#setCanceled(boolean)
401: */
402: public void setCanceled(boolean value) {
403: super Monitor.setCanceled(value);
404:
405: }
406:
407: /*
408: * (non-Javadoc)
409: *
410: * @see org.eclipse.core.runtime.IProgressMonitor#setTaskName(java.lang.String)
411: */
412: public void setTaskName(String name) {
413: super Monitor.setTaskName(name);
414: checkTicking();
415:
416: }
417:
418: /*
419: * (non-Javadoc)
420: *
421: * @see org.eclipse.core.runtime.IProgressMonitor#subTask(java.lang.String)
422: */
423: public void subTask(String name) {
424: super Monitor.subTask(name);
425: checkTicking();
426: }
427:
428: /*
429: * (non-Javadoc)
430: *
431: * @see org.eclipse.core.runtime.IProgressMonitor#worked(int)
432: */
433: public void worked(int work) {
434: super Monitor.worked(work);
435: checkTicking();
436:
437: }
438:
439: /*
440: * (non-Javadoc)
441: *
442: * @see org.eclipse.core.runtime.IProgressMonitorWithBlocking#clearBlocked()
443: */
444: public void clearBlocked() {
445: //We want to open on blocking too
446: if (super Monitor instanceof IProgressMonitorWithBlocking) {
447: ((IProgressMonitorWithBlocking) super Monitor)
448: .clearBlocked();
449: }
450:
451: }
452:
453: /*
454: * (non-Javadoc)
455: *
456: * @see org.eclipse.core.runtime.IProgressMonitorWithBlocking#setBlocked(org.eclipse.core.runtime.IStatus)
457: */
458: public void setBlocked(IStatus reason) {
459: openDialog();
460: if (super Monitor instanceof IProgressMonitorWithBlocking) {
461: ((IProgressMonitorWithBlocking) super Monitor)
462: .setBlocked(reason);
463: }
464:
465: }
466:
467: };
468: }
469:
470: /*
471: * (non-Javadoc)
472: *
473: * @see org.eclipse.jface.dialogs.ProgressMonitorDialog#getProgressMonitor()
474: */
475: public IProgressMonitor getProgressMonitor() {
476: if (wrapperedMonitor == null) {
477: createWrapperedMonitor();
478: }
479: return wrapperedMonitor;
480: }
481:
482: /*
483: * (non-Javadoc)
484: *
485: * @see org.eclipse.jface.dialogs.ProgressMonitorDialog#close()
486: */
487: public boolean close() {
488: alreadyClosed = true;//As this sometimes delayed cache if it was already closed
489: boolean result = super .close();
490: if (!result) {//If it fails reset the flag
491: alreadyClosed = false;
492: }
493: return result;
494: }
495:
496: /*
497: * (non-Javadoc)
498: * @see org.eclipse.jface.dialogs.Dialog#isResizable()
499: */
500: protected boolean isResizable() {
501: return true;
502: }
503: }
|