Merge branch 'topic/favorites-dnd'
diff --git a/org.eclipse.epp.mpc.ui/OSGI-INF/l10n/bundle.properties b/org.eclipse.epp.mpc.ui/OSGI-INF/l10n/bundle.properties
index 4799778..e4987c8 100644
--- a/org.eclipse.epp.mpc.ui/OSGI-INF/l10n/bundle.properties
+++ b/org.eclipse.epp.mpc.ui/OSGI-INF/l10n/bundle.properties
@@ -11,10 +11,18 @@
 ###############################################################################
 Bundle-Vendor = Eclipse Marketplace Client
 Bundle-Name = Marketplace Client
-command.description = Show the Eclipse Marketplace wizard
-command.name = Eclipse Marketplace
-command.label = Eclipse &Marketplace...
-command.tooltip = Open the Eclipse Marketplace wizard
+command.open.description = Show the Eclipse Marketplace wizard
+command.open.name = Eclipse Marketplace
+command.open.label = Eclipse &Marketplace...
+command.open.tooltip = Open the Eclipse Marketplace wizard
+command.importFavorites.description = Import another user's Marketplace Favorites List
+command.importFavorites.name = Import Marketplace Favorites
+command.installed.description = Update or uninstall plug-ins installed from the Marketplace
+command.installed.name = Manage installed plug-ins
+command.favorites.description = Open Marketplace Favorites
+command.favorites.name = Eclipse Marketplace Favorites
+command.favorites.label = Eclipse Marketplace &Favorites...
+command.favorites.tooltip = Open your personal Eclipse Marketplace favorites
 catalog.description = Eclipse Marketplace (MP) is a place to find and keep track of Eclipse-based solutions.
 catalog.label = Eclipse Marketplace
 extension-point.name = Marketplace Catalog
diff --git a/org.eclipse.epp.mpc.ui/plugin.xml b/org.eclipse.epp.mpc.ui/plugin.xml
index 3eaeaeb..99126f7 100644
--- a/org.eclipse.epp.mpc.ui/plugin.xml
+++ b/org.eclipse.epp.mpc.ui/plugin.xml
@@ -19,13 +19,45 @@
             class="org.eclipse.epp.internal.mpc.ui.commands.MarketplaceWizardCommand"
             commandId="org.eclipse.epp.mpc.ui.command.showMarketplaceWizard">
       </handler>
+      <handler
+            class="org.eclipse.epp.internal.mpc.ui.commands.ImportFavoritesWizardCommand"
+            commandId="org.eclipse.epp.mpc.ui.command.importFavoritesWizard">
+      </handler>
+      <handler
+            class="org.eclipse.epp.internal.mpc.ui.commands.ShowFavoritesCommand"
+            commandId="org.eclipse.epp.mpc.ui.command.showFavorites">
+      </handler>
+      <handler
+            class="org.eclipse.epp.internal.mpc.ui.commands.ShowInstalledSolutionsCommand"
+            commandId="org.eclipse.epp.mpc.ui.command.showInstalled">
+      </handler>
    </extension>
    <extension
          point="org.eclipse.ui.commands">
       <command
-            description="%command.description"
+            description="%command.open.description"
             id="org.eclipse.epp.mpc.ui.command.showMarketplaceWizard"
-            name="%command.name">
+            name="%command.open.name">
+      </command>
+      <command
+            description="%command.importFavorites.description"
+            id="org.eclipse.epp.mpc.ui.command.importFavoritesWizard"
+            name="%command.importFavorites.name">
+         <commandParameter
+               id="favoritesUrl"
+               name="favoritesUrl"
+               optional="true">
+         </commandParameter>
+      </command>
+      <command
+            description="%command.favorites.description"
+            id="org.eclipse.epp.mpc.ui.command.showFavorites"
+            name="%command.favorites.name">
+      </command>
+      <command
+            description="%command.installed.description"
+            id="org.eclipse.epp.mpc.ui.command.showInstalled"
+            name="%command.installed.name">
       </command>
    </extension>
    <extension
@@ -36,9 +68,9 @@
          <command
                commandId="org.eclipse.epp.mpc.ui.command.showMarketplaceWizard"
                icon="icons/marketplace16.png"
-               label="%command.label"
+               label="%command.open.label"
                style="push"
-               tooltip="%command.tooltip">
+               tooltip="%command.open.tooltip">
          </command>
       </menuContribution>
    </extension>
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceDiscoveryStrategy.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceDiscoveryStrategy.java
index c91c653..384c2ae 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceDiscoveryStrategy.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceDiscoveryStrategy.java
@@ -420,12 +420,17 @@
 	}
 
 	public void addCatalogItem(MarketplaceCategory catalogCategory) {
+		CatalogItem catalogItem = createCategoryItem(catalogCategory);
+		items.add(catalogItem);
+	}
+
+	private CatalogItem createCategoryItem(MarketplaceCategory catalogCategory) {
 		CatalogItem catalogItem = new CatalogItem();
 		catalogItem.setSource(source);
 		catalogItem.setData(catalogDescriptor);
 		catalogItem.setId(catalogDescriptor.getUrl().toString());
 		catalogItem.setCategoryId(catalogCategory.getId());
-		items.add(catalogItem);
+		return catalogItem;
 	}
 
 	public UserActionCatalogItem addUserActionItem(MarketplaceCategory catalogCategory, UserAction userAction) {
@@ -450,7 +455,7 @@
 		catalogItem.setData(data);
 		catalogItem.setId(catalogDescriptor.getUrl().toString() + "#" + userAction.name()); //$NON-NLS-1$
 		catalogItem.setCategoryId(catalogCategory.getId());
-		items.add(catalogItem);
+		items.add(0, catalogItem);
 		return catalogItem;
 	}
 
@@ -682,13 +687,17 @@
 					} else {
 						result = marketplaceService.userFavorites(progress.newChild(500));
 					}
-					handleSearchResult(catalogCategory, result, progress.newChild(500));
 					if (result.getNodes().isEmpty()) {
+						catalogCategory = addPopularItems(progress.newChild(500));
 						addNoFavoritesItem(catalogCategory);
+					} else {
+						handleSearchResult(catalogCategory, result, progress.newChild(500));
 					}
 				} catch (NotAuthorizedException e) {
+					catalogCategory = addPopularItems(progress.newChild(500));
 					addUserStorageLoginItem(catalogCategory, e.getLocalizedMessage());
 				} catch (UnsupportedOperationException ex) {
+					catalogCategory = addPopularItems(progress.newChild(500));
 					addFavoritesNotSupportedItem(catalogCategory);
 				} catch (Exception ex) {
 					//FIXME we should use the wizard page's status line to show errors, but that's unreachable from here...
@@ -696,6 +705,7 @@
 					addRetryErrorItem(catalogCategory, ex);
 				}
 			} else {
+				catalogCategory = addPopularItems(progress.newChild(1000));
 				addFavoritesNotSupportedItem(catalogCategory);
 			}
 		} finally {
@@ -703,6 +713,14 @@
 		}
 	}
 
+	private MarketplaceCategory addPopularItems(IProgressMonitor monitor) throws CoreException {
+		SubMonitor progress = SubMonitor.convert(monitor, 100);
+		MarketplaceCategory catalogCategory;
+		popular(progress.newChild(99));
+		catalogCategory = findMarketplaceCategory(progress.newChild(1));
+		return catalogCategory;
+	}
+
 	public void refreshUserFavorites(IProgressMonitor monitor) throws CoreException {
 		final SubMonitor progress = SubMonitor.convert(monitor, Messages.MarketplaceDiscoveryStrategy_FavoritesRefreshing, 1001);
 		try {
@@ -731,10 +749,13 @@
 						}
 					}
 				} catch (NotAuthorizedException e) {
+					catalogCategory = addPopularItems(progress.newChild(500));
 					addUserStorageLoginItem(catalogCategory, e.getLocalizedMessage());
 				} catch (UnsupportedOperationException ex) {
+					catalogCategory = addPopularItems(progress.newChild(500));
 					addFavoritesNotSupportedItem(catalogCategory);
 				} catch (Exception ex) {
+					//FIXME we should use the wizard page's status line to show errors, but that's unreachable from here...
 					MarketplaceClientCore.error(Messages.MarketplaceDiscoveryStrategy_FavoritesRetrieveError, ex);
 					addRetryErrorItem(catalogCategory, ex);
 				}
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceNodeCatalogItem.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceNodeCatalogItem.java
index bbeed43..1ad17d0 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceNodeCatalogItem.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceNodeCatalogItem.java
@@ -277,6 +277,15 @@
 	}
 
 	@Override
+	public void setSelected(boolean selected) {
+		boolean wasSelected = isSelected();
+		if (wasSelected != selected) {
+			super.setSelected(selected);
+			firePropertyChange("selected", wasSelected, selected); //$NON-NLS-1$
+		}
+	}
+
+	@Override
 	public int hashCode() {
 		final int prime = 31;
 		int result = 1;
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/commands/AbstractMarketplaceWizardCommand.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/commands/AbstractMarketplaceWizardCommand.java
new file mode 100644
index 0000000..bd001c2
--- /dev/null
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/commands/AbstractMarketplaceWizardCommand.java
@@ -0,0 +1,235 @@
+/*******************************************************************************
+ * Copyright (c) 2010 The Eclipse Foundation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * 	The Eclipse Foundation - initial API and implementation
+ * 	Yatta Solutions - category filtering (bug 314936), error handling (bug 374105),
+ *                      multiselect hints (bug 337774), public API (bug 432803),
+ *                      performance (bug 413871), featured market (bug 461603)
+ *******************************************************************************/
+package org.eclipse.epp.internal.mpc.ui.commands;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore;
+import org.eclipse.epp.internal.mpc.ui.CatalogRegistry;
+import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi;
+import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUiPlugin;
+import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCatalog;
+import org.eclipse.epp.internal.mpc.ui.catalog.ResourceProvider;
+import org.eclipse.epp.internal.mpc.ui.wizards.AbstractMarketplaceWizardDialog;
+import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceCatalogConfiguration;
+import org.eclipse.epp.mpc.core.model.ICatalog;
+import org.eclipse.epp.mpc.core.service.ICatalogService;
+import org.eclipse.epp.mpc.core.service.ServiceHelper;
+import org.eclipse.epp.mpc.ui.CatalogDescriptor;
+import org.eclipse.epp.mpc.ui.IMarketplaceClientConfiguration;
+import org.eclipse.equinox.internal.p2.discovery.DiscoveryCore;
+import org.eclipse.equinox.internal.p2.ui.discovery.wizards.DiscoveryWizard;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * @author David Green
+ * @author Carsten Reckord
+ */
+public abstract class AbstractMarketplaceWizardCommand extends AbstractHandler implements IHandler {
+
+	private List<CatalogDescriptor> catalogDescriptors;
+
+	private CatalogDescriptor selectedCatalogDescriptor;
+
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		final MarketplaceCatalog catalog = createCatalog();
+		MarketplaceCatalogConfiguration configuration = createConfiguration(catalog, event);
+		DiscoveryWizard wizard = createWizard(catalog, configuration, event);
+		openWizardDialog(wizard, event);
+
+		return null;
+	}
+
+	protected MarketplaceCatalog createCatalog() {
+		final MarketplaceCatalog catalog = new MarketplaceCatalog();
+
+		catalog.setEnvironment(DiscoveryCore.createEnvironment());
+		catalog.setVerifyUpdateSiteAvailability(false);
+		return catalog;
+	}
+
+	protected MarketplaceCatalogConfiguration createConfiguration(final MarketplaceCatalog catalog,
+			ExecutionEvent event) {
+		MarketplaceCatalogConfiguration configuration = new MarketplaceCatalogConfiguration();
+		configuration.setVerifyUpdateSiteAvailability(false);
+
+		if (catalogDescriptors == null || catalogDescriptors.isEmpty()) {
+			final IStatus remoteCatalogStatus = installRemoteCatalogs();
+			configuration.getCatalogDescriptors().addAll(CatalogRegistry.getInstance().getCatalogDescriptors());
+			if (configuration.getCatalogDescriptors().isEmpty()) {
+				// doesn't make much sense to continue without catalogs.
+				// nothing will work and no way to recover later
+				IStatus cause;
+				if (!remoteCatalogStatus.isOK()) {
+					cause = remoteCatalogStatus;
+				} else {
+					cause = new Status(IStatus.ERROR, MarketplaceClientUi.BUNDLE_ID,
+							Messages.MarketplaceWizardCommand_noRemoteCatalogs);
+				}
+				IStatus exitStatus = new Status(IStatus.ERROR, MarketplaceClientUi.BUNDLE_ID, cause.getCode(),
+						Messages.MarketplaceWizardCommand_cannotOpenMarketplace, new CoreException(cause));
+				try {
+					MarketplaceClientUi.handle(exitStatus,
+							StatusManager.SHOW | StatusManager.BLOCK
+							| (exitStatus.getSeverity() == IStatus.CANCEL ? 0 : StatusManager.LOG));
+				} catch (Exception ex) {
+					// HOTFIX for bug 477269 - Display might get disposed during call to handle due to workspace shutdown or similar.
+					// In that case, just log...
+					MarketplaceClientUi.getLog().log(exitStatus);
+				}
+				return null;
+			} else if (!remoteCatalogStatus.isOK()) {
+				MarketplaceClientUi.handle(remoteCatalogStatus, StatusManager.LOG);
+			}
+		} else {
+			configuration.getCatalogDescriptors().addAll(catalogDescriptors);
+		}
+		if (selectedCatalogDescriptor != null) {
+			if (selectedCatalogDescriptor.getLabel().equals("org.eclipse.epp.mpc.descriptorHint")) { //$NON-NLS-1$
+				CatalogDescriptor resolvedDescriptor = CatalogRegistry.getInstance().findCatalogDescriptor(
+						selectedCatalogDescriptor.getUrl().toExternalForm());
+				if (resolvedDescriptor == null) {
+					IStatus status = new Status(IStatus.ERROR, MarketplaceClientUi.BUNDLE_ID,
+							Messages.MarketplaceWizardCommand_CouldNotFindMarketplaceForSolution, new ExecutionException(
+									selectedCatalogDescriptor.getUrl().toExternalForm()));
+					MarketplaceClientUi.handle(status,
+							StatusManager.SHOW | StatusManager.BLOCK | StatusManager.LOG);
+					return null;
+				} else {
+					configuration.setCatalogDescriptor(resolvedDescriptor);
+				}
+			} else {
+				configuration.setCatalogDescriptor(selectedCatalogDescriptor);
+			}
+		}
+
+		return configuration;
+	}
+
+	protected void openWizardDialog(DiscoveryWizard wizard, ExecutionEvent event) {
+		WizardDialog dialog = createWizardDialog(wizard, event);
+		dialog.open();
+	}
+
+	protected abstract AbstractMarketplaceWizardDialog createWizardDialog(DiscoveryWizard wizard, ExecutionEvent event);
+
+	protected abstract DiscoveryWizard createWizard(final MarketplaceCatalog catalog,
+			MarketplaceCatalogConfiguration configuration, ExecutionEvent event);
+
+	public void setCatalogDescriptors(List<CatalogDescriptor> catalogDescriptors) {
+		this.catalogDescriptors = catalogDescriptors;
+	}
+
+	public void setSelectedCatalogDescriptor(CatalogDescriptor selectedCatalogDescriptor) {
+		this.selectedCatalogDescriptor = selectedCatalogDescriptor;
+	}
+
+	public IStatus installRemoteCatalogs() {
+		try {
+			final AtomicReference<List<? extends ICatalog>> result = new AtomicReference<List<? extends ICatalog>>();
+
+			PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() {
+				public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+					try {
+						ICatalogService catalogService = ServiceHelper.getMarketplaceServiceLocator()
+								.getCatalogService();
+						final List<? extends ICatalog> catalogs = catalogService.listCatalogs(monitor);
+						result.set(catalogs);
+					} catch (CoreException e) {
+						if (e.getStatus().getSeverity() == IStatus.CANCEL) {
+							throw new InterruptedException();
+						}
+						throw new InvocationTargetException(e);
+					}
+				}
+			});
+
+			List<? extends ICatalog> catalogs = result.get();
+			for (ICatalog catalog : catalogs) {
+				ResourceProvider resourceProvider = MarketplaceClientUiPlugin.getInstance().getResourceProvider();
+				String catalogName = catalog.getName();
+				String requestSource = NLS.bind(Messages.MarketplaceWizardCommand_requestCatalog, catalogName,
+						catalog.getId());
+				String catalogImageUrl = catalog.getImageUrl();
+				if (catalogImageUrl != null) {
+					try {
+						resourceProvider.retrieveResource(requestSource, catalogImageUrl);
+					} catch (Exception e) {
+						MarketplaceClientUi.log(IStatus.WARNING,
+								Messages.MarketplaceWizardCommand_FailedRetrievingCatalogImage, catalogName,
+								catalogImageUrl, e);
+					}
+				}
+				if (catalog.getBranding() != null && catalog.getBranding().getWizardIcon() != null) {
+					String wizardIconUrl = catalog.getBranding().getWizardIcon();
+					try {
+						resourceProvider.retrieveResource(requestSource, wizardIconUrl);
+					} catch (Exception e) {
+						MarketplaceClientUi.log(IStatus.WARNING,
+								Messages.MarketplaceWizardCommand_FailedRetrievingCatalogWizardIcon, catalogName,
+								wizardIconUrl, e);
+					}
+				}
+				CatalogDescriptor descriptor = new CatalogDescriptor(catalog);
+				registerOrOverrideCatalog(descriptor);
+			}
+		} catch (InterruptedException ie) {
+			if (ie.getMessage() == null || "".equals(ie.getMessage())) {
+				InterruptedException ie1 = new InterruptedException("Operation cancelled");
+				ie1.setStackTrace(ie.getStackTrace());
+				if (ie.getCause() != null) {
+					ie1.initCause(ie.getCause());
+				}
+				ie = ie1;
+			}
+			IStatus errorStatus = MarketplaceClientCore.computeStatus(ie,
+					Messages.MarketplaceWizardCommand_CannotInstallRemoteLocations);
+			return new Status(IStatus.CANCEL, MarketplaceClientCore.BUNDLE_ID, errorStatus.getMessage(), ie);
+		} catch (Exception e) {
+			IStatus status = MarketplaceClientCore.computeStatus(e, Messages.MarketplaceWizardCommand_CannotInstallRemoteLocations);
+			return status;
+		}
+		return Status.OK_STATUS;
+	}
+
+	private void registerOrOverrideCatalog(CatalogDescriptor descriptor) {
+		CatalogRegistry catalogRegistry = CatalogRegistry.getInstance();
+		List<CatalogDescriptor> descriptors = catalogRegistry.getCatalogDescriptors();
+		for (CatalogDescriptor catalogDescriptor : descriptors) {
+			if (catalogDescriptor.getUrl().toExternalForm().equals(descriptor.getUrl().toExternalForm())) {
+				catalogRegistry.unregister(catalogDescriptor);
+			}
+		}
+		catalogRegistry.register(descriptor);
+	}
+
+	public void setConfiguration(IMarketplaceClientConfiguration configuration) {
+		setCatalogDescriptors(configuration.getCatalogDescriptors());
+		setSelectedCatalogDescriptor(configuration.getCatalogDescriptor());
+	}
+}
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/commands/ImportFavoritesWizardCommand.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/commands/ImportFavoritesWizardCommand.java
new file mode 100644
index 0000000..17a74cf
--- /dev/null
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/commands/ImportFavoritesWizardCommand.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2010 The Eclipse Foundation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     The Eclipse Foundation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.epp.internal.mpc.ui.commands;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.epp.internal.mpc.ui.catalog.FavoritesCatalog;
+import org.eclipse.epp.internal.mpc.ui.catalog.FavoritesDiscoveryStrategy;
+import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCatalog;
+import org.eclipse.epp.internal.mpc.ui.wizards.ImportFavoritesPage;
+import org.eclipse.epp.internal.mpc.ui.wizards.ImportFavoritesWizard;
+import org.eclipse.epp.internal.mpc.ui.wizards.ImportFavoritesWizardDialog;
+import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceCatalogConfiguration;
+import org.eclipse.equinox.internal.p2.ui.discovery.util.WorkbenchUtil;
+import org.eclipse.equinox.internal.p2.ui.discovery.wizards.DiscoveryWizard;
+
+public class ImportFavoritesWizardCommand extends AbstractMarketplaceWizardCommand {
+
+	private static final String FAVORITES_URL_PARAMETER = "favoritesUrl"; //$NON-NLS-1$
+
+	private String favoritesUrl;
+
+	@Override
+	protected ImportFavoritesWizardDialog createWizardDialog(DiscoveryWizard wizard, ExecutionEvent event) {
+		return new ImportFavoritesWizardDialog(WorkbenchUtil.getShell(), (ImportFavoritesWizard) wizard);
+	}
+
+	@Override
+	protected ImportFavoritesWizard createWizard(MarketplaceCatalog catalog,
+			MarketplaceCatalogConfiguration configuration, ExecutionEvent event) {
+		String favoritesUrl = event.getParameter(FAVORITES_URL_PARAMETER);
+		if (favoritesUrl == null) {
+			favoritesUrl = this.favoritesUrl;
+		}
+
+		FavoritesCatalog favoritesCatalog = new FavoritesCatalog();
+
+		ImportFavoritesWizard wizard = new ImportFavoritesWizard(favoritesCatalog, configuration, null);
+		wizard.setInitialFavoritesUrl(favoritesUrl);
+		final ImportFavoritesPage importFavoritesPage = wizard.getImportFavoritesPage();
+
+		favoritesCatalog.getDiscoveryStrategies()
+		.add(new FavoritesDiscoveryStrategy(configuration.getCatalogDescriptor()) {
+			private String discoveryError = null;
+
+			@Override
+			protected void preDiscovery() {
+				discoveryError = null;
+			}
+
+			@Override
+			protected void handleDiscoveryError(CoreException ex) throws CoreException {
+				discoveryError = ImportFavoritesPage.handleDiscoveryError(getFavoritesReference(), ex);
+			}
+
+			@Override
+			protected void postDiscovery() {
+				final String errorMessage = this.discoveryError;
+				this.discoveryError = null;
+				importFavoritesPage.setDiscoveryError(errorMessage);
+			}
+		});
+		return wizard;
+	}
+
+	public void setFavoritesUrl(String favoritesUrl) {
+		this.favoritesUrl = favoritesUrl;
+	}
+
+	public String getFavoritesUrl() {
+		return favoritesUrl;
+	}
+
+}
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/commands/MarketplaceWizardCommand.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/commands/MarketplaceWizardCommand.java
index 1f43c5d..e2a0812 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/commands/MarketplaceWizardCommand.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/commands/MarketplaceWizardCommand.java
@@ -13,7 +13,6 @@
  *******************************************************************************/
 package org.eclipse.epp.internal.mpc.ui.commands;
 
