461603: Add an "intro" item that opens MPC on the "Eclipse Projects" market

- add a featured market tab, controlled by the branding info
- support opening MPC directly on that tab via IMarketplaceClientUiService

Bug: 461603
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=461603
diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/CatalogBranding.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/CatalogBranding.java
index 11fbc51..251404c 100644
--- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/CatalogBranding.java
+++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/CatalogBranding.java
@@ -7,7 +7,7 @@
  *
  * Contributors:
  *      The Eclipse Foundation  - initial API and implementation
- *      Yatta Solutions - bug 432803: public API
+ *      Yatta Solutions - bug 432803: public API, bug 461603: featured market
  *******************************************************************************/
 package org.eclipse.epp.internal.mpc.core.service;
 
@@ -39,6 +39,10 @@
 
 	private String relatedTabName;
 
+	private boolean hasFeaturedMarketTab;
+
+	private String featuredMarketTabName;
+
 	public String getWizardIcon() {
 		return wizardIcon;
 	}
@@ -111,6 +115,22 @@
 		this.relatedTabName = relatedTabName;
 	}
 
+	public boolean hasFeaturedMarketTab() {
+		return hasFeaturedMarketTab;
+	}
+
+	public void setHasFeaturedMarketTab(boolean hasFeaturedMarketTab) {
+		this.hasFeaturedMarketTab = hasFeaturedMarketTab;
+	}
+
+	public String getFeaturedMarketTabName() {
+		return featuredMarketTabName;
+	}
+
+	public void setFeaturedMarketTabName(String featuredMarketTabName) {
+		this.featuredMarketTabName = featuredMarketTabName;
+	}
+
 	public String getWizardTitle() {
 		return wizardTitle;
 	}
diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/xml/CatalogBrandingContentHandler.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/xml/CatalogBrandingContentHandler.java
index c5a302e..a3f5ecf 100644
--- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/xml/CatalogBrandingContentHandler.java
+++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/xml/CatalogBrandingContentHandler.java
@@ -7,6 +7,7 @@
  *
  * Contributors:
  *     The Eclipse Foundation - initial API and implementation
+ *     Yatta Solutions - bug 461603: featured market
  *******************************************************************************/
 package org.eclipse.epp.internal.mpc.core.service.xml;
 
@@ -25,23 +26,26 @@
 
 	@Override
 	public void startElement(String uri, String localName, Attributes attributes) {
-		if (localName.equals("wizard")) { //$NON-NLS-1$
+		if (localName.equalsIgnoreCase("wizard")) { //$NON-NLS-1$
 			model = new CatalogBranding();
 
 			model.setWizardTitle(attributes.getValue(NS_URI, "title")); //$NON-NLS-1$
-		} else if (localName.equals("icon")) { //$NON-NLS-1$
+		} else if (localName.equalsIgnoreCase("icon")) { //$NON-NLS-1$
 			capturingContent = true;
-		} else if (localName.equals("searchtab")) { //$NON-NLS-1$
-			model.setHasSearchTab("1".equals(attributes.getValue(NS_URI, "enabled"))); //$NON-NLS-1$//$NON-NLS-2$
+		} else if (localName.equalsIgnoreCase("searchtab")) { //$NON-NLS-1$
+			model.setHasSearchTab(toBoolean(attributes.getValue(NS_URI, "enabled"))); //$NON-NLS-1$
 			capturingContent = true;
-		} else if (localName.equals("populartab")) { //$NON-NLS-1$
-			model.setHasPopularTab("1".equals(attributes.getValue(NS_URI, "enabled"))); //$NON-NLS-1$//$NON-NLS-2$
+		} else if (localName.equalsIgnoreCase("populartab")) { //$NON-NLS-1$
+			model.setHasPopularTab(toBoolean(attributes.getValue(NS_URI, "enabled"))); //$NON-NLS-1$
 			capturingContent = true;
-		} else if (localName.equals("recenttab")) { //$NON-NLS-1$
-			model.setHasRecentTab("1".equals(attributes.getValue(NS_URI, "enabled"))); //$NON-NLS-1$//$NON-NLS-2$
+		} else if (localName.equalsIgnoreCase("recenttab")) { //$NON-NLS-1$
+			model.setHasRecentTab(toBoolean(attributes.getValue(NS_URI, "enabled"))); //$NON-NLS-1$
 			capturingContent = true;
-		} else if (localName.equals("relatedtab") || localName.equals("recommendationtab")) { //$NON-NLS-1$
-			model.setHasRelatedTab("1".equals(attributes.getValue(NS_URI, "enabled"))); //$NON-NLS-1$//$NON-NLS-2$
+		} else if (localName.equalsIgnoreCase("featuredmarkettab")) { //$NON-NLS-1$
+			model.setHasFeaturedMarketTab(toBoolean(attributes.getValue(NS_URI, "enabled"))); //$NON-NLS-1$
+			capturingContent = true;
+		} else if (localName.equalsIgnoreCase("relatedtab") || localName.equalsIgnoreCase("recommendationtab")) { //$NON-NLS-1$ //$NON-NLS-2$
+			model.setHasRelatedTab(toBoolean(attributes.getValue(NS_URI, "enabled"))); //$NON-NLS-1$
 			capturingContent = true;
 		}
 	}
diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/xml/UnmarshalContentHandler.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/xml/UnmarshalContentHandler.java
index 0b0a39a..a7598e1 100644
--- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/xml/UnmarshalContentHandler.java
+++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/xml/UnmarshalContentHandler.java
@@ -96,7 +96,7 @@
 		if (string.length() == 0) {
 			return null;
 		}
-		return "1".equals(string) || "true".equals(string); //$NON-NLS-1$ //$NON-NLS-2$
+		return "1".equals(string) || "true".equalsIgnoreCase(string); //$NON-NLS-1$ //$NON-NLS-2$
 	}
 
 	protected Integer toInteger(String string) {
diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ICatalogBranding.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ICatalogBranding.java
index ca6b8ff..27903dd 100644
--- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ICatalogBranding.java
+++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ICatalogBranding.java
@@ -7,7 +7,7 @@
  *
  * Contributors:
  *     The Eclipse Foundation - initial API and implementation
- *     Yatta Solutions - bug 432803: public API
+ *     Yatta Solutions - bug 432803: public API, bug 461603: featured market
  *******************************************************************************/
 package org.eclipse.epp.mpc.core.model;
 
@@ -40,6 +40,10 @@
 
 	String getRelatedTabName();
 
+	boolean hasFeaturedMarketTab();
+
+	String getFeaturedMarketTabName();
+
 	String getWizardTitle();
 
 }
