Bug 479145 - Show progress bar in InstallWizard during the
download of the p2 metadata

* adds ProgressBar to InstallWizard
* changes visibility of ProgressBar when fetching starts/ends

Change-Id: I731c6fb596d1306147aa94b097034c3c2e0f5c0b
Signed-off-by: David Weiser <david.weiser@vogella.com>
diff --git a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ProvUIMessages.java b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ProvUIMessages.java
index a3caadf..ac04365 100644
--- a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ProvUIMessages.java
+++ b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ProvUIMessages.java
@@ -192,6 +192,7 @@
 	public static String AvailableIUsPage_ShowLatestVersions;
 	public static String AvailableIUsPage_SingleSelectionCount;
 	public static String AvailableIUsPage_Title;
+	public static String AvailableIUsPage_Fetching;
 	public static String AvailableIUWrapper_AllAreInstalled;
 	public static String IUViewQueryContext_AllAreInstalledDescription;
 	public static String Label_Profiles;
diff --git a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/dialogs/AvailableIUsPage.java b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/dialogs/AvailableIUsPage.java
index b6a770f..ec8f9f9 100644
--- a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/dialogs/AvailableIUsPage.java
+++ b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/dialogs/AvailableIUsPage.java
@@ -16,6 +16,7 @@
 import java.net.URI;
 import org.eclipse.equinox.internal.p2.ui.*;
 import org.eclipse.equinox.internal.p2.ui.model.EmptyElementExplanation;
+import org.eclipse.equinox.internal.p2.ui.model.QueriedElement;
 import org.eclipse.equinox.internal.p2.ui.query.IUViewQueryContext;
 import org.eclipse.equinox.internal.p2.ui.viewers.*;
 import org.eclipse.equinox.p2.engine.ProvisioningContext;
@@ -26,6 +27,7 @@
 import org.eclipse.jface.dialogs.Dialog;
 import org.eclipse.jface.dialogs.IDialogConstants;
 import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.layout.GridLayoutFactory;
 import org.eclipse.jface.resource.JFaceResources;
 import org.eclipse.jface.viewers.*;
 import org.eclipse.osgi.util.NLS;
@@ -64,6 +66,7 @@
 	RepositorySelectionGroup repoSelector;
 	IUDetailsGroup iuDetailsGroup;
 	Label selectionCount;
+	int progressBarRefCount = 0;
 
 	public AvailableIUsPage(ProvisioningUI ui, ProvisioningOperationWizard wizard) {
 		super("AvailableSoftwarePage", ui, wizard); //$NON-NLS-1$
@@ -172,6 +175,11 @@
 
 		createViewControlsArea(controlsComposite);
 
+		Composite progressBarComposite = createProgressBar(composite);
+		gd = new GridData(SWT.FILL, SWT.TOP, false, false);
+		progressBarComposite.setLayoutData(gd);
+		progressBarComposite.setVisible(false);
+
 		initializeWidgetState();
 		setControl(composite);
 		composite.addDisposeListener(new DisposeListener() {
@@ -184,6 +192,46 @@
 		Dialog.applyDialogFont(composite);
 	}
 
+	private Composite createProgressBar(Composite parent) {
+		final Composite progressBarComposite = new Composite(parent, SWT.NONE);
+		Label progressBarLabel = new Label(progressBarComposite, SWT.NONE);
+		progressBarLabel.setText(ProvUIMessages.AvailableIUsPage_Fetching);
+		ProgressBar progressBar = new ProgressBar(progressBarComposite, SWT.INDETERMINATE);
+		IContentProvider contentProvider = availableIUGroup.getCheckboxTreeViewer().getContentProvider();
+		if (contentProvider instanceof DeferredQueryContentProvider) {
+			((DeferredQueryContentProvider) contentProvider).addOnFetchingActionListener(new IDeferredQueryTreeListener() {
+
+				@Override
+				public void finishedFetchingDeferredChildren(Object parent, Object placeHolder) {
+					if (parent instanceof QueriedElement) {
+						if (((QueriedElement) parent).getCachedChildren().length > 0) {
+							if (progressBarRefCount > 0) {
+								progressBarRefCount--;
+							}
+						}
+					}
+					changeProgressBarVisibility(progressBarComposite);
+				}
+
+				@Override
+				public void fetchingDeferredChildren(Object parent, Object placeHolder) {
+					progressBarRefCount++;
+					changeProgressBarVisibility(progressBarComposite);
+				}
+			});
+		}
+		GridLayoutFactory.fillDefaults().generateLayout(progressBarComposite);
+		return progressBarComposite;
+	}
+
+	void changeProgressBarVisibility(final Composite progressBarComposite) {
+		this.display.asyncExec(() -> {
+			if (!progressBarComposite.isDisposed()) {
+				progressBarComposite.setVisible(progressBarRefCount > 0 ? true : false);
+			}
+		});
+	}
+
 	private void createSelectButtons(Composite parent) {
 		Composite buttonParent = new Composite(parent, SWT.NONE);
 		GridLayout gridLayout = new GridLayout();
@@ -341,6 +389,7 @@
 					repoComboSelectionChanged(repoChoice, repoLocation);
 				}
 			});