-import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -21,22 +20,10 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.atomic.AtomicReference;
 
-import org.eclipse.core.commands.AbstractHandler;
 import org.eclipse.core.commands.ExecutionEvent;
-import org.eclipse.core.commands.ExecutionException;
 import org.eclipse.core.commands.IHandler;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore;
-import org.eclipse.epp.internal.mpc.ui.CatalogRegistry;
-import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi;
-import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUiPlugin;
 import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCatalog;
-import org.eclipse.epp.internal.mpc.ui.catalog.ResourceProvider;
 import org.eclipse.epp.internal.mpc.ui.wizards.AbstractTagFilter;
 import org.eclipse.epp.internal.mpc.ui.wizards.ComboTagFilter;
 import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceCatalogConfiguration;
@@ -44,35 +31,25 @@
 import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceWizard;
 import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceWizard.WizardState;
 import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceWizardDialog;
-import org.eclipse.epp.mpc.core.model.ICatalog;
 import org.eclipse.epp.mpc.core.model.ICategory;
 import org.eclipse.epp.mpc.core.model.IMarket;
-import org.eclipse.epp.mpc.core.service.ICatalogService;
-import org.eclipse.epp.mpc.core.service.ServiceHelper;
-import org.eclipse.epp.mpc.ui.CatalogDescriptor;
+import org.eclipse.epp.mpc.ui.IMarketplaceClientConfiguration;
 import org.eclipse.epp.mpc.ui.IMarketplaceClientConfiguration;
 import org.eclipse.epp.mpc.ui.Operation;
-import org.eclipse.equinox.internal.p2.discovery.DiscoveryCore;
 import org.eclipse.equinox.internal.p2.discovery.model.Tag;
 import org.eclipse.equinox.internal.p2.ui.discovery.util.WorkbenchUtil;
 import org.eclipse.equinox.internal.p2.ui.discovery.wizards.CatalogFilter;
-import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.equinox.internal.p2.ui.discovery.wizards.DiscoveryWizard;
 import org.eclipse.jface.util.IPropertyChangeListener;
 import org.eclipse.jface.util.PropertyChangeEvent;
-import org.eclipse.jface.wizard.WizardDialog;
-import org.eclipse.osgi.util.NLS;
-import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.statushandlers.StatusManager;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.handlers.HandlerUtil;
 
 /**
  * @author David Green
  * @author Carsten Reckord
  */
-public class MarketplaceWizardCommand extends AbstractHandler implements IHandler {
-
-	private List<CatalogDescriptor> catalogDescriptors;
-
-	private CatalogDescriptor selectedCatalogDescriptor;
+public class MarketplaceWizardCommand extends AbstractMarketplaceWizardCommand implements IHandler {
 
 	private String wizardState;
 
@@ -80,65 +57,10 @@
 
 	private WizardState wizardDialogState;
 
-	public Object execute(ExecutionEvent event) throws ExecutionException {
-		final MarketplaceCatalog catalog = new MarketplaceCatalog();
-
-		catalog.setEnvironment(DiscoveryCore.createEnvironment());
-		catalog.setVerifyUpdateSiteAvailability(false);
-
-		MarketplaceCatalogConfiguration configuration = new MarketplaceCatalogConfiguration();
-		configuration.setVerifyUpdateSiteAvailability(false);
-
-		if (catalogDescriptors == null || catalogDescriptors.isEmpty()) {
-			final IStatus remoteCatalogStatus = installRemoteCatalogs();
-			configuration.getCatalogDescriptors().addAll(CatalogRegistry.getInstance().getCatalogDescriptors());
-			if (configuration.getCatalogDescriptors().isEmpty()) {
-				// doesn't make much sense to continue without catalogs.
-				// nothing will work and no way to recover later
-				IStatus cause;
-				if (!remoteCatalogStatus.isOK()) {
-					cause = remoteCatalogStatus;
-				} else {
-					cause = new Status(IStatus.ERROR, MarketplaceClientUi.BUNDLE_ID,
-							Messages.MarketplaceWizardCommand_noRemoteCatalogs);
-				}
-				IStatus exitStatus = new Status(IStatus.ERROR, MarketplaceClientUi.BUNDLE_ID, cause.getCode(),
-						Messages.MarketplaceWizardCommand_cannotOpenMarketplace, new CoreException(cause));
-				try {
-					MarketplaceClientUi.handle(exitStatus,
-							StatusManager.SHOW | StatusManager.BLOCK
-							| (exitStatus.getSeverity() == IStatus.CANCEL ? 0 : StatusManager.LOG));
-				} catch (Exception ex) {
-					// HOTFIX for bug 477269 - Display might get disposed during call to handle due to workspace shutdown or similar.
-					// In that case, just log...
-					MarketplaceClientUi.getLog().log(exitStatus);
-				}
-				return null;
-			} else if (!remoteCatalogStatus.isOK()) {
-				MarketplaceClientUi.handle(remoteCatalogStatus, StatusManager.LOG);
-			}
-		} else {
-			configuration.getCatalogDescriptors().addAll(catalogDescriptors);
-		}
-		if (selectedCatalogDescriptor != null) {
-			if (selectedCatalogDescriptor.getLabel().equals("org.eclipse.epp.mpc.descriptorHint")) { //$NON-NLS-1$
-				CatalogDescriptor resolvedDescriptor = CatalogRegistry.getInstance().findCatalogDescriptor(
-						selectedCatalogDescriptor.getUrl().toExternalForm());
-				if (resolvedDescriptor == null) {
-					IStatus status = new Status(IStatus.ERROR, MarketplaceClientUi.BUNDLE_ID,
-							Messages.MarketplaceWizardCommand_CouldNotFindMarketplaceForSolution, new ExecutionException(
-									selectedCatalogDescriptor.getUrl().toExternalForm()));
-					MarketplaceClientUi.handle(status,
-							StatusManager.SHOW | StatusManager.BLOCK | StatusManager.LOG);
-					return null;
-				} else {
-					configuration.setCatalogDescriptor(resolvedDescriptor);
-				}
-			} else {
-				configuration.setCatalogDescriptor(selectedCatalogDescriptor);
-			}
-		}
-
+	@Override
+	protected MarketplaceCatalogConfiguration createConfiguration(final MarketplaceCatalog catalog,
+			ExecutionEvent event) {
+		MarketplaceCatalogConfiguration configuration = super.createConfiguration(catalog, event);
 		configuration.getFilters().clear();
 
 		final ComboTagFilter marketFilter = new ComboTagFilter() {
@@ -190,15 +112,25 @@
 		for (CatalogFilter filter : configuration.getFilters()) {
 			((MarketplaceFilter) filter).setCatalog(catalog);
 		}
+		return configuration;
+	}
 
+	@Override
+	protected MarketplaceWizardDialog createWizardDialog(DiscoveryWizard wizard, ExecutionEvent event) {
+		Shell activeShell = HandlerUtil.getActiveShell(event);
+		if (activeShell == null) {
+			activeShell = WorkbenchUtil.getShell();
+		}
+		return new MarketplaceWizardDialog(activeShell, (MarketplaceWizard) wizard);
+	}
+
+	@Override
+	protected MarketplaceWizard createWizard(final MarketplaceCatalog catalog,
+			MarketplaceCatalogConfiguration configuration, ExecutionEvent event) {
 		MarketplaceWizard wizard = new MarketplaceWizard(catalog, configuration);
 		wizard.setInitialState(wizardDialogState);
 		wizard.setWindowTitle(Messages.MarketplaceWizardCommand_eclipseMarketplace);
-
-		WizardDialog dialog = new MarketplaceWizardDialog(WorkbenchUtil.getShell(), wizard);
-		dialog.open();
-
-		return null;
+		return wizard;
 	}
 
 	private void updateCategoryChoices(final ComboTagFilter marketCategoryTagFilter, final ComboTagFilter marketFilter) {
@@ -231,14 +163,6 @@
 		marketCategoryTagFilter.setChoices(choices);
 	}
 
-	public void setCatalogDescriptors(List<CatalogDescriptor> catalogDescriptors) {
-		this.catalogDescriptors = catalogDescriptors;
-	}
-
-	public void setSelectedCatalogDescriptor(CatalogDescriptor selectedCatalogDescriptor) {
-		this.selectedCatalogDescriptor = selectedCatalogDescriptor;
-	}
-
 	public void setWizardState(String wizardState) {
 		this.wizardState = wizardState;
 	}
@@ -260,88 +184,9 @@
 	}
 
 	public void setConfiguration(IMarketplaceClientConfiguration configuration) {
-		setCatalogDescriptors(configuration.getCatalogDescriptors());
+	   super.setConfiguration(configuration);
 		setOperations(configuration.getInitialOperations());
 		setWizardState((String) configuration.getInitialState());
-		setSelectedCatalogDescriptor(configuration.getCatalogDescriptor());
 	}
 
-	public IStatus installRemoteCatalogs() {
-		try {
-			final AtomicReference<List<? extends ICatalog>> result = new AtomicReference<List<? extends ICatalog>>();
-
-			PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() {
-				public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
-					try {
-						ICatalogService catalogService = ServiceHelper.getMarketplaceServiceLocator()
-								.getCatalogService();
-						final List<? extends ICatalog> catalogs = catalogService.listCatalogs(monitor);
-						result.set(catalogs);
-					} catch (CoreException e) {
-						if (e.getStatus().getSeverity() == IStatus.CANCEL) {
-							throw new InterruptedException();
-						}
-						throw new InvocationTargetException(e);
-					}
-				}
-			});
-
-			List<? extends ICatalog> catalogs = result.get();
-			for (ICatalog catalog : catalogs) {
-				ResourceProvider resourceProvider = MarketplaceClientUiPlugin.getInstance().getResourceProvider();
-				String catalogName = catalog.getName();
-				String requestSource = NLS.bind(Messages.MarketplaceWizardCommand_requestCatalog, catalogName,
-						catalog.getId());
-				String catalogImageUrl = catalog.getImageUrl();
-				if (catalogImageUrl != null) {
-					try {
-						resourceProvider.retrieveResource(requestSource, catalogImageUrl);
-					} catch (Exception e) {
-						MarketplaceClientUi.log(IStatus.WARNING,
-								Messages.MarketplaceWizardCommand_FailedRetrievingCatalogImage, catalogName,
-								catalogImageUrl, e);
-					}
-				}
-				if (catalog.getBranding() != null && catalog.getBranding().getWizardIcon() != null) {
-					String wizardIconUrl = catalog.getBranding().getWizardIcon();
-					try {
-						resourceProvider.retrieveResource(requestSource, wizardIconUrl);
-					} catch (Exception e) {
-						MarketplaceClientUi.log(IStatus.WARNING,
-								Messages.MarketplaceWizardCommand_FailedRetrievingCatalogWizardIcon, catalogName,
-								wizardIconUrl, e);
-					}
-				}
-				CatalogDescriptor descriptor = new CatalogDescriptor(catalog);
-				registerOrOverrideCatalog(descriptor);
-			}
-		} catch (InterruptedException ie) {
-			if (ie.getMessage() == null || "".equals(ie.getMessage())) {
-				InterruptedException ie1 = new InterruptedException("Operation cancelled");
-				ie1.setStackTrace(ie.getStackTrace());
-				if (ie.getCause() != null) {
-					ie1.initCause(ie.getCause());
-				}
-				ie = ie1;
-			}
-			IStatus errorStatus = MarketplaceClientCore.computeStatus(ie,
-					Messages.MarketplaceWizardCommand_CannotInstallRemoteLocations);
-			return new Status(IStatus.CANCEL, MarketplaceClientCore.BUNDLE_ID, errorStatus.getMessage(), ie);
-		} catch (Exception e) {
-			IStatus status = MarketplaceClientCore.computeStatus(e, Messages.MarketplaceWizardCommand_CannotInstallRemoteLocations);
-			return status;
-		}
-		return Status.OK_STATUS;
-	}
-
-	private void registerOrOverrideCatalog(CatalogDescriptor descriptor) {
-		CatalogRegistry catalogRegistry = CatalogRegistry.getInstance();
-		List<CatalogDescriptor> descriptors = catalogRegistry.getCatalogDescriptors();
-		for (CatalogDescriptor catalogDescriptor : descriptors) {
-			if (catalogDescriptor.getUrl().toExternalForm().equals(descriptor.getUrl().toExternalForm())) {
-				catalogRegistry.unregister(catalogDescriptor);
-			}
-		}
-		catalogRegistry.register(descriptor);
-	}
 }
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/commands/ShowFavoritesCommand.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/commands/ShowFavoritesCommand.java
new file mode 100644
index 0000000..deac7e5
--- /dev/null
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/commands/ShowFavoritesCommand.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2010 The Eclipse Foundation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     The Eclipse Foundation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.epp.internal.mpc.ui.commands;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.epp.mpc.ui.IMarketplaceClientConfiguration;
+import org.eclipse.epp.mpc.ui.IMarketplaceClientService;
+import org.eclipse.epp.mpc.ui.MarketplaceClient;
+
+public class ShowFavoritesCommand extends AbstractHandler {
+
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IMarketplaceClientService marketplaceClientService = MarketplaceClient.getMarketplaceClientService();
+		IMarketplaceClientConfiguration config = marketplaceClientService.newConfiguration();
+		marketplaceClientService.openFavorites(config);
+		return null;
+	}
+
+}
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/commands/ShowInstalledSolutionsCommand.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/commands/ShowInstalledSolutionsCommand.java
new file mode 100644
index 0000000..ff9aa29
--- /dev/null
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/commands/ShowInstalledSolutionsCommand.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2010 The Eclipse Foundation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     The Eclipse Foundation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.epp.internal.mpc.ui.commands;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.epp.mpc.ui.IMarketplaceClientConfiguration;
+import org.eclipse.epp.mpc.ui.IMarketplaceClientService;
+import org.eclipse.epp.mpc.ui.MarketplaceClient;
+
+public class ShowInstalledSolutionsCommand extends AbstractHandler {
+
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IMarketplaceClientService marketplaceClientService = MarketplaceClient.getMarketplaceClientService();
+		IMarketplaceClientConfiguration config = marketplaceClientService.newConfiguration();
+		marketplaceClientService.openInstalled(config);
+		return null;
+	}
+
+}
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/AbstractMarketplaceDiscoveryItem.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/AbstractMarketplaceDiscoveryItem.java
index 70c3a3b..aaea77b 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/AbstractMarketplaceDiscoveryItem.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/AbstractMarketplaceDiscoveryItem.java
@@ -12,6 +12,8 @@
 
 package org.eclipse.epp.internal.mpc.ui.wizards;
 
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -33,8 +35,10 @@
 import org.eclipse.equinox.internal.p2.ui.discovery.wizards.AbstractDiscoveryItem;
 import org.eclipse.equinox.internal.p2.ui.discovery.wizards.CatalogViewer;
 import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
 import org.eclipse.jface.layout.GridDataFactory;
 import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.layout.PixelConverter;
 import org.eclipse.jface.window.ToolTip;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.swt.SWT;
