/******************************************************************************* * Copyright (c) 2009 Johannes Utzig. * 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: * Johannes Utzig - initial API and implementation *******************************************************************************/ package org.eclipse.buckminster.runtime; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; public class AttachableProgressMonitor { private class ProgressMonitor implements IProgressMonitor { private int totalWork; private int ticks; private String task; private String subTask; private IProgressMonitor mainProgressMonitor; public ProgressMonitor(IProgressMonitor mainprogressMonitor) { this.mainProgressMonitor = mainprogressMonitor; } @Override public void beginTask(String name, int work) { this.totalWork = work; this.task = name; mainProgressMonitor.beginTask(name, work); for (IProgressMonitor attachedMonitor : attachedMonitors) { attachedMonitor.beginTask(name, work); } } @Override public void done() { mainProgressMonitor.done(); for (IProgressMonitor attachedMonitor : attachedMonitors) { attachedMonitor.done(); } } @Override public void internalWorked(double work) { mainProgressMonitor.internalWorked(work); for (IProgressMonitor attachedMonitor : attachedMonitors) { attachedMonitor.internalWorked(work); } } @Override public boolean isCanceled() { return mainProgressMonitor.isCanceled(); } @Override public void setCanceled(boolean value) { mainProgressMonitor.setCanceled(value); for (IProgressMonitor attachedMonitor : attachedMonitors) { attachedMonitor.setCanceled(value); } } @Override public void setTaskName(String name) { mainProgressMonitor.setTaskName(name); for (IProgressMonitor attachedMonitor : attachedMonitors) { attachedMonitor.setTaskName(name); } } @Override public void subTask(String name) { this.subTask = name; mainProgressMonitor.subTask(name); for (IProgressMonitor attachedMonitor : attachedMonitors) { attachedMonitor.subTask(name); } } @Override public void worked(int work) { ticks += work; mainProgressMonitor.worked(work); for (IProgressMonitor attachedMonitor : attachedMonitors) { attachedMonitor.worked(work); } } void attachProgressMonitor(IProgressMonitor toAttach) { if (task != null) { toAttach.beginTask(task, totalWork); toAttach.worked(ticks); } if (subTask != null) { toAttach.subTask(subTask); } } } private ProgressMonitor monitor; private List<IProgressMonitor> attachedMonitors = new ArrayList<IProgressMonitor>(); /** * attaches the given IProgressMonitor to the main progress monitor that was * passed in {@link AttachableProgressMonitor#wrap(IProgressMonitor)}. All * work done on this main progress monitor will be mirrored to the attached * progress monitors. If the main progress monitor already did work before * this method was invoked, the monitor to be attached will be adjusted to * the current state of the main monitor. It * {@link AttachableProgressMonitor#wrap(IProgressMonitor)} has not been * called yet, the given monitor will be attached as soon as a main monitor * is being wrapped. * * @param toAttach * - the monitor to be attached to the main monitor * @throws RuntimeException * if wrap was not called prior to this method * @throws IllegalArgumentException * if the given monitor is <code>null</code> * @see AttachableProgressMonitor#wrap(IProgressMonitor) */ public void attachProgressMonitor(IProgressMonitor toAttach) { if (toAttach == null) { throw new IllegalArgumentException("The given IProgressMonitor must not be null"); //$NON-NLS-1$ } if (monitor != null) { monitor.attachProgressMonitor(monitor); } attachedMonitors.add(toAttach); } /** * Wraps this {@link AttachableProgressMonitor} around the given * {@link IProgressMonitor}. * <p> * The {@link AttachableProgressMonitor} will mirror all calls to the given * {@link IProgressMonitor} to all monitors that get attached in * {@link AttachableProgressMonitor#attachProgressMonitor(IProgressMonitor)} * . This method <b>must</b> be called prior to call * {@link AttachableProgressMonitor#attachedMonitors} and <b>must not</b> be * called more than once. * * @param mainProgressMonitor * the ProgressMonitor that monitors the actual work * @return A {@link ProgressMonitor} that forwards all calls to the given * mainProgressMonitor and all attached ones. * @throws IllegalArgumentException * if the given {@link IProgressMonitor} is <code>null</code> * @throws RuntimeException * if this method is called more than once * @see AttachableProgressMonitor#attachedMonitors */ public IProgressMonitor wrap(IProgressMonitor mainProgressMonitor) { if (mainProgressMonitor == null) { throw new IllegalArgumentException("The given IProgressMonitor must not be null"); //$NON-NLS-1$ } if (monitor != null) { throw new RuntimeException("Only one ProgressMonitor can be wrapped at a time"); //$NON-NLS-1$ } monitor = new ProgressMonitor(mainProgressMonitor); for (IProgressMonitor attachedMonitor : attachedMonitors) { monitor.attachProgressMonitor(attachedMonitor); } return monitor; } }