\ No newline at end of file
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceCatalog.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceCatalog.java
index 0f2b63f..7b8d92a 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceCatalog.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceCatalog.java
@@ -8,6 +8,7 @@
  * Contributors:
  * 	The Eclipse Foundation - initial API and implementation
  * 	Yatta Solutions - error handling (bug 374105), news (bug 401721), public API (bug 432803)
+ * 	                  featured market (bug 461603)
  *******************************************************************************/
 package org.eclipse.epp.internal.mpc.ui.catalog;
 
@@ -496,4 +497,19 @@
 	public void setNews(INews news) {
 		this.news = news;
 	}
+
+	public List<IMarket> getMarkets() {
+		List<IMarket> markets = new ArrayList<IMarket>();
+		for (CatalogCategory category : getCategories()) {
+			if (category instanceof MarketplaceCategory) {
+				MarketplaceCategory marketplaceCategory = (MarketplaceCategory) category;
+				for (IMarket market : marketplaceCategory.getMarkets()) {
+					if (!markets.contains(market)) {
+						markets.add(market);
+					}
+				}
+			}
+		}
+		return markets;
+	}
 }
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 35f7d69..89f85d7 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
@@ -9,7 +9,7 @@
  * 	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)
+ *                      performance (bug 413871), featured market (bug 461603)
  *******************************************************************************/
 package org.eclipse.epp.internal.mpc.ui.commands;
 
@@ -35,7 +35,6 @@
 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.MarketplaceCategory;
 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;
@@ -53,7 +52,6 @@
 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.CatalogCategory;
 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;
@@ -139,15 +137,11 @@
 			@Override
 			public void catalogUpdated(boolean wasCancelled) {
 				List<Tag> choices = new ArrayList<Tag>();
-				for (CatalogCategory category : catalog.getCategories()) {
-					if (category instanceof MarketplaceCategory) {
-						MarketplaceCategory marketplaceCategory = (MarketplaceCategory) category;
-						for (IMarket market : marketplaceCategory.getMarkets()) {
-							Tag marketTag = new Tag(IMarket.class, market.getId(), market.getName());
-							marketTag.setData(market);
-							choices.add(marketTag);
-						}
-					}
+				List<IMarket> markets = catalog.getMarkets();
+				for (IMarket market : markets) {
+					Tag marketTag = new Tag(IMarket.class, market.getId(), market.getName());
+					marketTag.setData(market);
+					choices.add(marketTag);
 				}
 				setChoices(choices);
 			}
@@ -209,18 +203,14 @@
 		}
 
 		final MarketplaceCatalog catalog = (MarketplaceCatalog) marketCategoryTagFilter.getCatalog();