@@ -54,6 +58,7 @@
 import org.eclipse.swt.graphics.Rectangle;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Display;
@@ -91,6 +96,8 @@
 
 	protected static final int SEPARATOR_MARGIN_TOP = 8;
 
+	protected static final int BUTTONBAR_MARGIN_TOP = 8;
+
 	protected static final int MAX_IMAGE_HEIGHT = 86;
 
 	protected static final int MIN_IMAGE_HEIGHT = 64;
@@ -143,6 +150,10 @@
 
 	private static Boolean browserAvailable;
 
+	private final PropertyChangeListener propertyChangeListener;
+
+	private PixelConverter pixelConverter;
+
 	public AbstractMarketplaceDiscoveryItem(Composite parent, int style, MarketplaceDiscoveryResources resources,
 			IMarketplaceWebBrowser browser, final T connector, CatalogViewer viewer) {
 		super(parent, style, resources, connector);
@@ -156,6 +167,29 @@
 				e.result = getNameLabelText();
 			}
 		});
+		propertyChangeListener = new PropertyChangeListener() {
+			public void propertyChange(PropertyChangeEvent evt) {
+				if (!isDisposed()) {
+					getDisplay().asyncExec(new Runnable() {
+						public void run() {
+							if (!isDisposed()) {
+								refresh(true);
+							}
+						}
+					});
+				}
+			}
+		};
+		connector.addPropertyChangeListener(propertyChangeListener);
+		this.addDisposeListener(new DisposeListener() {
+			public void widgetDisposed(DisposeEvent e) {
+				connector.removePropertyChangeListener(propertyChangeListener);
+			}
+		});
+	}
+
+	protected PixelConverter getPixelConverter() {
+		return pixelConverter;
 	}
 
 	protected void createContent() {
@@ -168,6 +202,7 @@
 	}
 
 	protected void createContent(Composite parent) {
+		pixelConverter = new PixelConverter(parent);
 		GridLayoutFactory.swtDefaults()
 		.numColumns(4)
 		.equalWidth(false)
@@ -209,6 +244,14 @@
 		.minSize(MAX_IMAGE_WIDTH, MIN_IMAGE_HEIGHT)
 		.span(1, alignIconWithName() ? 4 : 3)
 		.applyTo(checkboxContainer);
+		GridLayoutFactory.fillDefaults()
+		.margins(0, 0)
+		.numColumns(1)
+		.equalWidth(false)
+		.spacing(pixelConverter.convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING),
+				pixelConverter.convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING))
+		.applyTo(checkboxContainer);
+
 	}
 
 	protected void createSeparator(Composite parent) {
@@ -234,7 +277,7 @@
 		.span(3, 1)
 		.hint(100, SWT.DEFAULT)
 		.applyTo(description);
-		String descriptionText = connector.getDescription();
+		String descriptionText = getDescriptionText();
 		int maxDescriptionLength = 162;
 		if (descriptionText == null) {
 			descriptionText = ""; //$NON-NLS-1$
@@ -281,6 +324,10 @@
 		createInfoLink(description);
 	}
 
+	protected String getDescriptionText() {
+		return connector.getDescription();
+	}
+
 	protected void createNameLabel(Composite parent) {
 		nameLabel = new Label(parent, SWT.WRAP);
 		setWidgetId(nameLabel, WIDGET_ID_NAME);
@@ -309,6 +356,13 @@
 
 	protected abstract void createSocialButtons(Composite parent);
 
+	protected Label createButtonBarSpacer(Composite parent) {
+		Label spacer = new Label(parent, SWT.NONE);
+		spacer.setText(" ");//$NON-NLS-1$
+		GridDataFactory.fillDefaults().indent(0, BUTTONBAR_MARGIN_TOP).align(SWT.CENTER, SWT.FILL).applyTo(spacer);
+		return spacer;
+	}
+
 	private INode getCatalogItemNode() {
 		Object data = connector.getData();
 		if (data instanceof INode) {
@@ -344,15 +398,13 @@
 	}
 
 	protected void createIconControl(Composite checkboxContainer) {
-		GridLayoutFactory.fillDefaults().margins(0, 0).applyTo(checkboxContainer);
-
 		iconLabel = new Label(checkboxContainer, SWT.NONE);
 		setWidgetId(iconLabel, WIDGET_ID_ICON);
 		GridDataFactory.swtDefaults()
 		.align(SWT.CENTER, SWT.BEGINNING).grab(true, true)
 		.applyTo(iconLabel);
-		if (connector.getIcon() != null) {
-			provideIconImage(iconLabel, connector.getSource(), connector.getIcon(), 64, true);
+		if (getIcon() != null) {
+			provideIconImage(iconLabel, connector.getSource(), getIcon(), 64, true);
 		} else {
 			iconLabel.setImage(MarketplaceClientUiPlugin.getInstance()
 					.getImageRegistry()
@@ -360,6 +412,10 @@
 		}
 	}
 
+	protected Icon getIcon() {
+		return connector.getIcon();
+	}
+
 	private void provideIconImage(final Label iconLabel, AbstractCatalogSource source, Icon icon, int size,
 			boolean fallback) {
 		if (iconLabel == null) {
@@ -611,6 +667,10 @@
 
 	@Override
 	protected void refresh() {
+		refresh(true);
+	}
+
+	protected void refresh(boolean updateState) {
 		Color foreground = getForeground();
 
 		nameLabel.setForeground(foreground);
@@ -618,6 +678,13 @@
 		if (installInfoLink != null) {
 			installInfoLink.setForeground(foreground);
 		}
+		if (updateState) {
+			refreshState();
+		}
+	}
+
+	protected void refreshState() {
+		// ignore
 	}
 
 	private void hookRecursively(Control control, Listener listener) {
@@ -720,4 +787,19 @@
 	protected CatalogViewer getViewer() {
 		return viewer;
 	}
+
+	static GridDataFactory createButtonLayoutData(Button button, PixelConverter pixelConverter) {
+		GridDataFactory dataFactory = GridDataFactory.defaultsFor(button).align(SWT.END, SWT.CENTER).grab(true, true);
+		int minWidth = pixelConverter.convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
+		int maxWidth = button.getDisplay().getBounds().width / 5;
+		Point preferredSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
+
+		int widthHint = Math.max(minWidth, preferredSize.x);
+		widthHint = Math.min(widthHint, maxWidth);
+		minWidth = Math.min(preferredSize.x, maxWidth);
+
+		dataFactory.hint(widthHint, SWT.DEFAULT);
+		dataFactory.minSize(minWidth, SWT.DEFAULT);
+		return dataFactory;
+	}
 }
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/AbstractMarketplaceWizardDialog.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/AbstractMarketplaceWizardDialog.java
index 08ef650..f57404b 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/AbstractMarketplaceWizardDialog.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/AbstractMarketplaceWizardDialog.java
@@ -10,7 +10,9 @@
  *******************************************************************************/
 package org.eclipse.epp.internal.mpc.ui.wizards;
 
+import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUiPlugin;
 import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IDialogSettings;
 import org.eclipse.jface.dialogs.IPageChangedListener;
 import org.eclipse.jface.dialogs.IPageChangingListener;
 import org.eclipse.jface.dialogs.PageChangedEvent;
@@ -226,4 +228,54 @@
 		return IDialogConstants.CANCEL_LABEL;
 	}
 
+	@Override
+	protected IDialogSettings getDialogBoundsSettings() {
+		Class<? extends AbstractMarketplaceWizardDialog> dialogClass = getClass();
+		return getDialogBoundsSettings(dialogClass, getParentShell() != null, true);
+	}
+
+	protected static IDialogSettings getDialogBoundsSettings(
+			Class<? extends AbstractMarketplaceWizardDialog> dialogClass, boolean relative, boolean create) {
+		String sectionName = dialogClass.getName() + "_dialogBounds." + (relative ? "relative" : "absolute"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+		IDialogSettings settings = MarketplaceClientUiPlugin.getInstance().getDialogSettings();
+		IDialogSettings section = settings.getSection(sectionName);
+		if (section == null && create) {
+			section = settings.addNewSection(sectionName);
+			IDialogSettings companionSettings = getDialogBoundsSettings(dialogClass, !relative, false);
+			if (companionSettings != null) {
+				copyInitialSize(companionSettings, settings);
+			}
+		}
+		return section;
+	}
+
+	@Override
+	protected int getDialogBoundsStrategy() {
+		return DIALOG_PERSISTLOCATION | DIALOG_PERSISTSIZE;
+	}
+
+	static void copyInitialSize(IDialogSettings sourceSettings, IDialogSettings targetSettings) {
+		copySettings(sourceSettings, targetSettings, "DIALOG_WIDTH"); //$NON-NLS-1$
+		copySettings(sourceSettings, targetSettings, "DIALOG_HEIGHT"); //$NON-NLS-1$
+		copySettings(sourceSettings, targetSettings, "DIALOG_FONT_NAME"); //$NON-NLS-1$
+	}
+
+	static void copyInitialLocation(IDialogSettings sourceSettings, IDialogSettings targetSettings) {
+		copySettings(sourceSettings, targetSettings, "DIALOG_X_ORIGIN"); //$NON-NLS-1$
+		copySettings(sourceSettings, targetSettings, "DIALOG_Y_ORIGIN"); //$NON-NLS-1$
+	}
+
+	static void setInitialLocation(int x, int y, IDialogSettings targetSettings) {
+		targetSettings.put("DIALOG_X_ORIGIN", x); //$NON-NLS-1$
+		targetSettings.put("DIALOG_Y_ORIGIN", y); //$NON-NLS-1$
+	}
+
+	static void copySettings(IDialogSettings sourceSettings, IDialogSettings targetSettings, String key) {
+		String value = sourceSettings.get(key);
+		if (value != null) {
+			targetSettings.put(key, value);
+		}
+	}
+
 }
\ No newline at end of file
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/AbstractUserActionItem.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/AbstractUserActionItem.java
new file mode 100644
index 0000000..e808536
--- /dev/null
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/AbstractUserActionItem.java
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * Copyright (c) 2010 The Eclipse Foundation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     The Eclipse Foundation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.epp.internal.mpc.ui.wizards;
+
+import org.eclipse.epp.internal.mpc.ui.catalog.UserActionCatalogItem;
+import org.eclipse.equinox.internal.p2.discovery.model.Icon;
+import org.eclipse.equinox.internal.p2.ui.discovery.wizards.CatalogViewer;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyleRange;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+public abstract class AbstractUserActionItem extends AbstractMarketplaceDiscoveryItem<UserActionCatalogItem> {
+
+	public AbstractUserActionItem(Composite parent, MarketplaceDiscoveryResources resources,
+			UserActionCatalogItem connector, CatalogViewer viewer) {
+		super(parent, SWT.NONE, resources, null, connector, viewer);
+		//TODO we need a better color definition for this...
+		//see https://bugs.eclipse.org/bugs/show_bug.cgi?id=516804
+		setBackground(viewer.getControl().getDisplay().getSystemColor(SWT.COLOR_TITLE_BACKGROUND_GRADIENT));
+	}
+
+	protected void createButtons(Composite parent) {
+		// ignore
+	}
+
+	@Override
+	protected abstract Icon getIcon();
+
+	@Override
+	protected abstract String getDescriptionText();
+
+	@Override
+	protected abstract String getNameLabelText();
+
+	protected String getSublineText() {
+		return null;
+	}
+
+	@Override
+	protected void createTagsLabel(Composite parent) {
+		// we'll abuse this to create a 2-row container for action buttons that shows up
+		// below the description and to the right of the icon, instead of creating an extra
+		// row below
+		createButtonBar(parent);
+	}
+
+	protected void createButtonBar(Composite parent) {
+		createButtonBar(parent, getSublineText() == null ? 2 : 1);
+	}
+
+	@Override
+	protected void createProviderLabel(Composite parent) {
+		createSublineLabel(parent);
+	}
+
+	protected StyledText createSublineLabel(Composite parent) {
+		String sublineText = getSublineText();
+		if (sublineText == null) {
+			return null;
+		}
+
+		StyledText subline = StyledTextHelper.createStyledTextLabel(parent);
+
+		subline.setEditable(false);
+		GridDataFactory.fillDefaults()
+		.indent(DESCRIPTION_MARGIN_LEFT, DESCRIPTION_MARGIN_TOP)
+		.span(3, 1)
+		.align(SWT.BEGINNING, SWT.CENTER)
+		.grab(true, false)
+		.applyTo(subline);
+		// always disabled color to make it less prominent
+		subline.setForeground(resources.getColorDisabled());
+		subline.setText(sublineText);
+		StyleRange range = new StyleRange(0, subline.getText().length(), subline.getForeground(), null, SWT.ITALIC);
+		subline.setStyleRange(range);
+		return subline;
+	}
+
+	protected void createButtonBar(Composite parent, int vSpan) {
+		Label spacer = createButtonBarSpacer(parent);
+		GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).grab(true, true).span(1, vSpan).applyTo(spacer);
+
+		Composite buttonContainer = new Composite(parent, SWT.NONE);
+		buttonContainer.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_RED));
+		GridDataFactory.swtDefaults()
+		.indent(0, BUTTONBAR_MARGIN_TOP)
+		.align(SWT.END, SWT.END)
+		.grab(false, false)
+		.span(2, vSpan)
+		.applyTo(buttonContainer);
+		GridLayoutFactory.fillDefaults().numColumns(0).equalWidth(true).applyTo(buttonContainer);
+
+		createButtons(buttonContainer);
+	}
+
+	protected Button createButton(Composite parent, String text, String tooltipText, int id) {
+		((GridLayout) parent.getLayout()).numColumns++;
+		Button button = new Button(parent, SWT.PUSH | SWT.BOLD);
+		button.setText(text);
+		if (tooltipText != null) {
+			button.setToolTipText(tooltipText);
+		}
+		button.setFont(JFaceResources.getFontRegistry().getBold("")); //$NON-NLS-1$
+		button.setData(Integer.valueOf(id));
+		createButtonLayoutData(button, getPixelConverter()).align(SWT.END, SWT.END)
+		.grab(false, false)
+		.applyTo(button);
+
+		button.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				buttonPressed(((Integer) e.widget.getData()).intValue());
+			}
+		});
+		return button;
+	}
+
+	protected void buttonPressed(int id) {
+
+	}
+
+	@Override
+	protected void createInstallButtons(Composite parent) {
+		// ignore
+	}
+
+	@Override
+	protected void createInstallInfo(Composite parent) {
+		// ignore
+	}
+
+	@Override
+	protected void createSocialButtons(Composite parent) {
+		// ignore
+	}
+
+	@Override
+	protected void searchForProvider(String searchTerm) {
+		// ignore
+	}
+
+	@Override
+	protected void searchForTag(String tag) {
+		// ignore
+	}
+
+	@Override
+	protected void createSeparator(Composite parent) {
+		// ignore
+	}
+
+}
\ No newline at end of file
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/BrowseCatalogItem.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/BrowseCatalogItem.java
index be2fb12..e2d45e9 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/BrowseCatalogItem.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/BrowseCatalogItem.java
@@ -12,6 +12,7 @@
 package org.eclipse.epp.internal.mpc.ui.wizards;
 
 import java.net.MalformedURLException;
+import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 
@@ -75,31 +76,15 @@
 	}
 
 	protected void openMarketplace() {
-		CatalogDescriptor catalogDescriptor = getData();
+		openMarketplace(getData(), getViewer(), browser);
+	}
+
+	protected static void openMarketplace(CatalogDescriptor catalogDescriptor, MarketplaceViewer viewer,
+			IMarketplaceWebBrowser browser) {
 
 		try {
-			URL url = catalogDescriptor.getUrl();
-			try {
-				ContentType contentType = getViewer().getQueryContentType();
-				if (contentType == ContentType.SEARCH) {
-					String queryText = getViewer().getQueryText();
-					ICategory queryCategory = getViewer().getQueryCategory();
-					IMarket queryMarket = getViewer().getQueryMarket();
-					String path = new DefaultMarketplaceService(url).computeRelativeSearchUrl(queryMarket,
-							queryCategory, queryText, false);
-					if (path != null) {
-						url = new URL(url, path);
-					}
-				}
-			} catch (IllegalArgumentException e) {
-				// should never happen
-				MarketplaceClientUi.error(e);
-			} catch (MalformedURLException e) {
-				// should never happen
-				MarketplaceClientUi.error(e);
-			}
-
-			browser.openUrl(url.toURI().toString());
+			String url = getMarketplaceUrl(catalogDescriptor, viewer);
+			browser.openUrl(url);
 		} catch (URISyntaxException e) {
 			String message = String.format(Messages.BrowseCatalogItem_cannotOpenBrowser);
 			IStatus status = new Status(IStatus.ERROR, MarketplaceClientUi.BUNDLE_ID, IStatus.ERROR, message, e);
@@ -107,6 +92,33 @@
 		}
 	}
 
