org.netbeans.api.progress.aggregate.AggregateProgressHandle Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.api.progress.aggregate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.netbeans.api.progress.ProgressHandle;
import org.openide.util.Cancellable;
/**
* a progress handle that allows aggregation of progress indication from multiple
* independant sources. All of the progress contributors are considered equal and are given
* equal share of the global progress.
* The task progress contributors can be added dynamically and
* the progress bar adjusts accordingly, never stepping back though.
*
* For a more simple version of progress indication, see {@link org.netbeans.api.progress.ProgressHandle}
* @author Milos Kleint ([email protected])
*/
public final class AggregateProgressHandle implements AutoCloseable {
private static final Logger LOG = Logger.getLogger(AggregateProgressHandle.class.getName());
private ProgressMonitor monitor;
final ProgressHandle handle;
static final int WORKUNITS = 10000;
private boolean finished;
private Collection contributors;
private int current;
final String displayName;
/** Creates a new instance of AggregateProgressHandle */
AggregateProgressHandle(String displayName, ProgressContributor[] contribs, Cancellable cancellable, boolean systemtask,
ProgressHandle hdl) {
handle = hdl;
finished = false;
contributors = new ArrayList();
if (contribs != null) {
for (int i = 0; i < contribs.length; i++) {
addContributor(contribs[i]);
}
}
this.displayName = displayName;
}
/**
* start the progress indication for the task, shows the progress in the UI, events from the contributors are
* expected after this call.
*/
public void start() {
start(-1);
}
/**
* start the progress indication for the task with an initial time estimate, shows the progress in the UI, events from the contributors are
* expected after this call.
* @param estimate estimated time to process the task in seconds
*/
public synchronized void start(long estimate) {
handle.start(WORKUNITS, estimate);
current = 0;
}
/**
* Calls {@link #finish()}
*/
@Override
public void close() {
finish();
}
/**
* finish the task, remove the task's component from the progress bar UI, any additional incoming events from the
* contributors will be ignored.
*/
public synchronized void finish() {
if (finished) {
return;
}
finished = true;
handle.finish();
}
/**
* Currently running task can switch to silent suspend mode where the progress bar
* stops moving, hides completely or partially. Useful to make progress in status bar less intrusive
* for very long running tasks, eg. running an ant script that executes user application, debugs user application etc.
* Any incoming progress wakes up the progress bar to previous state.
* @param message a message to display in the silent mode
* @since org.netbeans.api.progress/1 1.10
*/
public void suspend(String message) {
LOG.log(Level.FINE, "{0}: {1}", new Object[] {displayName, message});
handle.suspend(message);
}
/**
* allows to set a custom initial delay for the progress task to appear in the
* status bar. This delay marks the time between starting of the progress handle
* and it's appearance in the status bar. If it finishes earlier, it's not shown at all.
* There is a default < 1s value for this. If you want to to appear earlier or later,
* call this method with the value you prefer before starting the handle.
* Progress bars that are placed in custom dialogs do always appear right away without a delay.
* @param millis amount of miliseconds that shall pass before the progress appears in status bar.
*/
public void setInitialDelay(int millis) {
handle.setInitialDelay(millis);
}
/**
* add a contributor to the global, aggregated progress.
* Adding makes sense only if the task is still in progress.
*/
public synchronized void addContributor(ProgressContributor contributor) {
if (finished) {
return;
}
// System.out.println("adding contributor=" + contributor.getTrackingId());
int length = contributors.size();
int remainingUnits = 0;
double completedRatio = 0;
Iterator it;
if (length > 0) {
it = contributors.iterator();
while (it.hasNext()) {
ProgressContributor cont = it.next();
remainingUnits = remainingUnits + cont.getRemainingParentWorkUnits();
completedRatio = completedRatio + (1 - cont.getCompletedRatio());
}
} else {
remainingUnits = WORKUNITS;
completedRatio = 0;
}
// int idealShare = WORKUNITS / (length + 1);
int currentShare = (int)(remainingUnits / (completedRatio + 1));
// System.out.println("ideal share=" + idealShare);
// System.out.println("current share=" + currentShare);
it = contributors.iterator();
while (it.hasNext()) {
ProgressContributor cont = it.next();
int newshare = (int)((1 - cont.getCompletedRatio()) * currentShare);
// System.out.println(" new share for " + cont.getTrackingId() + " is " + newshare);
remainingUnits = remainingUnits - newshare;
cont.setAvailableParentWorkUnits(newshare);
}
// System.out.println("new contributor share is=" + remainingUnits);
contributor.setAvailableParentWorkUnits(remainingUnits);
contributors.add(contributor);
contributor.setParent(this);
}
/**
* @deprecated do, not use, for tests only
*/
@Deprecated
int getCurrentProgress() {
return current;
}
void processContributorStep(ProgressContributor contributor, String message, int delta) {
synchronized (this) {
if (finished) {
return;
}
current = current + delta;
handle.progress(message, current);
}
//shall we sychronize the monitor calls? since it calls out to client code,
// cannot guarantee how long it will last..
if (monitor != null) {
monitor.progressed(contributor);
}
}
void processContributorStart(ProgressContributor contributor, String message) {
synchronized (this) {
if (finished) {
return;
}
if (message != null) {
handle.progress(message);
}
}
//shall we sychronize the monitor calls? since it calls out to client code,
// cannot guarantee how long it will last..
if (monitor != null) {
monitor.started(contributor);
}
}
void processContributorFinish(ProgressContributor contributor) {
synchronized (this) {
if (finished) {
return;
}
contributors.remove(contributor);
if (contributors.size() == 0) {
finish();
}
}
//shall we sychronize the monitor calls? since it calls out to client code,
// cannot guarantee how long it will last..
if (monitor != null) {
monitor.finished(contributor);
}
}
/**
* allow to watch the incoming events from the individual progress contributors.
*/
public void setMonitor(ProgressMonitor monitor) {
this.monitor = monitor;
}
/**
* change the display name of the progress task. Use with care, please make sure the changed name is not completely different,
* or otherwise it might appear to the user as a different task.
* @since 1.5
*/
public void setDisplayName(String newDisplayName) {
handle.setDisplayName(newDisplayName);
}
}