| /******************************************************************************* |
| * Copyright (c) 2003, 2015 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.time.Duration; |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.LinkedHashSet; |
| import java.util.Set; |
| import org.eclipse.jface.util.Throttler; |
| import org.eclipse.ui.IWorkbenchPreferenceConstants; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.internal.util.PrefUtil; |
| |
| /** |
| * The ProgressViewUpdater is the singleton that updates viewers. |
| */ |
| class ProgressViewUpdater implements IJobProgressManagerListener { |
| |
| private static ProgressViewUpdater singleton; |
| |
| private Set<IProgressUpdateCollector> collectors; |
| |
| UpdatesInfo currentInfo = new UpdatesInfo(); |
| |
| boolean debug; |
| |
| Throttler throttledUpdate = new Throttler(PlatformUI.getWorkbench().getDisplay(), Duration.ofMillis(100), |
| this::update); |
| |
| /** |
| * The UpdatesInfo is a private class for keeping track of the updates |
| * required. |
| */ |
| static class UpdatesInfo { |
| |
| Collection<JobTreeElement> additions = new LinkedHashSet<>(); |
| |
| Collection<JobTreeElement> deletions = new LinkedHashSet<>(); |
| |
| Collection<JobTreeElement> refreshes = new LinkedHashSet<>(); |
| |
| boolean updateAll; |
| |
| private UpdatesInfo() { |
| //Create a new instance of the info |
| } |
| |
| /** |
| * Add an add update |
| * |
| * @param addition |
| */ |
| void add(JobTreeElement addition) { |
| additions.add(addition); |
| } |
| |
| /** |
| * Add a remove update |
| * |
| * @param removal |
| */ |
| void remove(JobTreeElement removal) { |
| deletions.add(removal); |
| } |
| |
| /** |
| * Add a refresh update |
| * |
| * @param refresh |
| */ |
| void refresh(JobTreeElement refresh) { |
| refreshes.add(refresh); |
| } |
| |
| /** |
| * Reset the caches after completion of an update. |
| */ |
| void reset() { |
| additions.clear(); |
| deletions.clear(); |
| refreshes.clear(); |
| updateAll = false; |
| } |
| |
| void processForUpdate() { |
| HashSet<JobTreeElement> staleAdditions = new HashSet<>(); |
| |
| Iterator<JobTreeElement> additionsIterator = additions.iterator(); |
| while (additionsIterator.hasNext()) { |
| JobTreeElement treeElement = additionsIterator |
| .next(); |
| if (!treeElement.isActive()) { |
| if (deletions.contains(treeElement)) { |
| staleAdditions.add(treeElement); |
| } |
| } |
| } |
| |
| additions.removeAll(staleAdditions); |
| |
| HashSet<JobTreeElement> obsoleteRefresh = new HashSet<>(); |
| Iterator<JobTreeElement> refreshIterator = refreshes.iterator(); |
| while (refreshIterator.hasNext()) { |
| JobTreeElement treeElement = refreshIterator |
| .next(); |
| if (deletions.contains(treeElement) |
| || additions.contains(treeElement)) { |
| obsoleteRefresh.add(treeElement); |
| } |
| |
| //Also check for groups that are being added |
| Object parent = treeElement.getParent(); |
| if(parent != null && (deletions.contains(parent) |
| || additions.contains(parent))){ |
| obsoleteRefresh.add(treeElement); |
| } |
| |
| if (!treeElement.isActive()) { |
| //If it is done then delete it |
| obsoleteRefresh.add(treeElement); |
| deletions.add(treeElement); |
| } |
| } |
| |
| refreshes.removeAll(obsoleteRefresh); |
| |
| } |
| } |
| |
| /** |
| * Return a new instance of the receiver. |
| * |
| * @return ProgressViewUpdater |
| */ |
| static ProgressViewUpdater getSingleton() { |
| if (singleton == null) { |
| singleton = new ProgressViewUpdater(); |
| } |
| return singleton; |
| } |
| |
| /** |
| * Return whether or not there is a singleton for updates to avoid creating |
| * extra listeners. |
| * |
| * @return boolean <code>true</code> if there is already |
| * a singleton |
| */ |
| static boolean hasSingleton() { |
| return singleton != null; |
| } |
| |
| static void clearSingleton() { |
| if (singleton != null) { |
| ProgressManager.getInstance().removeListener(singleton); |
| } |
| singleton = null; |
| } |
| |
| /** |
| * Create a new instance of the receiver. |
| */ |
| private ProgressViewUpdater() { |
| collectors = new LinkedHashSet<>(); |
| ProgressManager.getInstance().addListener(this); |
| debug = |
| PrefUtil.getAPIPreferenceStore(). |
| getBoolean(IWorkbenchPreferenceConstants.SHOW_SYSTEM_JOBS); |
| } |
| |
| /** |
| * Add the new collector to the list of collectors. |
| * |
| * @param newCollector |
| */ |
| void addCollector(IProgressUpdateCollector newCollector) { |
| collectors.add(newCollector); |
| } |
| |
| /** |
| * Remove the collector from the list of collectors. |
| * |
| * @param provider |
| */ |
| void removeCollector(IProgressUpdateCollector provider) { |
| collectors.remove(provider); |
| //Remove ourselves if there is nothing to update |
| if (collectors.isEmpty()) { |
| clearSingleton(); |
| } |
| } |
| |
| private void update() { |
| // Abort the update if there isn't anything |
| if (collectors.isEmpty()) { |
| return; |
| } |
| |
| if (currentInfo.updateAll) { |
| currentInfo.reset(); |
| for (IProgressUpdateCollector collector : collectors) { |
| collector.refresh(); |
| } |
| |
| } else { |
| // Lock while getting local copies of the caches. |
| JobTreeElement[] updateItems; |
| JobTreeElement[] additionItems; |
| JobTreeElement[] deletionItems; |
| |
| currentInfo.processForUpdate(); |
| |
| updateItems = currentInfo.refreshes.toArray(new JobTreeElement[0]); |
| additionItems = currentInfo.additions.toArray(new JobTreeElement[0]); |
| deletionItems = currentInfo.deletions.toArray(new JobTreeElement[0]); |
| |
| currentInfo.reset(); |
| |
| for (IProgressUpdateCollector collector : collectors) { |
| if (updateItems.length > 0) { |
| collector.refresh(updateItems); |
| } |
| if (additionItems.length > 0) { |
| collector.add(additionItems); |
| } |
| if (deletionItems.length > 0) { |
| collector.remove(deletionItems); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Refresh the supplied JobInfo. |
| * @param info |
| */ |
| public void refresh(JobInfo info) { |
| currentInfo.refresh(info); |
| GroupInfo group = info.getGroupInfo(); |
| if (group != null) { |
| currentInfo.refresh(group); |
| } |
| //Add in a 100ms delay so as to keep priority low |
| throttledUpdate.throttledExec(); |
| |
| } |
| |
| @Override |
| public void refreshJobInfo(JobInfo info) { |
| currentInfo.refresh(info); |
| //Add in a 100ms delay so as to keep priority low |
| throttledUpdate.throttledExec(); |
| |
| } |
| |
| @Override |
| public void refreshGroup(GroupInfo info) { |
| currentInfo.refresh(info); |
| //Add in a 100ms delay so as to keep priority low |
| throttledUpdate.throttledExec(); |
| } |
| |
| @Override |
| public void addGroup(GroupInfo info) { |
| currentInfo.add(info); |
| throttledUpdate.throttledExec(); |
| } |
| |
| @Override |
| public void refreshAll() { |
| currentInfo.updateAll = true; |
| |
| //Add in a 100ms delay so as to keep priority low |
| throttledUpdate.throttledExec(); |
| } |
| |
| @Override |
| public void addJob(JobInfo info) { |
| GroupInfo group = info.getGroupInfo(); |
| |
| if (group == null) { |
| currentInfo.add(info); |
| } else { |
| currentInfo.refresh(group); |
| } |
| throttledUpdate.throttledExec(); |
| } |
| |
| @Override |
| public void removeJob(JobInfo info) { |
| GroupInfo group = info.getGroupInfo(); |
| if (group == null) { |
| currentInfo.remove(info); |
| } else { |
| currentInfo.refresh(group); |
| } |
| throttledUpdate.throttledExec(); |
| } |
| |
| @Override |
| public void removeGroup(GroupInfo group) { |
| currentInfo.remove(group); |
| throttledUpdate.throttledExec(); |
| } |
| |
| @Override |
| public boolean showsDebug() { |
| return debug; |
| } |
| |
| } |