511218: Provide a Favorites entry to the Eclipse Welcome Screen

Show "install favorites" banner the first time MPC is opened per
installation, or when triggered from the Welcome screen

Bug: 511218
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=511218
diff --git a/org.eclipse.epp.mpc.ui/icons/marketplace_banner.png b/org.eclipse.epp.mpc.ui/icons/marketplace_banner.png
new file mode 100644
index 0000000..5d6eab9
--- /dev/null
+++ b/org.eclipse.epp.mpc.ui/icons/marketplace_banner.png
Binary files differ
diff --git a/org.eclipse.epp.mpc.ui/plugin.xml b/org.eclipse.epp.mpc.ui/plugin.xml
index fb6e067..16aa68f 100644
--- a/org.eclipse.epp.mpc.ui/plugin.xml
+++ b/org.eclipse.epp.mpc.ui/plugin.xml
@@ -38,6 +38,11 @@
             description="%command.open.description"
             id="org.eclipse.epp.mpc.ui.command.showMarketplaceWizard"
             name="%command.open.name">
+         <commandParameter
+               id="trigger"
+               name="trigger"
+               optional="true">
+         </commandParameter>
       </command>
       <command
             description="%command.importFavorites.description"
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/MarketplaceClientUiPlugin.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/MarketplaceClientUiPlugin.java
index 16cd04e..bf6fb35 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/MarketplaceClientUiPlugin.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/MarketplaceClientUiPlugin.java
@@ -80,6 +80,8 @@
 
 	public static final String NO_ICON_PROVIDED_CATALOG = "NO_ICON_PROVIDED_CATALOG"; //$NON-NLS-1$
 
+	public static final String DEFAULT_MARKETPLACE_ICON = "DEFAULT_MARKETPLACE_ICON"; //$NON-NLS-1$
+
 	public static final String ITEM_ICON_STAR = "ITEM_ICON_STAR"; //$NON-NLS-1$
 
 	public static final String ITEM_ICON_STAR_SELECTED = "ITEM_ICON_STAR_SELECTED"; //$NON-NLS-1$
@@ -160,6 +162,8 @@
 				"icons/noiconprovided.png")); //$NON-NLS-1$
 		imageRegistry.put(NO_ICON_PROVIDED_CATALOG,
 				imageDescriptorFromPlugin(getBundle().getSymbolicName(), "icons/noiconprovided32.png")); //$NON-NLS-1$
+		imageRegistry.put(DEFAULT_MARKETPLACE_ICON,
+				imageDescriptorFromPlugin(getBundle().getSymbolicName(), "icons/marketplace_banner.png")); //$NON-NLS-1$
 		imageRegistry.put(IU_ICON, imageDescriptorFromPlugin(getBundle().getSymbolicName(), "icons/iu_obj.gif")); //$NON-NLS-1$
 		imageRegistry.put(IU_ICON_UPDATE, imageDescriptorFromPlugin(getBundle().getSymbolicName(),
 				"icons/iu_update_obj.gif")); //$NON-NLS-1$
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 384c2ae..fae1bb3 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
@@ -788,6 +788,10 @@
 		addUserActionItem(catalogCategory, UserAction.RETRY_ERROR, ex);
 	}
 