-		for (CatalogCategory category : catalog.getCategories()) {
-			if (category instanceof MarketplaceCategory) {
-				MarketplaceCategory marketplaceCategory = (MarketplaceCategory) category;
-				for (IMarket market : marketplaceCategory.getMarkets()) {
-					if (selectedMarkets.isEmpty() || selectedMarkets.contains(market)) {
-						for (ICategory marketCategory : market.getCategory()) {
-							Tag categoryTag = new Tag(ICategory.class, marketCategory.getId(), marketCategory.getName());
-							categoryTag.setData(marketCategory);
-							if (newChoices.add(categoryTag)) {
-								choices.add(categoryTag);
-							}
-						}
+		List<IMarket> markets = catalog.getMarkets();
+		for (IMarket market : markets) {
+			if (selectedMarkets.isEmpty() || selectedMarkets.contains(market)) {
+				for (ICategory marketCategory : market.getCategory()) {
+					Tag categoryTag = new Tag(ICategory.class, marketCategory.getId(), marketCategory.getName());
+					categoryTag.setData(marketCategory);
+					if (newChoices.add(categoryTag)) {
+						choices.add(categoryTag);
 					}
 				}
 			}
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/AbstractTagFilter.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/AbstractTagFilter.java
index 0ec2363..b433395 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/AbstractTagFilter.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/AbstractTagFilter.java
@@ -7,6 +7,7 @@
  *
  * Contributors:
  * 	The Eclipse Foundation - initial API and implementation
+ * 	Yatta Solutions - bug 461603: featured market
  *******************************************************************************/
 
 package org.eclipse.epp.internal.mpc.ui.wizards;
@@ -84,10 +85,16 @@
 	}
 
 	public void setSelected(Set<Tag> selected) {
+		boolean changed = (selected == null ? !this.selected.isEmpty() : !selected.equals(this.selected));
 		this.selected.clear();
 		if (selected != null) {
 			this.selected.addAll(selected);
 		}
+		if (changed) {
+			updateUi();
+			selectionUpdated();
+		}
+
 	}
 
 	public boolean isSelectAllOnNoSelection() {
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 e035486..1712256 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
@@ -7,7 +7,7 @@
  *
  * Contributors:
  * 	The Eclipse Foundation - initial API and implementation
- *  Yatta Solutions - bug 397004, bug 432803: public API
+ * 	Yatta Solutions - bug 397004, bug 432803: public API, bug 461603: featured market
  *******************************************************************************/
 package org.eclipse.epp.internal.mpc.ui.wizards;
 
@@ -76,7 +76,8 @@
 		GridLayoutFactory.swtDefaults().applyTo(parent);
 
 		Link link = new Link(parent, SWT.NULL);
-		if (viewer.getQueryContentType() == ContentType.SEARCH) {
+		if (viewer.getQueryContentType() == ContentType.SEARCH
+				|| viewer.getQueryContentType() == ContentType.FEATURED_MARKET) {
 			link.setText(NLS.bind(Messages.BrowseCatalogItem_browseMoreLink, category.getMatchCount()));
 		} else {
 			link.setText(Messages.BrowseCatalogItem_browseMoreLinkNoCount);
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/CheckboxTagFilter.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/CheckboxTagFilter.java
index afb7efe..80ec085 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/CheckboxTagFilter.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/CheckboxTagFilter.java
@@ -7,6 +7,7 @@
  *
  * Contributors:
  * 	The Eclipse Foundation - initial API and implementation
+ * 	Yatta Solutions - bug 461603: featured market
  *******************************************************************************/
 
 package org.eclipse.epp.internal.mpc.ui.wizards;
@@ -37,6 +38,7 @@
 			throw new IllegalStateException();
 		}
 		buttonContainer = new Composite(parent, SWT.NULL);
+		buttonContainer.setData(this);
 		rebuildChoicesUi();
 	}
 
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ComboTagFilter.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ComboTagFilter.java
index 41112d5..971dde8 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ComboTagFilter.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ComboTagFilter.java
@@ -7,10 +7,12 @@
  *
  * Contributors:
  * 	The Eclipse Foundation - initial API and implementation
+ * 	Yatta Solutions - bug 461603: featured market
  *******************************************************************************/
 
 package org.eclipse.epp.internal.mpc.ui.wizards;
 
+import java.util.Collections;
 import java.util.List;
 
 import org.eclipse.equinox.internal.p2.discovery.model.Tag;
@@ -40,15 +42,16 @@
 			throw new IllegalStateException();
 		}
 		combo = new Combo(parent, SWT.READ_ONLY | SWT.DROP_DOWN);
+		combo.setData(this);
 		listener = new SelectionListener() {
 			public void widgetSelected(SelectionEvent e) {
 				int selectionIndex = combo.getSelectionIndex();
-				getSelected().clear();
 				if (selectionIndex > 0) {
 					Tag tag = getChoices().get(selectionIndex - 1);
-					getSelected().add(tag);
+					setSelected(Collections.singleton(tag));
+				} else {
+					setSelected(Collections.<Tag> emptySet());
 				}
-				selectionUpdated();
 			}
 
 			public void widgetDefaultSelected(SelectionEvent e) {
diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceCatalogConfiguration.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceCatalogConfiguration.java
index 72022a2..7cb3544 100644
--- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceCatalogConfiguration.java
+++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceCatalogConfiguration.java
@@ -7,7 +7,7 @@
  *
  * Contributors:
  * 	The Eclipse Foundation - initial API and implementation
- * 	Yatta Solutions - bug 432803: public API
+ * 	Yatta Solutions - bug 432803: public API, bug 461603: featured market
  *******************************************************************************/
 package org.eclipse.epp.internal.mpc.ui.wizards;
 
@@ -17,6 +17,7 @@
 import java.util.List;
 import java.util.Map;
 
+import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceViewer.ContentType;
 import org.eclipse.epp.mpc.ui.CatalogDescriptor;
 import org.eclipse.epp.mpc.ui.IMarketplaceClientConfiguration;
 import org.eclipse.epp.mpc.ui.Operation;
@@ -35,6 +36,8 @@
 
 	private Map<String, Operation> initialOperations;
 
+	private ContentType initialContentType;
+
 	public MarketplaceCatalogConfiguration() {
 		setShowTagFilter(false);
 		setShowInstalled(true);
@@ -51,6 +54,14 @@
 		setInitialOperations(configuration.getInitialOperations());
 	}
 
+	public ContentType getInitialContentType() {
+		return initialContentType;
+	}
+
+	public void setInitialContentType(ContentType initialContentType) {
+		this.initialContentType = initialContentType;
+	}
+
 	public List<CatalogDescriptor> getCatalogDescriptors() {
 		return catalogDescriptors;
 	}
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 0b5c3e7..5efe47d 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
@@ -6,7 +6,8 @@
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
- *     Yatta Solutions - initial API and implementation, bug 432803: public API
+ *     Yatta Solutions - initial API and implementation, bug 432803: public API,
+ *                       bug 461603: featured market
  *******************************************************************************/
 package org.eclipse.epp.internal.mpc.ui.wizards;
 
@@ -35,11 +36,22 @@
 		MarketplaceWizardCommand command = new MarketplaceWizardCommand();
 		command.setConfiguration(configuration);
 		WizardState wizardState = new WizardState();
+		setInitialContentType(configuration, wizardState);
 		wizardState.setProceedWithInstallation(false);
 		command.setWizardDialogState(wizardState);
 		execute(command);
 	}
 
+	private void setInitialContentType(IMarketplaceClientConfiguration configuration, WizardState wizardState) {
+		if (configuration instanceof MarketplaceCatalogConfiguration) {
+			MarketplaceCatalogConfiguration catalogConfiguration = (MarketplaceCatalogConfiguration) configuration;
+			ContentType initialContentType = catalogConfiguration.getInitialContentType();
+			if (initialContentType != null) {
+				wizardState.setContentType(initialContentType);
+			}
+		}
+	}
+
 	public void openSelected(IMarketplaceClientConfiguration configuration) {
 		checkInitialState(configuration);
 		MarketplaceWizardCommand command = new MarketplaceWizardCommand();
@@ -79,6 +91,7 @@
 		MarketplaceWizardCommand command = new MarketplaceWizardCommand();
 		command.setConfiguration(configuration);
 		WizardState wizardState = new WizardState();
+		setInitialContentType(configuration, wizardState);
 		wizardState.setContent(nodes);
 		wizardState.setProceedWithInstallation(false);
 		command.setWizardDialogState(wizardState);
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 6f7c7eb..05c660e 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
@@ -7,13 +7,15 @@
  *
  * Contributors:
  * 	The Eclipse Foundation - initial API and implementation
- * 	Yatta Solutions - news (bug 401721), public API (bug 432803), performance (bug 413871)
+ * 	Yatta Solutions - news (bug 401721), public API (bug 432803), performance (bug 413871),
+ * 	                  bug 461603: featured market
  * 	JBoss (Pascal Rapicault) - Bug 406907 - Add p2 remediation page to MPC install flow
  *******************************************************************************/
 package org.eclipse.epp.internal.mpc.ui.wizards;
 
 import java.lang.reflect.InvocationTargetException;
 import java.net.URL;
+import java.util.List;
 import java.util.Set;
 
 import org.eclipse.core.runtime.IProgressMonitor;
@@ -73,6 +75,8 @@
 
 	public static final String WIDGET_ID_TAB_SEARCH = "tab:search"; //$NON-NLS-1$
 
+	public static final String WIDGET_ID_TAB_FEATURED_MARKET = "tab:featured-market"; //$NON-NLS-1$
+
 	public static final String WIDGET_ID_TAB_RECENT = "tab:recent"; //$NON-NLS-1$
 
 	public static final String WIDGET_ID_TAB_POPULAR = "tab:popular"; //$NON-NLS-1$
@@ -101,6 +105,8 @@
 
 	private TabItem popularTabItem;
 
+	private TabItem featuredMarketTabItem;
+
 	private TabItem relatedTabItem;
 
 	private TabItem newsTabItem;
@@ -150,7 +156,6 @@
 		searchTabItem = createCatalogTab(-1, WIDGET_ID_TAB_SEARCH, currentBranding.getSearchTabName());
 		recentTabItem = createCatalogTab(-1, WIDGET_ID_TAB_RECENT, currentBranding.getRecentTabName());
 		popularTabItem = createCatalogTab(-1, WIDGET_ID_TAB_POPULAR, currentBranding.getPopularTabName());
-		relatedTabItem = createCatalogTab(-1, WIDGET_ID_TAB_RELATED, currentBranding.getRelatedTabName());
 		installedTabItem = createCatalogTab(-1, WIDGET_ID_TAB_INSTALLED, Messages.MarketplacePage_installed);
 		updateNewsTab();
 
@@ -272,7 +277,7 @@
 		throw new IllegalArgumentException();
 	}
 
-	private void setActiveTab(ContentType contentType) {
+	public void setActiveTab(ContentType contentType) {
 		if (disableTabSelection) {
 			return;
 		}
@@ -302,6 +307,8 @@
 		switch (content) {
 		case INSTALLED:
 			return installedTabItem;
+		case FEATURED_MARKET:
+			return featuredMarketTabItem;
 		case POPULAR:
 			return popularTabItem;
 		case RECENT:
@@ -557,6 +564,12 @@
 		if (hasTab) {
 			tabIndex++;
 		}
+		hasTab = branding.hasFeaturedMarketTab();
+		featuredMarketTabItem = updateTab(featuredMarketTabItem, WIDGET_ID_TAB_FEATURED_MARKET,
+				branding.getFeaturedMarketTabName(), hasTab, oldBranding.hasFeaturedMarketTab(), tabIndex);
+		if (hasTab) {
+			tabIndex++;
+		}
 		hasTab = branding.hasRecentTab();
 		recentTabItem = updateTab(recentTabItem, WIDGET_ID_TAB_RECENT, branding.getRecentTabName(), hasTab,
 				oldBranding.hasRecentTab(),
@@ -610,6 +623,21 @@
 		disableTabSelection = false;
 	}
 
+	private boolean hasFeaturedMarketTab(ICatalogBranding branding) {
+		if (branding.hasFeaturedMarketTab()) {
+			String marketName = branding.getFeaturedMarketTabName();
+			if (marketName != null && marketName.length() > 0) {
+				List<IMarket> markets = getCatalog().getMarkets();
+				for (IMarket market : markets) {
+					if (marketName.equals(market.getName())) {
+						return true;
+					}
+				}
+			}
+		}
+		return false;
+	}
+
 	private TabItem updateTab(TabItem tabItem, String widgetId, String tabLabel, boolean hasTab, boolean hadTab,
 			int tabIndex) {
 		if (hasTab) {
@@ -630,10 +658,12 @@
 		branding.setHasPopularTab(true);
 		branding.setHasRecentTab(true);
 		branding.setHasRelatedTab(false);
+		branding.setHasFeaturedMarketTab(false);
 		branding.setSearchTabName(Messages.MarketplacePage_search);
 		branding.setPopularTabName(Messages.MarketplacePage_popular);
 		branding.setRecentTabName(Messages.MarketplacePage_recent);
 		branding.setRelatedTabName(Messages.MarketplacePage_related);
+		branding.setFeaturedMarketTabName(Messages.MarketplacePage_featuredMarket);
 		branding.setWizardTitle(Messages.MarketplacePage_eclipseMarketplaceSolutions);
 		branding.setWizardIcon(null);
 		return branding;
@@ -745,6 +775,11 @@
 	}
 
 	@Override
+	public MarketplaceCatalog getCatalog() {
+		return (MarketplaceCatalog) super.getCatalog();
+	}
+
+	@Override
 	public void dispose() {
 		if (marketplaceSwitcher != null) {
 			marketplaceSwitcher.dispose();
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 2175f41..9986046 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
@@ -8,7 +8,8 @@
  * Contributors:
  * 	The Eclipse Foundation - initial API and implementation
  * 	Yatta Solutions - error handling (bug 374105), header layout (bug 341014),
- *                      news (bug 401721), public API (bug 432803), performance (bug 413871)
+ *                      news (bug 401721), public API (bug 432803), performance (bug 413871),
+ *                      featured market (bug 461603)
  *******************************************************************************/
 package org.eclipse.epp.internal.mpc.ui.wizards;
 
@@ -16,9 +17,11 @@
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
@@ -33,6 +36,7 @@
 import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCategory;
 import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCategory.Contents;
 import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceWizard.WizardState;
+import org.eclipse.epp.mpc.core.model.ICatalogBranding;
 import org.eclipse.epp.mpc.core.model.ICategory;
 import org.eclipse.epp.mpc.core.model.IIdentifiable;
 import org.eclipse.epp.mpc.core.model.IMarket;
@@ -83,7 +87,7 @@
 public class MarketplaceViewer extends CatalogViewer {
 
 	public enum ContentType {
-		SEARCH, RECENT, POPULAR, INSTALLED, SELECTION, RELATED
+		SEARCH, FEATURED_MARKET, RECENT, POPULAR, INSTALLED, SELECTION, RELATED
 	}
 
 	public static class MarketplaceCatalogContentProvider extends CatalogContentProvider {
@@ -115,6 +119,72 @@
 
 	}
 
+	private static class QueryData {
+
+		public QueryData() {
+			super();
+		}
+
+		public QueryData(IMarket queryMarket, ICategory queryCategory, String queryText) {
+			super();
+			this.queryMarket = queryMarket;
+			this.queryCategory = queryCategory;
+			this.queryText = queryText;
+		}
+
+		public String queryText;
+
+		public IMarket queryMarket;
+
+		public ICategory queryCategory;
+
+		@Override
+		public int hashCode() {
+			final int prime = 31;
+			int result = 1;
+			result = prime * result + ((queryCategory == null) ? 0 : queryCategory.hashCode());
+			result = prime * result + ((queryMarket == null) ? 0 : queryMarket.hashCode());
+			result = prime * result + ((queryText == null) ? 0 : queryText.hashCode());
+			return result;
+		}
+
+		@Override
+		public boolean equals(Object obj) {
+			if (this == obj) {
+				return true;
+			}
+			if (obj == null) {
+				return false;
+			}
+			if (getClass() != obj.getClass()) {
+				return false;
+			}
+			QueryData other = (QueryData) obj;
+			if (queryCategory == null) {
+				if (other.queryCategory != null) {
+					return false;
+				}
+			} else if (!queryCategory.equals(other.queryCategory)) {
+				return false;
+			}
+			if (queryMarket == null) {
+				if (other.queryMarket != null) {
+					return false;
+				}
+			} else if (!queryMarket.equals(other.queryMarket)) {
+				return false;
+			}
+			if (queryText == null) {
+				if (other.queryText != null) {
+					return false;
+				}
+			} else if (!queryText.equals(other.queryText)) {
+				return false;
+			}
+			return true;
+		}
+	}
+
 	private ViewerFilter[] filters;
 
 	private ContentType contentType = ContentType.SEARCH;
@@ -123,11 +193,9 @@
 
 	private final SelectionModel selectionModel;
 
-	private String queryText;
+	private QueryData queryData = new QueryData();
 
-	private IMarket queryMarket;
-
-	private ICategory queryCategory;
+	private final Map<ContentType, QueryData> tabQueries = new HashMap<MarketplaceViewer.ContentType, MarketplaceViewer.QueryData>();
 
 	private ContentType queryContentType;
 
@@ -145,6 +213,8 @@
 
 	private boolean inUpdate;
 
+	private Composite header;
+
 	public MarketplaceViewer(Catalog catalog, IShellProvider shellProvider, MarketplaceWizard wizard) {
 		super(catalog, shellProvider, wizard.getContainer(), wizard.getConfiguration());
 		this.browser = wizard;
@@ -155,6 +225,7 @@
 
 	@Override
 	protected void doCreateHeaderControls(Composite parent) {
+		header = parent;
 		final int originalChildCount = parent.getChildren().length;
 		for (CatalogFilter filter : getConfiguration().getFilters()) {
 			if (filter instanceof MarketplaceFilter) {
@@ -206,7 +277,7 @@
 						((MarketplaceFilter) filter).catalogUpdated(wasCancelled);
 					}
 				}
-				setFilters(queryMarket, queryCategory, queryText);
+				setFilters(queryData);
 			}
 		});
 	}
@@ -265,7 +336,7 @@
 		contentType = newContentType;
 		fireContentTypeChange(oldContentType, newContentType);
 
-		doQuery(null, null, null, nodes);
+		doQuery(new QueryData(), nodes);
 	}
 
 	public void search(String query) {
@@ -273,20 +344,19 @@
 	}
 
 	public void search(IMarket market, ICategory category, String query) {
-		setFilters(market, category, query);
-		queryMarket = market;
-		queryCategory = category;
-		queryText = query;
+		final QueryData queryData = new QueryData(market, category, query);
+		setFilters(queryData);
+		this.queryData = queryData;
 
 		updateContent(contentType, new Runnable() {
 			public void run() {
-				doQuery(queryMarket, queryCategory, queryText, null);
+				doQuery(queryData, null);
 			}
 		});
 	}
 
-	private void setFilters(IMarket market, ICategory category, String query) {
-		setFindText(query == null ? "" : query); //$NON-NLS-1$
+	private void setFilters(QueryData queryData) {
+		setFindText(queryData.queryText == null ? "" : queryData.queryText); //$NON-NLS-1$
 		for (CatalogFilter filter : getConfiguration().getFilters()) {
 			if (filter instanceof AbstractTagFilter) {
 				AbstractTagFilter tagFilter = (AbstractTagFilter) filter;
@@ -296,9 +366,9 @@
 					if (tag != null) {
 						IIdentifiable data = null;
 						if (tag.getTagClassifier() == IMarket.class) {
-							data = market;
+							data = queryData.queryMarket;
 						} else if (tag.getTagClassifier() == ICategory.class) {
-							data = category;
+							data = queryData.queryCategory;
 						} else {
 							continue;
 						}
@@ -327,15 +397,14 @@
 
 	private void doQuery() {
 		initQueryFromFilters();
-		doQuery(queryMarket, queryCategory, queryText, null);
+		doQuery(queryData, null);
 	}
 
 	private void initQueryFromFilters() {
-		queryMarket = null;
-		queryCategory = null;
-		queryText = null;
+		queryData = new QueryData();
 		findText = getFilterText();
 
+		AbstractTagFilter marketFilter = null;
 		for (CatalogFilter filter : getConfiguration().getFilters()) {
 			if (filter instanceof AbstractTagFilter) {
 				AbstractTagFilter tagFilter = (AbstractTagFilter) filter;
@@ -343,17 +412,40 @@
 					Tag tag = tagFilter.getSelected().isEmpty() ? null : tagFilter.getSelected().iterator().next();
 					if (tag != null) {
 						if (tag.getTagClassifier() == IMarket.class) {
-							queryMarket = (IMarket) tag.getData();
+							marketFilter = tagFilter;
+							queryData.queryMarket = (IMarket) tag.getData();
 						} else if (tag.getTagClassifier() == ICategory.class) {
-							queryCategory = (ICategory) tag.getData();
+							queryData.queryCategory = (ICategory) tag.getData();
 						}
 					}
 				}
 			}
 		}
-		queryText = findText;
+		if (marketFilter != null) {
+			setFilterEnabled(marketFilter, contentType != ContentType.FEATURED_MARKET);
+		}
+		queryData.queryText = findText;
 	}
 
+	private void setFilterEnabled(MarketplaceFilter filter, boolean enabled) {
+		if (header != null) {
+			Control[] children = header.getChildren();
+			for (Control control : children) {
+				if (control.getData() == filter) {
+					control.setEnabled(enabled);
+				}
+			}
+		}
+	}
+
+	/**
+	 * Search for a free-form tag
+	 *
+	 * @param tag
+	 *            the tag to search for
+	 * @deprecated tag support was removed from Marketplace
+	 */
+	@Deprecated
 	public void doQueryForTag(String tag) {
 		setFindText(tag);
 		doSetContentType(ContentType.SEARCH);
@@ -378,7 +470,7 @@
 		firePropertyChangeEvent(new PropertyChangeEvent(source, property, oldValue, newValue));
 	}
 
-	private void doQuery(final IMarket market, final ICategory category, final String queryText,
+	private void doQuery(final QueryData queryData,
 			final Set<? extends INode> nodes) {
 		try {
 			final ContentType queryType = contentType;
@@ -407,13 +499,15 @@
 						result[0] = getCatalog().performQuery(monitor, nodeIds);
 						break;
 					case SEARCH:
+					case FEATURED_MARKET:
 					default:
 						if (nodes != null && !nodes.isEmpty()) {
 							result[0] = getCatalog().performNodeQuery(monitor, nodes);
-						} else if (queryText != null && queryText.length() > 0) {
-							result[0] = getCatalog().performQuery(market, category, queryText, monitor);
+						} else if (queryData.queryText != null && queryData.queryText.length() > 0) {
+							result[0] = getCatalog().performQuery(queryData.queryMarket, queryData.queryCategory,
+									queryData.queryText, monitor);
 						} else {
-							result[0] = getCatalog().featured(monitor, market, category);
+							result[0] = getCatalog().featured(monitor, queryData.queryMarket, queryData.queryCategory);
 						}
 						break;
 					}
@@ -422,7 +516,7 @@
 					}
 					MarketplaceViewer.this.getControl().getDisplay().syncExec(new Runnable() {
 						public void run() {
-							updateViewer(queryText);
+							updateViewer(queryData.queryText);
 						}
 					});
 				}
@@ -476,15 +570,13 @@
 
 	public void showSelected() {
 		contentType = ContentType.SELECTION;
-		queryMarket = null;
-		queryCategory = null;
-		queryText = null;
+		queryData = new QueryData();
 		findText = null;
 		runUpdate(new Runnable() {
 
 			public void run() {
 				setHeaderVisible(true);
-				doQuery(null, null, findText, null);
+				doQuery(new QueryData(null, null, findText), null);
 			}
 		});
 		contentType = ContentType.SEARCH;
@@ -526,16 +618,85 @@
 	private void updateContent(final ContentType contentType, final Runnable queryCall) {
 		final ContentType oldContentType = this.contentType;
 		this.contentType = contentType;
+
+		final boolean hadQuery = showQueryHeader(oldContentType);
+		final boolean hasQuery = showQueryHeader(contentType);
+
+		ContentType oldQueryType = oldContentType;
+		if (oldQueryType == ContentType.SELECTION) {
+			oldQueryType = ContentType.SEARCH;
+		}
+		ContentType queryType = contentType;
+		if (queryType == ContentType.SELECTION) {
+			queryType = ContentType.SEARCH;
+		}
+
+		if (oldQueryType != queryType || hasQuery != hadQuery) {
+			if (hadQuery) {
+				initQueryFromFilters();
+				tabQueries.put(oldQueryType, queryData);
+			}
+			if (hasQuery) {
+				QueryData newQueryData = tabQueries.get(queryType);
+				if (newQueryData == null) {
+					newQueryData = new QueryData();
+					if (queryType == ContentType.FEATURED_MARKET) {
+						//WIP init market
+						CatalogDescriptor catalogDescriptor = this.getWizard()
+								.getConfiguration()
+								.getCatalogDescriptor();
+						ICatalogBranding catalogBranding = catalogDescriptor.getCatalogBranding();
+						if (catalogBranding != null) {
+							boolean hasFeaturedMarketTab = catalogBranding.hasFeaturedMarketTab();
+							if (hasFeaturedMarketTab) {
+								String marketName = catalogBranding.getFeaturedMarketTabName();
+								if (marketName != null) {
+									for (CatalogFilter filter : getConfiguration().getFilters()) {
+										if (filter instanceof AbstractTagFilter) {
+											AbstractTagFilter tagFilter = (AbstractTagFilter) filter;
+											if (tagFilter.getTagClassification() == ICategory.class) {
+												for (Tag tag : tagFilter.getChoices()) {
+													if (tag.getTagClassifier() != IMarket.class) {
+														break;
+													}
+													IMarket market = (IMarket) tag.getData();
+													if (marketName.equals(market.getName())) {
+														//tagFilter.setSelected(Collections.singleton(tag));
+														newQueryData.queryMarket = market;
+														break;
+													}
+												}
+											}
+										}
+									}
+									if (newQueryData.queryMarket == null) {
+										setContentType(oldContentType);//TODO remove/disable tab?
+										return;
+									}
+								}
+							}
+						}
+					}
+					tabQueries.put(queryType, newQueryData);
+				}
+				setFilters(newQueryData);
+			}
+		}
 		runUpdate(new Runnable() {
 
 			public void run() {
 				fireContentTypeChange(oldContentType, contentType);
-				setHeaderVisible(contentType == ContentType.SEARCH || contentType == ContentType.SELECTION);
+				setHeaderVisible(hasQuery);
 				queryCall.run();
 			}
 		});
 	}
 
+	private boolean showQueryHeader(final ContentType contentType) {
+		return contentType == ContentType.SEARCH || contentType == ContentType.SELECTION
+				|| contentType == ContentType.FEATURED_MARKET;
+	}
+
 	public void addPropertyChangeListener(IPropertyChangeListener listener) {
 		listeners.add(listener);
 	}
@@ -698,7 +859,7 @@
 	 * the text for the current query
 	 */
 	public String getQueryText() {
-		return queryText;
+		return queryData.queryText;
 	}
 
 	/**
@@ -707,7 +868,7 @@
 	 * @return the market or null if no category has been selected
 	 */
 	public ICategory getQueryCategory() {
-		return queryCategory;
+		return queryData.queryCategory;
 	}
 
 	/**
@@ -716,7 +877,7 @@
 	 * @return the market or null if no market has been selected
 	 */
 	public IMarket getQueryMarket() {
-		return queryMarket;
+		return queryData.queryMarket;
 	}
 
 	/**
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 dfd43c0..8697c1e 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
@@ -129,6 +129,8 @@
 
 	public static String MarketplacePage_eclipseMarketplaceSolutions;
 
+	public static String MarketplacePage_featuredMarket;
+
 	public static String MarketplacePage_installed;
 
 	public static String MarketplacePage_linkShowSelection_Multiple;
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 810ed0c..2510578 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
@@ -65,6 +65,7 @@
 MarketplacePage_DefaultNewsTitle=News
 MarketplacePage_discardPendingSolutions=There are solutions pending for installation. Switching the marketplace will discard your selection. Proceed?
 MarketplacePage_eclipseMarketplaceSolutions=Eclipse Marketplace Solutions
+MarketplacePage_featuredMarket=Featured Market
 MarketplacePage_installed=&Installed
 MarketplacePage_linkShowSelection_Multiple=<a>{0} solutions selected</a>
 MarketplacePage_linkShowSelection_One=<a>One solution selected</a>