+
 			// The ProvisioningOperationWizard signals the start of a repository operation as a way
 			// to keep side-effect events from changing the selections or state of the wizard.
 			// This is the one case where we want to respond to repo events, because we are
@@ -350,7 +399,7 @@
 			repoSelector.setRepositoryManipulationHook(new IRepositoryManipulationHook() {
 				@Override
 				public void preManipulateRepositories() {
-					getProvisioningUI().signalRepositoryOperationComplete(null, false);
+					getProvisioningUI().signalRepositoryOperationComplete(null, true);
 				}
 
 				@Override
diff --git a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/messages.properties b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/messages.properties
index 7d61f00..a219956 100644
--- a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/messages.properties
+++ b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/messages.properties
@@ -216,6 +216,7 @@
 AvailableIUsPage_ShowLatestVersions=Show only the &latest versions of available software
 AvailableIUsPage_SingleSelectionCount={0} item selected
 AvailableIUsPage_Title=Available Software
+AvailableIUsPage_Fetching=Fetching children
 AvailableIUWrapper_AllAreInstalled=All items are installed
 InstallRemediationPage_Title=Install Remediation Page
 InstallRemediationPage_Description=The installation cannot be completed as requested.
diff --git a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/viewers/DeferredQueryContentProvider.java b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/viewers/DeferredQueryContentProvider.java
index dc0d0ce..6ce5469 100644
--- a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/viewers/DeferredQueryContentProvider.java
+++ b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/viewers/DeferredQueryContentProvider.java
@@ -35,6 +35,7 @@
 	AbstractTreeViewer viewer = null;
 	ListenerList<IInputChangeListener> listeners = new ListenerList<IInputChangeListener>();
 	boolean synchronous = false;
+	IDeferredQueryTreeListener onFetchingActionListener;
 
 	/**
 	 * 
@@ -51,6 +52,10 @@
 		listeners.remove(listener);
 	}
 
+	public void addOnFetchingActionListener(IDeferredQueryTreeListener listener) {
+		onFetchingActionListener = listener;
+	}
+
 	@Override
 	public void inputChanged(Viewer v, Object oldInput, Object newInput) {
 		super.inputChanged(v, oldInput, newInput);
@@ -59,8 +64,9 @@
 			manager.cancel(oldInput);
 		if (v instanceof AbstractTreeViewer) {
 			manager = new DeferredQueryTreeContentManager((AbstractTreeViewer) v);
+			manager.addListener(onFetchingActionListener);
 			viewer = (AbstractTreeViewer) v;
-			manager.setListener(new IDeferredQueryTreeListener() {
+			manager.addListener(new IDeferredQueryTreeListener() {
 
 				@Override
 				public void fetchingDeferredChildren(Object parent, Object placeholder) {
diff --git a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/viewers/DeferredQueryTreeContentManager.java b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/viewers/DeferredQueryTreeContentManager.java
index d59689c..a628372 100644
--- a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/viewers/DeferredQueryTreeContentManager.java
+++ b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/viewers/DeferredQueryTreeContentManager.java
@@ -11,6 +11,7 @@
 
 package org.eclipse.equinox.internal.p2.ui.viewers;
 
+import org.eclipse.core.runtime.ListenerList;
 import org.eclipse.jface.viewers.AbstractTreeViewer;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.progress.*;
@@ -41,10 +42,11 @@
 	}
 
 	Object elementRequested;
-	IDeferredQueryTreeListener listener;
+	ListenerList<IDeferredQueryTreeListener> listeners;
 
 	public DeferredQueryTreeContentManager(AbstractTreeViewer viewer) {
 		super(viewer);
+		listeners = new ListenerList<IDeferredQueryTreeListener>();
 	}
 
 	/*
@@ -86,16 +88,23 @@
 		return new ElementPendingUpdateAdapter(elementRequested);
 	}
 
-	public void setListener(IDeferredQueryTreeListener listener) {
-		this.listener = listener;
+	public void addListener(IDeferredQueryTreeListener listener) {
+		if (listener != null) {
+			this.listeners.add(listener);
+		}
 	}
 
 	private void notifyListener(boolean starting, ElementPendingUpdateAdapter placeholder) {
-		if (listener == null)
+		if (listeners == null || listeners.isEmpty())
 			return;
-		if (starting)
-			listener.fetchingDeferredChildren(placeholder.element, placeholder);
-		else
-			listener.finishedFetchingDeferredChildren(placeholder.element, placeholder);
+		if (starting) {
+			for (IDeferredQueryTreeListener deferredQueryTreeListener : listeners) {
+				deferredQueryTreeListener.fetchingDeferredChildren(placeholder.element, placeholder);
+			}
+		} else {
+			for (IDeferredQueryTreeListener deferredQueryTreeListener : listeners) {
+				deferredQueryTreeListener.finishedFetchingDeferredChildren(placeholder.element, placeholder);
+			}
+		}
 	}
 }