+	public void addOpenFavoritesItem(MarketplaceCategory catalogCategory) {
+		addUserActionItem(catalogCategory, UserAction.OPEN_FAVORITES);
+	}
+
 	public void installed(IProgressMonitor monitor) throws CoreException {
 		SubMonitor progress = SubMonitor.convert(monitor, Messages.MarketplaceDiscoveryStrategy_findingInstalled,
 				1000);
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/UserActionCatalogItem.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/UserActionCatalogItem.java
index c914196..dfbb4f9 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/UserActionCatalogItem.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/UserActionCatalogItem.java
@@ -14,7 +14,7 @@
 
 public class UserActionCatalogItem extends CatalogItem {
 	public static enum UserAction {
-		BROWSE, LOGIN, CREATE_FAVORITES, FAVORITES_UNSUPPORTED, RETRY_ERROR, INFO;
+		BROWSE, LOGIN, CREATE_FAVORITES, FAVORITES_UNSUPPORTED, RETRY_ERROR, INFO, OPEN_FAVORITES;
 	}
 
 	private UserAction userAction;
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 e2a0812..f56c03d 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
@@ -34,7 +34,6 @@
 import org.eclipse.epp.mpc.core.model.ICategory;
 import org.eclipse.epp.mpc.core.model.IMarket;
 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.model.Tag;
 import org.eclipse.equinox.internal.p2.ui.discovery.util.WorkbenchUtil;
@@ -51,6 +50,8 @@
  */
 public class MarketplaceWizardCommand extends AbstractMarketplaceWizardCommand implements IHandler {
 
+	private static final String TRIGGER_PARAMETER = "trigger"; //$NON-NLS-1$
+
 	private String wizardState;
 
 	private Map<String, Operation> operations;
@@ -130,6 +131,8 @@
 		MarketplaceWizard wizard = new MarketplaceWizard(catalog, configuration);
 		wizard.setInitialState(wizardDialogState);
 		wizard.setWindowTitle(Messages.MarketplaceWizardCommand_eclipseMarketplace);
+		String trigger = event.getParameter(TRIGGER_PARAMETER);
+		wizard.setTrigger(trigger);
 		return wizard;
 	}
 
@@ -183,8 +186,9 @@
 		this.operations = operationByNodeId;
 	}
 
+	@Override
 	public void setConfiguration(IMarketplaceClientConfiguration configuration) {
-	   super.setConfiguration(configuration);
+		super.setConfiguration(configuration);
 		setOperations(configuration.getInitialOperations());
 		setWizardState((String) configuration.getInitialState());
 	}
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 aaea77b..7f15be4 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
@@ -76,6 +76,8 @@
  */
 public abstract class AbstractMarketplaceDiscoveryItem<T extends CatalogItem> extends AbstractDiscoveryItem<T> {
 
+	protected static final String REGISTRY_SCHEME = "registry:"; //$NON-NLS-1$
+
 	private static final String FILE_EXTENSION_TAG_PREFIX = "fileExtension_"; //$NON-NLS-1$
 
 	private static final String ELLIPSIS = new String("\u2026"); //$NON-NLS-1$
@@ -234,7 +236,7 @@
 		createInstallButtons(parent);
 	}
 
-	private void createIconContainer(Composite parent) {
+	protected void createIconContainer(Composite parent) {
 		checkboxContainer = new Composite(parent, SWT.NONE);
 		GridDataFactory.swtDefaults()
 		.indent(0, DESCRIPTION_MARGIN_TOP)
@@ -421,39 +423,46 @@
 		if (iconLabel == null) {
 			return;
 		}
-		String iconPath = getResources().getIconPath(icon, size, fallback);
-		getResources().setImage(
-				new ImageReceiver() {
+		ImageReceiver receiver = new ImageReceiver() {
 
-					public void setImage(Image image) {
-						if (image == null || image.isDisposed() || iconLabel.isDisposed()) {
-							return;
-						}
-						try {
-							Rectangle bounds = image.getBounds();
-							if (bounds.width < 0.8 * MAX_IMAGE_WIDTH || bounds.width > MAX_IMAGE_WIDTH
-									|| bounds.height > MAX_IMAGE_HEIGHT) {
-								final Image scaledImage = Util.scaleImage(image, MAX_IMAGE_WIDTH, MAX_IMAGE_HEIGHT);
-								image = scaledImage;
-								iconLabel.addDisposeListener(new DisposeListener() {
-									public void widgetDisposed(DisposeEvent e) {
-										scaledImage.dispose();
-									}
-								});
+			public void setImage(Image image) {
+				if (image == null || image.isDisposed() || iconLabel.isDisposed()) {
+					return;
+				}
+				try {
+					Rectangle bounds = image.getBounds();
+					if (bounds.width < 0.8 * MAX_IMAGE_WIDTH || bounds.width > MAX_IMAGE_WIDTH
+							|| bounds.height > MAX_IMAGE_HEIGHT) {
+						final Image scaledImage = Util.scaleImage(image, MAX_IMAGE_WIDTH, MAX_IMAGE_HEIGHT);
+						image = scaledImage;
+						iconLabel.addDisposeListener(new DisposeListener() {
+							public void widgetDisposed(DisposeEvent e) {
+								scaledImage.dispose();
 							}
-							iconLabel.setImage(image);
-						} catch (SWTException e) {
-							// ignore, probably a bad image format
+						});
+					}
+					iconLabel.setImage(image);
+				} catch (SWTException e) {
+					// ignore, probably a bad image format
 //							MarketplaceClientUi.error(NLS.bind(Messages.DiscoveryItem_cannotRenderImage_reason, connector.getIcon()
 //									.getImage32(), e.getMessage()), e);
-						}
-					}
-				},
-				source,
-				iconPath,
-				MarketplaceClientUiPlugin.getInstance()
-				.getImageRegistry()
-				.get(MarketplaceClientUiPlugin.NO_ICON_PROVIDED));
+				}
+			}
+		};
+		String iconPath = getResources().getIconPath(icon, size, fallback);
+		if (iconPath.startsWith(REGISTRY_SCHEME)) {
+			String key = iconPath.substring(REGISTRY_SCHEME.length());
+			Image image = MarketplaceClientUiPlugin.getInstance().getImageRegistry().get(key);
+			receiver.setImage(image);
+		} else {
+			getResources().setImage(
+					receiver,
+					source,
+					iconPath,
+					MarketplaceClientUiPlugin.getInstance()
+					.getImageRegistry()
+					.get(MarketplaceClientUiPlugin.NO_ICON_PROVIDED));
+		}
 	}
 
 	public MarketplaceDiscoveryResources getResources() {
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/AbstractUserActionLinksItem.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/AbstractUserActionLinksItem.java
deleted file mode 100644
index e211014..0000000
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/AbstractUserActionLinksItem.java
+++ /dev/null
@@ -1,112 +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 java.text.MessageFormat;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.eclipse.epp.internal.mpc.ui.catalog.UserActionCatalogItem;
-import org.eclipse.equinox.internal.p2.ui.discovery.wizards.DiscoveryResources;
-import org.eclipse.jface.layout.GridDataFactory;
-import org.eclipse.jface.layout.GridLayoutFactory;
-import org.eclipse.jface.window.IShellProvider;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Listener;
-
-public abstract class AbstractUserActionLinksItem extends UserActionViewerItem<UserActionCatalogItem> {
-
-	private final Map<String, ActionLink> actions = new HashMap<String, ActionLink>();
-
-	public AbstractUserActionLinksItem(Composite parent, DiscoveryResources resources,
-			IShellProvider shellProvider,
-			UserActionCatalogItem element, MarketplaceViewer viewer) {
-		super(parent, resources, shellProvider, element, viewer);
-	}
-
-	protected void createContent(ActionLink... actionLinks) {
-		Composite parent = this;
-		GridLayoutFactory.swtDefaults().numColumns(1).applyTo(parent);
-
-		int vAlignLinks = SWT.CENTER;
-		String descriptionText = getDescriptionText();
-		if (descriptionText != null) {
-			Label descriptionLabel = new Label(parent, SWT.CENTER);
-			descriptionLabel.setText(descriptionText);
-			GridDataFactory.swtDefaults()
-			.grab(true, false)
-			.align(SWT.CENTER, SWT.END)
-			.applyTo(descriptionLabel);
-			vAlignLinks = SWT.BEGINNING;
-		}
-		Listener listener = new Listener() {
-			public void handleEvent(Event event) {
-				Object data = event.data;
-				if (data == null) {
-					data = event.text;
-					if (data == null) {
-						data = event.widget.getData();
-					}
-				}
-				actionPerformed(data);
-			}
-		};
-		Composite linkParent = new Composite(parent, SWT.NONE);
-		GridDataFactory.swtDefaults().grab(true, false).align(SWT.CENTER, vAlignLinks).applyTo(linkParent);
-		GridLayoutFactory.swtDefaults().numColumns(3).applyTo(linkParent);
-
-		boolean first = true;
-		for (ActionLink actionLink : actionLinks) {
-			actions.put(actionLink.getId(), actionLink);
-			if (first) {
-				first = false;
-			} else {
-				Label separator = new Label(linkParent, SWT.CENTER);
-				separator.setText(" | "); //$NON-NLS-1$
-				GridDataFactory.swtDefaults().align(SWT.CENTER, vAlignLinks).applyTo(separator);
-			}
-			String linkText = getLinkText(actionLink);
-			String tooltip = actionLink.getTooltip();
-			if (tooltip == null) {
-				tooltip = getLinkToolTipText();
-			}
-			Control link = createActionLink(linkParent, linkText, tooltip);
-			link.setData(actionLink.getId());
-			link.addListener(SWT.Selection, listener);
-			GridDataFactory.swtDefaults().align(SWT.END, vAlignLinks).applyTo(link);
-		}
-	}
-
-	private String getLinkText(ActionLink actionLink) {
-		return MessageFormat.format("<a href=\"{0}\">{1}</a>", actionLink.getId(), actionLink.getLabel()); //$NON-NLS-1$
-	}
-
-	protected String getDescriptionText() {
-		return null;
-	}
-
-	@Override
-	protected String getLinkText() {
-		return null;
-	}
-
-	@Override
-	protected void actionPerformed(Object data) {
-		ActionLink actionLink = actions.get(data);
-		if (actionLink != null) {
-			actionLink.selected();
-		}
-	}
-}
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 1f27e46..26fd831 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
@@ -311,6 +311,15 @@
 			if (discoveryStrategy instanceof MarketplaceDiscoveryStrategy) {
 				MarketplaceDiscoveryStrategy marketplaceDiscoveryStrategy = (MarketplaceDiscoveryStrategy) discoveryStrategy;
 				marketplaceDiscoveryStrategy.addLoginListener(loginListener);
+				for (CatalogCategory catalogCategory : catalog.getCategories()) {
+					if (catalogCategory instanceof MarketplaceCategory) {
+						MarketplaceCategory marketplaceCategory = (MarketplaceCategory) catalogCategory;
+						if (marketplaceCategory.getContents() == Contents.FEATURED
+								&& getWizard().shouldShowOpenFavoritesBanner()) {
+							marketplaceDiscoveryStrategy.addOpenFavoritesItem(marketplaceCategory);
+						}
+					}
+				}
 			}
 		}
 		runUpdate(new Runnable() {
@@ -398,6 +407,9 @@
 			return new UserFavoritesSignInActionItem(parent, getResources(), catalogItem, this);
 		case RETRY_ERROR:
 			return new RetryErrorActionItem(parent, getResources(), catalogItem, this);
+		case OPEN_FAVORITES:
+			getWizard().didShowOpenFavoritesBanner();
+			return new OpenFavoritesNotificationItem(parent, getResources(), catalogItem, getWizard().getCatalogPage());
 		}
 		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 5c9b9b9..69afafd 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
@@ -43,6 +43,8 @@
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.preferences.ConfigurationScope;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
 import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore;
 import org.eclipse.epp.internal.mpc.core.model.News;
 import org.eclipse.epp.internal.mpc.ui.CatalogRegistry;
@@ -103,6 +105,7 @@
 import org.eclipse.ui.browser.IWorkbenchBrowserSupport;
 import org.eclipse.ui.internal.browser.WorkbenchBrowserSupport;
 import org.eclipse.ui.statushandlers.StatusManager;
+import org.osgi.service.prefs.BackingStoreException;
 
 /**
  * A wizard for interacting with a marketplace service.
@@ -112,6 +115,10 @@
  */
 public class MarketplaceWizard extends DiscoveryWizard implements InstallProfile, IMarketplaceWebBrowser {
 
+	private static final String WELCOME_TRIGGER_ID = "welcome"; //$NON-NLS-1$
+
+	private static final String OPEN_FAVORITES_NOTIFICATION_PREFERENCE = "showOpenFavoritesNotification"; //$NON-NLS-1$
+
 	private static final String PREF_DEFAULT_CATALOG = CatalogDescriptor.class.getSimpleName();
 
 	private static final String DEBUG_NEWS_FLAG = MarketplaceClientUi.BUNDLE_ID + "/news/debug"; //$NON-NLS-1$
@@ -204,10 +211,14 @@
 
 	private boolean withRemediation;
 
+	private String trigger;
+
 	private String errorMessage;
 
 	private WizardState initialState;
 
+	private boolean openFavoritesBannerShown;
+
 	public String getErrorMessage() {
 		return errorMessage;
 	}
@@ -1025,6 +1036,39 @@
 		return false;
 	}
 
+	protected boolean shouldShowOpenFavoritesBanner() {
+		if (openFavoritesBannerShown) {
+			return false;
+		}
+		if (alwaysShowForTrigger()) {
+			return true;
+		}
+		boolean show = isFirstTimeInInstallation();
+		return show;
+	}
+
+	protected boolean isFirstTimeInInstallation() {
+		return ConfigurationScope.INSTANCE.getNode(MarketplaceClientUi.BUNDLE_ID)
+				.getBoolean(OPEN_FAVORITES_NOTIFICATION_PREFERENCE, true);
+	}
+
+	protected boolean alwaysShowForTrigger() {
+		return trigger != null && WELCOME_TRIGGER_ID.equals(trigger);
+	}
+
+	protected void didShowOpenFavoritesBanner() {
+		openFavoritesBannerShown = true;
+		IEclipsePreferences node = ConfigurationScope.INSTANCE.getNode(MarketplaceClientUi.BUNDLE_ID);
+		if (node.getBoolean(OPEN_FAVORITES_NOTIFICATION_PREFERENCE, true)) {
+			node.putBoolean(OPEN_FAVORITES_NOTIFICATION_PREFERENCE, false);
+			try {
+				node.flush();
+			} catch (BackingStoreException e) {
+				MarketplaceClientUi.error(e);
+			}
+		}
+	}
+
 	public Object suspendWizard() {
 		String catalogUrl = getCatalogUrl();
 		String key = appendWizardState(catalogUrl);
@@ -1040,6 +1084,14 @@
 		return initialState;
 	}
 
+	public String getTrigger() {
+		return trigger;
+	}
+
+	public void setTrigger(String trigger) {
+		this.trigger = trigger;
+	}
+
 	public static void resumeWizard(Display display, Object state, boolean proceedWithInstall) {
 		String catalogUrl = (String) state;
 		if (proceedWithInstall) {
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 8651b01..d1a5cec 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
@@ -244,6 +244,12 @@
 
 	public static String NewsViewer_No_news;
 
+	public static String OpenFavoritesNotificationItem_description;
+
+	public static String OpenFavoritesNotificationItem_InstallButtonLabel;
+
+	public static String OpenFavoritesNotificationItem_title;
+
 	public static String Operation_install;
 
 	public static String Operation_uninstall;
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/OpenFavoritesNotificationItem.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/OpenFavoritesNotificationItem.java
new file mode 100644
index 0000000..a6f50b1
--- /dev/null
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/OpenFavoritesNotificationItem.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * 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.MarketplaceClientUiPlugin;
+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.discovery.model.Icon;
+import org.eclipse.swt.widgets.Composite;
+
+public class OpenFavoritesNotificationItem extends AbstractUserActionItem {
+
+	private final MarketplacePage marketplacePage;
+
+	public OpenFavoritesNotificationItem(Composite parent, MarketplaceDiscoveryResources resources,
+			UserActionCatalogItem connector, MarketplacePage page) {
+		super(parent, resources, connector, page.getViewer());
+		this.marketplacePage = page;
+	}
+
+	@Override
+	protected boolean alignIconWithName() {
+		return true;
+	}
+
+	@Override
+	protected Icon getIcon() {
+		String path = REGISTRY_SCHEME + MarketplaceClientUiPlugin.DEFAULT_MARKETPLACE_ICON;
+		Icon icon = new Icon();
+		icon.setImage128(path);
+		icon.setImage64(path);
+		icon.setImage32(path);
+		icon.setImage16(path);
+		return icon;
+	}
+
+	@Override
+	protected String getDescriptionText() {
+		return Messages.OpenFavoritesNotificationItem_description;
+	}
+
+	@Override
+	protected String getNameLabelText() {
+		return Messages.OpenFavoritesNotificationItem_title;
+	}
+
+	@Override
+	protected void createButtons(Composite parent) {
+		createButton(parent, Messages.OpenFavoritesNotificationItem_InstallButtonLabel, null, 0);
+	}
+
+	@Override
+	protected void buttonPressed(int id) {
+		marketplacePage.setActiveTab(ContentType.FAVORITES);
+	}
+}
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 5a21356..6b4a4a7 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
@@ -123,6 +123,9 @@
 NewsViewer_Loading=Loading
 NewsViewer_No_embeddable_browser=No embeddable Browser component was found for your platform. Please click here to open the news in an external browser:
 NewsViewer_No_news=(No news available)
+OpenFavoritesNotificationItem_description=If you already have some favorite Marketplace entries, now is the perfect time to install them.
+OpenFavoritesNotificationItem_InstallButtonLabel=Install Favorites...
+OpenFavoritesNotificationItem_title=Welcome to the Eclipse Marketplace
 Operation_install=install
 Operation_uninstall=uninstall
 Operation_unknownOperation=Unknown operation: {0}