+	private static String getMarketplaceUrl(CatalogDescriptor catalogDescriptor, MarketplaceViewer viewer)
+			throws URISyntaxException {
+		URL url = catalogDescriptor.getUrl();
+		try {
+			ContentType contentType = viewer.getQueryContentType();
+			if (contentType == ContentType.SEARCH) {
+				String queryText = viewer.getQueryText();
+				ICategory queryCategory = viewer.getQueryCategory();
+				IMarket queryMarket = viewer.getQueryMarket();
+				String path = new DefaultMarketplaceService(url).computeRelativeSearchUrl(queryMarket, queryCategory,
+						queryText, false);
+				if (path != null) {
+					url = new URL(url, path);
+				}
+			}
+		} catch (IllegalArgumentException e) {
+			// should never happen
+			MarketplaceClientUi.error(e);
+		} catch (MalformedURLException e) {
+			// should never happen
+			MarketplaceClientUi.error(e);
+		}
+
+		URI uri = url.toURI();
+		return uri.toString();
+	}
+
 	@Override
 	protected MarketplaceViewer getViewer() {
 		return (MarketplaceViewer) super.getViewer();
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/DiscoveryItem.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/DiscoveryItem.java
index bc30970..a30220f 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/DiscoveryItem.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/DiscoveryItem.java
@@ -12,8 +12,6 @@
 
 package org.eclipse.epp.internal.mpc.ui.wizards;
 
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
 import java.lang.reflect.InvocationTargetException;
 import java.text.MessageFormat;
 import java.util.concurrent.Callable;
@@ -46,8 +44,6 @@
 import org.eclipse.swt.custom.BusyIndicator;
 import org.eclipse.swt.custom.StyleRange;
 import org.eclipse.swt.custom.StyledText;
-import org.eclipse.swt.events.DisposeEvent;
-import org.eclipse.swt.events.DisposeListener;
 import org.eclipse.swt.events.SelectionAdapter;
 import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.events.SelectionListener;
@@ -66,13 +62,10 @@
  * @author David Green
  * @author Carsten Reckord
  */
-public class DiscoveryItem<T extends CatalogItem> extends AbstractMarketplaceDiscoveryItem<T>
-implements PropertyChangeListener {
+public class DiscoveryItem<T extends CatalogItem> extends AbstractMarketplaceDiscoveryItem<T> {
 
 	private static final String FAVORITED_BUTTON_STATE_DATA = "favorited"; //$NON-NLS-1$
 
-	private static final int BUTTONBAR_MARGIN_TOP = 8;
-
 	public static final String WIDGET_ID_INSTALLS = "installs"; //$NON-NLS-1$
 
 	public static final String WIDGET_ID_TAGS = "tags"; //$NON-NLS-1$
@@ -103,12 +96,6 @@
 			IMarketplaceWebBrowser browser,
 			final T connector, MarketplaceViewer viewer) {
 		super(parent, style, resources, browser, connector, viewer);
-		connector.addPropertyChangeListener(this);
-		this.addDisposeListener(new DisposeListener() {
-			public void widgetDisposed(DisposeEvent e) {
-				connector.removePropertyChangeListener(DiscoveryItem.this);
-			}
-		});
 	}
 
 	@Override
@@ -245,10 +232,7 @@
 	protected void createSocialButtons(Composite parent) {
 		Integer favorited = getFavoriteCount();
 		if (favorited == null || getCatalogItemUrl() == null) {
-			Label spacer = new Label(this, SWT.NONE);
-			spacer.setText(" ");//$NON-NLS-1$
-
-			GridDataFactory.fillDefaults().indent(0, BUTTONBAR_MARGIN_TOP).align(SWT.CENTER, SWT.FILL).applyTo(spacer);
+			createButtonBarSpacer(parent);
 
 		} else {
 			createFavoriteButton(parent);
@@ -262,9 +246,7 @@
 			.align(SWT.BEGINNING, SWT.FILL)
 			.applyTo(shareControl);
 		} else {
-			Label spacer = new Label(this, SWT.NONE);
-			spacer.setText(" ");//$NON-NLS-1$
-			GridDataFactory.fillDefaults().indent(0, BUTTONBAR_MARGIN_TOP).align(SWT.CENTER, SWT.FILL).applyTo(spacer);
+			createButtonBarSpacer(parent);
 		}
 	}
 
@@ -489,29 +471,17 @@
 		return getViewer().getSelectionModel().getSelectedOperation(getData());
 	}
 
-	public void propertyChange(PropertyChangeEvent evt) {
-		if (!isDisposed()) {
-			getDisplay().asyncExec(new Runnable() {
-				public void run() {
-					if (!isDisposed()) {
-						refresh(true);
-					}
-				}
-			});
-		}
+	@Override
+	protected void refresh(boolean updateState) {
+		super.refresh(updateState);
+		refreshFavoriteButton();
 	}
 
 	@Override
-	protected void refresh() {
-		refresh(true);
-	}
-
-	protected void refresh(boolean updateState) {
-		super.refresh();
-		if (updateState && buttonController != null) {
+	protected void refreshState() {
+		if (buttonController != null) {
 			buttonController.refresh();
 		}
-		refreshFavoriteButton();
 	}
 
 	@Override
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/FavoritesDiscoveryItem.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/FavoritesDiscoveryItem.java
index a2e9a38..858dbf7 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/FavoritesDiscoveryItem.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/FavoritesDiscoveryItem.java
@@ -10,13 +10,17 @@
  *******************************************************************************/
 package org.eclipse.epp.internal.mpc.ui.wizards;
 
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
 import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceNodeCatalogItem;
 import org.eclipse.jface.layout.GridDataFactory;
-import org.eclipse.jface.layout.GridLayoutFactory;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
 import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
 
@@ -25,8 +29,8 @@
 	private Button checkbox;
 
 	public FavoritesDiscoveryItem(Composite parent, int style, MarketplaceDiscoveryResources resources,
-			IMarketplaceWebBrowser browser, MarketplaceNodeCatalogItem connector, FavoritesViewer viewer) {
-		super(parent, style, resources, browser, connector, viewer);
+			MarketplaceNodeCatalogItem connector, FavoritesViewer viewer) {
+		super(parent, style, resources, null, connector, viewer);
 	}
 
 	@Override
@@ -47,6 +51,7 @@
 
 	@Override
 	protected void createIconControl(Composite checkboxContainer) {
+		((GridLayout) checkboxContainer.getLayout()).numColumns++;
 		checkbox = new Button(checkboxContainer, SWT.CHECK | SWT.INHERIT_FORCE);
 		checkbox.setSelection(connector.isSelected());
 		checkbox.setText(""); //$NON-NLS-1$
@@ -62,16 +67,44 @@
 				widgetSelected(e);
 			}
 		});
+		connector.addPropertyChangeListener(new PropertyChangeListener() {
+
+			public void propertyChange(PropertyChangeEvent evt) {
+				if ("selected".equals(evt.getPropertyName())) { //$NON-NLS-1$
+					final Button checkbox = FavoritesDiscoveryItem.this.checkbox;
+
+					if (checkbox == null || checkbox.isDisposed()) {
+						return;
+					}
+					final boolean selected = Boolean.TRUE.equals(evt.getNewValue());
+					try {
+						checkbox.getDisplay().syncExec(new Runnable() {
+
+							public void run() {
+								if (checkbox == null || checkbox.isDisposed()) {
+									return;
+								}
+								checkbox.setSelection(selected);
+							}
+
+						});
+					} catch (SWTException ex) {
+						//disposed - ignore
+					}
+				}
+			}
+		});
 		GridDataFactory.swtDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(checkbox);
 		super.createIconControl(checkboxContainer);
 
-		GridLayoutFactory.fillDefaults().spacing(1, 1).margins(0, 0).numColumns(2).applyTo(checkboxContainer);
+		GridLayout containerLayout = ((GridLayout) checkboxContainer.getLayout());
 		GridData containerLayoutData = (GridData) checkboxContainer.getLayoutData();
-		int xHint = containerLayoutData.widthHint + checkbox.computeSize(SWT.DEFAULT, SWT.DEFAULT).x;
+		int xHint = containerLayoutData.widthHint + checkbox.computeSize(SWT.DEFAULT, SWT.DEFAULT).x
+				+ containerLayout.horizontalSpacing;
 		GridDataFactory.createFrom(containerLayoutData)
-				.hint(xHint, containerLayoutData.heightHint)
-				.minSize(xHint, containerLayoutData.minimumHeight)
-				.applyTo(checkboxContainer);
+		.hint(xHint, containerLayoutData.heightHint)
+		.minSize(xHint, containerLayoutData.minimumHeight)
+		.applyTo(checkboxContainer);
 	}
 
 	@Override
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/FavoritesViewer.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/FavoritesViewer.java
index 3fdade4..70b4cd0 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/FavoritesViewer.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/FavoritesViewer.java
@@ -10,7 +10,9 @@
  *******************************************************************************/
 package org.eclipse.epp.internal.mpc.ui.wizards;
 
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
@@ -23,12 +25,26 @@
 import org.eclipse.equinox.internal.p2.ui.discovery.util.ControlListItem;
 import org.eclipse.equinox.internal.p2.ui.discovery.wizards.CatalogConfiguration;
 import org.eclipse.equinox.internal.p2.ui.discovery.wizards.CatalogViewer;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.layout.PixelConverter;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.jface.viewers.StructuredViewer;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.DisposeEvent;
 import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.events.VerifyEvent;
 import org.eclipse.swt.events.VerifyListener;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Label;
@@ -37,28 +53,174 @@
 
 public class FavoritesViewer extends CatalogViewer {
 
-	private static final String HTTPS_PREFIX = "https://"; //$NON-NLS-1$
-
-	private static final String HTTP_PREFIX = "http://"; //$NON-NLS-1$
-
-	private static final int MIN_URL_LENGTH = HTTP_PREFIX.length() + 5;
-
 	private MarketplaceDiscoveryResources discoveryResources;
 
-	private final IMarketplaceWebBrowser browser;
+	private Button installSelectedCheckbox;
 
-	private final ImportFavoritesPage importFavoritesPage;
+	private PixelConverter pixelConverter;
 
-	public FavoritesViewer(Catalog catalog, ImportFavoritesPage page, IMarketplaceWebBrowser browser,
-			CatalogConfiguration configuration) {
+	private boolean installSelected;
+
+	private Button selectAllButton;
+
+	private Button deselectAllButton;
+
+	public FavoritesViewer(Catalog catalog, ImportFavoritesPage page, CatalogConfiguration configuration) {
 		super(catalog, page, page.getWizard().getContainer(), configuration);
-		this.importFavoritesPage = page;
-		this.browser = browser;
 		setAutomaticFind(false);
 		setRefreshJobDelay(50L);
 	}
 
 	@Override
+	public void setFilterText(String newFilter) {
+		super.setFilterText(newFilter);
+	}
+
+	@Override
+	public void createControl(Composite parent) {
+		super.createControl(parent);
+		createViewerButtonBar((Composite) getControl());
+	}
+
+	protected void createViewerButtonBar(Composite parent) {
+		Composite buttonBar = new Composite(parent, SWT.NONE);
+		buttonBar.setFont(parent.getFont());
+
+		pixelConverter = new PixelConverter(parent);
+		GridLayoutFactory layoutFactory = GridLayoutFactory.swtDefaults()
+				.numColumns(2)
+				.equalWidth(false)
+				.margins(pixelConverter.convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN), 0)
+				.spacing(pixelConverter.convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING), 0);
+		layoutFactory.applyTo(buttonBar);
+		GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false).applyTo(buttonBar);
+		createInstallCheckbox(buttonBar);
+
+		Composite buttonContainer = new Composite(buttonBar, SWT.NONE);
+		buttonContainer.setFont(parent.getFont());
+		layoutFactory.margins(0, 0).equalWidth(true).numColumns(0).applyTo(buttonContainer);
+		GridDataFactory.swtDefaults().align(SWT.END, SWT.FILL).grab(true, false).applyTo(buttonContainer);
+		createButtonsForViewerButtonBar(buttonContainer);
+
+		updateButtonState(getSelection());
+	}
+
+	private void createButtonsForViewerButtonBar(Composite buttonContainer) {
+		selectAllButton = createButton(buttonContainer, IDialogConstants.SELECT_ALL_ID, Messages.FavoritesViewer_SelectAll);
+		deselectAllButton = createButton(buttonContainer, IDialogConstants.DESELECT_ALL_ID, Messages.FavoritesViewer_DeselectAll);
+		addSelectionChangedListener(new ISelectionChangedListener() {
+
+			public void selectionChanged(SelectionChangedEvent event) {
+				IStructuredSelection selection = event.getStructuredSelection();
+				updateButtonState(selection);
+			}
+		});
+	}
+
+	private void updateButtonState(IStructuredSelection selection) {
+		List<MarketplaceNodeCatalogItem> items = filterSelectableItems(getCatalog().getItems().iterator());
+		List<MarketplaceNodeCatalogItem> selectedItems = filterSelectableItems(
+				selection == null ? null : selection.iterator());
+		installSelectedCheckbox.setEnabled(!items.isEmpty());
+		if (items.isEmpty()) {
+			selectAllButton.setEnabled(false);
+			deselectAllButton.setEnabled(false);
+		} else if (selectedItems.isEmpty()) {
+			selectAllButton.setEnabled(true);
+			deselectAllButton.setEnabled(false);
+		} else {
+			deselectAllButton.setEnabled(true);
+			if (selectedItems.size() == items.size()) {
+				selectAllButton.setEnabled(false);
+			} else {
+				selectAllButton.setEnabled(true);
+			}
+		}
+	}
+
+	private static List<MarketplaceNodeCatalogItem> filterSelectableItems(Iterator<?> items) {
+		if (items == null || !items.hasNext()) {
+			return Collections.emptyList();
+		}
+		ArrayList<MarketplaceNodeCatalogItem> selectableItems = null;
+		while (items.hasNext()) {
+			Object element = items.next();
+			if (element instanceof MarketplaceNodeCatalogItem) {
+				if (selectableItems == null) {
+					selectableItems = new ArrayList<MarketplaceNodeCatalogItem>();
+				}
+				selectableItems.add((MarketplaceNodeCatalogItem) element);
+			}
+		}
+		return selectableItems == null ? Collections.<MarketplaceNodeCatalogItem> emptyList() : selectableItems;
+	}
+
+	protected Button createButton(Composite parent, int id, String label) {
+		// increment the number of columns in the button bar
+		((GridLayout) parent.getLayout()).numColumns++;
+		Button button = new Button(parent, SWT.PUSH);
+		button.setText(label);
+		button.setFont(JFaceResources.getDialogFont());
+		button.setData(Integer.valueOf(id));
+		button.addSelectionListener(new SelectionListener() {
+
+			public void widgetSelected(SelectionEvent e) {
+				buttonPressed(((Integer) e.widget.getData()).intValue());
+			}
+
+			public void widgetDefaultSelected(SelectionEvent e) {
+				// ignore
+
+			}
+		});
+		setButtonLayoutData(button);
+		return button;
+	}
+
+	private void setButtonLayoutData(Button button) {
+		AbstractMarketplaceDiscoveryItem.createButtonLayoutData(button, pixelConverter).applyTo(button);
+	}
+
+	protected void buttonPressed(int id) {
+		if (id == IDialogConstants.SELECT_ALL_ID) {
+			selectAll();
+		} else if (id == IDialogConstants.DESELECT_ALL_ID) {
+			deselectAll();
+		}
+	}
+
+	private void deselectAll() {
+		setSelection(StructuredSelection.EMPTY);
+	}
+
+	private void selectAll() {
+		StructuredSelection all = new StructuredSelection(getCatalog().getItems());
+		setSelection(all);
+	}
+
+	protected void createInstallCheckbox(Composite buttonContainer) {
+		installSelectedCheckbox = new Button(buttonContainer, SWT.CHECK);
+		installSelectedCheckbox.setText(Messages.FavoritesViewer_SelectForInstallation);
+		installSelectedCheckbox.setToolTipText(
+				Messages.FavoritesViewer_SelectForInstallationTooltip);
+		GridDataFactory.defaultsFor(installSelectedCheckbox).applyTo(installSelectedCheckbox);
+
+		installSelectedCheckbox.setSelection(this.installSelected);
+		installSelectedCheckbox.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				installSelected = ((Button) e.widget).getSelection();
+			}
+		});
+	}
+
+	private void updateInstallSelectedCheckbox() {
+		if (installSelectedCheckbox != null && !installSelectedCheckbox.isDisposed()) {
+			installSelectedCheckbox.setSelection(this.installSelected);
+		}
+	}
+
+	@Override
 	protected StructuredViewer doCreateViewer(Composite container) {
 		StructuredViewer viewer = super.doCreateViewer(container);
 		discoveryResources = new MarketplaceDiscoveryResources(container.getDisplay());
@@ -123,6 +285,7 @@
 			modifySelection(catalogItem, false);
 		}
 		super.updateCatalog();
+		updateButtonState(getSelection());
 	}
 
 	@Override
@@ -143,7 +306,7 @@
 	}
 
 	private FavoritesDiscoveryItem createDiscoveryItem(Composite parent, MarketplaceNodeCatalogItem catalogItem) {
-		return new FavoritesDiscoveryItem(parent, SWT.NONE, getResources(), browser, catalogItem, this);
+		return new FavoritesDiscoveryItem(parent, SWT.NONE, getResources(), catalogItem, this);
 	}
 
 	@Override
@@ -180,4 +343,13 @@
 			modifySelection(catalogItem, catalogItem.isSelected());
 		}
 	}
+
+	public void setInstallSelected(boolean install) {
+		this.installSelected = install;
+		updateInstallSelectedCheckbox();
+	}
+
+	public boolean isInstallSelected() {
+		return installSelected;
+	}
 }
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ImportFavoritesActionLink.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ImportFavoritesActionLink.java
index b6d863f..0c3ada9 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ImportFavoritesActionLink.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ImportFavoritesActionLink.java
@@ -11,12 +11,14 @@
 package org.eclipse.epp.internal.mpc.ui.wizards;
 
 import java.util.List;
+import java.util.Map;
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.epp.internal.mpc.ui.catalog.FavoritesCatalog;
 import org.eclipse.epp.internal.mpc.ui.catalog.FavoritesDiscoveryStrategy;
 import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceDiscoveryStrategy;
 import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceViewer.ContentType;
+import org.eclipse.epp.mpc.ui.Operation;
 import org.eclipse.equinox.internal.p2.discovery.AbstractDiscoveryStrategy;
 import org.eclipse.jface.window.Window;
 
@@ -34,19 +36,19 @@
 
 	@Override
 	public void selected() {
-		importFavorites();
+		importFavorites(marketplacePage.getWizard());
 	}
 
