// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package org.chromium.debug.core.util; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.SubProgressMonitor; /** * A small set of utility classes that help programming progress monitor logic. */ public class ProgressUtil { /** * Represents one stage of the whole process with a name and relative length called "weight". * Knowing all stages in advance helps calculate their ticks for {@link IProgressMonitor} * (this process is called layout here). */ public static class Stage { private final String name; private final float weight; private int workNumberForMonitor = 0; public Stage(String name, float weight) { this.name = name; this.weight = weight; } public void start(MonitorWrapper monitorWrapper) { monitorWrapper.setTaskName(name); } public void finish(MonitorWrapper monitorWrapper) { monitorWrapper.worked(workNumberForMonitor); monitorWrapper.clearTaskName(); } public MonitorWrapper createSubMonitorWrapper(MonitorWrapper monitorWrapper) { return monitorWrapper.createSubMonitorWrapper(name, workNumberForMonitor); } public IProgressMonitor createSubMonitor(MonitorWrapper monitorWrapper) { return monitorWrapper.createSubMonitor(workNumberForMonitor); } } /** * From a list of all stages of some process calculates their tick numbers * for {@link IProgressMonitor} according to their weights. The whole process * should be {@link #LAYOUT_TOTAL_STEPS} in ticks. * Method has a return value so that it could be called from expressions (notably, * constant initializer of an interface so that layout could be performed in initialization * phase). * @return always true */ public static boolean layoutProgressPlan(Stage ... stages) { float totalWeight = 0; for (Stage stage : stages) { totalWeight += stage.weight; } float sum = 0; int steps = 0; for (Stage stage : stages) { sum += stage.weight; int nextSteps = (int)(sum / totalWeight * LAYOUT_TOTAL_STEPS); stage.workNumberForMonitor = nextSteps - steps; steps = nextSteps; } return true; } /** * A small wrapper around the {@link IProgressMonitor} that keeps a default label -- the string * to show when a current stage has no label of its own. */ public static class MonitorWrapper { private final IProgressMonitor progressMonitor; private final String defaultLabel; public MonitorWrapper(IProgressMonitor progressMonitor, String defaultLabel) { this.progressMonitor = progressMonitor; this.defaultLabel = defaultLabel; } public void beginTask() { progressMonitor.beginTask(defaultLabel, LAYOUT_TOTAL_STEPS); } public void setTaskName(String name) { if (name == null) { name = defaultLabel; } progressMonitor.setTaskName(name); } public void clearTaskName() { progressMonitor.setTaskName(defaultLabel); } public void worked(int work) { progressMonitor.worked(work); } public MonitorWrapper createSubMonitorWrapper(String label, int steps) { final SubProgressMonitor subProgressMonitor = new SubProgressMonitor(progressMonitor, steps); return new MonitorWrapper(subProgressMonitor, label); } public IProgressMonitor createSubMonitor(int steps) { return new SubProgressMonitor(progressMonitor, steps); } public void done() { clearTaskName(); progressMonitor.done(); } public boolean isCanceled() { return progressMonitor.isCanceled(); } } private static final int LAYOUT_TOTAL_STEPS = 1000; }