import com.android.sdkuilib.internal.repository.ISettingsPage;\r
\r
import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.SelectionAdapter;\r
+import org.eclipse.swt.events.SelectionEvent;\r
import org.eclipse.swt.layout.GridData;\r
import org.eclipse.swt.layout.GridLayout;\r
import org.eclipse.swt.widgets.Button;\r
import org.eclipse.swt.widgets.Group;\r
import org.eclipse.swt.widgets.Label;\r
import org.eclipse.swt.widgets.Text;\r
-import org.eclipse.swt.events.SelectionAdapter;\r
-import org.eclipse.swt.events.SelectionEvent;\r
\r
import java.io.File;\r
import java.io.FileInputStream;\r
import java.io.FileOutputStream;\r
-import java.io.FileReader;\r
-import java.io.FileWriter;\r
import java.io.IOException;\r
-import java.io.InputStream;\r
import java.net.URL;\r
import java.util.Properties;\r
\r
/**\r
* Sets the max value of the progress bar.\r
* This method can be invoked from a non-UI thread.\r
+ *\r
+ * This method MUST be invoked once before using {@link #incProgress(int)} or\r
+ * {@link #getProgress()} or {@link #createSubMonitor(int)}. Callers are\r
+ * discouraged from using more than once -- implementations can either discard\r
+ * the next calls or behave incoherently.\r
*/\r
public void setProgressMax(int max);\r
\r
/**\r
* Increments the current value of the progress bar.\r
* This method can be invoked from a non-UI thread.\r
+ *\r
+ * Callers MUST use setProgressMax before using this method.\r
*/\r
public void incProgress(int delta);\r
\r
/**\r
* Returns the current value of the progress bar,\r
* between 0 and up to {@link #setProgressMax(int)} - 1.\r
+ *\r
+ * Callers MUST use setProgressMax before using this method.\r
*/\r
public int getProgress();\r
\r
* as possible.\r
*/\r
public boolean isCancelRequested();\r
+\r
+ /**\r
+ * Creates a sub-monitor that will use up to tickCount on the progress bar.\r
+ * tickCount must be 1 or more.\r
+ */\r
+ public ITaskMonitor createSubMonitor(int tickCount);\r
}\r
}\r
\r
/**\r
- * Returns the list of known packages found by the last call to {@link #load(ITaskFactory)}.\r
+ * Returns the list of known packages found by the last call to {@link #load(ITaskMonitor)}.\r
* This is null when the source hasn't been loaded yet.\r
*/\r
public Package[] getPackages() {\r
\r
/**\r
* Clear the internal packages list. After this call, {@link #getPackages()} will return\r
- * null till {@link #load(ITaskFactory)} is called.\r
+ * null till {@link #load(ITaskMonitor)} is called.\r
*/\r
public void clearPackages() {\r
mPackages = null;\r
/**\r
* Tries to fetch the repository index for the given URL.\r
*/\r
- public void load(ITaskFactory taskFactory) {\r
+ public void load(ITaskMonitor monitor) {\r
\r
- taskFactory.start("Init SDK Updater", new ITask() {\r
- public void run(ITaskMonitor monitor) {\r
- monitor.setProgressMax(4);\r
+ monitor.setProgressMax(4);\r
\r
- setDefaultDescription();\r
+ setDefaultDescription();\r
\r
- monitor.setDescription("Fetching %1$s", mUrl);\r
- monitor.incProgress(1);\r
+ monitor.setDescription("Fetching %1$s", mUrl);\r
+ monitor.incProgress(1);\r
\r
- String xml = fetchUrl(mUrl, monitor);\r
+ String xml = fetchUrl(mUrl, monitor);\r
\r
- if (xml == null) {\r
- mDescription += String.format("\nFailed to fetch URL %1$s", mUrl);\r
- return;\r
- }\r
+ if (xml == null) {\r
+ mDescription += String.format("\nFailed to fetch URL %1$s", mUrl);\r
+ return;\r
+ }\r
\r
- monitor.setDescription("Validate XML");\r
- monitor.incProgress(1);\r
+ monitor.setDescription("Validate XML");\r
+ monitor.incProgress(1);\r
\r
- if (!validateXml(xml, monitor)) {\r
- mDescription += String.format("\nFailed to validate XML at %1$s", mUrl);\r
- return;\r
- }\r
+ if (!validateXml(xml, monitor)) {\r
+ mDescription += String.format("\nFailed to validate XML at %1$s", mUrl);\r
+ return;\r
+ }\r
\r
- monitor.setDescription("Parse XML");\r
- monitor.incProgress(1);\r
- parsePackages(xml, monitor);\r
- if (mPackages.length == 0) {\r
- mDescription += "\nNo packages found.";\r
- } else if (mPackages.length == 1) {\r
- mDescription += "\nOne package found.";\r
- } else {\r
- mDescription += String.format("\n%1$d packages found.", mPackages.length);\r
- }\r
+ monitor.setDescription("Parse XML");\r
+ monitor.incProgress(1);\r
+ parsePackages(xml, monitor);\r
+ if (mPackages.length == 0) {\r
+ mDescription += "\nNo packages found.";\r
+ } else if (mPackages.length == 1) {\r
+ mDescription += "\nOne package found.";\r
+ } else {\r
+ mDescription += String.format("\n%1$d packages found.", mPackages.length);\r
+ }\r
\r
- // done\r
- monitor.incProgress(1);\r
- }\r
- });\r
+ // done\r
+ monitor.incProgress(1);\r
}\r
\r
private void setDefaultDescription() {\r
}\r
\r
/**\r
- * Increments the current value of the progress bar.\r
+ * Sets the current value of the progress bar.\r
* This method can be invoked from a non-UI thread.\r
*/\r
- public void incProgress(final int delta) {\r
+ public void setProgress(final int value) {\r
if (!mDialogShell.isDisposed()) {\r
mDialogShell.getDisplay().syncExec(new Runnable() {\r
public void run() {\r
if (!mProgressBar.isDisposed()) {\r
- mProgressBar.setSelection(mProgressBar.getSelection() + delta);\r
+ mProgressBar.setSelection(value);\r
}\r
}\r
});\r
*/\r
class ProgressTask implements ITaskMonitor {\r
\r
- private ProgressDialog mDialog;\r
+ private static final double MAX_COUNT = 10000.0;\r
+\r
+ private final ProgressDialog mDialog;\r
private boolean mAutomaticallyCloseOnTaskCompletion = true;\r
+ private double mIncCoef = 0;\r
+ private double mValue = 0;\r
\r
\r
/**\r
\r
/**\r
* Sets the description in the current task dialog.\r
- * This method can be invoke from a non-UI thread.\r
+ * This method can be invoked from a non-UI thread.\r
*/\r
- public void setDescription(final String descriptionFormat, final Object...args) {\r
+ public void setDescription(String descriptionFormat, Object...args) {\r
mDialog.setDescription(descriptionFormat, args);\r
}\r
\r
/**\r
* Sets the description in the current task dialog.\r
- * This method can be invoke from a non-UI thread.\r
+ * This method can be invoked from a non-UI thread.\r
*/\r
- public void setResult(final String resultFormat, final Object...args) {\r
+ public void setResult(String resultFormat, Object...args) {\r
mAutomaticallyCloseOnTaskCompletion = false;\r
mDialog.setResult(resultFormat, args);\r
}\r
\r
/**\r
* Sets the max value of the progress bar.\r
- * This method can be invoke from a non-UI thread.\r
+ * This method can be invoked from a non-UI thread.\r
+ *\r
+ * Weird things will happen if setProgressMax is called multiple times\r
+ * *after* {@link #incProgress(int)}: we don't try to adjust it on the\r
+ * fly.\r
*\r
* @see ProgressBar#setMaximum(int)\r
*/\r
- public void setProgressMax(final int max) {\r
- mDialog.setProgressMax(max);\r
+ public void setProgressMax(int max) {\r
+ assert max > 0;\r
+ // Always set the dialog's progress max to 10k since it only handles\r
+ // integers and we want to have a better inner granularity. Instead\r
+ // we use the max to compute a coefficient for inc deltas.\r
+ mDialog.setProgressMax((int) MAX_COUNT);\r
+ mIncCoef = max > 0 ? MAX_COUNT / max : 0;\r
+ assert mIncCoef > 0;\r
}\r
\r
/**\r
*\r
* This method can be invoked from a non-UI thread.\r
*/\r
- public void incProgress(final int delta) {\r
- mDialog.incProgress(delta);\r
+ public void incProgress(int delta) {\r
+ assert mIncCoef > 0;\r
+ assert delta > 0;\r
+ internalIncProgress(delta * mIncCoef);\r
+ }\r
+\r
+ private void internalIncProgress(double realDelta) {\r
+ mValue += realDelta;\r
+ mDialog.setProgress((int)mValue);\r
}\r
\r
/**\r
* This method can be invoked from a non-UI thread.\r
*/\r
public int getProgress() {\r
- return mDialog.getProgress();\r
+ assert mIncCoef > 0;\r
+ return mIncCoef > 0 ? (int)(mDialog.getProgress() / mIncCoef) : 0;\r
}\r
\r
/**\r
}\r
return null;\r
}\r
+\r
+ /**\r
+ * Creates a sub-monitor that will use up to tickCount on the progress bar.\r
+ * tickCount must be 1 or more.\r
+ */\r
+ public ITaskMonitor createSubMonitor(int tickCount) {\r
+ assert mIncCoef > 0;\r
+ assert tickCount > 0;\r
+ return new SubTaskMonitor(this, null, mValue, tickCount * mIncCoef);\r
+ }\r
+\r
+ private interface ISubTaskMonitor extends ITaskMonitor {\r
+ public void subIncProgress(double realDelta);\r
+ }\r
+\r
+ private static class SubTaskMonitor implements ISubTaskMonitor {\r
+\r
+ private final ProgressTask mRoot;\r
+ private final ISubTaskMonitor mParent;\r
+ private final double mStart;\r
+ private final double mSpan;\r
+ private double mSubValue;\r
+ private double mSubCoef;\r
+\r
+ /**\r
+ * Creates a new sub task monitor which will work for the given range [start, start+span]\r
+ * in its parent.\r
+ *\r
+ * @param root The ProgressTask root\r
+ * @param parent The immediate parent. Can be the null or another sub task monitor.\r
+ * @param start The start value in the root's coordinates\r
+ * @param span The span value in the root's coordinates\r
+ */\r
+ public SubTaskMonitor(ProgressTask root,\r
+ ISubTaskMonitor parent,\r
+ double start,\r
+ double span) {\r
+ mRoot = root;\r
+ mParent = parent;\r
+ mStart = start;\r
+ mSpan = span;\r
+ mSubValue = start;\r
+ }\r
+\r
+ public boolean isCancelRequested() {\r
+ return mRoot.isCancelRequested();\r
+ }\r
+\r
+ public void setDescription(String descriptionFormat, Object... args) {\r
+ mRoot.setDescription(descriptionFormat, args);\r
+ }\r
+\r
+ public void setResult(String resultFormat, Object... args) {\r
+ mRoot.setResult(resultFormat, args);\r
+ }\r
+\r
+ public void setProgressMax(int max) {\r
+ assert max > 0;\r
+ mSubCoef = max > 0 ? mSpan / max : 0;\r
+ assert mSubCoef > 0;\r
+ }\r
+\r
+ public int getProgress() {\r
+ assert mSubCoef > 0;\r
+ return mSubCoef > 0 ? (int)((mSubValue - mStart) / mSubCoef) : 0;\r
+ }\r
+\r
+ public void incProgress(int delta) {\r
+ assert mSubCoef > 0;\r
+ subIncProgress(delta * mSubCoef);\r
+ }\r
+\r
+ public void subIncProgress(double realDelta) {\r
+ mSubValue += realDelta;\r
+ if (mParent != null) {\r
+ mParent.subIncProgress(realDelta);\r
+ } else {\r
+ mRoot.internalIncProgress(realDelta);\r
+ }\r
+ }\r
+\r
+ public ITaskMonitor createSubMonitor(int tickCount) {\r
+ assert mSubCoef > 0;\r
+ assert tickCount > 0;\r
+ return new SubTaskMonitor(mRoot,\r
+ this,\r
+ mSubValue,\r
+ tickCount * mSubCoef);\r
+ }\r
+ }\r
+\r
}\r
\r
import com.android.sdklib.internal.repository.Archive;\r
import com.android.sdklib.internal.repository.IDescription;\r
+import com.android.sdklib.internal.repository.ITask;\r
+import com.android.sdklib.internal.repository.ITaskMonitor;\r
\r
import org.eclipse.jface.viewers.CheckStateChangedEvent;\r
import org.eclipse.jface.viewers.CheckboxTreeViewer;\r
\r
private void onRefreshSelected() {\r
if (mUpdaterWindow != null) {\r
- mUpdaterWindow.refreshSources(false /*forceFetching*/);\r
+ mUpdaterWindow.refreshSources(false /*forceFetching*/, null /*monitor*/);\r
}\r
}\r
\r
\r
import com.android.sdklib.internal.repository.Archive;\r
import com.android.sdklib.internal.repository.IDescription;\r
+import com.android.sdklib.internal.repository.ITask;\r
+import com.android.sdklib.internal.repository.ITaskMonitor;\r
import com.android.sdklib.internal.repository.Package;\r
import com.android.sdklib.internal.repository.RepoSource;\r
import com.android.sdklib.internal.repository.RepoSources;\r
return ((RepoSourcesAdapter) parentElement).mRepoSources.getSources().toArray();\r
\r
} else if (parentElement instanceof RepoSource) {\r
- RepoSource source = (RepoSource) parentElement;\r
+ final RepoSource source = (RepoSource) parentElement;\r
Package[] packages = source.getPackages();\r
\r
if (packages == null) {\r
- source.load(mInput.mRepoSources.getTaskFactory());\r
+\r
+ mInput.mRepoSources.getTaskFactory().start("Loading Source", new ITask() {\r
+ public void run(ITaskMonitor monitor) {\r
+ source.load(monitor);\r
+ }\r
+ });\r
+\r
packages = source.getPackages();\r
}\r
if (packages != null) {\r
}\r
\r
public void updateAll() {\r
- refreshSources(true);\r
-\r
- // TODO have refreshSources reuse the current progress task\r
-// mTaskFactory.start("Update Archives", new ITask() {\r
-// public void run(ITaskMonitor monitor) {\r
-// monitor.setProgressMax(3);\r
-//\r
-// monitor.setDescription("Refresh sources");\r
-// refreshSources(true);\r
-// }\r
-// });\r
+ mTaskFactory.start("Update Archives", new ITask() {\r
+ public void run(ITaskMonitor monitor) {\r
+ monitor.setProgressMax(3);\r
+\r
+ monitor.setDescription("Refresh sources");\r
+ refreshSources(true, monitor.createSubMonitor(1));\r
+ }\r
+ });\r
}\r
\r
/**\r
* @param forceFetching When true, load sources that haven't been loaded yet. When\r
* false, only refresh sources that have been loaded yet.\r
*/\r
- public void refreshSources(final boolean forceFetching) {\r
- ArrayList<RepoSource> sources = mUpdaterData.getSources().getSources();\r
- for (RepoSource source : sources) {\r
- if (forceFetching || source.getPackages() != null) {\r
- source.load(mTaskFactory);\r
+ public void refreshSources(final boolean forceFetching, ITaskMonitor monitor) {\r
+ ITask task = new ITask() {\r
+ public void run(ITaskMonitor monitor) {\r
+ ArrayList<RepoSource> sources = mUpdaterData.getSources().getSources();\r
+ monitor.setProgressMax(sources.size());\r
+ for (RepoSource source : sources) {\r
+ if (forceFetching || source.getPackages() != null) {\r
+ source.load(monitor.createSubMonitor(1));\r
+ }\r
+ monitor.incProgress(1);\r
+\r
+ }\r
}\r
+ };\r
\r
+ if (monitor != null) {\r
+ task.run(monitor);\r
+ } else {\r
+ mTaskFactory.start("Refresh Sources", task);\r
}\r
-\r
- // TODO have source.load reuse the current progress task\r
-// mTaskFactory.start("Refresh sources", new ITask() {\r
-// public void run(ITaskMonitor monitor) {\r
-// ArrayList<RepoSource> sources = mUpdaterData.getSources().getSources();\r
-// monitor.setProgressMax(sources.size());\r
-//\r
-// for (RepoSource source : sources) {\r
-// if (forceFetching || source.getPackages() != null) {\r
-// monitor.setDescription(String.format("Refresh %1$s",\r
-// source.getShortDescription()));\r
-// source.load(mTaskFactory);\r
-// }\r
-// monitor.incProgress(1);\r
-// }\r
-// }\r
-// });\r
-\r
}\r
\r
// End of hiding from SWT Designer\r