-	protected void importFavorites() {
-		MarketplaceDiscoveryStrategy marketplaceStrategy = findMarketplaceDiscoveryStrategy();
+	protected static void importFavorites(MarketplaceWizard wizard) {
+		MarketplaceDiscoveryStrategy marketplaceStrategy = findMarketplaceDiscoveryStrategy(wizard);
 		if (marketplaceStrategy != null && marketplaceStrategy.hasUserFavoritesService()) {
-			importFavorites(marketplaceStrategy);
+			importFavorites(wizard, marketplaceStrategy);
 		}
 	}
 
-	protected MarketplaceDiscoveryStrategy findMarketplaceDiscoveryStrategy() {
+	protected static MarketplaceDiscoveryStrategy findMarketplaceDiscoveryStrategy(MarketplaceWizard wizard) {
 		MarketplaceDiscoveryStrategy marketplaceStrategy = null;
-		List<AbstractDiscoveryStrategy> discoveryStrategies = marketplacePage.getCatalog().getDiscoveryStrategies();
+		List<AbstractDiscoveryStrategy> discoveryStrategies = wizard.getCatalog().getDiscoveryStrategies();
 		for (AbstractDiscoveryStrategy strategy : discoveryStrategies) {
 			if (strategy instanceof MarketplaceDiscoveryStrategy) {
 				marketplaceStrategy = (MarketplaceDiscoveryStrategy) strategy;
@@ -56,8 +58,7 @@
 		return marketplaceStrategy;
 	}
 
-	protected void importFavorites(MarketplaceDiscoveryStrategy marketplaceStrategy) {
-		MarketplaceWizard wizard = marketplacePage.getWizard();
+	protected static void importFavorites(MarketplaceWizard wizard, MarketplaceDiscoveryStrategy marketplaceStrategy) {
 		FavoritesCatalog favoritesCatalog = new FavoritesCatalog();
 
 		ImportFavoritesWizard importFavoritesWizard = new ImportFavoritesWizard(favoritesCatalog,
@@ -69,12 +70,12 @@
 			protected void preDiscovery() {
 				discoveryError = null;
 			}
-			
+
 			@Override
 			protected void handleDiscoveryError(CoreException ex) throws CoreException {
-				discoveryError = importFavoritesPage.handleDiscoveryError(getFavoritesReference(), ex);
+				discoveryError = ImportFavoritesPage.handleDiscoveryError(getFavoritesReference(), ex);
 			}
-			
+
 			@Override
 			protected void postDiscovery() {
 				final String errorMessage = this.discoveryError;
@@ -82,11 +83,18 @@
 				importFavoritesPage.setDiscoveryError(errorMessage);
 			}
 		});
-		int result = new ImportFavoritesWizardDialog(wizard.getShell(), importFavoritesWizard).open();
+		ImportFavoritesWizardDialog importWizard = new ImportFavoritesWizardDialog(wizard.getShell(), importFavoritesWizard);
+
+		Map<String, Operation> oldOperations = wizard.getSelectionModel().getItemIdToSelectedOperation();
+		int result = importWizard.open();
 		if (result == Window.OK) {
 			MarketplacePage catalogPage = wizard.getCatalogPage();
 			catalogPage.setActiveTab(ContentType.FAVORITES);
 			catalogPage.reloadCatalog();
+			Map<String, Operation> newOperations = wizard.getSelectionModel().getItemIdToSelectedOperation();
+			if (!newOperations.equals(oldOperations)) {
+				wizard.updateSelection();
+			}
 		}
 	}
 
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ImportFavoritesPage.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ImportFavoritesPage.java
index c5216fd..9f3b45d 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ImportFavoritesPage.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ImportFavoritesPage.java
@@ -20,6 +20,7 @@
 import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore;
 import org.eclipse.epp.internal.mpc.core.service.AbstractDataStorageService.NotAuthorizedException;
 import org.eclipse.epp.internal.mpc.core.service.UserFavoritesService;
+import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUiPlugin;
 import org.eclipse.epp.internal.mpc.ui.catalog.FavoritesDiscoveryStrategy;
 import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCatalog;
 import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceNodeCatalogItem;
@@ -28,7 +29,7 @@
 import org.eclipse.equinox.internal.p2.discovery.AbstractDiscoveryStrategy;
 import org.eclipse.equinox.internal.p2.ui.discovery.wizards.CatalogPage;
 import org.eclipse.equinox.internal.p2.ui.discovery.wizards.CatalogViewer;
-import org.eclipse.equinox.internal.p2.ui.discovery.wizards.DiscoveryWizard;
+import org.eclipse.jface.dialogs.IDialogSettings;
 import org.eclipse.jface.operation.IRunnableWithProgress;
 import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.osgi.util.NLS;
@@ -38,12 +39,10 @@
 import org.eclipse.userstorage.util.ConflictException;
 
 public class ImportFavoritesPage extends CatalogPage {
+	private static final String INSTALL_SELECTED_SETTING = "installSelected"; //$NON-NLS-1$
 
-	private final IMarketplaceWebBrowser browser;
-
-	public ImportFavoritesPage(MarketplaceCatalog catalog, IMarketplaceWebBrowser browser) {
+	public ImportFavoritesPage(MarketplaceCatalog catalog) {
 		super(catalog);
-		this.browser = browser;
 		setTitle(Messages.ImportFavoritesPage_Title);
 		setDescription(Messages.ImportFavoritesPage_Description);
 	}
@@ -94,20 +93,51 @@
 	}
 
 	@Override
+	protected FavoritesViewer getViewer() {
+		return (FavoritesViewer) super.getViewer();
+	}
+
+	@Override
 	protected CatalogViewer doCreateViewer(Composite parent) {
-		DiscoveryWizard wizard = getWizard();
-		CatalogViewer viewer = new FavoritesViewer(getCatalog(), this, browser,
-				wizard.getConfiguration());
+		ImportFavoritesWizard wizard = getWizard();
+		FavoritesViewer viewer = new FavoritesViewer(getCatalog(), this, wizard.getConfiguration());
 		viewer.setMinimumHeight(MINIMUM_HEIGHT);
 		viewer.createControl(parent);
+		boolean installSelected = true;
+		IDialogSettings section = getDialogSettings(false);
+		if (section != null) {
+			installSelected = section.getBoolean(INSTALL_SELECTED_SETTING);
+		}
+		viewer.setInstallSelected(installSelected);
+
+		String initialFavoritesUrl = wizard.getInitialFavoritesUrl();
+		setFavoritesUrl(viewer, initialFavoritesUrl);
 		return viewer;
 	}
 
+	private IDialogSettings getDialogSettings(boolean create) {
+		IDialogSettings dialogSettings = MarketplaceClientUiPlugin.getInstance().getDialogSettings();
+		String sectionName = this.getClass().getName();
+		IDialogSettings section = dialogSettings.getSection(sectionName);
+		if (create && section == null) {
+			section = dialogSettings.addNewSection(sectionName);
+		}
+		return section;
+	}
+
+	public void setFavoritesUrl(String url) {
+		FavoritesViewer viewer = getViewer();
+		setFavoritesUrl(viewer, url);
+	}
+
+	private void setFavoritesUrl(FavoritesViewer viewer, String url) {
+		viewer.setFilterText(url == null ? "" : url.trim()); //$NON-NLS-1$
+	}
+
 	public void performImport() {
 		setErrorMessage(null);
-		IStructuredSelection selection = getViewer().getSelection();
-		@SuppressWarnings("unchecked")
-		List<MarketplaceNodeCatalogItem> importFavorites = selection.toList();
+		saveInstallSelected();
+		List<MarketplaceNodeCatalogItem> importFavorites = getSelection();
 		if (importFavorites.isEmpty()) {
 			return;
 		}
@@ -152,6 +182,13 @@
 		}
 	}
 
+	public List<MarketplaceNodeCatalogItem> getSelection() {
+		IStructuredSelection selection = getViewer().getSelection();
+		@SuppressWarnings("unchecked")
+		List<MarketplaceNodeCatalogItem> importFavorites = selection.toList();
+		return new ArrayList<MarketplaceNodeCatalogItem>(importFavorites);
+	}
+
 	private IUserFavoritesService findUserFavoritesService() {
 		IUserFavoritesService userFavoritesService = null;
 		for (AbstractDiscoveryStrategy strategy : getCatalog().getDiscoveryStrategies()) {
@@ -162,4 +199,28 @@
 		}
 		return userFavoritesService;
 	}
+
+	@Override
+	public ImportFavoritesWizard getWizard() {
+		return (ImportFavoritesWizard) super.getWizard();
+	}
+
+	@Override
+	public void dispose() {
+		saveInstallSelected();
+		super.dispose();
+	}
+
+	public boolean isInstallSelected() {
+		return getViewer().isInstallSelected();
+	}
+
+	private void saveInstallSelected() {
+		FavoritesViewer viewer = getViewer();
+		if (viewer != null) {
+			boolean installSelected = viewer.isInstallSelected();
+			IDialogSettings dialogSettings = getDialogSettings(true);
+			dialogSettings.put(INSTALL_SELECTED_SETTING, installSelected);
+		}
+	}
 }
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ImportFavoritesWizard.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ImportFavoritesWizard.java
index 9a68474..78f880c 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ImportFavoritesWizard.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ImportFavoritesWizard.java
@@ -10,17 +10,44 @@
  *******************************************************************************/
 package org.eclipse.epp.internal.mpc.ui.wizards;
 
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCatalog;
+import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceNodeCatalogItem;
+import org.eclipse.epp.mpc.ui.IMarketplaceClientConfiguration;
+import org.eclipse.epp.mpc.ui.IMarketplaceClientService;
+import org.eclipse.epp.mpc.ui.MarketplaceClient;
+import org.eclipse.epp.mpc.ui.Operation;
 import org.eclipse.equinox.internal.p2.ui.discovery.wizards.DiscoveryWizard;
+import org.eclipse.swt.widgets.Display;
 
 public class ImportFavoritesWizard extends DiscoveryWizard {
 
 	private final ImportFavoritesPage importFavoritesPage;
 
-	public ImportFavoritesWizard(MarketplaceCatalog catalog, MarketplaceCatalogConfiguration configuration, IMarketplaceWebBrowser browser) {
+	private String initialFavoritesUrl;
+
+	private final MarketplaceWizard parent;
+
+	public ImportFavoritesWizard(MarketplaceCatalog catalog, MarketplaceCatalogConfiguration configuration,
+			MarketplaceWizard parent) {
 		super(catalog, configuration);
-		setWindowTitle("Import Favorites List");
-		this.importFavoritesPage = new ImportFavoritesPage(catalog, browser);
+		setWindowTitle(Messages.ImportFavoritesWizard_title);
+		this.importFavoritesPage = new ImportFavoritesPage(catalog);
+		this.parent = parent;
+	}
+
+	@Override
+	public MarketplaceCatalogConfiguration getConfiguration() {
+		return (MarketplaceCatalogConfiguration) super.getConfiguration();
+	}
+
+	@Override
+	public MarketplaceCatalog getCatalog() {
+		return (MarketplaceCatalog) super.getCatalog();
 	}
 
 	@Override
@@ -31,10 +58,61 @@
 	@Override
 	public boolean performFinish() {
 		importFavoritesPage.performImport();
-		return importFavoritesPage.getErrorMessage() == null;
+		boolean result = importFavoritesPage.getErrorMessage() == null;
+		if (result) {
+			showFavoritesInMarketplace(importFavoritesPage.isInstallSelected());
+		}
+		return result;
+	}
+
+	private void showFavoritesInMarketplace(boolean install) {
+		List<MarketplaceNodeCatalogItem> selection = importFavoritesPage.getSelection();
+		if (selection.isEmpty()) {
+			return;
+		}
+		if (!install) {
+			selection = Collections.emptyList();
+		}
+		if (parent == null) {
+			openFavoritesInMarketplace(selection);
+		} else {
+			selectForInstallation(selection);
+		}
+	}
+
+	private void selectForInstallation(List<MarketplaceNodeCatalogItem> selection) {
+		for (MarketplaceNodeCatalogItem item : selection) {
+			parent.getSelectionModel().select(item, Operation.INSTALL);
+		}
+	}
+
+	private void openFavoritesInMarketplace(List<MarketplaceNodeCatalogItem> selection) {
+		final IMarketplaceClientService clientService = MarketplaceClient.getMarketplaceClientService();
+		final IMarketplaceClientConfiguration config = clientService.newConfiguration();
+		MarketplaceCatalogConfiguration catalogConfiguration = getConfiguration();
+		config.setCatalogDescriptors(catalogConfiguration.getCatalogDescriptors());
+		config.setCatalogDescriptor(catalogConfiguration.getCatalogDescriptor());
+		Map<String, Operation> initialOperations = new HashMap<String, Operation>();
+		for (MarketplaceNodeCatalogItem item : selection) {
+			initialOperations.put(item.getData().getId(), Operation.INSTALL);
+		}
+		config.setInitialOperations(initialOperations);
+		Display.getCurrent().asyncExec(new Runnable() {
+			public void run() {
+				clientService.openFavorites(config);
+			}
+		});
 	}
 
 	public ImportFavoritesPage getImportFavoritesPage() {
 		return importFavoritesPage;
 	}
+
+	public void setInitialFavoritesUrl(String initialFavoritesUrl) {
+		this.initialFavoritesUrl = initialFavoritesUrl;
+	}
+
+	public String getInitialFavoritesUrl() {
+		return initialFavoritesUrl;
+	}
 }
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ImportFavoritesWizardDialog.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ImportFavoritesWizardDialog.java
index 4d502ac..f85403f 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ImportFavoritesWizardDialog.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ImportFavoritesWizardDialog.java
@@ -10,18 +10,71 @@
  *******************************************************************************/
 package org.eclipse.epp.internal.mpc.ui.wizards;
 
-import org.eclipse.jface.wizard.IWizard;
+import org.eclipse.jface.dialogs.IDialogSettings;
 import org.eclipse.jface.wizard.IWizardPage;
 import org.eclipse.swt.widgets.Shell;
 
 public class ImportFavoritesWizardDialog extends AbstractMarketplaceWizardDialog {
 
-	public ImportFavoritesWizardDialog(Shell parentShell, IWizard newWizard) {
+	public ImportFavoritesWizardDialog(Shell parentShell, ImportFavoritesWizard newWizard) {
 		super(parentShell, newWizard);
 	}
 
 	@Override
+	protected ImportFavoritesWizard getWizard() {
+		return (ImportFavoritesWizard) super.getWizard();
+	}
+
+	@Override
+	protected void configureShell(Shell newShell) {
+		super.configureShell(newShell);
+		newShell.setData(this);//make jface dialog accessible for swtbot
+		new MarketplaceDropAdapter() {
+			@Override
+			protected void proceedFavorites(String url) {
+				ImportFavoritesWizard wizard = getWizard();
+				wizard.setInitialFavoritesUrl(url);
+				ImportFavoritesPage importPage = wizard.getImportFavoritesPage();
+				importPage.setFavoritesUrl(url);
+			}
+		}.installDropTarget(newShell);
+	}
+
+	@Override
 	public String getFinishButtonLabel(IWizardPage page) {
 		return Messages.ImportFavoritesWizardDialog_FinishButtonLabel;
 	}
+
+	@Override
+	protected IDialogSettings getDialogBoundsSettings() {
+		boolean relative = getParentShell() != null;
+		IDialogSettings settings = getDialogBoundsSettings(getClass(), relative, false);
+		if (settings == null) {
+			//This tries to be smart in intializing its defaults:
+			//- if there are settings for the opposite mode (!relative), take the size from there
+			//- initialize the relative position to be slightly to the bottom left
+			//- if there are settings for the main Marketplace wizard dialog, take the initial position
+			//  from there for absolute position
+			//- if we don't have an initial size yet, take the Marketplace wizard size, which should be
+			//  a good match
+			settings = getDialogBoundsSettings(getClass(), relative, true);
+			if (relative) {
+				setInitialLocation(80, 80, settings);
+			}
+			IDialogSettings marketplaceWizardSettings = getDialogBoundsSettings(MarketplaceWizardDialog.class, false,
+					false);
+			if (marketplaceWizardSettings != null) {
+				if (!relative) {
+					copyInitialLocation(marketplaceWizardSettings, settings);
+				}
+				IDialogSettings companionSettings = getDialogBoundsSettings(getClass(), !relative, false);
+				//If we had companion settings, the call to getDialogBoundsSettings(..., true) would have
+				//already initialized them
+				if (companionSettings == null) {
+					copyInitialSize(marketplaceWizardSettings, settings);
+				}
+			}
+		}
+		return settings;
+	}
 }
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/InstallAllActionLink.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/InstallAllActionLink.java
index abbd2c9..7c335ec 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/InstallAllActionLink.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/InstallAllActionLink.java
@@ -44,8 +44,7 @@
 		for (CatalogItem catalogItem : items) {
 			if (catalogItem instanceof MarketplaceNodeCatalogItem) {
 				MarketplaceNodeCatalogItem nodeItem = (MarketplaceNodeCatalogItem) catalogItem;
-				if (selectionModel.getSelectedOperation(nodeItem) != Operation.INSTALL
-						&& nodeItem.getAvailableOperations().contains(Operation.INSTALL)) {
+				if (selectionModel.getSelectedOperation(nodeItem) == Operation.NONE) {
 					selectionModel.select(nodeItem, Operation.INSTALL);
 				}
 			}
@@ -53,5 +52,8 @@
 		//viewer.getCheckedItems() is based on the SelectionModel state, so it already has the
 		//updated selection. Just let the viewer synchronize its remaining selection state with it.
 		viewer.setSelection(new StructuredSelection(viewer.getCheckedItems()));
+		if (!viewer.getSelection().isEmpty()) {
+			marketplacePage.showNextPage();
+		}
 	}
 }
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceClientService.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceClientService.java
index e4836f7..315ab59 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceClientService.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceClientService.java
@@ -17,6 +17,8 @@
 import org.eclipse.core.commands.ExecutionException;
 import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore;
 import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi;
+import org.eclipse.epp.internal.mpc.ui.commands.AbstractMarketplaceWizardCommand;
+import org.eclipse.epp.internal.mpc.ui.commands.ImportFavoritesWizardCommand;
 import org.eclipse.epp.internal.mpc.ui.commands.MarketplaceWizardCommand;
 import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceViewer.ContentType;
 import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceWizard.WizardState;
@@ -119,6 +121,13 @@
 		execute(command);
 	}
 
+	public void openFavoritesImport(IMarketplaceClientConfiguration configuration, String favoritesUrl) {
+		ImportFavoritesWizardCommand command = new ImportFavoritesWizardCommand();
+		command.setConfiguration(configuration);
+		command.setFavoritesUrl(favoritesUrl);
+		execute(command);
+	}
+
 	private void checkInitialState(IMarketplaceClientConfiguration configuration) {
 		if (configuration.getInitialState() == null
 				&& (configuration.getInitialOperations() == null || configuration.getInitialOperations().isEmpty())) {
@@ -126,7 +135,7 @@
 		}
 	}
 
-	private void execute(MarketplaceWizardCommand command) {
+	private void execute(AbstractMarketplaceWizardCommand command) {
 		try {
 			command.execute(new ExecutionEvent());
 		} catch (ExecutionException e) {
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceDropAdapter.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceDropAdapter.java
index 0c12799..5c4c740 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceDropAdapter.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceDropAdapter.java
@@ -169,6 +169,10 @@
 		}
 	}
 
+	protected void proceedFavorites(String url) {
+		MarketplaceUrlHandler.triggerFavorites(url);
+	}
+
 	private class MarketplaceDropTargetListener extends DropTargetAdapter {
 
 		@Override
@@ -228,7 +232,11 @@
 						return !isDrop;
 					}
 					final String url = getUrl(e.data);
-					if (!MarketplaceUrlHandler.isPotentialSolution(url)) {
+					if (MarketplaceUrlHandler.isPotentialSolution(url)) {
+						return true;
+					} else if (MarketplaceUrlHandler.isPotentialFavoritesList(url)) {
+						return true;
+					} else {
 						traceInvalidEventData(e);
 						return false;
 					}
@@ -270,8 +278,8 @@
 				return;
 			}
 			final String url = getUrl(event.data);
-			//http://marketplace.eclipse.org/marketplace-client-intro?mpc_install=1640500
 			if (MarketplaceUrlHandler.isPotentialSolution(url)) {
+				//http://marketplace.eclipse.org/marketplace-client-intro?mpc_install=1640500
 				DropTarget source = (DropTarget) event.getSource();
 				Display display = source.getDisplay();
 				display.asyncExec(new Runnable() {
@@ -279,6 +287,15 @@
 						proceedInstallation(url);
 					}
 				});
+			} else if (MarketplaceUrlHandler.isPotentialFavoritesList(url)) {
+				//https://marketplace.eclipse.org/user/xxx/favorites
+				DropTarget source = (DropTarget) event.getSource();
+				Display display = source.getDisplay();
+				display.asyncExec(new Runnable() {
+					public void run() {
+						proceedFavorites(url);
+					}
+				});
 			} else {
 				traceInvalidEventData(event);
 			}
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplacePage.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplacePage.java
index cc0586a..8e207d1 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplacePage.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplacePage.java
@@ -116,6 +116,8 @@
 
 	private ActionLink selectionLink;
 
+	private ActionLink deselectLink;
+
 	private TabFolder tabFolder;
 
 	private TabItem searchTabItem;
@@ -651,6 +653,8 @@
 					if (selectionLink != null) {
 						removeActionLink(selectionLink);
 						selectionLink = null;
+						removeActionLink(deselectLink);
+						deselectLink = null;
 					}
 				} else {
 					ActionLink newSelectionLink = createSelectionLink(text);
@@ -658,6 +662,8 @@
 						updateActionLink(selectionLink, newSelectionLink);
 					} else {
 						addActionLink(0, newSelectionLink);
+						deselectLink = createDeselectionLink();
+						addActionLink(1, deselectLink);
 					}
 					selectionLink = newSelectionLink;
 				}
@@ -665,8 +671,18 @@
 		}
 	}
 
