blob: f958a40e77c64a504ce8cdf8ae5cda9dc79d5a4d [file] [log] [blame]
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed 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 com.android.sdkuilib.internal.tasks;
import com.android.sdklib.internal.repository.ITask;
import com.android.sdklib.internal.repository.ITaskMonitor;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.ProgressBar;
import org.eclipse.swt.widgets.Shell;
/**
* An {@link ITaskMonitor} that displays a {@link ProgressDialog}.
*/
public final class ProgressTask implements ITaskMonitor {
private static final double MAX_COUNT = 10000.0;
private final ProgressDialog mDialog;
private boolean mAutomaticallyCloseOnTaskCompletion = true;
private double mIncCoef = 0;
private double mValue = 0;
/**
* Creates a new {@link ProgressTask} with the given title.
* The given task will execute in a separate thread (not the UI thread).
*
* This blocks till the thread ends.
*/
public ProgressTask(Shell parent, String title, ITask task) {
mDialog = new ProgressDialog(parent, createTaskThread(title, task));
mDialog.setText(title);
mDialog.open();
}
/**
* Sets the description in the current task dialog.
* This method can be invoked from a non-UI thread.
*/
public void setDescription(String descriptionFormat, Object...args) {
mDialog.setDescription(descriptionFormat, args);
}
/**
* Sets the description in the current task dialog.
* This method can be invoked from a non-UI thread.
*/
public void setResult(String resultFormat, Object...args) {
mAutomaticallyCloseOnTaskCompletion = false;
mDialog.setResult(resultFormat, args);
}
/**
* Sets the max value of the progress bar.
* This method can be invoked from a non-UI thread.
*
* Weird things will happen if setProgressMax is called multiple times
* *after* {@link #incProgress(int)}: we don't try to adjust it on the
* fly.
*
* @see ProgressBar#setMaximum(int)
*/
public void setProgressMax(int max) {
assert max > 0;
// Always set the dialog's progress max to 10k since it only handles
// integers and we want to have a better inner granularity. Instead
// we use the max to compute a coefficient for inc deltas.
mDialog.setProgressMax((int) MAX_COUNT);
mIncCoef = max > 0 ? MAX_COUNT / max : 0;
assert mIncCoef > 0;
}
/**
* Increments the current value of the progress bar.
*
* This method can be invoked from a non-UI thread.
*/
public void incProgress(int delta) {
assert mIncCoef > 0;
assert delta > 0;
internalIncProgress(delta * mIncCoef);
}
private void internalIncProgress(double realDelta) {
mValue += realDelta;
mDialog.setProgress((int)mValue);
}
/**
* Returns the current value of the progress bar,
* between 0 and up to {@link #setProgressMax(int)} - 1.
*
* This method can be invoked from a non-UI thread.
*/
public int getProgress() {
assert mIncCoef > 0;
return mIncCoef > 0 ? (int)(mDialog.getProgress() / mIncCoef) : 0;
}
/**
* Returns true if the "Cancel" button was selected.
* It is up to the task thread to pool this and exit.
*/
public boolean isCancelRequested() {
return mDialog.isCancelRequested();
}
/**
* Creates a thread to run the task. The thread has not been started yet.
* When the task completes, requests to close the dialog.
* @return A new thread that will run the task. The thread has not been started yet.
*/
private Thread createTaskThread(String title, final ITask task) {
if (task != null) {
return new Thread(title) {
@Override
public void run() {
task.run(ProgressTask.this);
if (mAutomaticallyCloseOnTaskCompletion) {
mDialog.setAutoCloseRequested();
} else {
mDialog.setManualCloseRequested();
}
}
};
}
return null;
}
/**
* Display a yes/no question dialog box.
*
* This implementation allow this to be called from any thread, it
* makes sure the dialog is opened synchronously in the ui thread.
*
* @param title The title of the dialog box
* @param message The error message
* @return true if YES was clicked.
*/
public boolean displayPrompt(final String title, final String message) {
final Shell shell = mDialog.getParent();
Display display = shell.getDisplay();
// we need to ask the user what he wants to do.
final boolean[] result = new boolean[] { false };
display.syncExec(new Runnable() {
public void run() {
result[0] = MessageDialog.openQuestion(shell, title, message);
}
});
return result[0];
}
/**
* Creates a sub-monitor that will use up to tickCount on the progress bar.
* tickCount must be 1 or more.
*/
public ITaskMonitor createSubMonitor(int tickCount) {
assert mIncCoef > 0;
assert tickCount > 0;
return new SubTaskMonitor(this, null, mValue, tickCount * mIncCoef);
}
private interface ISubTaskMonitor extends ITaskMonitor {
public void subIncProgress(double realDelta);
}
private static class SubTaskMonitor implements ISubTaskMonitor {
private final ProgressTask mRoot;
private final ISubTaskMonitor mParent;
private final double mStart;
private final double mSpan;
private double mSubValue;
private double mSubCoef;
/**
* Creates a new sub task monitor which will work for the given range [start, start+span]
* in its parent.
*
* @param root The ProgressTask root
* @param parent The immediate parent. Can be the null or another sub task monitor.
* @param start The start value in the root's coordinates
* @param span The span value in the root's coordinates
*/
public SubTaskMonitor(ProgressTask root,
ISubTaskMonitor parent,
double start,
double span) {
mRoot = root;
mParent = parent;
mStart = start;
mSpan = span;
mSubValue = start;
}
public boolean isCancelRequested() {
return mRoot.isCancelRequested();
}
public void setDescription(String descriptionFormat, Object... args) {
mRoot.setDescription(descriptionFormat, args);
}
public void setResult(String resultFormat, Object... args) {
mRoot.setResult(resultFormat, args);
}
public void setProgressMax(int max) {
assert max > 0;
mSubCoef = max > 0 ? mSpan / max : 0;
assert mSubCoef > 0;
}
public int getProgress() {
assert mSubCoef > 0;
return mSubCoef > 0 ? (int)((mSubValue - mStart) / mSubCoef) : 0;
}
public void incProgress(int delta) {
assert mSubCoef > 0;
subIncProgress(delta * mSubCoef);
}
public void subIncProgress(double realDelta) {
mSubValue += realDelta;
if (mParent != null) {
mParent.subIncProgress(realDelta);
} else {
mRoot.internalIncProgress(realDelta);
}
}
public boolean displayPrompt(String title, String message) {
return mRoot.displayPrompt(title, message);
}
public ITaskMonitor createSubMonitor(int tickCount) {
assert mSubCoef > 0;
assert tickCount > 0;
return new SubTaskMonitor(mRoot,
this,
mSubValue,
tickCount * mSubCoef);
}
}
}