| /******************************************************************************* |
| * Copyright (c) 2004, 2020 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM - Initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.ui.internal.progress; |
| |
| import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| 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.swt.SWT; |
| 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; |
| |
| /** Flag to prevent nested closes. */ |
| 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 dialogs parent shell |
| */ |
| public ProgressMonitorJobsDialog(Shell parent) { |
| super(parent); |
| } |
| |
| @Override |
| protected Control createDialogArea(Composite parent) { |
| Composite top = (Composite) super.createDialogArea(parent); |
| createExtendedDialogArea(parent); |
| return top; |
| } |
| |
| /** |
| * Create the extensions to the dialog area. |
| * |
| * @param parent the parent composite |
| */ |
| 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(ProgressManagerUtil.getProgressViewerComparator()); |
| |
| viewer.setContentProvider(new ProgressViewerContentProvider(viewer, true, false) { |
| @Override |
| 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); |
| } |
| } |
| |
| @Override |
| 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(widgetSelectedAdapter(e -> handleDetailsButtonSelect())); |
| detailsButton.setCursor(arrowCursor); |
| detailsButton.setEnabled(enableDetailsButton); |
| } |
| |
| @Override |
| 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; |
| } |
| |
| @Override |
| protected void clearCursors() { |
| if (detailsButton != null && !detailsButton.isDisposed()) { |
| detailsButton.setCursor(null); |
| } |
| super.clearCursors(); |
| } |
| |
| @Override |
| protected void updateForSetBlocked(IStatus reason) { |
| if (alreadyClosed) |
| return; |
| |
| super.updateForSetBlocked(reason); |
| enableDetails(true); |
| if (viewer == null) { |
| handleDetailsButtonSelect(); |
| } |
| } |
| |
| @Override |
| 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 IProgressMonitor() { |
| |
| IProgressMonitor superMonitor = ProgressMonitorJobsDialog.super.getProgressMonitor(); |
| |
| @Override |
| 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(() -> { |
| // Reset the watch if it is not safe to open |
| if (!ProgressManagerUtil.safeToOpen(ProgressMonitorJobsDialog.this, null)) { |
| watchTicks(); |
| return; |
| } |
| |
| if (!alreadyClosed) { |
| open(); |
| } |
| }); |
| } |
| |
| @Override |
| public void done() { |
| superMonitor.done(); |
| checkTicking(); |
| } |
| |
| @Override |
| public void internalWorked(double work) { |
| superMonitor.internalWorked(work); |
| checkTicking(); |
| } |
| |
| @Override |
| public boolean isCanceled() { |
| return superMonitor.isCanceled(); |
| } |
| |
| @Override |
| public void setCanceled(boolean value) { |
| superMonitor.setCanceled(value); |
| |
| } |
| |
| @Override |
| public void setTaskName(String name) { |
| superMonitor.setTaskName(name); |
| checkTicking(); |
| |
| } |
| |
| @Override |
| public void subTask(String name) { |
| superMonitor.subTask(name); |
| checkTicking(); |
| } |
| |
| @Override |
| public void worked(int work) { |
| superMonitor.worked(work); |
| checkTicking(); |
| |
| } |
| |
| @Override |
| public void clearBlocked() { |
| // We want to open on blocking too |
| superMonitor.clearBlocked(); |
| |
| } |
| |
| @Override |
| public void setBlocked(IStatus reason) { |
| openDialog(); |
| superMonitor.setBlocked(reason); |
| } |
| |
| }; |
| } |
| |
| @Override |
| public IProgressMonitor getProgressMonitor() { |
| if (wrapperedMonitor == null) { |
| createWrapperedMonitor(); |
| } |
| return wrapperedMonitor; |
| } |
| |
| @Override |
| 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; |
| } |
| |
| @Override |
| protected boolean isResizable() { |
| return true; |
| } |
| } |