+	private ActionLink createDeselectionLink() {
+		return new ActionLink("clearSelection", Messages.MarketplacePage_DeselectAll, Messages.MarketplacePage_DeselectAllTooltip) { //$NON-NLS-1$
+
+			@Override
+			public void selected() {
+				deselectionLinkActivated();
+			}
+		};
+	}
+
 	private ActionLink createSelectionLink(String text) {
-		return new ActionLink("showSelection", text, Messages.MarketplacePage_showSelection) {
+		return new ActionLink("showSelection", text, Messages.MarketplacePage_showSelection) { //$NON-NLS-1$
 
 			@Override
 			public void selected() {
@@ -681,6 +697,12 @@
 		setActiveTab(ContentType.SELECTION);
 	}
 
+	protected void deselectionLinkActivated() {
+		SelectionModel selectionModel = getWizard().getSelectionModel();
+		selectionModel.clear();
+		getWizard().updateSelection();
+	}
+
 	@Override
 	public IWizardPage getPreviousPage() {
 		return super.getPreviousPage();
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceViewer.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceViewer.java
index a29237f..1f27e46 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceViewer.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceViewer.java
@@ -116,8 +116,16 @@
 				for (CatalogCategory category : getCatalog().getCategories()) {
 					if (category instanceof MarketplaceCategory) {
 						MarketplaceCategory marketplaceCategory = (MarketplaceCategory) category;
-						if (marketplaceCategory.getContents() == Contents.FEATURED) {
-							items.add(0, category);
+						int pos = 0;
+						for(int i=0;i < items.size(); i++) {
+							if (!(items.get(i) instanceof UserActionCatalogItem)) {
+								pos=i;
+								break;
+							}
+						}
+						if (marketplaceCategory.getContents() == Contents.FEATURED
+								|| (pos > 0 && pos < items.size() - 1)) {
+							items.add(pos, category);
 						}
 					}
 				}
@@ -356,6 +364,8 @@
 			MarketplaceCategory category = (MarketplaceCategory) element;
 			if (category.getContents() == Contents.FEATURED) {
 				category.setName(Messages.MarketplaceViewer_featured);
+			} else if (category.getContents() == Contents.POPULAR) {
+				category.setName(Messages.MarketplaceViewer_PopularBannerTitle);
 			} else {
 				throw new IllegalStateException();
 			}
@@ -373,21 +383,21 @@
 				(MarketplaceCategory) catalogItem.getCategory(), catalogDescriptor, this);
 	}
 
-	private UserActionViewerItem<?> createUserActionViewerItem(UserActionCatalogItem catalogItem, Composite parent) {
+	private ControlListItem<?> createUserActionViewerItem(UserActionCatalogItem catalogItem, Composite parent) {
 		UserAction userAction = catalogItem.getUserAction();
 		switch (userAction) {
 		case BROWSE:
 			return createBrowseItem(catalogItem, parent);
 		case CREATE_FAVORITES:
-			return new UserFavoritesFindFavoritesActionItem(parent, getResources(), shellProvider, catalogItem,
+			return new UserFavoritesFindFavoritesActionItem(parent, getResources(), catalogItem,
 					getWizard().getCatalogPage());
 		case FAVORITES_UNSUPPORTED:
-			return new UserFavoritesUnsupportedActionItem(parent, getResources(), shellProvider, catalogItem,
+			return new UserFavoritesUnsupportedActionItem(parent, getResources(), catalogItem,
 					getWizard().getCatalogPage());
 		case LOGIN:
-			return new UserFavoritesLoginActionItem(parent, getResources(), shellProvider, catalogItem, this);
+			return new UserFavoritesSignInActionItem(parent, getResources(), catalogItem, this);
 		case RETRY_ERROR:
-			return new RetryErrorActionItem(parent, getResources(), shellProvider, catalogItem, this);
+			return new RetryErrorActionItem(parent, getResources(), catalogItem, this);
 		}
 		return null;
 	}
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceWizard.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceWizard.java
index a152078..5c9b9b9 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceWizard.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceWizard.java
@@ -12,6 +12,8 @@
  *******************************************************************************/
 package org.eclipse.epp.internal.mpc.ui.wizards;
 
+import static org.eclipse.epp.mpc.ui.MarketplaceUrlHandler.UTF_8;
+
 import java.io.UnsupportedEncodingException;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
@@ -61,6 +63,7 @@
 import org.eclipse.epp.mpc.core.model.INode;
 import org.eclipse.epp.mpc.ui.CatalogDescriptor;
 import org.eclipse.epp.mpc.ui.MarketplaceUrlHandler;
+import org.eclipse.epp.mpc.ui.MarketplaceUrlHandler.SolutionInstallationInfo;
 import org.eclipse.epp.mpc.ui.Operation;
 import org.eclipse.equinox.internal.p2.discovery.AbstractDiscoveryStrategy;
 import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem;
@@ -80,6 +83,7 @@
 import org.eclipse.jface.operation.IRunnableWithProgress;
 import org.eclipse.jface.viewers.IStructuredContentProvider;
 import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.jface.viewers.TableViewer;
 import org.eclipse.jface.viewers.Viewer;
 import org.eclipse.jface.wizard.IWizardContainer;
@@ -273,25 +277,34 @@
 				// user canceled
 				throw new CoreException(Status.CANCEL_STATUS);
 			}
-			List<Entry<CatalogItem, Operation>> itemToSelectedOperation = new ArrayList<Entry<CatalogItem, Operation>>(
-					getSelectionModel().getItemToSelectedOperation().entrySet());
-			final List<CatalogItem> noninstallableItems = new ArrayList<CatalogItem>();
-			for (Entry<CatalogItem, Operation> entry : itemToSelectedOperation) {
-				if (entry.getValue() != Operation.NONE) {
-					boolean unavailableInstall = (Boolean.FALSE.equals(entry.getKey().getAvailable()) || entry.getKey()
-							.getSiteUrl() == null)
-							&& (entry.getValue() == Operation.INSTALL || entry.getValue() == Operation.UPDATE);
-					if (unavailableInstall) {
-						getSelectionModel().select(entry.getKey(), Operation.NONE);
-						noninstallableItems.add(entry.getKey());
-					} else {
-						entry.getKey().setSelected(true);
-					}
+		}
+	}
+
+	protected void updateSelection() {
+		List<Entry<CatalogItem, Operation>> itemToSelectedOperation = new ArrayList<Entry<CatalogItem, Operation>>(
+				getSelectionModel().getItemToSelectedOperation().entrySet());
+		final List<CatalogItem> noninstallableItems = new ArrayList<CatalogItem>();
+		for (Entry<CatalogItem, Operation> entry : itemToSelectedOperation) {
+			if (entry.getValue() != Operation.NONE) {
+				boolean unavailableInstall = (Boolean.FALSE.equals(entry.getKey().getAvailable())
+						|| entry.getKey().getSiteUrl() == null)
+						&& (entry.getValue() == Operation.INSTALL || entry.getValue() == Operation.UPDATE);
+				if (unavailableInstall) {
+					getSelectionModel().select(entry.getKey(), Operation.NONE);
+					noninstallableItems.add(entry.getKey());
+				} else {
+					entry.getKey().setSelected(true);
 				}
 			}
-			if (!noninstallableItems.isEmpty()) {
-				notifyNonInstallableItems(noninstallableItems);
-			}
+		}
+		MarketplacePage marketplacePage = getCatalogPage();
+		MarketplaceViewer viewer = marketplacePage == null ? null : marketplacePage.getViewer();
+		if (marketplacePage != null && viewer != null && !viewer.getControl().isDisposed()) {
+			viewer.setSelection(new StructuredSelection(viewer.getCheckedItems()));
+			marketplacePage.setPageComplete(viewer.isComplete());
+		}
+		if (!noninstallableItems.isEmpty()) {
+			notifyNonInstallableItems(noninstallableItems);
 		}
 	}
 
@@ -644,7 +657,7 @@
 		}
 	}
 
-	private String getCatalogUrl() {
+	protected String getCatalogUrl() {
 		CatalogDescriptor catalogDescriptor = getConfiguration().getCatalogDescriptor();
 		URL catalogUrl = catalogDescriptor.getUrl();
 		URI catalogUri;
@@ -949,6 +962,69 @@
 		CatalogRegistry.getInstance().addCatalogNews(catalogDescriptor, news);
 	}
 
+	protected boolean handleInstallRequest(final SolutionInstallationInfo installInfo, String url) {
+		final String installId = installInfo.getInstallId();
+		if (installId == null) {
+			return false;
+		}
+		try {
+			getContainer().run(true, true, new IRunnableWithProgress() {
+
+				public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+					Map<String, Operation> nodeIdToOperation = new HashMap<String, Operation>();
+					nodeIdToOperation.putAll(getSelectionModel().getItemIdToSelectedOperation());
+					try {
+						nodeIdToOperation.put(URLDecoder.decode(installId, UTF_8), Operation.INSTALL);
+					} catch (UnsupportedEncodingException e) {
+						//should be unreachable
+						throw new IllegalStateException();
+					}
+
+					final SelectionModel selectionModel = getSelectionModel();
+					MarketplacePage catalogPage = getCatalogPage();
+					IStatus showingDescriptor = catalogPage.showMarketplace(installInfo.getCatalogDescriptor());
+					if (!showingDescriptor.isOK()) {
+						return;
+					}
+
+					SelectionModelStateSerializer stateSerializer = new SelectionModelStateSerializer(
+							getCatalog(), selectionModel);
+					stateSerializer.deserialize(installInfo.getState(), nodeIdToOperation, monitor);
+
+					if (selectionModel.getItemToSelectedOperation().size() > 0) {
+						Display display = getShell().getDisplay();
+						if (!display.isDisposed()) {
+							display.asyncExec(new Runnable() {
+
+								public void run() {
+									MarketplacePage catalogPage = getCatalogPage();
+									IWizardPage currentPage = getContainer().getCurrentPage();
+									if (catalogPage == currentPage) {
+										catalogPage.getViewer().setSelection(new StructuredSelection(
+												selectionModel.getSelectedCatalogItems().toArray()));
+										catalogPage.show(installInfo.getCatalogDescriptor(), ContentType.SELECTION);
+										IWizardPage nextPage = catalogPage.getNextPage();
+										if (nextPage != null && catalogPage.isPageComplete()) {
+											getContainer().showPage(nextPage);
+										}
+									}
+								}
+							});
+						}
+					}
+				}
+			});
+			return true;
+		} catch (InvocationTargetException e) {
+			IStatus status = MarketplaceClientCore.computeStatus(e, Messages.MarketplaceViewer_unexpectedException);
+			MarketplaceClientUi.handle(status, StatusManager.SHOW | StatusManager.BLOCK | StatusManager.LOG);
+		} catch (InterruptedException e) {
+			// action canceled, but this still counts as handled
+			return true;
+		}
+		return false;
+	}
+
 	public Object suspendWizard() {
 		String catalogUrl = getCatalogUrl();
 		String key = appendWizardState(catalogUrl);
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceWizardDialog.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceWizardDialog.java
index 1808c2f..6a2a837 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceWizardDialog.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceWizardDialog.java
@@ -13,6 +13,9 @@
 
 import java.util.Arrays;
 
+import org.eclipse.epp.mpc.ui.CatalogDescriptor;
+import org.eclipse.epp.mpc.ui.MarketplaceUrlHandler;
+import org.eclipse.epp.mpc.ui.MarketplaceUrlHandler.SolutionInstallationInfo;
 import org.eclipse.jface.dialogs.IDialogConstants;
 import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.jface.wizard.IWizardPage;
@@ -43,7 +46,19 @@
 	protected void configureShell(Shell newShell) {
 		super.configureShell(newShell);
 		newShell.setData(this);//make jface dialog accessible for swtbot
-		new MarketplaceDropAdapter().installDropTarget(newShell);
+		new MarketplaceDropAdapter() {
+			@Override
+			protected void proceedInstallation(String url) {
+				SolutionInstallationInfo info = MarketplaceUrlHandler.createSolutionInstallInfo(url);
+				CatalogDescriptor catalogDescriptor = info.getCatalogDescriptor();
+				String installItem = info.getInstallId();
+				//we ignore previous wizard state here, since the wizard is still open...
+				if (installItem != null && installItem.length() > 0) {
+					info.setState(null);
+					getWizard().handleInstallRequest(info, url);
+				}
+			}
+		}.installDropTarget(newShell);
 		final IWorkbenchListener workbenchListener = new IWorkbenchListener() {
 
 			public boolean preShutdown(IWorkbench workbench, boolean forced) {
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/Messages.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/Messages.java
index 424e40d..8651b01 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/Messages.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/Messages.java
@@ -73,10 +73,18 @@
 
 	public static String DiscoveryItem_UnnamedSolution;
 
+	public static String FavoritesViewer_DeselectAll;
+
 	public static String FavoritesViewer_searchInputDescription;
 
 	public static String FavoritesViewer_searchLabel;
 
+	public static String FavoritesViewer_SelectAll;
+
+	public static String FavoritesViewer_SelectForInstallation;
+
+	public static String FavoritesViewer_SelectForInstallationTooltip;
+
 	public static String FeatureSelectionWizardPage_confirmSelectedFeatures;
 
 	public static String FeatureSelectionWizardPage_confirmSelectedFeatures_description;
@@ -115,6 +123,8 @@
 
 	public static String ImportFavoritesPage_Description;
 
+	public static String ImportFavoritesWizard_title;
+
 	public static String ImportFavoritesWizardDialog_FinishButtonLabel;
 
 	public static String ImportFavoritesPage_Title;
@@ -156,6 +166,10 @@
 
 	public static String MarketplacePage_DefaultNewsTitle;
 
+	public static String MarketplacePage_DeselectAll;
+
+	public static String MarketplacePage_DeselectAllTooltip;
+
 	public static String MarketplacePage_discardPendingSolutions;
 
 	public static String MarketplacePage_eclipseMarketplaceSolutions;
@@ -194,6 +208,8 @@
 
 	public static String MarketplaceViewer_go;
 
+	public static String MarketplaceViewer_PopularBannerTitle;
+
 	public static String MarketplaceViewer_unexpectedException;
 
 	public static String MarketplaceWizard_cannotOpenUrl;
@@ -262,6 +278,8 @@
 
 	public static String RetryErrorActionItem_showDetailsTooltip;
 
+	public static String RetryErrorActionItem_subline;
+
 	public static String RetryErrorActionItem_unsupportedLinkMessage;
 
 	public static String SelectionModel_cannotInstallRemoveConcurrently;
@@ -303,19 +321,39 @@
 	public static String UserFavoritesAbstractImportActionItem_importFavoritesActionLabel;
 
 	public static String UserFavoritesAbstractImportActionItem_importFavoritesTooltip;
+	public static String UserFavoritesFindFavoritesActionItem_BrowseButtonLabel;
+
+	public static String UserFavoritesFindFavoritesActionItem_BrowseButtonTooltip;
+
 	public static String UserFavoritesFindFavoritesActionItem_browsePopularActionLabel;
 
 	public static String UserFavoritesFindFavoritesActionItem_browsePopularTooltip;
 
 	public static String UserFavoritesFindFavoritesActionItem_noFavoritesYetMessage;
 
+	public static String UserFavoritesFindFavoritesActionItem_subline;
+
+	public static String UserFavoritesFindFavoritesActionItem_title;
+
 	public static String UserFavoritesInstallAllActionItem_installAllActionLabel;
 
 	public static String UserFavoritesInstallAllActionItem_installAllTooltip;
 
-	public static String UserFavoritesLoginActionItem_logInActionLabel;
+	public static String UserFavoritesSignInActionItem_SignInButtonText;
 
-	public static String UserFavoritesLoginActionItem_retryLoginLabel;
+	public static String UserFavoritesSignInActionItem_SignInDescription;
+
+	public static String UserFavoritesSignInActionItem_subline;
+
+	public static String SignInUserActionItem_signInActionLabel;
+
+	public static String SignInUserActionItem_retryLoginLabel;
+
+	public static String UserFavoritesUnsupportedActionItem_Body;
+
+	public static String UserFavoritesUnsupportedActionItem_GoBackButtonLabel;
+
+	public static String UserFavoritesUnsupportedActionItem_Subline;
 
 	public static String UserFavoritesUnsupportedActionItem_unsupportedFavoritesLabel;
 	static {
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/NewsUrlHandler.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/NewsUrlHandler.java
index 0649c1a..a3358a0 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/NewsUrlHandler.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/NewsUrlHandler.java
@@ -10,40 +10,27 @@
  *******************************************************************************/
 package org.eclipse.epp.internal.mpc.ui.wizards;
 
-import java.io.UnsupportedEncodingException;
-import java.lang.reflect.InvocationTargetException;
 import java.net.URI;
 import java.net.URISyntaxException;
-import java.net.URLDecoder;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
-import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore;
 import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi;
 import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCategory;
-import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceViewer.ContentType;
 import org.eclipse.epp.mpc.core.model.ICategory;
 import org.eclipse.epp.mpc.core.model.IMarket;
 import org.eclipse.epp.mpc.core.model.INode;
 import org.eclipse.epp.mpc.ui.CatalogDescriptor;
-import org.eclipse.epp.mpc.ui.Operation;
 import org.eclipse.equinox.internal.p2.discovery.model.CatalogCategory;
-import org.eclipse.jface.operation.IRunnableWithProgress;
-import org.eclipse.jface.viewers.StructuredSelection;
-import org.eclipse.jface.wizard.IWizardPage;
 import org.eclipse.swt.SWTException;
 import org.eclipse.swt.browser.LocationEvent;
 import org.eclipse.swt.browser.LocationListener;
 import org.eclipse.swt.browser.ProgressEvent;
 import org.eclipse.swt.browser.ProgressListener;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.ui.statushandlers.StatusManager;
 
 /**
  * @author Carsten Reckord
@@ -214,61 +201,11 @@
 
 	@Override
 	protected boolean handleInstallRequest(final SolutionInstallationInfo installInfo, String url) {
-		final String installId = installInfo.getInstallId();
-		if (installId == null) {
+		if (installInfo.getInstallId() == null) {
 			return false;
 		}
 		final MarketplaceWizard wizard = viewer.getWizard();
-		try {
-			wizard.getContainer().run(true, true, new IRunnableWithProgress() {
-
-				public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
-					Map<String, Operation> nodeIdToOperation = new HashMap<String, Operation>();
-					try {
-						nodeIdToOperation.put(URLDecoder.decode(installId, UTF_8), Operation.INSTALL);
-					} catch (UnsupportedEncodingException e) {
-						//should be unreachable
-						throw new IllegalStateException();
-					}
-
-					final SelectionModel selectionModel = viewer.getWizard().getSelectionModel();
-					SelectionModelStateSerializer stateSerializer = new SelectionModelStateSerializer(
-							wizard.getCatalog(), selectionModel);
-					stateSerializer.deserialize(installId, nodeIdToOperation, monitor);
-
-					if (selectionModel.getItemToSelectedOperation().size() > 0) {
-						Display display = wizard.getShell().getDisplay();
-						if (!display.isDisposed()) {
-							display.asyncExec(new Runnable() {
-
-								public void run() {
-									MarketplacePage catalogPage = wizard.getCatalogPage();
-									IWizardPage currentPage = wizard.getContainer().getCurrentPage();
-									if (catalogPage == currentPage) {
-										catalogPage.getViewer().setSelection(
-												new StructuredSelection(selectionModel.getSelectedCatalogItems()
-														.toArray()));
-										catalogPage.show(installInfo.getCatalogDescriptor(), ContentType.SELECTION);
-										IWizardPage nextPage = catalogPage.getNextPage();
-										if (nextPage != null && catalogPage.isPageComplete()) {
-											wizard.getContainer().showPage(nextPage);
-										}
-									}
-								}
-							});
-						}
-					}
-				}
-			});
-			return true;
-		} catch (InvocationTargetException e) {
-			IStatus status = MarketplaceClientCore.computeStatus(e, Messages.MarketplaceViewer_unexpectedException);
-			MarketplaceClientUi.handle(status, StatusManager.SHOW | StatusManager.BLOCK | StatusManager.LOG);
-		} catch (InterruptedException e) {
-			// action canceled, but this still counts as handled
-			return true;
-		}
-		return false;
+		return wizard.handleInstallRequest(installInfo, url);
 	}
 
 	public void completed(ProgressEvent event) {
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/OverviewToolTip.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/OverviewToolTip.java
index d35f7c3..667cb76 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/OverviewToolTip.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/OverviewToolTip.java
@@ -97,7 +97,7 @@
 	protected Composite createToolTipContentArea(Event event, final Composite parent) {
 		Shell shell = parent.getShell();
 		setData(Shell.class.getName(), shell);
-		DiscoveryItem.setWidgetId(shell, DiscoveryItem.WIDGET_ID_OVERVIEW);
+		AbstractMarketplaceDiscoveryItem.setWidgetId(shell, DiscoveryItem.WIDGET_ID_OVERVIEW);
 		GridLayoutFactory.fillDefaults().applyTo(parent);
 
 		Color backgroundColor = parent.getDisplay().getSystemColor(SWT.COLOR_WHITE);
@@ -108,7 +108,7 @@
 		if (overview.getScreenshot() != null) {
 			hasImage = true;
 		}
-		final boolean hasLearnMoreLink = overview.getUrl() != null && overview.getUrl().length() > 0;
+		final boolean addLearnMoreLink = browser != null && overview.getUrl() != null && overview.getUrl().length() > 0;
 
 		final int borderWidth = 1;
 		final int heightHint = SCREENSHOT_HEIGHT + (borderWidth * 2);
@@ -119,8 +119,8 @@
 
 		GridDataFactory.fillDefaults().grab(true, true).hint(
 				hasImage ? containerWidthHintWithImage : containerWidthHintWithoutImage, SWT.DEFAULT)
-				.applyTo(
-						container);
+		.applyTo(
+				container);
 
 		GridLayoutFactory.fillDefaults().numColumns((leftImage != null) ? 3 : 2).margins(5, 5).spacing(3, 0).applyTo(
 				container);
@@ -166,7 +166,7 @@
 				+ "} body { margin: 0px; background-color: white;}"; //$NON-NLS-1$
 		summaryLabel.setFont(dialogFont);
 		String html = "<html><style>" + cssStyle + "</style><body>" + TextUtil.cleanInformalHtmlMarkup(summary) //$NON-NLS-1$//$NON-NLS-2$
-				+ "</body></html>"; //$NON-NLS-1$
+		+ "</body></html>"; //$NON-NLS-1$
 		summaryLabel.setText(html);
 		summaryLabel.setBackground(backgroundColor);
 		// instead of opening links in the tooltip, open a new browser window
@@ -186,7 +186,7 @@
 
 		GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).hint(SWT.DEFAULT,
 				hasImage ? SWT.DEFAULT : SCREENSHOT_HEIGHT)
-				.applyTo(summaryLabel);
+		.applyTo(summaryLabel);
 
 		if (hasImage) {
 			final Composite imageContainer = new Composite(container, SWT.BORDER);
@@ -221,9 +221,9 @@
 			// creates a border
 			imageContainer.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
 		}
-		if (hasLearnMoreLink) {
+		if (addLearnMoreLink) {
 			Link link = new Link(summaryContainer, SWT.NULL);
-			DiscoveryItem.setWidgetId(link, DiscoveryItem.WIDGET_ID_LEARNMORE);
+			AbstractMarketplaceDiscoveryItem.setWidgetId(link, DiscoveryItem.WIDGET_ID_LEARNMORE);
 			GridDataFactory.fillDefaults().grab(false, false).align(SWT.BEGINNING, SWT.CENTER).applyTo(link);
 			link.setText(Messages.OverviewToolTip_learnMoreLink);
 			link.setBackground(backgroundColor);
@@ -302,8 +302,8 @@
 								} catch (SWTException e) {
 									// ignore, probably a bad image format
 									MarketplaceClientUi
-											.error(NLS.bind(Messages.OverviewToolTip_cannotRenderImage_reason,
-													imagePath, e.getMessage()), e);
+									.error(NLS.bind(Messages.OverviewToolTip_cannotRenderImage_reason,
+											imagePath, e.getMessage()), e);
 								}
 							}
 						}
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/RetryErrorActionItem.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/RetryErrorActionItem.java
index e019d76..a57fff0 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/RetryErrorActionItem.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/RetryErrorActionItem.java
@@ -13,51 +13,70 @@
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore;
 import org.eclipse.epp.internal.mpc.ui.catalog.UserActionCatalogItem;
-import org.eclipse.equinox.internal.p2.ui.discovery.wizards.DiscoveryResources;
+import org.eclipse.equinox.internal.p2.discovery.model.Icon;
 import org.eclipse.jface.dialogs.ErrorDialog;
-import org.eclipse.jface.window.IShellProvider;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.swt.widgets.Composite;
 
-public class RetryErrorActionItem extends AbstractUserActionLinksItem {
+public class RetryErrorActionItem extends AbstractUserActionItem {
 
-	private static final String RETRY_ACTION_ID = "retry"; //$NON-NLS-1$
+	private static final int RETRY_ACTION_ID = 1;
 
-	private static final String DETAILS_ACTION_ID = "details"; //$NON-NLS-1$
+	private static final int DETAILS_ACTION_ID = 0;
 
-	private final IStatus error;
+	public RetryErrorActionItem(Composite parent, MarketplaceDiscoveryResources resources,
+			UserActionCatalogItem connector, MarketplaceViewer viewer) {
+		super(parent, resources, connector, viewer);
+	}
 
-	public RetryErrorActionItem(Composite parent, DiscoveryResources resources, IShellProvider shellProvider,
-			UserActionCatalogItem element, MarketplaceViewer viewer) {
-		super(parent, resources, shellProvider, element, viewer);
-		this.error = MarketplaceClientCore.computeStatus((Throwable) element.getData(), null);
-		createContent(new ActionLink(DETAILS_ACTION_ID, Messages.RetryErrorActionItem_showDetailsActionLabel,
-				Messages.RetryErrorActionItem_showDetailsTooltip) {
+	private IStatus getError() {
+		return MarketplaceClientCore.computeStatus((Throwable) connector.getData(), null);
+	}
 
-			@Override
-			public void selected() {
-				showDetails();
-			}
-
-		}, new ActionLink(RETRY_ACTION_ID, Messages.RetryErrorActionItem_retryActionLabel,
-				Messages.RetryErrorActionItem_retryTooltip) {
-
-			@Override
-			public void selected() {
-				retry();
-			}
-
-		});
+	@Override
+	protected String getNameLabelText() {
+		return Messages.UserFavoritesUnsupportedActionItem_unsupportedFavoritesLabel;
 	}
 
 	@Override
 	protected String getDescriptionText() {
+		IStatus error = getError();
 		return NLS.bind(Messages.RetryErrorActionItem_failedToLoadMessage,
 				error.getMessage() == null ? error.getClass().getSimpleName() : error.getMessage());
 	}
 
+	@Override
+	protected Icon getIcon() {
+		// TODO see https://bugs.eclipse.org/bugs/show_bug.cgi?id=516804
+		return null;
+	}
+
+	@Override
+	protected String getSublineText() {
+		return Messages.RetryErrorActionItem_subline;
+	}
+
+	@Override
+	protected void createButtons(Composite parent) {
+		createButton(parent, Messages.RetryErrorActionItem_showDetailsActionLabel,
+				Messages.RetryErrorActionItem_showDetailsTooltip, DETAILS_ACTION_ID);
+		createButton(parent, Messages.RetryErrorActionItem_retryActionLabel,
+				Messages.RetryErrorActionItem_retryTooltip, RETRY_ACTION_ID);
+	}
+
+	@Override
+	protected void buttonPressed(int id) {
+		if (id == RETRY_ACTION_ID) {
+			retry();
+		} else {
+			showDetails();
+		}
+	}
+
 	protected void showDetails() {
-		ErrorDialog.openError(getShell(), Messages.RetryErrorActionItem_errorDetailsDialogTitle, getDescriptionText(), error);
+		IStatus error = getError();
+		ErrorDialog.openError(getShell(), Messages.RetryErrorActionItem_errorDetailsDialogTitle, getDescriptionText(),
+				error);
 	}
 
 	protected void retry() {
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/SelectionModel.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/SelectionModel.java
index 340f745..4932de7 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/SelectionModel.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/SelectionModel.java
@@ -72,9 +72,29 @@
 	 * @param operation
 	 *            the operation to perform. Providing {@link Operation#NONE} removes the selection
 	 */
-	public void select(CatalogItem item, Operation operation) {
+	public boolean select(CatalogItem item, Operation operation) {
 		boolean changed = false;
-		if (operation == null || Operation.NONE == operation) {
+		Operation sanitizedOperation = operation;
+		if (operation != null && Operation.NONE != operation && item instanceof MarketplaceNodeCatalogItem) {
+			MarketplaceNodeCatalogItem nodeItem = (MarketplaceNodeCatalogItem) item;
+			List<Operation> availableOperations = nodeItem.getAvailableOperations();
+			if (!availableOperations.contains(operation)) {
+				sanitizedOperation = null;
+				switch (operation) {
+				case INSTALL:
+					if (availableOperations.contains(Operation.UPDATE)) {
+						sanitizedOperation = Operation.UPDATE;
+					}
+					break;
+				case UPDATE:
+					if (availableOperations.contains(Operation.INSTALL)) {
+						sanitizedOperation = Operation.UPDATE;
+					}
+					break;
+				}
+			}
+		}
+		if (sanitizedOperation == null || Operation.NONE == sanitizedOperation) {
 			if (itemToOperation.remove(item) != Operation.NONE) {
 				changed = true;
 			}
@@ -88,8 +108,8 @@
 				}
 			}
 		} else {
-			Operation previous = itemToOperation.put(item, operation);
-			if (previous != operation) {
+			Operation previous = itemToOperation.put(item, sanitizedOperation);
+			if (previous != sanitizedOperation) {
 				changed = true;
 				if (entries != null) {
 					Iterator<CatalogItemEntry> it = entries.iterator();
@@ -99,7 +119,7 @@
 							it.remove();
 						}
 					}
-					CatalogItemEntry itemEntry = createItemEntry(item, operation);
+					CatalogItemEntry itemEntry = createItemEntry(item, sanitizedOperation);
 					entries.add(itemEntry);
 				}
 			}
@@ -107,6 +127,7 @@
 		if (changed) {
 			selectionChanged();
 		}
+		return changed;
 	}
 
 	public List<CatalogItemEntry> getCatalogItemEntries() {
@@ -425,6 +446,15 @@
 		return Collections.unmodifiableMap(itemToOperation);
 	}
 
+	public Map<String, Operation> getItemIdToSelectedOperation() {
+		Map<CatalogItem, Operation> itemToSelectedOperation = getItemToSelectedOperation();
+		Map<String, Operation> itemIdToOperation = new HashMap<String, Operation>(itemToSelectedOperation.size());
+		for (Entry<CatalogItem, Operation> entry : itemToSelectedOperation.entrySet()) {
+			itemIdToOperation.put(entry.getKey().getId(), entry.getValue());
+		}
+		return itemIdToOperation;
+	}
+
 	public void selectionChanged() {
 		// ignore
 
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/UserFavoritesFindFavoritesActionItem.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/UserFavoritesFindFavoritesActionItem.java
index 5d95c33..f7e91d7 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/UserFavoritesFindFavoritesActionItem.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/UserFavoritesFindFavoritesActionItem.java
@@ -11,39 +11,63 @@
 package org.eclipse.epp.internal.mpc.ui.wizards;
 
 import org.eclipse.epp.internal.mpc.ui.catalog.UserActionCatalogItem;
-import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceViewer.ContentType;
-import org.eclipse.equinox.internal.p2.ui.discovery.wizards.DiscoveryResources;
-import org.eclipse.jface.window.IShellProvider;
-import org.eclipse.jface.wizard.IWizardPage;
+import org.eclipse.epp.mpc.ui.CatalogDescriptor;
+import org.eclipse.equinox.internal.p2.discovery.model.Icon;
 import org.eclipse.swt.widgets.Composite;
 
-public class UserFavoritesFindFavoritesActionItem extends AbstractUserActionLinksItem {
+public class UserFavoritesFindFavoritesActionItem extends AbstractUserActionItem {
 
-	private static final String BROWSE_ACTION_ID = "browse"; //$NON-NLS-1$
+	private static final int IMPORT_BUTTON_ID = 1;
 
-	public UserFavoritesFindFavoritesActionItem(Composite parent, DiscoveryResources resources,
-			IShellProvider shellProvider, UserActionCatalogItem element, final MarketplacePage marketplacePage) {
-		super(parent, resources, shellProvider, element, marketplacePage.getViewer());
-		createContent(new ImportFavoritesActionLink(marketplacePage),
-				new ActionLink(BROWSE_ACTION_ID,
-						Messages.UserFavoritesFindFavoritesActionItem_browsePopularActionLabel,
-						Messages.UserFavoritesFindFavoritesActionItem_browsePopularTooltip) {
+	private static final int BROWSE_BUTTON_ID = 0;
 
-			@Override
-			public void selected() {
-				MarketplaceWizard wizard = marketplacePage.getWizard();
-				IWizardPage currentPage = wizard.getContainer().getCurrentPage();
-				if (currentPage == marketplacePage
-						&& marketplacePage.getViewer().getContentType() == ContentType.FAVORITES) {
-							marketplacePage.setActiveTab(ContentType.POPULAR);
-				}
-			}
+	private final MarketplaceWizard wizard;
 
-		});
+	private final CatalogDescriptor descriptor;
+
+	public UserFavoritesFindFavoritesActionItem(Composite parent, MarketplaceDiscoveryResources resources,
+			UserActionCatalogItem connector, MarketplacePage page) {
+		super(parent, resources, connector, page.getViewer());
+		this.wizard = page.getWizard();
+		this.descriptor = wizard.getConfiguration().getCatalogDescriptor();
+	}
+
+	@Override
+	protected String getNameLabelText() {
+		return Messages.UserFavoritesFindFavoritesActionItem_title;
 	}
 
 	@Override
 	protected String getDescriptionText() {
 		return Messages.UserFavoritesFindFavoritesActionItem_noFavoritesYetMessage;
 	}
+
+	@Override
+	protected Icon getIcon() {
+		// TODO see https://bugs.eclipse.org/bugs/show_bug.cgi?id=516804
+		return null;
+	}
+
+	@Override
+	protected String getSublineText() {
+		return Messages.UserFavoritesFindFavoritesActionItem_subline;
+	}
+
+	@Override
+	protected void createButtons(Composite parent) {
+		createButton(parent, Messages.UserFavoritesFindFavoritesActionItem_BrowseButtonLabel, Messages.UserFavoritesFindFavoritesActionItem_BrowseButtonTooltip,
+				BROWSE_BUTTON_ID);
+		createButton(parent, Messages.UserFavoritesAbstractImportActionItem_importFavoritesActionLabel,
+				Messages.UserFavoritesAbstractImportActionItem_importFavoritesTooltip,
+				IMPORT_BUTTON_ID);
+	}
+
+	@Override
+	protected void buttonPressed(int id) {
+		if (id == BROWSE_BUTTON_ID) {
+			BrowseCatalogItem.openMarketplace(descriptor, (MarketplaceViewer) getViewer(), wizard);
+		} else {
+			ImportFavoritesActionLink.importFavorites(wizard);
+		}
+	}
 }
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/UserFavoritesLoginActionItem.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/UserFavoritesLoginActionItem.java
deleted file mode 100644
index 2e86449..0000000
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/UserFavoritesLoginActionItem.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2010 The Eclipse Foundation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *     The Eclipse Foundation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.epp.internal.mpc.ui.wizards;
-
-import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCatalog;
-import org.eclipse.epp.internal.mpc.ui.catalog.UserActionCatalogItem;
-import org.eclipse.equinox.internal.p2.ui.discovery.wizards.DiscoveryResources;
-import org.eclipse.jface.window.IShellProvider;
-import org.eclipse.osgi.util.NLS;
-import org.eclipse.swt.widgets.Composite;
-
-public class UserFavoritesLoginActionItem extends UserActionViewerItem<UserActionCatalogItem> {
-	public UserFavoritesLoginActionItem(Composite parent, DiscoveryResources resources, IShellProvider shellProvider,
-			UserActionCatalogItem element, MarketplaceViewer viewer) {
-		super(parent, resources, shellProvider, element, viewer);
-		createContent();
-	}
-
-	@Override
-	protected String getLinkText() {
-		String linkText = "<a>" + Messages.UserFavoritesLoginActionItem_logInActionLabel + "</a>"; //$NON-NLS-1$ //$NON-NLS-2$
-		UserActionCatalogItem loginItem = getData();
-		if (loginItem != null && loginItem.getData() != null && !"".equals(loginItem.getData())) { //$NON-NLS-1$
-			String loginMessage = (String) loginItem.getData();
-			loginMessage = loginMessage.trim();
-			linkText = NLS.bind(Messages.UserFavoritesLoginActionItem_retryLoginLabel, loginMessage);
-		}
-		return linkText;
-	}
-
-	@Override
-	protected void actionPerformed(Object data) {
-		final MarketplaceCatalog catalog = getViewer().getCatalog();
-		catalog.userFavorites(true, new NullProgressMonitor());
-		getViewer().updateContents();
-	}
-
-	@Override
-	protected MarketplaceViewer getViewer() {
-		return (MarketplaceViewer) super.getViewer();
-	}
-
-}
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/UserFavoritesSignInActionItem.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/UserFavoritesSignInActionItem.java
new file mode 100644
index 0000000..3aa6bcc
--- /dev/null
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/UserFavoritesSignInActionItem.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2010 The Eclipse Foundation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     The Eclipse Foundation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.epp.internal.mpc.ui.wizards;
+
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCatalog;
+import org.eclipse.epp.internal.mpc.ui.catalog.UserActionCatalogItem;
+import org.eclipse.equinox.internal.p2.discovery.model.Icon;
+import org.eclipse.equinox.internal.p2.ui.discovery.wizards.CatalogViewer;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Composite;
+
+public class UserFavoritesSignInActionItem extends AbstractUserActionItem {
+
+	public UserFavoritesSignInActionItem(Composite parent, MarketplaceDiscoveryResources resources,
+			UserActionCatalogItem connector, CatalogViewer viewer) {
+		super(parent, resources, connector, viewer);
+	}
+
+	@Override
+	protected String getNameLabelText() {
+		return Messages.SignInUserActionItem_signInActionLabel;
+	}
+
+	@Override
+	protected String getDescriptionText() {
+		UserActionCatalogItem loginItem = getData();
+		if (loginItem != null && loginItem.getData() != null && !"".equals(loginItem.getData())) { //$NON-NLS-1$
+			String loginMessage = (String) loginItem.getData();
+			loginMessage = loginMessage.trim();
+			return NLS.bind(Messages.SignInUserActionItem_retryLoginLabel, loginMessage);
+		}
+
+		return Messages.UserFavoritesSignInActionItem_SignInDescription;
+	}
+
+	@Override
+	protected Icon getIcon() {
+		// TODO see https://bugs.eclipse.org/bugs/show_bug.cgi?id=516804
+		return null;
+	}
+
+	@Override
+	protected String getSublineText() {
+		return Messages.UserFavoritesSignInActionItem_subline;
+	}
+
+	@Override
+	protected void createButtons(Composite parent) {
+		createButton(parent, Messages.UserFavoritesSignInActionItem_SignInButtonText, null, 0);
+	}
+
+	@Override
+	protected void buttonPressed(int id) {
+		MarketplaceViewer viewer = (MarketplaceViewer) getViewer();
+		final MarketplaceCatalog catalog = viewer.getCatalog();
+		catalog.userFavorites(true, new NullProgressMonitor());
+		viewer.updateContents();
+	}
+}
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/UserFavoritesUnsupportedActionItem.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/UserFavoritesUnsupportedActionItem.java
index f2088fc..ea061b7 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/UserFavoritesUnsupportedActionItem.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/UserFavoritesUnsupportedActionItem.java
@@ -11,28 +11,47 @@
 package org.eclipse.epp.internal.mpc.ui.wizards;
 
 import org.eclipse.epp.internal.mpc.ui.catalog.UserActionCatalogItem;
-import org.eclipse.equinox.internal.p2.ui.discovery.wizards.DiscoveryResources;
-import org.eclipse.jface.window.IShellProvider;
+import org.eclipse.equinox.internal.p2.discovery.model.Icon;
 import org.eclipse.swt.widgets.Composite;
 
-public class UserFavoritesUnsupportedActionItem extends UserActionViewerItem<UserActionCatalogItem> {
+public class UserFavoritesUnsupportedActionItem extends AbstractUserActionItem {
 
 	private final MarketplacePage marketplacePage;
 
-	public UserFavoritesUnsupportedActionItem(Composite parent, DiscoveryResources resources,
-			IShellProvider shellProvider, UserActionCatalogItem element, MarketplacePage marketplacePage) {
-		super(parent, resources, shellProvider, element, marketplacePage.getViewer());
+	public UserFavoritesUnsupportedActionItem(Composite parent, MarketplaceDiscoveryResources resources,
+			UserActionCatalogItem connector, MarketplacePage marketplacePage) {
+		super(parent, resources, connector, marketplacePage.getViewer());
 		this.marketplacePage = marketplacePage;
-		createContent();
 	}
 
 	@Override
-	protected String getLinkText() {
+	protected String getNameLabelText() {
 		return Messages.UserFavoritesUnsupportedActionItem_unsupportedFavoritesLabel;
 	}
 
 	@Override
-	protected void actionPerformed(Object data) {
+	protected String getDescriptionText() {
+		return Messages.UserFavoritesUnsupportedActionItem_Body;
+	}
+
+	@Override
+	protected Icon getIcon() {
+		// TODO see https://bugs.eclipse.org/bugs/show_bug.cgi?id=516804
+		return null;
+	}
+
+	@Override
+	protected String getSublineText() {
+		return Messages.UserFavoritesUnsupportedActionItem_Subline;
+	}
+
+	@Override
+	protected void createButtons(Composite parent) {
+		createButton(parent, Messages.UserFavoritesUnsupportedActionItem_GoBackButtonLabel, null, 0);
+	}
+
+	@Override
+	protected void buttonPressed(int id) {
 		marketplacePage.setPreviouslyActiveTab();
 	}
 }
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/messages.properties b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/messages.properties
index 8f700fa..5a21356 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/messages.properties
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/messages.properties
@@ -37,8 +37,12 @@
 DiscoveryItem_Unknown_Installs=?
 DiscoveryItem_UnknownProvider=Unknown
 DiscoveryItem_UnnamedSolution=<Unnamed Solution ''{0}''>
+FavoritesViewer_DeselectAll=Deselect All
 FavoritesViewer_searchInputDescription=Favorites Url
 FavoritesViewer_searchLabel=Import from:
+FavoritesViewer_SelectAll=Select All
+FavoritesViewer_SelectForInstallation=Also select entries for installation
+FavoritesViewer_SelectForInstallationTooltip=After importing the selected favorites, mark them for installation in the Marketplace wizard
 FeatureSelectionWizardPage_confirmSelectedFeatures=Confirm Selected Features
 FeatureSelectionWizardPage_confirmSelectedFeatures_description=Press Confirm to continue with the installation. Or go back to choose more solutions to install.
 FeatureSelectionWizardPage_details=Details
@@ -58,6 +62,7 @@
 ImportFavoritesActionLink_noFavoritesFoundForUser=No favorites list found for {0}
 ImportFavoritesPage_conflictErrorMessage=Failed to update your favorites, because they were changed on the server in the meantime.\nPress 'Next' to try again.
 ImportFavoritesPage_Description=Import another user's favorite Marketplace entries into your own Favorites list
+ImportFavoritesWizard_title=Import Favorites List
 ImportFavoritesWizardDialog_FinishButtonLabel=&Import
 ImportFavoritesPage_Title=Import Favorites List
 ImportFavoritesPage_unauthorizedErrorMessage=You need to log in to proceed. Press 'Next' to try again.
@@ -79,6 +84,8 @@
 MarketplaceDiscoveryResources_retrievingImage=Retrieving catalog image
 MarketplaceDropAdapter_0=Marketplace DND Initialization
 MarketplacePage_DefaultNewsTitle=News
+MarketplacePage_DeselectAll=Deselect all
+MarketplacePage_DeselectAllTooltip=Clear selected items
 MarketplacePage_discardPendingSolutions=There are solutions pending for installation. Switching the marketplace will discard your selection. Proceed?
 MarketplacePage_eclipseMarketplaceSolutions=Eclipse Marketplace Solutions
 MarketplacePage_favorites=Favorites
@@ -98,6 +105,7 @@
 MarketplaceViewer_Could_not_change_find_text=Could not set text for find field.
 MarketplaceViewer_featured=Featured
 MarketplaceViewer_go=&Go
+MarketplaceViewer_PopularBannerTitle=Popular Solutions
 MarketplaceViewer_unexpectedException=Unexpected exception
 MarketplaceWizard_cannotOpenUrl=Cannot open url {0}: {1}
 MarketplaceWizard_eclipseSolutionCatalogs=Eclipse Solution Catalogs
@@ -132,6 +140,7 @@
 RetryErrorActionItem_retryTooltip=Try loading this tab's contents again
 RetryErrorActionItem_showDetailsActionLabel=Show details
 RetryErrorActionItem_showDetailsTooltip=Show more details about the error
+RetryErrorActionItem_subline=Go back, or check out some popular solutions below.
 RetryErrorActionItem_unsupportedLinkMessage=Unsupported link: {0}
 SelectionModel_cannotInstallRemoveConcurrently=Cannot install and remove solutions concurrently
 SelectionModel_count_selectedFor_operation={0} selected for {1}
@@ -153,11 +162,21 @@
 ShareSolutionLink_Twitter=Twitter
 UserFavoritesAbstractImportActionItem_importFavoritesActionLabel=Import Favorites List...
 UserFavoritesAbstractImportActionItem_importFavoritesTooltip=Import another user's favorites into your own favorites list.
+UserFavoritesFindFavoritesActionItem_BrowseButtonLabel=Browse
+UserFavoritesFindFavoritesActionItem_BrowseButtonTooltip=Open the Marketplace in a browser and check out other users' favorites
 UserFavoritesFindFavoritesActionItem_browsePopularActionLabel=Browse popular entries
 UserFavoritesFindFavoritesActionItem_browsePopularTooltip=Find some interesting entries in the Marketplace
-UserFavoritesFindFavoritesActionItem_noFavoritesYetMessage=You don't have any favorites yet. Choose some favorite on the marketplace to see them here.
+UserFavoritesFindFavoritesActionItem_noFavoritesYetMessage=Choose some favorite on the marketplace to see them here, or import another user's favorites list.
+UserFavoritesFindFavoritesActionItem_subline=Below are some popular solutions to get you started.
+UserFavoritesFindFavoritesActionItem_title=You don't have any favorites yet
 UserFavoritesInstallAllActionItem_installAllActionLabel=Install all...
 UserFavoritesInstallAllActionItem_installAllTooltip=Select all your favorited entries for installation
-UserFavoritesLoginActionItem_logInActionLabel=Log in to view your favorites
-UserFavoritesLoginActionItem_retryLoginLabel=Login failed: {0} - <a>Retry</a>
-UserFavoritesUnsupportedActionItem_unsupportedFavoritesLabel=Favorites are not supported on this Marketplace. <a>Go back</a>
+UserFavoritesSignInActionItem_SignInButtonText=Sign in
+UserFavoritesSignInActionItem_SignInDescription=Please sign in with your eclipse.org account and authorize the Marketplace application to access your favorites.
+UserFavoritesSignInActionItem_subline=Meanwhile, check out some popular solutions below.
+SignInUserActionItem_signInActionLabel=Sign in to view your favorites
+SignInUserActionItem_retryLoginLabel=Sign in failed: {0} - Please retry.
+UserFavoritesUnsupportedActionItem_Body=This marketplace does not support favorite entries.
+UserFavoritesUnsupportedActionItem_GoBackButtonLabel=Go back
+UserFavoritesUnsupportedActionItem_Subline=Go back, or check out some popular solutions below.
+UserFavoritesUnsupportedActionItem_unsupportedFavoritesLabel=Favorites are not supported on this Marketplace.
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/IMarketplaceClientService.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/IMarketplaceClientService.java
index 885d191..49edae5 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/IMarketplaceClientService.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/IMarketplaceClientService.java
@@ -76,6 +76,20 @@
 	void openFavorites(IMarketplaceClientConfiguration configuration);
 
 	/**
+	 * Open the Favorites Import wizard, optionally initialized to the given favorites list.
+	 * <p>
+	 * After performing the import, the Marketplace wizard is opened for the
+	 * {@link IMarketplaceClientConfiguration#getCatalogDescriptor() active catalog}. Cancelling the import will not
+	 * open the Marketplace wizard.
+	 *
+	 * @param configuration
+	 *            the initial configuration applied to the MPC wizard
+	 * @param favoritesUrl
+	 *            The url to the Favorites list to import, or null to start with an empty dialog
+	 */
+	void openFavoritesImport(IMarketplaceClientConfiguration configuration, String favoritesUrl);
+
+	/**
 	 * Open the Marketplace Wizard showing the result of the given search on the
 	 * {@link IMarketplaceClientConfiguration#getCatalogDescriptor() active catalog}.
 	 *
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/MarketplaceUrlHandler.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/MarketplaceUrlHandler.java
index 4fcb1b6..44101b1 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/MarketplaceUrlHandler.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/MarketplaceUrlHandler.java
@@ -34,6 +34,7 @@
 import org.eclipse.epp.internal.mpc.core.util.URLUtil;
 import org.eclipse.epp.internal.mpc.ui.CatalogRegistry;
 import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi;
+import org.eclipse.epp.internal.mpc.ui.commands.ImportFavoritesWizardCommand;
 import org.eclipse.epp.internal.mpc.ui.commands.MarketplaceWizardCommand;
 import org.eclipse.epp.mpc.core.model.INode;
 import org.eclipse.osgi.util.NLS;
@@ -61,6 +62,8 @@
 
 	private static final Pattern NODE_URL_PATTERN = Pattern.compile("(?:^|/)node/([^/#?]+)"); //$NON-NLS-1$
 
+	private static final Pattern FAVORITES_URL_PATTERN = Pattern.compile("(?:^|/)user/([^/#?]+)/favorites(/?[#?].*)?$"); //$NON-NLS-1$
+
 	public static class SolutionInstallationInfo {
 
 		private String requestUrl;
@@ -81,14 +84,26 @@
 			this.catalogDescriptor = catalogDescriptor;
 		}
 
+		public void setInstallId(String installId) {
+			this.installId = installId;
+		}
+
 		public String getInstallId() {
 			return installId;
 		}
 
+		public void setState(String state) {
+			this.state = state;
+		}
+
 		public String getState() {
 			return state;
 		}
 
+		public void setCatalogDescriptor(CatalogDescriptor catalogDescriptor) {
+			this.catalogDescriptor = catalogDescriptor;
+		}
+
 		public CatalogDescriptor getCatalogDescriptor() {
 			return catalogDescriptor;
 		}
@@ -102,7 +117,7 @@
 		}
 	}
 
-	protected static final String UTF_8 = "UTF-8"; //$NON-NLS-1$
+	public static final String UTF_8 = "UTF-8"; //$NON-NLS-1$
 
 	private static final String PARAM_SPLIT_REGEX = "&"; //$NON-NLS-1$
 
@@ -121,14 +136,7 @@
 			state = query.get(MPC_STATE);
 		}
 		if (installId != null) {
-			CatalogDescriptor descriptor = CatalogRegistry.getInstance().findCatalogDescriptor(url);
-			if (descriptor == null) {
-				try {
-					descriptor = new CatalogDescriptor(URLUtil.toURL(url), DESCRIPTOR_HINT);
-				} catch (MalformedURLException e) {
-					return null;
-				}
-			}
+			CatalogDescriptor descriptor = findCatalogDescriptor(url, true);
 			SolutionInstallationInfo info = new SolutionInstallationInfo(installId, state, descriptor);
 			info.setRequestUrl(url);
 			return info;
@@ -136,6 +144,18 @@
 		return null;
 	}
 
+	private static CatalogDescriptor findCatalogDescriptor(String url, boolean allowUnknown) {
+		CatalogDescriptor descriptor = CatalogRegistry.getInstance().findCatalogDescriptor(url);
+		if (descriptor == null && allowUnknown) {
+			try {
+				descriptor = new CatalogDescriptor(URLUtil.toURL(url), DESCRIPTOR_HINT);
+			} catch (MalformedURLException e) {
+				return null;
+			}
+		}
+		return descriptor;
+	}
+
 	public static String getMPCState(String url) {
 		Map<String, String> query = parseQuery(url);
 		return query == null ? null : query.get(MPC_STATE);
@@ -168,6 +188,10 @@
 		return url != null && url.contains(MPC_INSTALL);
 	}
 
+	public static boolean isPotentialFavoritesList(String url) {
+		return url != null && FAVORITES_URL_PATTERN.matcher(url).find();
+	}
+
 	public static void triggerInstall(SolutionInstallationInfo info) {
 		if (info.getRequestUrl() != null) {
 			MarketplaceClientUi.getLog().log(
@@ -197,6 +221,20 @@
 		}
 	}
 
+	public static void triggerFavorites(String favoritesUrl) {
+		CatalogDescriptor catalogDescriptor = findCatalogDescriptor(favoritesUrl, true);
+		ImportFavoritesWizardCommand command = new ImportFavoritesWizardCommand();
+		command.setSelectedCatalogDescriptor(catalogDescriptor);
+		command.setFavoritesUrl(favoritesUrl);
+		try {
+			command.execute(new ExecutionEvent());
+		} catch (ExecutionException e) {
+			IStatus status = MarketplaceClientCore.computeStatus(e,
+					Messages.MarketplaceUrlHandler_cannotOpenMarketplaceWizard);
+			MarketplaceClientUi.handle(status, StatusManager.SHOW | StatusManager.BLOCK | StatusManager.LOG);
+		}
+	}
+
 	public boolean handleUri(String uri) {
 		if (isPotentialSolution(uri)) {
 			SolutionInstallationInfo installInfo = createSolutionInstallInfo(uri);
@@ -232,7 +270,7 @@
 		}
 		String relativeUri = uri.substring(baseUri.length());
 		if (relativeUri.startsWith(DefaultMarketplaceService.API_FAVORITES_URI)) {
-			return handleFavorites(descriptor, relativeUri);
+			return handleTopFavorites(descriptor, relativeUri);
 		} else if (relativeUri.startsWith(DefaultMarketplaceService.API_FEATURED_URI)) {
 			return handleFeatured(descriptor, relativeUri);
 		} else if (relativeUri.startsWith(DefaultMarketplaceService.API_NODE_CONTENT_URI)) {
@@ -414,7 +452,7 @@
 		return false;
 	}
 
-	protected boolean handleFavorites(CatalogDescriptor descriptor, String url) {
+	protected boolean handleTopFavorites(CatalogDescriptor descriptor, String url) {
 		return false;
 	}