diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java index a7c1a83a1..6ea040c34 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java @@ -62,7 +62,6 @@ public class RemotePackagesPage extends Composite implements ISdkListener { private Group mDescriptionContainer; private Button mAddSiteButton; private Button mDeleteSiteButton; - private Label mPlaceholder3; private Button mRefreshButton; private Button mInstallSelectedButton; private Label mDescriptionLabel; @@ -118,16 +117,6 @@ public class RemotePackagesPage extends Composite implements ISdkListener { spacer.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); gd.heightHint = 0; - mUpdateOnlyCheckBox = new Button(composite, SWT.CHECK); - mUpdateOnlyCheckBox.setText("Display updates only"); - mUpdateOnlyCheckBox.setSelection(mUpdaterData.getSettingsController().getShowUpdateOnly()); - mUpdateOnlyCheckBox.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent arg0) { - onShowUpdateOnly(); //$hide$ - } - }); - mDescriptionContainer = new Group(parent, SWT.NONE); mDescriptionContainer.setLayout(new GridLayout(1, false)); mDescriptionContainer.setText("Description"); @@ -155,8 +144,16 @@ public class RemotePackagesPage extends Composite implements ISdkListener { }); mDeleteSiteButton.setText("Delete Site..."); - mPlaceholder3 = new Label(parent, SWT.NONE); - mPlaceholder3.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false, 1, 1)); + mUpdateOnlyCheckBox = new Button(parent, SWT.CHECK); + mUpdateOnlyCheckBox.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false, 1, 1)); + mUpdateOnlyCheckBox.setText("Display updates only"); + mUpdateOnlyCheckBox.setSelection(mUpdaterData.getSettingsController().getShowUpdateOnly()); + mUpdateOnlyCheckBox.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent arg0) { + onShowUpdateOnly(); //$hide$ + } + }); mRefreshButton = new Button(parent, SWT.NONE); mRefreshButton.addSelectionListener(new SelectionAdapter() { diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RepoSourcesAdapter.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RepoSourcesAdapter.java index dbf46f593..de12666e2 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RepoSourcesAdapter.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RepoSourcesAdapter.java @@ -43,6 +43,11 @@ public class RepoSourcesAdapter { private final UpdaterData mUpdaterData; + /** + * A dummy RepoSource entry returned for sources which had load errors. + * It displays a summary of the error as its short description or + * it displays the source's long description. + */ public static class RepoSourceError implements IDescription { private final RepoSource mSource; @@ -60,6 +65,33 @@ public class RepoSourcesAdapter { } } + /** + * A dummy RepoSource entry returned for sources with no packages. + * We need that to force the SWT tree to display an open/close triangle + * even for empty sources. + */ + public static class RepoSourceEmpty implements IDescription { + + private final RepoSource mSource; + private final boolean mEmptyBecauseOfUpdateOnly; + + public RepoSourceEmpty(RepoSource source, boolean emptyBecauseOfUpdateOnly) { + mSource = source; + mEmptyBecauseOfUpdateOnly = emptyBecauseOfUpdateOnly; + } + + public String getLongDescription() { + return mSource.getLongDescription(); + } + + public String getShortDescription() { + if (mEmptyBecauseOfUpdateOnly) { + return "Some packages were found but are not compatible updates."; + } else { + return "No packages found"; + } + } + } public RepoSourcesAdapter(UpdaterData updaterData) { mUpdaterData = updaterData; @@ -137,50 +169,78 @@ public class RepoSourcesAdapter { return mUpdaterData.getSources().getSources(); } else if (parentElement instanceof RepoSource) { - final RepoSource source = (RepoSource) parentElement; - Package[] packages = source.getPackages(); - - if (packages == null && source.getFetchError() == null) { - final boolean forceHttp = mUpdaterData.getSettingsController().getForceHttp(); - - mUpdaterData.getTaskFactory().start("Loading Source", new ITask() { - public void run(ITaskMonitor monitor) { - source.load(monitor, forceHttp); - } - }); - - packages = source.getPackages(); - } - if (packages != null) { - // filter out only the packages that are new/upgrade. - if (mUpdaterData.getSettingsController().getShowUpdateOnly()) { - return filteredPackages(packages); - } - return packages; - } else if (source.getFetchError() != null) { - // Return a dummy entry to display the fetch error - return new Object[] { new RepoSourceError(source) }; - } + return getRepoSourceChildren((RepoSource) parentElement); } else if (parentElement instanceof Package) { - Archive[] archives = ((Package) parentElement).getArchives(); - if (mUpdaterData.getSettingsController().getShowUpdateOnly()) { - for (Archive archive : archives) { - // if we only want the compatible archives, then we just take the first - // one. it's unlikely there are 2 compatible archives for the same - // package - if (archive.isCompatible()) { - return new Object[] { archive }; - } - } - } - - return archives; + return getPackageChildren((Package) parentElement); } return new Object[0]; } + /** + * Returns the list of packages for this repo source, eventually filtered to display + * only update packages. If the list is empty, returns a specific empty node. If there's + * an error, returns a specific error node. + */ + private Object[] getRepoSourceChildren(final RepoSource source) { + Package[] packages = source.getPackages(); + + if (packages == null && source.getFetchError() == null) { + final boolean forceHttp = mUpdaterData.getSettingsController().getForceHttp(); + + mUpdaterData.getTaskFactory().start("Loading Source", new ITask() { + public void run(ITaskMonitor monitor) { + source.load(monitor, forceHttp); + } + }); + + packages = source.getPackages(); + } + + boolean wasEmptyBeforeFilter = (packages == null || packages.length == 0); + + // filter out only the packages that are new/upgrade. + if (packages != null && mUpdaterData.getSettingsController().getShowUpdateOnly()) { + packages = filteredPackages(packages); + } + if (packages != null && packages.length == 0) { + packages = null; + } + + if (packages != null && source.getFetchError() != null) { + // Return a dummy entry to display the fetch error + return new Object[] { new RepoSourceError(source) }; + } + + // Either return a non-null package list or create a new empty node + if (packages != null) { + return packages; + } else { + return new Object[] { new RepoSourceEmpty(source, !wasEmptyBeforeFilter) } ; + } + } + + /** + * Returns the list of archives for the given package, eventually filtering it + * to only show the compatible archives. + */ + private Object[] getPackageChildren(Package pkg) { + Archive[] archives = pkg.getArchives(); + if (mUpdaterData.getSettingsController().getShowUpdateOnly()) { + for (Archive archive : archives) { + // if we only want the compatible archives, then we just take the first + // one. it's unlikely there are 2 compatible archives for the same + // package + if (archive.isCompatible()) { + return new Object[] { archive }; + } + } + } + + return archives; + } + /** * Returns the parent of a given element. * The input {@link RepoSourcesAdapter} is the parent of all {@link RepoSource} elements. @@ -213,7 +273,7 @@ public class RepoSourcesAdapter { * @param remotePackages the list of packages to filter. * @return a non null (but maybe empty) list of new or update packages. */ - private Object[] filteredPackages(Package[] remotePackages) { + private Package[] filteredPackages(Package[] remotePackages) { // get the installed packages Package[] installedPackages = mUpdaterData.getInstalledPackage(); @@ -233,10 +293,10 @@ public class RepoSourcesAdapter { if (info == UpdateInfo.UPDATE) { filteredList.add(remotePkg); newPkg = false; - break; // there shouldn't be 2 revision of the same package + break; // there shouldn't be 2 revisions of the same package } else if (info != UpdateInfo.INCOMPATIBLE) { newPkg = false; - break; // there shouldn't be 2 revision of the same package + break; // there shouldn't be 2 revisions of the same package } } @@ -247,6 +307,6 @@ public class RepoSourcesAdapter { } } - return filteredList.toArray(); + return filteredList.toArray(new Package[filteredList.size()]); } } diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/icons/ImageFactory.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/icons/ImageFactory.java index bd39c5e82..cbd846e42 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/icons/ImageFactory.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/icons/ImageFactory.java @@ -91,31 +91,34 @@ public class ImageFactory { */ public Image getImageForObject(Object object) { if (object instanceof RepoSource) { - return getImageByName("source_icon16.png"); + return getImageByName("source_icon16.png"); //$NON-NLS-1$ } else if (object instanceof RepoSourcesAdapter.RepoSourceError) { - return getImageByName("error_icon16.png"); + return getImageByName("error_icon16.png"); //$NON-NLS-1$ + + } else if (object instanceof RepoSourcesAdapter.RepoSourceEmpty) { + return getImageByName("nopkg_icon16.png"); //$NON-NLS-1$ } else if (object instanceof PlatformPackage) { - return getImageByName("android_icon_16.png"); + return getImageByName("android_icon_16.png"); //$NON-NLS-1$ } else if (object instanceof AddonPackage) { - return getImageByName("addon_icon16.png"); + return getImageByName("addon_icon16.png"); //$NON-NLS-1$ } else if (object instanceof ToolPackage) { - return getImageByName("tool_icon16.png"); + return getImageByName("tool_icon16.png"); //$NON-NLS-1$ } else if (object instanceof DocPackage) { - return getImageByName("doc_icon16.png"); + return getImageByName("doc_icon16.png"); //$NON-NLS-1$ } else if (object instanceof ExtraPackage) { - return getImageByName("extra_icon16.png"); + return getImageByName("extra_icon16.png"); //$NON-NLS-1$ } else if (object instanceof Archive) { if (((Archive) object).isCompatible()) { - return getImageByName("archive_icon16.png"); + return getImageByName("archive_icon16.png"); //$NON-NLS-1$ } else { - return getImageByName("incompat_icon16.png"); + return getImageByName("incompat_icon16.png"); //$NON-NLS-1$ } } return null; diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/icons/nopkg_icon16.png b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/icons/nopkg_icon16.png new file mode 100755 index 000000000..147837fd6 Binary files /dev/null and b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/icons/nopkg_icon16.png differ