| /******************************************************************************* |
| * Copyright (c) 2003, 2006 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 Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.ui.internal.progress; |
| |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.QualifiedName; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.jface.viewers.Viewer; |
| import org.eclipse.jface.viewers.ViewerComparator; |
| import org.eclipse.jface.window.IShellProvider; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.graphics.GC; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.ui.IWorkbench; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.IWorkbenchWindow; |
| import org.eclipse.ui.PartInitException; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.internal.RectangleAnimation; |
| import org.eclipse.ui.internal.WorkbenchPlugin; |
| import org.eclipse.ui.internal.WorkbenchWindow; |
| import org.eclipse.ui.internal.misc.StatusUtil; |
| import org.eclipse.ui.internal.util.BundleUtility; |
| import org.eclipse.ui.progress.IProgressConstants; |
| import org.eclipse.ui.views.IViewDescriptor; |
| |
| /** |
| * The ProgressUtil is a class that contains static utility methods used for the |
| * progress API. |
| */ |
| |
| public class ProgressManagerUtil { |
| /** |
| * A constant used by the progress support to determine if an operation is |
| * too short to show progress. |
| */ |
| public static long SHORT_OPERATION_TIME = 250; |
| |
| static final QualifiedName KEEP_PROPERTY = IProgressConstants.KEEP_PROPERTY; |
| |
| static final QualifiedName KEEPONE_PROPERTY = IProgressConstants.KEEPONE_PROPERTY; |
| |
| static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; |
| |
| static final QualifiedName INFRASTRUCTURE_PROPERTY = new QualifiedName(WorkbenchPlugin.PI_WORKBENCH,"INFRASTRUCTURE_PROPERTY");//$NON-NLS-1$ |
| |
| |
| private static String ellipsis = ProgressMessages.ProgressFloatingWindow_EllipsisValue; |
| |
| /** |
| * Return a status for the exception. |
| * |
| * @param exception |
| * @return IStatus |
| */ |
| static IStatus exceptionStatus(Throwable exception) { |
| return StatusUtil.newStatus(IStatus.ERROR, |
| exception.getMessage() == null ? "" : exception.getMessage(), //$NON-NLS-1$ |
| exception); |
| } |
| |
| /** |
| * Log the exception for debugging. |
| * |
| * @param exception |
| */ |
| static void logException(Throwable exception) { |
| BundleUtility.log(PlatformUI.PLUGIN_ID, exception); |
| } |
| |
| // /** |
| // * Sets the label provider for the viewer. |
| // * |
| // * @param viewer |
| // */ |
| // static void initLabelProvider(ProgressTreeViewer viewer) { |
| // viewer.setLabelProvider(new ProgressLabelProvider()); |
| // } |
| /** |
| * Return a viewer comparator for looking at the jobs. |
| * |
| * @return ViewerComparator |
| */ |
| static ViewerComparator getProgressViewerComparator() { |
| return 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); |
| } |
| }; |
| } |
| |
| /** |
| * Open the progress view in the supplied window. |
| * |
| * @param window |
| */ |
| static void openProgressView(WorkbenchWindow window) { |
| IWorkbenchPage page = window.getActivePage(); |
| if (page == null) { |
| return; |
| } |
| try { |
| IViewDescriptor reference = WorkbenchPlugin.getDefault() |
| .getViewRegistry() |
| .find(IProgressConstants.PROGRESS_VIEW_ID); |
| |
| if (reference == null) { |
| return; |
| } |
| page.showView(IProgressConstants.PROGRESS_VIEW_ID); |
| } catch (PartInitException exception) { |
| logException(exception); |
| } |
| } |
| |
| /** |
| * Shorten the given text <code>t</code> so that its length doesn't exceed |
| * the given width. The default implementation replaces characters in the |
| * center of the original string with an ellipsis ("..."). Override if you |
| * need a different strategy. |
| * |
| * @param textValue |
| * @param control |
| * @return String |
| */ |
| static String shortenText(String textValue, Control control) { |
| if (textValue == null) { |
| return null; |
| } |
| GC gc = new GC(control); |
| int maxWidth = control.getBounds().width - 5; |
| if (gc.textExtent(textValue).x < maxWidth) { |
| gc.dispose(); |
| return textValue; |
| } |
| int length = textValue.length(); |
| int ellipsisWidth = gc.textExtent(ellipsis).x; |
| // Find the second space seperator and start from there |
| int secondWord = findSecondWhitespace(textValue, gc, maxWidth); |
| int pivot = ((length - secondWord) / 2) + secondWord; |
| int start = pivot; |
| int end = pivot + 1; |
| while (start >= secondWord && end < length) { |
| String s1 = textValue.substring(0, start); |
| String s2 = textValue.substring(end, length); |
| int l1 = gc.textExtent(s1).x; |
| int l2 = gc.textExtent(s2).x; |
| if (l1 + ellipsisWidth + l2 < maxWidth) { |
| gc.dispose(); |
| return s1 + ellipsis + s2; |
| } |
| start--; |
| end++; |
| } |
| gc.dispose(); |
| return textValue; |
| } |
| |
| /** |
| * Find the second index of a whitespace. Return the first index if there |
| * isn't one or 0 if there is no space at all. |
| * |
| * @param textValue |
| * @param gc |
| * The GC to test max length |
| * @param maxWidth |
| * The maximim extent |
| * @return int |
| */ |
| private static int findSecondWhitespace(String textValue, GC gc, |
| int maxWidth) { |
| int firstCharacter = 0; |
| char[] chars = textValue.toCharArray(); |
| // Find the first whitespace |
| for (int i = 0; i < chars.length; i++) { |
| if (Character.isWhitespace(chars[i])) { |
| firstCharacter = i; |
| break; |
| } |
| } |
| // If we didn't find it once don't continue |
| if (firstCharacter == 0) { |
| return 0; |
| } |
| // Initialize to firstCharacter in case there is no more whitespace |
| int secondCharacter = firstCharacter; |
| // Find the second whitespace |
| for (int i = firstCharacter; i < chars.length; i++) { |
| if (Character.isWhitespace(chars[i])) { |
| secondCharacter = i; |
| break; |
| } |
| } |
| // Check that we haven't gone over max width. Throw |
| // out an index that is too high |
| if (gc.textExtent(textValue.substring(0, secondCharacter)).x > maxWidth) { |
| if (gc.textExtent(textValue.substring(0, firstCharacter)).x > maxWidth) { |
| return 0; |
| } |
| return firstCharacter; |
| } |
| return secondCharacter; |
| } |
| |
| /** |
| * If there are any modal shells open reschedule openJob to wait until they |
| * are closed. Return true if it rescheduled, false if there is nothing |
| * blocking it. |
| * |
| * @param openJob |
| * @return boolean. true if the job was rescheduled due to modal dialogs. |
| */ |
| public static boolean rescheduleIfModalShellOpen(Job openJob) { |
| Shell modal = getModalShellExcluding(null); |
| if (modal == null) { |
| return false; |
| } |
| |
| // try again in a few seconds |
| openJob.schedule(PlatformUI.getWorkbench().getProgressService() |
| .getLongOperationTime()); |
| return true; |
| } |
| |
| /** |
| * Return whether or not it is safe to open this dialog. If so then return |
| * <code>true</code>. If not then set it to open itself when it has had |
| * ProgressManager#longOperationTime worth of ticks. |
| * |
| * @param dialog |
| * ProgressMonitorJobsDialog that will be opening |
| * @param excludedShell |
| * The shell |
| * @return boolean. <code>true</code> if it can open. Otherwise return |
| * false and set the dialog to tick. |
| */ |
| public static boolean safeToOpen(ProgressMonitorJobsDialog dialog, |
| Shell excludedShell) { |
| Shell modal = getModalShellExcluding(excludedShell); |
| if (modal == null) { |
| return true; |
| } |
| |
| dialog.watchTicks(); |
| return false; |
| } |
| |
| /** |
| * Return the modal shell that is currently open. If there isn't one then |
| * return null. |
| * |
| * @param shell |
| * A shell to exclude from the search. May be <code>null</code>. |
| * |
| * @return Shell or <code>null</code>. |
| */ |
| public static Shell getModalShellExcluding(Shell shell) { |
| IWorkbench workbench = PlatformUI.getWorkbench(); |
| Shell[] shells = workbench.getDisplay().getShells(); |
| int modal = SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL |
| | SWT.PRIMARY_MODAL; |
| for (int i = 0; i < shells.length; i++) { |
| if (shells[i].equals(shell)) { |
| break; |
| } |
| // Do not worry about shells that will not block the user. |
| if (shells[i].isVisible()) { |
| int style = shells[i].getStyle(); |
| if ((style & modal) != 0) { |
| return shells[i]; |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Utility method to get the best parenting possible for a dialog. If there |
| * is a modal shell create it so as to avoid two modal dialogs. If not then |
| * return the shell of the active workbench window. If neither can be found |
| * return null. |
| * |
| * @return Shell or <code>null</code> |
| */ |
| public static Shell getDefaultParent() { |
| Shell modal = getModalShellExcluding(null); |
| if (modal != null) { |
| return modal; |
| } |
| |
| return getNonModalShell(); |
| } |
| |
| /** |
| * Get the active non modal shell. If there isn't one return null. |
| * |
| * @return Shell |
| */ |
| public static Shell getNonModalShell() { |
| IWorkbenchWindow window = PlatformUI.getWorkbench() |
| .getActiveWorkbenchWindow(); |
| if (window == null) { |
| IWorkbenchWindow[] windows = PlatformUI.getWorkbench() |
| .getWorkbenchWindows(); |
| if (windows.length > 0) |
| return windows[0].getShell(); |
| } else |
| return window.getShell(); |
| |
| return null; |
| } |
| |
| /** |
| * Animate the closing of a window given the start position down to the |
| * progress region. |
| * |
| * @param startPosition |
| * Rectangle. The position to start drawing from. |
| */ |
| public static void animateDown(Rectangle startPosition) { |
| IWorkbenchWindow currentWindow = PlatformUI.getWorkbench() |
| .getActiveWorkbenchWindow(); |
| if (currentWindow == null) { |
| return; |
| } |
| WorkbenchWindow internalWindow = (WorkbenchWindow) currentWindow; |
| |
| ProgressRegion progressRegion = internalWindow.getProgressRegion(); |
| if (progressRegion == null) { |
| return; |
| } |
| Rectangle endPosition = progressRegion.getControl().getBounds(); |
| |
| Point windowLocation = internalWindow.getShell().getLocation(); |
| endPosition.x += windowLocation.x; |
| endPosition.y += windowLocation.y; |
| RectangleAnimation animation = new RectangleAnimation(internalWindow |
| .getShell(), startPosition, endPosition); |
| animation.schedule(); |
| } |
| |
| /** |
| * Animate the opening of a window given the start position down to the |
| * progress region. |
| * |
| * @param endPosition |
| * Rectangle. The position to end drawing at. |
| */ |
| public static void animateUp(Rectangle endPosition) { |
| IWorkbenchWindow currentWindow = PlatformUI.getWorkbench() |
| .getActiveWorkbenchWindow(); |
| if (currentWindow == null) { |
| return; |
| } |
| WorkbenchWindow internalWindow = (WorkbenchWindow) currentWindow; |
| Point windowLocation = internalWindow.getShell().getLocation(); |
| |
| ProgressRegion progressRegion = internalWindow.getProgressRegion(); |
| if (progressRegion == null) { |
| return; |
| } |
| Rectangle startPosition = progressRegion.getControl().getBounds(); |
| startPosition.x += windowLocation.x; |
| startPosition.y += windowLocation.y; |
| |
| RectangleAnimation animation = new RectangleAnimation(internalWindow |
| .getShell(), startPosition, endPosition); |
| animation.schedule(); |
| } |
| |
| /** |
| * Get the shell provider to use in the progress support dialogs. This |
| * provider will try to always parent off of an existing modal shell. If |
| * there isn't one it will use the current workbench window. |
| * |
| * @return IShellProvider |
| */ |
| static IShellProvider getShellProvider() { |
| return new IShellProvider() { |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.window.IShellProvider#getShell() |
| */ |
| public Shell getShell() { |
| return getDefaultParent(); |
| } |
| }; |
| } |
| |
| /** |
| * Get the icons root for the progress support. |
| * @return URL |
| */ |
| public static URL getIconsRoot() { |
| return BundleUtility.find(PlatformUI.PLUGIN_ID, |
| ProgressManager.PROGRESS_FOLDER); |
| } |
| |
| /** |
| * Return the location of the progress spinner. |
| * @return URL or <code>null</code> if it cannot be found |
| */ |
| public static URL getProgressSpinnerLocation(){ |
| try { |
| return new URL(getIconsRoot(), "progress_spinner.gif");//$NON-NLS-1$ |
| } catch (MalformedURLException e) { |
| return null; |
| } |
| } |
| } |