| /******************************************************************************* |
| * Copyright (c) 2005, 2015 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 Corporation - initial API and implementation |
| * Lars Vogel <Lars.Vogel@gmail.com> - Bug 422040, 440810 |
| * G.R.Prakash <me@grprakash.com> - Bug 394036 |
| * Manumitting Technologies - Bug 394036 |
| *******************************************************************************/ |
| |
| package org.eclipse.ui.internal.progress; |
| |
| import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter; |
| |
| import java.net.URL; |
| import java.text.DateFormat; |
| import java.util.ArrayList; |
| import java.util.Date; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Optional; |
| import org.eclipse.core.commands.ExecutionException; |
| import org.eclipse.core.commands.NotEnabledException; |
| import org.eclipse.core.commands.NotHandledException; |
| import org.eclipse.core.commands.ParameterizedCommand; |
| import org.eclipse.core.commands.common.NotDefinedException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.e4.core.commands.EHandlerService; |
| import org.eclipse.e4.core.contexts.IEclipseContext; |
| import org.eclipse.e4.core.contexts.RunAndTrack; |
| import org.eclipse.e4.ui.css.swt.theme.ITheme; |
| import org.eclipse.e4.ui.css.swt.theme.IThemeEngine; |
| import org.eclipse.jface.action.IAction; |
| import org.eclipse.jface.dialogs.Dialog; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.resource.ImageDescriptor; |
| import org.eclipse.jface.resource.JFaceResources; |
| import org.eclipse.jface.resource.LocalResourceManager; |
| import org.eclipse.jface.resource.ResourceManager; |
| import org.eclipse.jface.util.Util; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.MouseAdapter; |
| import org.eclipse.swt.events.MouseEvent; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.RGB; |
| import org.eclipse.swt.layout.FormAttachment; |
| import org.eclipse.swt.layout.FormData; |
| import org.eclipse.swt.layout.FormLayout; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Link; |
| import org.eclipse.swt.widgets.ProgressBar; |
| import org.eclipse.swt.widgets.ToolBar; |
| import org.eclipse.swt.widgets.ToolItem; |
| import org.eclipse.ui.IWorkbench; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.handlers.IHandlerService; |
| import org.eclipse.ui.internal.WorkbenchImages; |
| import org.eclipse.ui.progress.IProgressConstants; |
| import org.eclipse.ui.progress.IProgressConstants2; |
| import org.eclipse.ui.statushandlers.StatusManager; |
| |
| /** |
| * ProgressInfoItem is the item used to show jobs. |
| * |
| * @since 3.1 |
| * |
| */ |
| public class ProgressInfoItem extends Composite { |
| |
| static String STOP_IMAGE_KEY = "org.eclipse.ui.internal.progress.PROGRESS_STOP"; //$NON-NLS-1$ |
| |
| static String DISABLED_STOP_IMAGE_KEY = "org.eclipse.ui.internal.progress.DISABLED_PROGRESS_STOP"; //$NON-NLS-1$ |
| |
| static String CLEAR_FINISHED_JOB_KEY = "org.eclipse.ui.internal.progress.CLEAR_FINISHED_JOB"; //$NON-NLS-1$ |
| |
| static String DISABLED_CLEAR_FINISHED_JOB_KEY = "org.eclipse.ui.internal.progress.DISABLED_CLEAR_FINISHED_JOB"; //$NON-NLS-1$ |
| |
| static String DEFAULT_JOB_KEY = "org.eclipse.ui.internal.progress.PROGRESS_DEFAULT"; //$NON-NLS-1$ |
| |
| static String DARK_COLOR_KEY = "org.eclipse.ui.internal.progress.PROGRESS_DARK_COLOR"; //$NON-NLS-1$ |
| |
| static String DEFAULT_THEME = "org.eclipse.e4.ui.css.theme.e4_default"; //$NON-NLS-1$ |
| |
| JobTreeElement info; |
| |
| Label progressLabel; |
| |
| ToolBar actionBar; |
| |
| ToolItem actionButton; |
| |
| List<Link> taskEntries = new ArrayList<>(0); |
| |
| private ProgressBar progressBar; |
| |
| private Label jobImageLabel; |
| |
| static final int MAX_PROGRESS_HEIGHT = 12; |
| |
| static final int MIN_ICON_SIZE = 16; |
| |
| private static final String TEXT_KEY = "Text"; //$NON-NLS-1$ |
| |
| private static final String TRIGGER_KEY = "Trigger";//$NON-NLS-1$ |
| |
| interface IndexListener { |
| /** |
| * Select the item previous to the receiver. |
| */ |
| void selectPrevious(); |
| |
| /** |
| * Select the next previous to the receiver. |
| */ |
| void selectNext(); |
| |
| /** |
| * Select the receiver. |
| */ |
| void select(); |
| } |
| |
| IndexListener indexListener; |
| |
| private int currentIndex; |
| |
| private boolean selected; |
| |
| private MouseAdapter mouseListener; |
| |
| private boolean isShowing = true; |
| |
| private ResourceManager resourceManager; |
| |
| private Link link; |
| |
| private HandlerChangeTracker tracker; |
| |
| private boolean isThemed; |
| |
| static { |
| JFaceResources.getImageRegistry().put(STOP_IMAGE_KEY, |
| WorkbenchImages.getWorkbenchImageDescriptor("elcl16/progress_stop.png"));//$NON-NLS-1$ |
| |
| JFaceResources.getImageRegistry().put(DISABLED_STOP_IMAGE_KEY, |
| WorkbenchImages.getWorkbenchImageDescriptor("dlcl16/progress_stop.png"));//$NON-NLS-1$ |
| |
| JFaceResources.getImageRegistry().put(DEFAULT_JOB_KEY, |
| WorkbenchImages.getWorkbenchImageDescriptor("progress/progress_task.png")); //$NON-NLS-1$ |
| |
| JFaceResources.getImageRegistry().put(CLEAR_FINISHED_JOB_KEY, |
| WorkbenchImages.getWorkbenchImageDescriptor("elcl16/progress_rem.png")); //$NON-NLS-1$ |
| |
| JFaceResources.getImageRegistry().put(DISABLED_CLEAR_FINISHED_JOB_KEY, |
| WorkbenchImages.getWorkbenchImageDescriptor("dlcl16/progress_rem.png")); //$NON-NLS-1$ |
| |
| // Mac has different Gamma value |
| int shift = Util.isMac() ? -25 : -10; |
| |
| Color lightColor = PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND); |
| |
| // Determine a dark color by shifting the list color |
| RGB darkRGB = new RGB(Math.max(0, lightColor.getRed() + shift), Math.max(0, lightColor.getGreen() + shift), |
| Math.max(0, lightColor.getBlue() + shift)); |
| JFaceResources.getColorRegistry().put(DARK_COLOR_KEY, darkRGB); |
| } |
| |
| /** |
| * Create a new instance of the receiver with the specified parent, style and |
| * info object/ |
| * |
| * @param parent the parent composite |
| * @param style the style to use for the info item's composite |
| * @param progressInfo the job element to represent |
| */ |
| public ProgressInfoItem(Composite parent, int style, JobTreeElement progressInfo) { |
| super(parent, style); |
| info = progressInfo; |
| isThemed = getCustomThemeFlag(); |
| setData(info); |
| setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false)); |
| createChildren(); |
| } |
| |
| /** |
| * Create the child widgets of the receiver. |
| */ |
| protected void createChildren() { |
| |
| FormLayout layout = new FormLayout(); |
| setLayout(layout); |
| |
| jobImageLabel = new Label(this, SWT.NONE); |
| Image infoImage = getInfoImage(); |
| jobImageLabel.setImage(infoImage); |
| FormData imageData = new FormData(); |
| if (infoImage != null) { |
| // position it in the center |
| imageData.top = new FormAttachment(50, -infoImage.getBounds().height / 2); |
| } else { |
| imageData.top = new FormAttachment(0, IDialogConstants.VERTICAL_SPACING); |
| } |
| imageData.left = new FormAttachment(0, IDialogConstants.HORIZONTAL_SPACING / 2); |
| jobImageLabel.setLayoutData(imageData); |
| |
| progressLabel = new Label(this, SWT.NONE); |
| progressLabel.addListener(SWT.Resize, event -> setMainText()); |
| setMainText(); |
| |
| actionBar = new ToolBar(this, SWT.FLAT); |
| actionBar.setCursor(getDisplay().getSystemCursor(SWT.CURSOR_ARROW)); |
| |
| // set cursor to overwrite any busy cursor we might have |
| |
| actionButton = new ToolItem(actionBar, SWT.NONE); |
| actionButton.setToolTipText(ProgressMessages.NewProgressView_CancelJobToolTip); |
| actionButton.addSelectionListener(widgetSelectedAdapter(e -> { |
| actionButton.setEnabled(false); |
| cancelOrRemove(); |
| })); |
| actionBar.addListener(SWT.Traverse, event -> { |
| if (indexListener == null) { |
| return; |
| } |
| int detail = event.detail; |
| if (detail == SWT.TRAVERSE_ARROW_NEXT) { |
| indexListener.selectNext(); |
| } |
| if (detail == SWT.TRAVERSE_ARROW_PREVIOUS) { |
| indexListener.selectPrevious(); |
| } |
| |
| }); |
| updateToolBarValues(); |
| |
| FormData progressData = new FormData(); |
| progressData.top = new FormAttachment(0, IDialogConstants.VERTICAL_SPACING); |
| progressData.left = new FormAttachment(jobImageLabel, IDialogConstants.HORIZONTAL_SPACING / 2); |
| progressData.right = new FormAttachment(actionBar, IDialogConstants.HORIZONTAL_SPACING * -1); |
| progressLabel.setLayoutData(progressData); |
| |
| mouseListener = new MouseAdapter() { |
| @Override |
| public void mouseDown(MouseEvent e) { |
| if (indexListener != null) { |
| indexListener.select(); |
| } |
| } |
| }; |
| addMouseListener(mouseListener); |
| jobImageLabel.addMouseListener(mouseListener); |
| progressLabel.addMouseListener(mouseListener); |
| |
| setLayoutsForNoProgress(); |
| |
| refresh(); |
| } |
| |
| /** |
| * Set the main text of the receiver. Truncate to fit the available space. |
| */ |
| private void setMainText() { |
| progressLabel.setText(Dialog.shortenText(getMainTitle(), progressLabel)); |
| } |
| |
| /** |
| * Set the layout of the widgets for the no progress case. |
| * |
| */ |
| private void setLayoutsForNoProgress() { |
| |
| FormData buttonData = new FormData(); |
| buttonData.top = new FormAttachment(progressLabel, 0, SWT.TOP); |
| buttonData.right = new FormAttachment(100, IDialogConstants.HORIZONTAL_SPACING * -1); |
| |
| actionBar.setLayoutData(buttonData); |
| if (taskEntries.size() > 0) { |
| FormData linkData = new FormData(); |
| linkData.top = new FormAttachment(progressLabel, IDialogConstants.VERTICAL_SPACING); |
| linkData.left = new FormAttachment(progressLabel, 0, SWT.LEFT); |
| linkData.right = new FormAttachment(actionBar, 0, SWT.LEFT); |
| taskEntries.get(0).setLayoutData(linkData); |
| |
| } |
| } |
| |
| /** |
| * Cancel or remove the receiver. |
| * |
| */ |
| protected void cancelOrRemove() { |
| |
| if (FinishedJobs.getInstance().isKept(info) && isCompleted()) { |
| FinishedJobs.getInstance().remove(info); |
| } else { |
| info.cancel(); |
| } |
| |
| } |
| |
| /** |
| * Get the image for the info. |
| * |
| * @return Image |
| */ |
| private Image getInfoImage() { |
| |
| if (!info.isJobInfo()) { |
| return JFaceResources.getImage(DEFAULT_JOB_KEY); |
| } |
| |
| JobInfo jobInfo = (JobInfo) info; |
| |
| ImageDescriptor descriptor = null; |
| Object property = jobInfo.getJob().getProperty(IProgressConstants.ICON_PROPERTY); |
| |
| if (property instanceof ImageDescriptor) { |
| descriptor = (ImageDescriptor) property; |
| } else if (property instanceof URL) { |
| descriptor = ImageDescriptor.createFromURL((URL) property); |
| } |
| |
| Image image = null; |
| if (descriptor == null) { |
| image = ProgressManager.getInstance().getIconFor(jobInfo.getJob()); |
| } else { |
| image = getResourceManager().createImageWithDefault(descriptor); |
| } |
| |
| if (image == null) |
| image = jobInfo.getDisplayImage(); |
| |
| return image; |
| } |
| |
| /** |
| * Return a resource manager for the receiver. |
| * |
| * @return {@link ResourceManager} |
| */ |
| private ResourceManager getResourceManager() { |
| if (resourceManager == null) |
| resourceManager = new LocalResourceManager(JFaceResources.getResources()); |
| return resourceManager; |
| } |
| |
| /** |
| * Get the main title for the receiver. |
| * |
| * @return String |
| */ |
| private String getMainTitle() { |
| if (info.isJobInfo()) { |
| return getJobNameAndStatus((JobInfo) info); |
| } |
| if (info.hasChildren()) { |
| return ((GroupInfo) info).getTaskName(); |
| } |
| return info.getDisplayString(); |
| |
| } |
| |
| /** |
| * Get the name and status for a jobInfo |
| * |
| * @param jobInfo job element to get display string for |
| * @return display string for job |
| */ |
| public String getJobNameAndStatus(JobInfo jobInfo) { |
| |
| Job job = jobInfo.getJob(); |
| |
| String name = job.getName(); |
| |
| if (job.isSystem()) { |
| name = NLS.bind(ProgressMessages.JobInfo_System, name); |
| } |
| |
| if (jobInfo.isCanceled()) { |
| if (job.getState() == Job.RUNNING) |
| return NLS.bind(ProgressMessages.JobInfo_Cancel_Requested, name); |
| return NLS.bind(ProgressMessages.JobInfo_Cancelled, name); |
| } |
| |
| IStatus blockedStatus = jobInfo.getBlockedStatus(); |
| if (blockedStatus != null) { |
| return NLS.bind(ProgressMessages.JobInfo_Blocked, name, blockedStatus.getMessage()); |
| } |
| |
| switch (job.getState()) { |
| case Job.RUNNING: |
| return name; |
| case Job.SLEEPING: { |
| return NLS.bind(ProgressMessages.JobInfo_Sleeping, name); |
| |
| } |
| case Job.NONE: // Only happens for kept jobs |
| return getJobInfoFinishedString(job, true); |
| default: |
| return NLS.bind(ProgressMessages.JobInfo_Waiting, name); |
| } |
| } |
| |
| /** |
| * Return the finished String for a job. |
| * |
| * @param job the completed Job |
| * @param withTime |
| * @return String |
| */ |
| String getJobInfoFinishedString(Job job, boolean withTime) { |
| String time = null; |
| if (withTime) { |
| time = getTimeString(); |
| } |
| if (time != null) { |
| return NLS.bind(ProgressMessages.JobInfo_FinishedAt, job.getName(), time); |
| } |
| return NLS.bind(ProgressMessages.JobInfo_Finished, job.getName()); |
| } |
| |
| /** |
| * Get the time string the finished job |
| * |
| * @return String or <code>null</code> if this is not one of the finished jobs. |
| */ |
| private String getTimeString() { |
| Date date = FinishedJobs.getInstance().getFinishDate(info); |
| if (date != null) { |
| return DateFormat.getTimeInstance(DateFormat.SHORT).format(date); |
| } |
| return null; |
| } |
| |
| /** |
| * Refresh the contents of the receiver. |
| * |
| */ |
| void refresh() { |
| |
| // Don't refresh if not visible |
| if (isDisposed() || !isShowing) |
| return; |
| |
| jobImageLabel.setImage(getInfoImage()); |
| int percentDone = getPercentDone(); |
| ProgressBar currentProgressBar = progressBar; |
| |
| JobInfo[] infos = getJobInfos(); |
| if (isRunning()) { |
| if (progressBar == null) { |
| if (percentDone == IProgressMonitor.UNKNOWN) { |
| // Only do it if there is an indeterminate task |
| // There may be no task so we don't want to create it |
| // until we know for sure |
| for (JobInfo jobInfo : infos) { |
| Optional<TaskInfo> optionalInfo = jobInfo.getTaskInfo(); |
| if (optionalInfo.isPresent() && optionalInfo.get().totalWork == IProgressMonitor.UNKNOWN) { |
| createProgressBar(SWT.INDETERMINATE); |
| break; |
| } |
| } |
| } else { |
| createProgressBar(SWT.NONE); |
| progressBar.setMinimum(0); |
| progressBar.setMaximum(100); |
| } |
| } |
| |
| // Protect against bad counters |
| if (percentDone >= 0 && percentDone <= 100 && percentDone != progressBar.getSelection()) { |
| progressBar.setSelection(percentDone); |
| } |
| } |
| |
| else if (isCompleted()) { |
| |
| if (progressBar != null) { |
| progressBar.dispose(); |
| progressBar = null; |
| } |
| setLayoutsForNoProgress(); |
| |
| } |
| |
| for (int i = 0; i < infos.length; i++) { |
| JobInfo jobInfo = infos[i]; |
| Optional<TaskInfo> optionalInfo = jobInfo.getTaskInfo(); |
| if (optionalInfo.isPresent()) { |
| TaskInfo taskInfo = optionalInfo.get(); |
| |
| String taskString = taskInfo.getTaskName(); |
| String subTaskString = null; |
| Object[] jobChildren = jobInfo.getChildren(); |
| if (jobChildren.length > 0) { |
| subTaskString = ((JobTreeElement) jobChildren[0]).getDisplayString(); |
| } |
| |
| if (subTaskString != null) { |
| if (taskString == null || taskString.length() == 0) { |
| taskString = subTaskString; |
| } else { |
| taskString = NLS.bind(ProgressMessages.JobInfo_DoneNoProgressMessage, taskString, |
| subTaskString); |
| } |
| } |
| if (taskString != null) { |
| setLinkText(infos[i].getJob(), taskString, i); |
| } |
| } else {// Check for the finished job state |
| Job job = jobInfo.getJob(); |
| IStatus result = job.getResult(); |
| |
| if (result == null || result.getMessage().length() == 0 && !info.isJobInfo()) { |
| setLinkText(job, getJobNameAndStatus(jobInfo), i); |
| } else { |
| setLinkText(job, result.getMessage(), i); |
| |
| } |
| |
| } |
| setColor(currentIndex); |
| } |
| |
| // Remove completed tasks |
| if (infos.length < taskEntries.size()) { |
| for (int i = infos.length; i < taskEntries.size(); i++) { |
| taskEntries.get(i).dispose(); |
| |
| } |
| if (infos.length > 1) |
| taskEntries = taskEntries.subList(0, infos.length - 1); |
| else |
| taskEntries.clear(); |
| } |
| |
| updateToolBarValues(); |
| setMainText(); |
| |
| if (currentProgressBar != progressBar) { |
| requestLayout(); |
| } |
| } |
| |
| /** |
| * Return whether or not the receiver is a completed job. |
| * |
| * @return boolean <code>true</code> if the state is Job#NONE. |
| */ |
| private boolean isCompleted() { |
| |
| JobInfo[] infos = getJobInfos(); |
| for (JobInfo jobInfo : infos) { |
| if (jobInfo.getJob().getState() != Job.NONE) { |
| return false; |
| } |
| } |
| // Only completed if there are any jobs |
| return infos.length > 0; |
| } |
| |
| /** |
| * Return the job infos in the receiver. |
| * |
| * @return JobInfo[] |
| */ |
| public JobInfo[] getJobInfos() { |
| if (info.isJobInfo()) { |
| return new JobInfo[] { (JobInfo) info }; |
| } |
| Object[] children = info.getChildren(); |
| JobInfo[] infos = new JobInfo[children.length]; |
| System.arraycopy(children, 0, infos, 0, children.length); |
| return infos; |
| } |
| |
| /** |
| * Return whether or not the receiver is being displayed as running. |
| * |
| * @return boolean |
| */ |
| private boolean isRunning() { |
| |
| for (JobInfo jobInfo : getJobInfos()) { |
| int state = jobInfo.getJob().getState(); |
| if (state == Job.WAITING || state == Job.RUNNING) |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Get the current percent done. |
| * |
| * @return int |
| */ |
| private int getPercentDone() { |
| if (info.isJobInfo()) { |
| return ((JobInfo) info).getPercentDone(); |
| } |
| |
| if (info.hasChildren()) { |
| Object[] roots = ((GroupInfo) info).getChildren(); |
| if (roots.length == 1 && roots[0] instanceof JobTreeElement) { |
| Optional<TaskInfo> optionalInfo = ((JobInfo) roots[0]).getTaskInfo(); |
| if (optionalInfo.isPresent()) { |
| return optionalInfo.get().getPercentDone(); |
| } |
| } |
| return ((GroupInfo) info).getPercentDone(); |
| } |
| return 0; |
| } |
| |
| /** |
| * Set the images in the toolbar based on whether the receiver is finished or |
| * not. Also update tooltips if required. |
| * |
| */ |
| private void updateToolBarValues() { |
| if (isCompleted()) { |
| actionButton.setImage(JFaceResources.getImage(CLEAR_FINISHED_JOB_KEY)); |
| actionButton.setDisabledImage(JFaceResources.getImage(DISABLED_CLEAR_FINISHED_JOB_KEY)); |
| actionButton.setToolTipText(ProgressMessages.NewProgressView_ClearJobToolTip); |
| } else { |
| actionButton.setImage(JFaceResources.getImage(STOP_IMAGE_KEY)); |
| actionButton.setDisabledImage(JFaceResources.getImage(DISABLED_STOP_IMAGE_KEY)); |
| |
| } |
| |
| for (JobInfo jobInfo : getJobInfos()) { |
| // Only disable if there is an unresponsive operation |
| if (jobInfo.isCanceled() && !isCompleted()) { |
| actionButton.setEnabled(false); |
| return; |
| } |
| } |
| actionButton.setEnabled(true); |
| } |
| |
| /** |
| * Create the progress bar and apply any style bits from style. |
| * |
| * @param style |
| */ |
| void createProgressBar(int style) { |
| FormData buttonData = new FormData(); |
| buttonData.top = new FormAttachment(progressLabel, 0); |
| buttonData.right = new FormAttachment(100, IDialogConstants.HORIZONTAL_SPACING * -1); |
| |
| actionBar.setLayoutData(buttonData); |
| |
| progressBar = new ProgressBar(this, SWT.HORIZONTAL | style); |
| FormData barData = new FormData(); |
| barData.top = new FormAttachment(actionBar, IDialogConstants.VERTICAL_SPACING, SWT.TOP); |
| barData.left = new FormAttachment(progressLabel, 0, SWT.LEFT); |
| barData.right = new FormAttachment(actionBar, IDialogConstants.HORIZONTAL_SPACING * -1); |
| barData.height = MAX_PROGRESS_HEIGHT; |
| barData.width = 0;// default is too large |
| progressBar.setLayoutData(barData); |
| |
| if (taskEntries.size() > 0) { |
| // Reattach the link label if there is one |
| FormData linkData = new FormData(); |
| linkData.top = new FormAttachment(progressBar, IDialogConstants.VERTICAL_SPACING); |
| linkData.left = new FormAttachment(progressBar, 0, SWT.LEFT); |
| linkData.right = new FormAttachment(progressBar, 0, SWT.RIGHT); |
| |
| taskEntries.get(0).setLayoutData(linkData); |
| } |
| } |
| |
| /** |
| * Set the text of the link to the taskString. |
| * |
| * @param taskString |
| */ |
| void setLinkText(Job linkJob, String taskString, int index) { |
| if (index >= taskEntries.size()) {// Is it new? |
| link = new Link(this, SWT.NONE); |
| |
| FormData linkData = new FormData(); |
| if (index == 0 || taskEntries.isEmpty()) { |
| Control top = progressBar; |
| if (top == null) { |
| top = progressLabel; |
| } |
| linkData.top = new FormAttachment(top, IDialogConstants.VERTICAL_SPACING); |
| linkData.left = new FormAttachment(top, 0, SWT.LEFT); |
| linkData.right = new FormAttachment(top, 0, SWT.RIGHT); |
| } else { |
| Link previous = taskEntries.get(index - 1); |
| linkData.top = new FormAttachment(previous, IDialogConstants.VERTICAL_SPACING); |
| linkData.left = new FormAttachment(previous, 0, SWT.LEFT); |
| linkData.right = new FormAttachment(previous, 0, SWT.RIGHT); |
| } |
| |
| link.setLayoutData(linkData); |
| |
| link.addSelectionListener(widgetSelectedAdapter(e -> executeTrigger())); |
| |
| link.addListener(SWT.Resize, event -> { |
| |
| Object text = link.getData(TEXT_KEY); |
| if (text == null) |
| return; |
| |
| updateText((String) text, link); |
| |
| }); |
| taskEntries.add(link); |
| } else { |
| link = taskEntries.get(index); |
| } |
| |
| // check for action property |
| Object actionProperty = linkJob.getProperty(IProgressConstants.ACTION_PROPERTY); |
| Object commandProperty = linkJob.getProperty(IProgressConstants2.COMMAND_PROPERTY); |
| |
| if (actionProperty != null && commandProperty != null) { |
| // if both are specified, then use neither |
| updateTrigger(null, link); |
| } else { |
| Object property = actionProperty != null ? actionProperty : commandProperty; |
| updateTrigger(property, link); |
| } |
| |
| if (link.getData(TRIGGER_KEY) == null && (taskString == null || taskString.equals(getMainTitle()))) { |
| // workaround for https://bugs.eclipse.org/383570 |
| taskString = ""; //$NON-NLS-1$ |
| } |
| link.setToolTipText(taskString); |
| link.setData(TEXT_KEY, taskString); |
| |
| updateText(taskString, link); |
| } |
| |
| /** |
| * The action/trigger associated with this progress item should be executed. |
| */ |
| public void executeTrigger() { |
| Object data = link.getData(TRIGGER_KEY); |
| if (data instanceof IAction) { |
| IAction action = (IAction) data; |
| if (action.isEnabled()) |
| action.run(); |
| updateTrigger(action, link); |
| } else if (data instanceof ParameterizedCommand) { |
| IWorkbench workbench = PlatformUI.getWorkbench(); |
| IHandlerService handlerService = workbench.getService(IHandlerService.class); |
| IStatus status = Status.OK_STATUS; |
| try { |
| handlerService.executeCommand((ParameterizedCommand) data, null); |
| } catch (NotEnabledException e) { |
| status = new Status(IStatus.WARNING, PlatformUI.PLUGIN_ID, e.getMessage(), e); |
| } catch (ExecutionException | NotDefinedException | NotHandledException e) { |
| status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, e.getMessage(), e); |
| } |
| |
| if (!status.isOK()) { |
| StatusManager.getManager().handle(status, StatusManager.LOG | StatusManager.SHOW); |
| } |
| } |
| |
| if (link.isDisposed()) { |
| return; |
| } |
| |
| Object text = link.getData(TEXT_KEY); |
| if (text == null) |
| return; |
| |
| // Refresh the text as enablement might have changed |
| updateText((String) text, link); |
| } |
| |
| /** |
| * Update the trigger key if either action is available and enabled or command |
| * is available |
| * |
| * @param trigger {@link Object} or <code>null</code> |
| * @param link |
| */ |
| private void updateTrigger(Object trigger, Link link) { |
| if (link.isDisposed()) { |
| return; |
| } |
| |
| if (trigger instanceof IAction && ((IAction) trigger).isEnabled()) { |
| link.setData(TRIGGER_KEY, trigger); |
| } else if (trigger instanceof ParameterizedCommand) { |
| link.setData(TRIGGER_KEY, trigger); |
| hookTriggerCommandEnablement(); |
| } else { |
| link.setData(TRIGGER_KEY, null); |
| } |
| } |
| |
| /** |
| * Update the text in the link |
| * |
| * @param taskString |
| * @param link |
| */ |
| private void updateText(String taskString, Link link) { |
| if (taskString == null) { |
| taskString = ""; //$NON-NLS-1$ |
| } |
| if (!taskString.isEmpty()) { |
| taskString = Dialog.shortenText(taskString, link); |
| } |
| |
| // Put in a hyperlink if there is an action |
| String text = link.getData(TRIGGER_KEY) == null ? taskString : NLS.bind("<a>{0}</a>", taskString); //$NON-NLS-1$ |
| if (!text.equals(link.getText())) { |
| link.setText(text); |
| } |
| } |
| |
| /** |
| * Set the color base on the index |
| * |
| * @param row the item's index in presentation |
| */ |
| public void setColor(int row) { |
| currentIndex = row; |
| |
| if (selected) { |
| setAllBackgrounds(getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION)); |
| setAllForegrounds(getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT)); |
| return; |
| } |
| |
| if (!isThemed) { |
| if (row % 2 == 0) { |
| setAllBackgrounds(JFaceResources.getColorRegistry().get(DARK_COLOR_KEY)); |
| } else { |
| setAllBackgrounds(getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND)); |
| } |
| setAllForegrounds(getDisplay().getSystemColor(SWT.COLOR_LIST_FOREGROUND)); |
| } |
| |
| } |
| |
| /** |
| * Set the foreground of all widgets to the supplied color. |
| * |
| * @param color the new foreground color |
| */ |
| private void setAllForegrounds(Color color) { |
| setForeground(color); |
| progressLabel.setForeground(color); |
| |
| Iterator<Link> taskEntryIterator = taskEntries.iterator(); |
| while (taskEntryIterator.hasNext()) { |
| taskEntryIterator.next().setForeground(color); |
| } |
| |
| } |
| |
| /** |
| * Set the background of all widgets to the supplied color. |
| * |
| * @param color the new background color |
| */ |
| private void setAllBackgrounds(Color color) { |
| setBackground(color); |
| progressLabel.setBackground(color); |
| actionBar.setBackground(color); |
| jobImageLabel.setBackground(color); |
| |
| Iterator<Link> taskEntryIterator = taskEntries.iterator(); |
| while (taskEntryIterator.hasNext()) { |
| taskEntryIterator.next().setBackground(color); |
| } |
| |
| } |
| |
| /** |
| * Set the focus to the button. |
| */ |
| void setButtonFocus() { |
| actionBar.setFocus(); |
| } |
| |
| /** |
| * Set the selection colors. |
| * |
| * @param select boolean that indicates whether or not to show selection. |
| */ |
| void selectWidgets(boolean select) { |
| if (select) { |
| setButtonFocus(); |
| } |
| selected = select; |
| setColor(currentIndex); |
| } |
| |
| /** |
| * Set the listener for index changes. |
| * |
| * @param indexListener |
| */ |
| void setIndexListener(IndexListener indexListener) { |
| this.indexListener = indexListener; |
| } |
| |
| /** |
| * Return whether or not the receiver is selected. |
| * |
| * @return receiver selected state |
| */ |
| boolean isSelected() { |
| return selected; |
| } |
| |
| /** |
| * Set whether or not the receiver is being displayed based on the top and |
| * bottom of the currently visible area. |
| * |
| * @param top |
| * @param bottom |
| */ |
| void setDisplayed(int top, int bottom) { |
| int itemTop = getLocation().y; |
| int itemBottom = itemTop + getBounds().height; |
| setDisplayed(itemTop <= bottom && itemBottom > top); |
| |
| } |
| |
| /** |
| * Set whether or not the receiver is being displayed |
| * |
| * @param displayed |
| */ |
| private void setDisplayed(boolean displayed) { |
| // See if this element has been turned off |
| boolean refresh = !isShowing && displayed; |
| isShowing = displayed; |
| if (refresh) |
| refresh(); |
| } |
| |
| @Override |
| public void dispose() { |
| super.dispose(); |
| if (resourceManager != null) |
| resourceManager.dispose(); |
| } |
| |
| /** |
| * @return Returns the info. |
| */ |
| public JobTreeElement getInfo() { |
| return info; |
| } |
| |
| /** |
| * For testing only |
| * |
| * @return true if the trigger is enabled |
| * @noreference |
| */ |
| public boolean isTriggerEnabled() { |
| return link != null && !link.isDisposed() && link.isEnabled(); |
| } |
| |
| /** Called whenever trigger details change */ |
| private void hookTriggerCommandEnablement() { |
| final Object data = link.getData(TRIGGER_KEY); |
| if (!(data instanceof ParameterizedCommand) || !PlatformUI.isWorkbenchRunning()) |
| return; |
| |
| // Would be nice to have the window's context, but we're too deep |
| IEclipseContext context = PlatformUI.getWorkbench().getService(IEclipseContext.class); |
| if (context == null) { |
| return; |
| } |
| if (tracker != null) { |
| // stop any existing RATs as the command details may have changed |
| tracker.stop(); |
| } |
| tracker = new HandlerChangeTracker((ParameterizedCommand) data); |
| context.runAndTrack(tracker); |
| } |
| |
| /** |
| * A RAT to update the trigger link on handler changes for the given command |
| */ |
| private class HandlerChangeTracker extends RunAndTrack { |
| private ParameterizedCommand parmCommand; |
| private boolean stop = false; |
| |
| public HandlerChangeTracker(ParameterizedCommand parmCommand) { |
| this.parmCommand = parmCommand; |
| } |
| |
| public void stop() { |
| this.stop = true; |
| } |
| |
| @Override |
| public boolean changed(IEclipseContext context) { |
| if (stop || isDisposed() || !link.isVisible()) { |
| // stop listening for changes |
| return false; |
| } |
| EHandlerService service = context.get(EHandlerService.class); |
| link.setEnabled(service != null && service.canExecute(parmCommand)); |
| return true; |
| } |
| } |
| /* |
| * Check if workspace is using a theme. If it is, confirm it is not the default |
| * theme. |
| */ |
| |
| private boolean getCustomThemeFlag() { |
| IThemeEngine engine = PlatformUI.getWorkbench().getService(IThemeEngine.class); |
| if (engine != null) { |
| ITheme activeTheme = engine.getActiveTheme(); |
| if (activeTheme != null) { |
| return !DEFAULT_THEME.equals(activeTheme.getId()); |
| } |
| } |
| return false; |
| } |
| } |