/*******************************************************************************
* Copyright (c) 2005, 2010 Texas Instruments Incorporated 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:
* Texas Instruments - initial API and implementation
* Intel Corporation - adaptation to new project model
* IBM Corporation
*******************************************************************************/
package org.eclipse.cdt.managedbuilder.ui.wizards;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.TreeMap;
import org.eclipse.cdt.managedbuilder.core.BuildException;
import org.eclipse.cdt.managedbuilder.core.IToolChain;
import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
import org.eclipse.cdt.managedbuilder.internal.ui.Messages;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.wizard.IWizardPage;
/**
* This class is responsible for managing the use of custom pages in the Managed Build System's
* New Project wizards.
*
* This class is a singleton.
*
* @noinstantiate This class is not intended to be instantiated by clients.
*/
public final class MBSCustomPageManager
{
public static final String PAGE_ID = "org.eclipse.cdt.managedbuilder.ui.wizard.platformPage"; //$NON-NLS-1$
/**
* ID attribute of nature element
*/
public static final String NATURE_ID = "natureID"; //$NON-NLS-1$
/**
* versions supported attribute of toolchain element
*/
public static final String VERSIONS_SUPPORTED = "versionsSupported"; //$NON-NLS-1$
/**
* ID attribute of toolchain element
*/
public static final String TOOLCHAIN_ID = "toolchainID"; //$NON-NLS-1$
/**
* ID attribute of projectType element
*/
public static final String PROJECT_TYPE_ID = "projectTypeID"; //$NON-NLS-1$
/**
* nature element
*/
public static final String NATURE = "nature"; //$NON-NLS-1$
/**
* toolchain element
*/
public static final String TOOLCHAIN = "toolchain"; //$NON-NLS-1$
/**
* project type element
*/
public static final String PROJECT_TYPE = "projectType"; //$NON-NLS-1$
/**
* attribute for the class associated witha wizardPage element
*/
public static final String PAGE_CLASS = "pageClass"; //$NON-NLS-1$
/**
* attribute for the operation that is run for a wizardPage during the wizard's DoRunEpilogue() method
*/
public static final String OPERATION_CLASS = "operationClass"; //$NON-NLS-1$
/**
* ID attribute for wizardPage
*/
public static final String ID = "ID"; //$NON-NLS-1$
/**
* element for a custom wizard page
*/
public static final String WIZARD_PAGE = "wizardPage"; //$NON-NLS-1$
/**
* Maps String IDs to IWizardPages
*/
private static Map idToPageDataMap = null;
/**
* The set of pages that this manager knows about.
*/
private static Set pageSet = null;
/**
* Maps page IDs to the properties that page has set.
*/
private static java.util.Map pageIDtoPagePropertiesMap = null;
private static final String EXTENSION_POINT_ID = "org.eclipse.cdt.managedbuilder.ui.newWizardPages"; //$NON-NLS-1$
private static List hiddenList;
/**
*
* Looks for contributions to the extension point org.eclipse.cdt.managedbuilder.ui.newWizardPages and adds all pages to the manager.
* @since 3.0
*
*/
public static void loadExtensions() throws BuildException
{
loadExtensionsSynchronized();
}
private synchronized static void loadExtensionsSynchronized()
throws BuildException
{
// Get the extensions
IExtensionPoint extensionPoint = Platform.getExtensionRegistry()
.getExtensionPoint(EXTENSION_POINT_ID);
if (extensionPoint != null)
{
IExtension[] extensions = extensionPoint.getExtensions();
if (extensions != null)
{
for (int i = 0; i < extensions.length; ++i)
{
IExtension extension = extensions[i];
// Get the "configuraton elements" defined in the plugin.xml file.
// Note that these "configuration elements" are not related to the
// managed build system "configurations".
// From the PDE Guide:
// A configuration element, with its attributes and children, directly
// reflects the content and structure of the extension section within the
// declaring plug-in's manifest (plugin.xml) file.
IConfigurationElement[] elements = extension.getConfigurationElements();
// process the top level elements for this extension
for (int k = 0; k < elements.length; k++)
{
IConfigurationElement element = elements[k];
if (element.getName().equals(WIZARD_PAGE))
{
// load the data associated with the wizard page
loadWizardPage(element);
}
else
{
// there are currently no other supported element types
// so throw an exception
throw new BuildException(Messages.MBSCustomPageManager_error0
+ element.getName()
+ Messages.MBSCustomPageManager_error1
+ EXTENSION_POINT_ID);
}
}
}
}
}
}
private static void loadWizardPage(IConfigurationElement element)
throws BuildException
{
// get the ID and wizard page
String id = element.getAttribute(ID);
// String operationClassName = element.getAttribute(OPERATION_CLASS); // optional element so may be null
IWizardPage wizardPage = null;
Object operation = null;
// instantiate the classes specified in the manifest
// first try to create the page class, which is required
try
{
wizardPage = (IWizardPage) element.createExecutableExtension(PAGE_CLASS);
// the operation is an optional element so it might not be present
if (element.getAttribute(OPERATION_CLASS) != null)
operation = element.createExecutableExtension(OPERATION_CLASS);
}
catch (CoreException e)
{
// convert to a build exception
throw new BuildException(e.getMessage());
}
// create the page data and add it to ourselves
MBSCustomPageData currentPageData;
// Custom pages prior to CDT 4.0 were required to provide Runnables as operations.
// Post 4.0, IRunnableWithProgress are accepted as well.
if (operation instanceof Runnable) {
currentPageData = new MBSCustomPageData(id, wizardPage, (Runnable) operation, false);
} else if (operation instanceof IRunnableWithProgress || operation == null) {
currentPageData = new MBSCustomPageData(id, wizardPage, (IRunnableWithProgress) operation, false);
} else {
throw new BuildException(element.getName());
}
idToPageDataMap.put(id, currentPageData);
pageSet.add(currentPageData);
// load any child elements
IConfigurationElement[] children = element.getChildren();
for (int k = 0; k < children.length; k++)
{
IConfigurationElement childElement = children[k];
if (childElement.getName().equals(PROJECT_TYPE))
{
loadProjectType(childElement, currentPageData);
}
else
{
if (childElement.getName().equals(TOOLCHAIN))
{
loadToolchain(childElement, currentPageData);
}
else
{
if (childElement.getName().equals(NATURE))
{
loadNature(childElement, currentPageData);
}
else
{
// no other types supported... throw an exception
// there are currently no other supported element types
// so throw an exception
throw new BuildException(Messages.MBSCustomPageManager_error2
+ element.getName()
+ Messages.MBSCustomPageManager_error3
+ EXTENSION_POINT_ID);
}
}
}
}
}
private static void loadProjectType(IConfigurationElement element,
MBSCustomPageData currentPageData) throws BuildException
{
String projectType = element.getAttribute(PROJECT_TYPE_ID);
if (projectType != null)
currentPageData.addProjectType(projectType);
else
throw new BuildException(Messages.MBSCustomPageManager_error4);
}
private static void loadToolchain(IConfigurationElement element,
MBSCustomPageData currentPageData) throws BuildException
{
String toolchainID = element.getAttribute(TOOLCHAIN_ID);
if (toolchainID != null)
{
// get the supported versions
String unparsedVersions = element.getAttribute(VERSIONS_SUPPORTED);
String[] versionsSupported = null;
if (unparsedVersions != null)
{
// parse out the individual versions - they are comma separated
versionsSupported = unparsedVersions.split(","); //$NON-NLS-1$
}
// add toolchain data for the page
currentPageData.addToolchain(toolchainID, versionsSupported);
}
else
throw new BuildException(Messages.MBSCustomPageManager_error5);
}
private static void loadNature(IConfigurationElement element,
MBSCustomPageData currentPageData) throws BuildException
{
String nature = element.getAttribute(NATURE_ID);
if (nature != null)
currentPageData.addNature(nature);
else
throw new BuildException(Messages.MBSCustomPageManager_error6);
}
/**
*
* @param pageID - The unique ID of the page to search for.
*
* @return - The MBSCustomPageData corresponding to the page, or null
* if not found.
*
* @since 3.0
*/
public static MBSCustomPageData getPageData(String pageID)
{
return (MBSCustomPageData) idToPageDataMap.get(pageID);
}
/**
* @param pageID - The unique ID of the page to be tested.
* @return true if the page is visible given the currently selected project type, nature, and toolchain. false otherwise.
* @since 3.0
*/
public static boolean isPageVisible(String pageID)
{
MBSCustomPageData page = getPageData(pageID);
if(page == null)
return false;
if (getPageHideStatus(pageID))
return false;
// first, find out what project type, toolchain, and nature have been set
Map pagePropertiesMap = (Map) pageIDtoPagePropertiesMap.get(PAGE_ID);
Object projectType = pagePropertiesMap.get(PROJECT_TYPE);
List toolchainList = (List) pagePropertiesMap.get(TOOLCHAIN);
Object nature = pagePropertiesMap.get(NATURE);
// does the page follow nature and project type constraints?
if (page.shouldBeVisibleForNature(nature)
&& page.shouldBeVisibleForProjectType(projectType))
{
MBSCustomPageData.ToolchainData[] toolchainData = page.getToolchains();
// if no toolchains are specified then we're done
if (toolchainData == null || toolchainList == null)
return true;
// otherwise, iterate through the toolchains to see if one matches
for (int k = 0; k < toolchainData.length; k++)
{
// check all toolchains, see if there is one for which we should be present
Iterator toolchainIterator = toolchainList.iterator();
while (toolchainIterator.hasNext())
{
IToolChain toolchain = (IToolChain) toolchainIterator.next();
if(toolchain != null){
String id = ManagedBuildManager.getIdFromIdAndVersion(toolchain.getId());
String version = ManagedBuildManager.getVersionFromIdAndVersion(toolchain.getId());
// check the ID and version
if (page.shouldBeVisibleForToolchain(id, version))
return true;
}
}
}
}
return false;
}
/**
*
* Publishes a piece of data associated with a wizard page. Clients (e.g. other wizard pages) can retrieve
* the values of these pieces of data later given the proper page ID and key.
*
* @param pageID - The unique ID of the page for which the data is being added.
*
* @param key - A unique name by which the data is referred to.
*
* @param data - The data to be stored. No assumptions are made about the type of data stored. It is up to the
* contributor of a given page to establish their own contract as to what type of data is stored.
*
* @since 3.0
*
* @see org.eclipse.cdt.managedbuilder.ui.wizards.MBSCustomPageManager#getPageProperty(String, String)
*/
public static void addPageProperty(String pageID, String key, Object data)
{
Map propertiesMap = (Map) pageIDtoPagePropertiesMap.get(pageID);
if (propertiesMap == null)
{
propertiesMap = new TreeMap();
pageIDtoPagePropertiesMap.put(pageID, propertiesMap);
}
propertiesMap.put(key, data);
}
/**
* Retrieves a previously published piece of data associated with a wizard page.
*
*
* @param pageID - The unique ID of the page for which the
* data should be retrieved.
*
* @param key - The unique name of the data to be retrieved.
*
* @return The data that was stored for the given key. No assumptions are made about the type of data stored. It is up to the
* contributor of a given page to establish their own contract as to what type of data is stored.
*
* There are certain well known pieces of data published by the stock wizard pages provided by the Managed Build System.
* See org.eclipse.cdt.maangedbuilder.ui.wizards.CProjectPlatformPage.
*
* @see org.eclipse.cdt.maangedbuilder.ui.wizards.CProjectPlatformPage
* @see org.eclipse.cdt.managedbuilder.ui.wizards.MBSCustomPageManager#addPageProperty(String, String, Object)
*
* @since 3.0
*/
public static Object getPageProperty(String pageID, String key)
{
Map propertiesMap = (Map) pageIDtoPagePropertiesMap.get(pageID);
if (propertiesMap != null)
{
return propertiesMap.get(key);
}
else
return null;
}
/**
* Gets the next page that should appear in the wizard. This takes into account the selected
* project type, project nature, and toolchains.
*
* @param currentPageID - The unique ID of the page the wizard is currently displaying.
* @return The next page that should be displayed in the wizard, or null if at the end of the wizard.
* @since 3.0
*/
public static IWizardPage getNextPage(String currentPageID)
{
// find the current page in the set of pages
MBSCustomPageData pageData = getPageData(currentPageID);
Iterator iterator = pageSet.iterator();
while (iterator.hasNext())
{
if (pageData.equals(iterator.next())) {
IWizardPage nextPage = null;
while (iterator.hasNext() && nextPage == null)
{
MBSCustomPageData potentialPage = (MBSCustomPageData) iterator.next();
if (isPageVisible(potentialPage.getID()))
nextPage = potentialPage.getWizardPage();
}
return nextPage;
}
}
return null;
}
/**
* Adds an entry for a stock page into the manager. This is used for pages provided by the Managed Build System that are not loaded via the
* extension point mechanism.
*
* @param page - The IWizardPage to add.
* @param pageID - A unique ID to associate with this page. This ID will be used to refer to the page by the rest of the system.
* @since 3.0
*/
public static void addStockPage(IWizardPage page, String pageID)
{
MBSCustomPageData pageData = new MBSCustomPageData(pageID, page, (IRunnableWithProgress) null, true);
idToPageDataMap.put(pageID, pageData);
pageSet.add(pageData);
}
/**
* Gets the previous page that should appear in the wizard. This takes into account the selected
* project type, project nature, and toolchains. Stock pages can be returned by this method as well as
* custom pages.
*
* @param currentPageID - The unique ID of the page currently being displayed in the wizard.
* @return - The IWizardPage that corresponds to the previous page to be displayed in the wizard, or null if at the start of the wizard.
* @since 3.0
*/
public static IWizardPage getPreviousPage(String currentPageID)
{
// find the current page in the set of pages
MBSCustomPageData pageData = getPageData(currentPageID);
MBSCustomPageData currentData = null;
Iterator iterator = pageSet.iterator();
// since Java has no concept of a reverse-iterator yet, we must keep a stack of the
// pages we have visited, so that we can get them in reverse chronological order
Stack pageDataStack = new Stack();
while (iterator.hasNext())
{
currentData = (MBSCustomPageData) iterator.next();
if (currentData == pageData)
{
// we found the page we're looking for so stop looking
break;
}
else
{
pageDataStack.push(currentData);
}
}
if (currentData == pageData)
{
// we found our page
// look for the previous page that satisfies all project type, toolchain, and nature criteria
// first, find out what project type, toolchain, and nature have been set
// Map pagePropertiesMap = (Map) pageIDtoPagePropertiesMap.get(PAGE_ID);
// String projectType = pagePropertiesMap.get(PROJECT_TYPE).toString();
// Set toolchainSet = (Set) pagePropertiesMap.get(TOOLCHAIN);
// String nature = pagePropertiesMap.get(NATURE).toString();
IWizardPage prevPage = null;
boolean pageFound = false;
// use the stack to visit the previous pages
while (pageDataStack.size() != 0 && !pageFound)
{
MBSCustomPageData potentialPage = (MBSCustomPageData) pageDataStack.pop();
if (isPageVisible(potentialPage.getID()))
{
pageFound = true;
prevPage = potentialPage.getWizardPage();
}
}
if (pageFound)
return prevPage;
}
return null;
}
/**
* Gets the pages that the page manager knows about.
*
* @return An array of IWizardPage objects corresponding to all pages the manager knows about.
* Pages are returned in the order they appear in the wizard, and include both stock and custom pages.
*
* @since 3.0
*
* @see getCustomPages()
*/
public static IWizardPage[] getPages()
{
IWizardPage[] pages = new IWizardPage[pageSet.size()];
Iterator iterator = pageSet.iterator();
int k = 0;
while(iterator.hasNext())
{
MBSCustomPageData page = (MBSCustomPageData) iterator.next();
pages[k++] = page.getWizardPage();
}
return pages;
}
/**
* Gets all custom pages that the page manager knows about.
*
* @return An array of IWizardPage objects corresponding to all custom pages the manager knows about.
* Pages are returned in the order they appear in the wizard. Stock pages are not included.
*
* @since 3.0
*
* @see getPages()
*/
public static IWizardPage[] getCustomPages()
{
Set customPageSet = new LinkedHashSet();
Iterator pageIterator = pageSet.iterator();
while(pageIterator.hasNext())
{
MBSCustomPageData page = (MBSCustomPageData) pageIterator.next();
if (!page.isStockPage())
{
customPageSet.add(page.getWizardPage());
}
}
Iterator iterator = customPageSet.iterator();
IWizardPage[] pages = new IWizardPage[customPageSet.size()];
int k = 0;
while (iterator.hasNext())
{
pages[k++] = (IWizardPage) iterator.next();
}
return pages;
}
/**
* Gets all operations that should be run during the wizard's DoRunEpilogue() method. Only operations for visible pages are returned.
*
* @return array of type Runnable[] corresponding to the operations.
*
* @since 3.0
*/
public static IRunnableWithProgress[] getOperations()
{
Set operationSet = new LinkedHashSet();
Iterator pageIterator = pageSet.iterator();
while(pageIterator.hasNext())
{
MBSCustomPageData page = (MBSCustomPageData) pageIterator.next();
if (!page.isStockPage()
&& isPageVisible(page.getID()))
{
if (page.getOperation() != null)
{
operationSet.add(page.getOperation());
}
}
}
if(operationSet.size() == 0)
return null;
Iterator iterator = operationSet.iterator();
IRunnableWithProgress[] operations = new IRunnableWithProgress[operationSet.size()];
int k = 0;
while (iterator.hasNext())
{
operations[k++] = (IRunnableWithProgress) iterator.next();
}
return operations;
}
/**
* Initializes the manager.
*
* This method should be called before any other operations are performed using this class, and should
* be called every time pages are added to the wizard.
*
* @since 3.0
*/
public static void init()
{
idToPageDataMap = new TreeMap();
pageIDtoPagePropertiesMap = new TreeMap();
pageSet = new LinkedHashSet();
hiddenList = new ArrayList();
}
// singleton class - do not use
private MBSCustomPageManager()
{
}
/**
* Ability to hide pages explicitly,
* not depending of nature/projecttype filter
*
* @param p - page to hide
* @param status - true means hidden
*/
public static void setPageHideStatus(String Id, boolean status) {
if (hiddenList.contains(Id)) {
if (!status) hiddenList.remove(Id);
} else {
if (status) hiddenList.add(Id);
}
}
public static boolean getPageHideStatus(String Id) {
return hiddenList.contains(Id);
}
}