blob: c79fb8f7e1db3fa28e00137f53ab684127997afb [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM - Initial API and implementation
*******************************************************************************/
package org.eclipse.ui.internal.progress;
import java.lang.reflect.InvocationTargetException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IProgressMonitorWithBlocking;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.misc.Policy;
/**
* The ProgressMonitorJobsDialog is the progress monitor dialog used by the
* progress service to allow locks to show the current jobs.
*/
public class ProgressMonitorJobsDialog extends ProgressMonitorDialog {
private DetailedProgressViewer viewer;
/**
* The height of the viewer. Set when the details button is selected.
*/
private int viewerHeight = -1;
Composite viewerComposite;
private Button detailsButton;
private long watchTime = -1;
protected boolean alreadyClosed = false;
private IProgressMonitor wrapperedMonitor;
//Cache initial enablement in case the enablement state is set
//before the button is created
protected boolean enableDetailsButton = false;
/**
* Create a new instance of the receiver.
*
* @param parent
*/
public ProgressMonitorJobsDialog(Shell parent) {
super(parent);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
*/
protected Control createDialogArea(Composite parent) {
Composite top = (Composite) super.createDialogArea(parent);
createExtendedDialogArea(parent);
return top;
}
/**
* Create the extensions to the dialog area.
* @param parent
*/
protected void createExtendedDialogArea(Composite parent) {
viewerComposite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
viewerComposite.setLayout(layout);
GridData viewerData = new GridData(GridData.FILL_BOTH);
viewerData.horizontalSpan = 2;
viewerData.heightHint = 0;
viewerComposite.setLayoutData(viewerData);
}
/**
* The details button has been selected. Open or close the progress viewer
* as appropriate.
*
*/
void handleDetailsButtonSelect() {
Shell shell = getShell();
Point shellSize = shell.getSize();
Composite composite = (Composite) getDialogArea();
if (viewer != null) {
viewer.getControl().dispose();
viewer = null;
composite.layout();
shell.setSize(shellSize.x, shellSize.y - viewerHeight);
detailsButton.setText(ProgressMessages.ProgressMonitorJobsDialog_DetailsTitle);
} else {
//Abort if there are no jobs visible
if (ProgressManager.getInstance().getRootElements(Policy.DEBUG_SHOW_ALL_JOBS).length == 0) {
detailsButton.setEnabled(false);
return;
}
viewer = new DetailedProgressViewer(viewerComposite, SWT.MULTI
| SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
viewer.setComparator(new ViewerComparator() {
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.ViewerComparator#compare(org.eclipse.jface.viewers.Viewer,
* java.lang.Object, java.lang.Object)
*/
public int compare(Viewer testViewer, Object e1, Object e2) {
return ((Comparable) e1).compareTo(e2);
}
});
viewer.setContentProvider(new ProgressViewerContentProvider(viewer,true,false){
public Object[] getElements(Object inputElement) {
return super.getElements(inputElement);
}}
);
viewer.setLabelProvider(new ProgressLabelProvider());
viewer.setInput(this);
GridData viewerData = new GridData(GridData.FILL_BOTH);
viewer.getControl().setLayoutData(viewerData);
GridData viewerCompositeData = (GridData) viewerComposite.getLayoutData();
viewerCompositeData.heightHint = convertHeightInCharsToPixels(10);
viewerComposite.layout(true);
viewer.getControl().setVisible(true);
viewerHeight = viewerComposite.computeTrim(0, 0, 0, viewerCompositeData.heightHint).height;
detailsButton.setText(ProgressMessages.ProgressMonitorJobsDialog_HideTitle);
shell.setSize(shellSize.x, shellSize.y + viewerHeight);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)
*/
protected void createButtonsForButtonBar(Composite parent) {
super.createButtonsForButtonBar(parent);
createDetailsButton(parent);
}
/**
* Create a spacer label to get the layout to not bunch the widgets.
*
* @param parent
* The parent of the new button.
*/
protected void createSpacer(Composite parent) {
//Make a label to force the spacing
Label spacer = new Label(parent, SWT.NONE);
spacer.setLayoutData(new GridData(GridData.FILL_HORIZONTAL
| GridData.GRAB_HORIZONTAL));
}
/**
* Create the details button for the receiver.
*
* @param parent
* The parent of the new button.
*/
protected void createDetailsButton(Composite parent) {
detailsButton = createButton(parent, IDialogConstants.DETAILS_ID,
ProgressMessages.ProgressMonitorJobsDialog_DetailsTitle,
false);
detailsButton.addSelectionListener(new SelectionAdapter() {
/*
* (non-Javadoc)
*
* @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
*/
public void widgetSelected(SelectionEvent e) {
handleDetailsButtonSelect();
}
});
detailsButton.setCursor(arrowCursor);
detailsButton.setEnabled(enableDetailsButton);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.dialogs.IconAndMessageDialog#createButtonBar(org.eclipse.swt.widgets.Composite)
*/
protected Control createButtonBar(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
// create a layout with spacing and margins appropriate for the font
// size.
GridLayout layout = new GridLayout();
layout.numColumns = 1; // this is incremented by createButton
layout.makeColumnsEqualWidth = false;
layout.marginWidth = 0;
layout.marginHeight = 0;
layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
composite.setLayout(layout);
GridData data = new GridData(GridData.FILL_HORIZONTAL);
data.horizontalSpan = 2;
data.horizontalAlignment = GridData.END;
data.grabExcessHorizontalSpace = true;
composite.setLayoutData(data);
composite.setFont(parent.getFont());
// Add the buttons to the button bar.
if (arrowCursor == null) {
arrowCursor = new Cursor(parent.getDisplay(), SWT.CURSOR_ARROW);
}
createButtonsForButtonBar(composite);
return composite;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.dialogs.ProgressMonitorDialog#clearCursors()
*/
protected void clearCursors() {
if (detailsButton != null && !detailsButton.isDisposed()) {
detailsButton.setCursor(null);
}
super.clearCursors();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.dialogs.ProgressMonitorDialog#updateForSetBlocked(org.eclipse.core.runtime.IStatus)
*/
protected void updateForSetBlocked(IStatus reason) {
if(alreadyClosed)
return;
super.updateForSetBlocked(reason);
enableDetails(true);
if (viewer == null) {
handleDetailsButtonSelect();
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.dialogs.ProgressMonitorDialog#run(boolean,
* boolean, org.eclipse.jface.operation.IRunnableWithProgress)
*/
public void run(boolean fork, boolean cancelable,
IRunnableWithProgress runnable) throws InvocationTargetException,
InterruptedException {
//if it is run in the UI Thread don't do anything.
if (!fork) {
enableDetails(false);
}
super.run(fork, cancelable, runnable);
}
/**
* Set the enable state of the details button now or when it will be
* created.
*
* @param enableState
* a boolean to indicate the preferred' state
*/
protected void enableDetails(boolean enableState) {
if (detailsButton == null) {
enableDetailsButton = enableState;
} else {
detailsButton.setEnabled(enableState);
}
}
/**
* Start watching the ticks. When the long operation time has
* passed open the dialog.
*/
public void watchTicks() {
watchTime = System.currentTimeMillis();
}
/**
* Create a monitor for the receiver that wrappers the superclasses monitor.
*
*/
public void createWrapperedMonitor() {
wrapperedMonitor = new IProgressMonitorWithBlocking() {
IProgressMonitor superMonitor = ProgressMonitorJobsDialog.super
.getProgressMonitor();
/*
* (non-Javadoc)
*
* @see org.eclipse.core.runtime.IProgressMonitor#beginTask(java.lang.String,
* int)
*/
public void beginTask(String name, int totalWork) {
superMonitor.beginTask(name, totalWork);
checkTicking();
}
/**
* Check if we have ticked in the last 800ms.
*/
private void checkTicking() {
if (watchTime < 0) {
return;
}
if ((System.currentTimeMillis() - watchTime) > ProgressManager
.getInstance().getLongOperationTime()) {
watchTime = -1;
openDialog();
}
}
/**
* Open the dialog in the ui Thread
*/
private void openDialog() {
if (!PlatformUI.isWorkbenchRunning()) {
return;
}
PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
public void run() {
//Reset the watch if it is not safe to open
if (!ProgressManagerUtil.safeToOpen(ProgressMonitorJobsDialog.this,null)){
watchTicks();
return;
}
if (!alreadyClosed) {
open();
}
}
});
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.runtime.IProgressMonitor#done()
*/
public void done() {
superMonitor.done();
checkTicking();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.runtime.IProgressMonitor#internalWorked(double)
*/
public void internalWorked(double work) {
superMonitor.internalWorked(work);
checkTicking();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.runtime.IProgressMonitor#isCanceled()
*/
public boolean isCanceled() {
return superMonitor.isCanceled();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.runtime.IProgressMonitor#setCanceled(boolean)
*/
public void setCanceled(boolean value) {
superMonitor.setCanceled(value);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.runtime.IProgressMonitor#setTaskName(java.lang.String)
*/
public void setTaskName(String name) {
superMonitor.setTaskName(name);
checkTicking();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.runtime.IProgressMonitor#subTask(java.lang.String)
*/
public void subTask(String name) {
superMonitor.subTask(name);
checkTicking();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.runtime.IProgressMonitor#worked(int)
*/
public void worked(int work) {
superMonitor.worked(work);
checkTicking();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.runtime.IProgressMonitorWithBlocking#clearBlocked()
*/
public void clearBlocked() {
//We want to open on blocking too
if (superMonitor instanceof IProgressMonitorWithBlocking) {
((IProgressMonitorWithBlocking) superMonitor)
.clearBlocked();
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.runtime.IProgressMonitorWithBlocking#setBlocked(org.eclipse.core.runtime.IStatus)
*/
public void setBlocked(IStatus reason) {
openDialog();
if (superMonitor instanceof IProgressMonitorWithBlocking) {
((IProgressMonitorWithBlocking) superMonitor)
.setBlocked(reason);
}
}
};
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.dialogs.ProgressMonitorDialog#getProgressMonitor()
*/
public IProgressMonitor getProgressMonitor() {
if (wrapperedMonitor == null) {
createWrapperedMonitor();
}
return wrapperedMonitor;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.dialogs.ProgressMonitorDialog#close()
*/
public boolean close() {
alreadyClosed = true;//As this sometimes delayed cache if it was already closed
boolean result = super.close();
if (!result) {//If it fails reset the flag
alreadyClosed = false;
}
return result;
}
/*
* (non-Javadoc)
* @see org.eclipse.jface.dialogs.Dialog#isResizable()
*/
protected boolean isResizable() {
return true;
}
}