SDK Updater: Revamp ITaskMonitor to be able to create sub monitors.

This allows us to nest tasks that share the same
progress task dialog..
This commit is contained in:
Raphael
2009-06-10 18:33:45 -07:00
parent 64638a165f
commit b399193542
8 changed files with 211 additions and 89 deletions

View File

@@ -21,6 +21,8 @@ import com.android.prefs.AndroidLocation.AndroidLocationException;
import com.android.sdkuilib.internal.repository.ISettingsPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
@@ -28,16 +30,11 @@ import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Properties;

View File

@@ -45,18 +45,27 @@ public interface ITaskMonitor {
/**
* Sets the max value of the progress bar.
* This method can be invoked from a non-UI thread.
*
* This method MUST be invoked once before using {@link #incProgress(int)} or
* {@link #getProgress()} or {@link #createSubMonitor(int)}. Callers are
* discouraged from using more than once -- implementations can either discard
* the next calls or behave incoherently.
*/
public void setProgressMax(int max);
/**
* Increments the current value of the progress bar.
* This method can be invoked from a non-UI thread.
*
* Callers MUST use setProgressMax before using this method.
*/
public void incProgress(int delta);
/**
* Returns the current value of the progress bar,
* between 0 and up to {@link #setProgressMax(int)} - 1.
*
* Callers MUST use setProgressMax before using this method.
*/
public int getProgress();
@@ -66,4 +75,10 @@ public interface ITaskMonitor {
* as possible.
*/
public boolean isCancelRequested();
/**
* 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);
}

View File

@@ -68,7 +68,7 @@ public class RepoSource implements IDescription {
}
/**
* Returns the list of known packages found by the last call to {@link #load(ITaskFactory)}.
* Returns the list of known packages found by the last call to {@link #load(ITaskMonitor)}.
* This is null when the source hasn't been loaded yet.
*/
public Package[] getPackages() {
@@ -77,7 +77,7 @@ public class RepoSource implements IDescription {
/**
* Clear the internal packages list. After this call, {@link #getPackages()} will return
* null till {@link #load(ITaskFactory)} is called.
* null till {@link #load(ITaskMonitor)} is called.
*/
public void clearPackages() {
mPackages = null;
@@ -94,10 +94,8 @@ public class RepoSource implements IDescription {
/**
* Tries to fetch the repository index for the given URL.
*/
public void load(ITaskFactory taskFactory) {
public void load(ITaskMonitor monitor) {
taskFactory.start("Init SDK Updater", new ITask() {
public void run(ITaskMonitor monitor) {
monitor.setProgressMax(4);
setDefaultDescription();
@@ -134,8 +132,6 @@ public class RepoSource implements IDescription {
// done
monitor.incProgress(1);
}
});
}
private void setDefaultDescription() {
if (mAddonOnly) {

View File

@@ -320,15 +320,15 @@ final class ProgressDialog extends Dialog {
}
/**
* Increments the current value of the progress bar.
* Sets the current value of the progress bar.
* This method can be invoked from a non-UI thread.
*/
public void incProgress(final int delta) {
public void setProgress(final int value) {
if (!mDialogShell.isDisposed()) {
mDialogShell.getDisplay().syncExec(new Runnable() {
public void run() {
if (!mProgressBar.isDisposed()) {
mProgressBar.setSelection(mProgressBar.getSelection() + delta);
mProgressBar.setSelection(value);
}
}
});

View File

@@ -28,8 +28,12 @@ import org.eclipse.swt.widgets.Shell;
*/
class ProgressTask implements ITaskMonitor {
private ProgressDialog mDialog;
private static final double MAX_COUNT = 10000.0;
private final ProgressDialog mDialog;
private boolean mAutomaticallyCloseOnTaskCompletion = true;
private double mIncCoef = 0;
private double mValue = 0;
/**
@@ -46,29 +50,39 @@ class ProgressTask implements ITaskMonitor {
/**
* Sets the description in the current task dialog.
* This method can be invoke from a non-UI thread.
* This method can be invoked from a non-UI thread.
*/
public void setDescription(final String descriptionFormat, final Object...args) {
public void setDescription(String descriptionFormat, Object...args) {
mDialog.setDescription(descriptionFormat, args);
}
/**
* Sets the description in the current task dialog.
* This method can be invoke from a non-UI thread.
* This method can be invoked from a non-UI thread.
*/
public void setResult(final String resultFormat, final Object...args) {
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 invoke from a non-UI thread.
* 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(final int max) {
mDialog.setProgressMax(max);
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;
}
/**
@@ -76,8 +90,15 @@ class ProgressTask implements ITaskMonitor {
*
* This method can be invoked from a non-UI thread.
*/
public void incProgress(final int delta) {
mDialog.incProgress(delta);
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);
}
/**
@@ -87,7 +108,8 @@ class ProgressTask implements ITaskMonitor {
* This method can be invoked from a non-UI thread.
*/
public int getProgress() {
return mDialog.getProgress();
assert mIncCoef > 0;
return mIncCoef > 0 ? (int)(mDialog.getProgress() / mIncCoef) : 0;
}
/**
@@ -119,4 +141,95 @@ class ProgressTask implements ITaskMonitor {
}
return null;
}
/**
* 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 ITaskMonitor createSubMonitor(int tickCount) {
assert mSubCoef > 0;
assert tickCount > 0;
return new SubTaskMonitor(mRoot,
this,
mSubValue,
tickCount * mSubCoef);
}
}
}

View File

@@ -19,6 +19,8 @@ package com.android.sdkuilib.internal.repository;
import com.android.sdklib.internal.repository.Archive;
import com.android.sdklib.internal.repository.IDescription;
import com.android.sdklib.internal.repository.ITask;
import com.android.sdklib.internal.repository.ITaskMonitor;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
@@ -265,7 +267,7 @@ public class RemotePackagesPage extends Composite {
private void onRefreshSelected() {
if (mUpdaterWindow != null) {
mUpdaterWindow.refreshSources(false /*forceFetching*/);
mUpdaterWindow.refreshSources(false /*forceFetching*/, null /*monitor*/);
}
}

View File

@@ -18,6 +18,8 @@ package com.android.sdkuilib.internal.repository;
import com.android.sdklib.internal.repository.Archive;
import com.android.sdklib.internal.repository.IDescription;
import com.android.sdklib.internal.repository.ITask;
import com.android.sdklib.internal.repository.ITaskMonitor;
import com.android.sdklib.internal.repository.Package;
import com.android.sdklib.internal.repository.RepoSource;
import com.android.sdklib.internal.repository.RepoSources;
@@ -110,11 +112,17 @@ class RepoSourcesAdapter {
return ((RepoSourcesAdapter) parentElement).mRepoSources.getSources().toArray();
} else if (parentElement instanceof RepoSource) {
RepoSource source = (RepoSource) parentElement;
final RepoSource source = (RepoSource) parentElement;
Package[] packages = source.getPackages();
if (packages == null) {
source.load(mInput.mRepoSources.getTaskFactory());
mInput.mRepoSources.getTaskFactory().start("Loading Source", new ITask() {
public void run(ITaskMonitor monitor) {
source.load(monitor);
}
});
packages = source.getPackages();
}
if (packages != null) {

View File

@@ -407,17 +407,14 @@ public class UpdaterWindowImpl {
}
public void updateAll() {
refreshSources(true);
mTaskFactory.start("Update Archives", new ITask() {
public void run(ITaskMonitor monitor) {
monitor.setProgressMax(3);
// TODO have refreshSources reuse the current progress task
// mTaskFactory.start("Update Archives", new ITask() {
// public void run(ITaskMonitor monitor) {
// monitor.setProgressMax(3);
//
// monitor.setDescription("Refresh sources");
// refreshSources(true);
// }
// });
monitor.setDescription("Refresh sources");
refreshSources(true, monitor.createSubMonitor(1));
}
});
}
/**
@@ -426,32 +423,26 @@ public class UpdaterWindowImpl {
* @param forceFetching When true, load sources that haven't been loaded yet. When
* false, only refresh sources that have been loaded yet.
*/
public void refreshSources(final boolean forceFetching) {
public void refreshSources(final boolean forceFetching, ITaskMonitor monitor) {
ITask task = new ITask() {
public void run(ITaskMonitor monitor) {
ArrayList<RepoSource> sources = mUpdaterData.getSources().getSources();
monitor.setProgressMax(sources.size());
for (RepoSource source : sources) {
if (forceFetching || source.getPackages() != null) {
source.load(mTaskFactory);
source.load(monitor.createSubMonitor(1));
}
monitor.incProgress(1);
}
}
};
// TODO have source.load reuse the current progress task
// mTaskFactory.start("Refresh sources", new ITask() {
// public void run(ITaskMonitor monitor) {
// ArrayList<RepoSource> sources = mUpdaterData.getSources().getSources();
// monitor.setProgressMax(sources.size());
//
// for (RepoSource source : sources) {
// if (forceFetching || source.getPackages() != null) {
// monitor.setDescription(String.format("Refresh %1$s",
// source.getShortDescription()));
// source.load(mTaskFactory);
// }
// monitor.incProgress(1);
// }
// }
// });
if (monitor != null) {
task.run(monitor);
} else {
mTaskFactory.start("Refresh Sources", task);
}
}
// End of hiding from SWT Designer