resolveConfigurations() {
+ return workspace.getConfigurations(resolveProject());
+ }
+
+ @Override
+ public ICConfigurationDescription resolveSelectedConfiguration() {
+ return workspace.getConfiguration(resolveProject(), getSelectedConfigurationID());
+ }
+ }
+}
\ No newline at end of file
Index: src/org/eclipse/cdt/internal/ui/workingsets/ActivateWorkingSetConfigsContribution.java
===================================================================
RCS file: src/org/eclipse/cdt/internal/ui/workingsets/ActivateWorkingSetConfigsContribution.java
diff -N src/org/eclipse/cdt/internal/ui/workingsets/ActivateWorkingSetConfigsContribution.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/internal/ui/workingsets/ActivateWorkingSetConfigsContribution.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2009 QNX Software Systems 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:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.internal.ui.workingsets;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * A dynamic contribution of items to activate configurations of a working set.
+ *
+ * @author Christian W. Damus (cdamus)
+ *
+ * @since 6.0
+ */
+public class ActivateWorkingSetConfigsContribution extends AbstractWorkingSetConfigsContribution {
+
+ /**
+ * Initializes me without a working set. I figure it out, later. This is only appropriate usage for
+ * context-menu contribution, where the workbench selection is obvious.
+ */
+ public ActivateWorkingSetConfigsContribution() {
+ super();
+ }
+
+ /**
+ * Initializes me with my working set.
+ *
+ * @param workingSet
+ * my working set
+ */
+ ActivateWorkingSetConfigsContribution(IWorkingSetProxy workingSet) {
+ super(workingSet);
+ }
+
+ @Override
+ protected IContributionItem createContribution(IWorkingSetConfiguration config, int index) {
+ return new ActionContributionItem(new ActivateConfigAction(config, index + 1));
+ }
+
+ //
+ // Nested classes
+ //
+
+ private static class ActivateConfigAction extends Action {
+ private IWorkingSetConfiguration workingSetConfig;
+
+ ActivateConfigAction(IWorkingSetConfiguration workingSetConfig, int ordinal) {
+ super(NLS.bind(WorkingSetMessages.WorkingSetMenus_enumPattern, ordinal, workingSetConfig
+ .getName()));
+
+ this.workingSetConfig = workingSetConfig;
+ }
+
+ @Override
+ public void run() {
+ workingSetConfig.activate();
+ }
+ }
+}
Index: src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetProjectConfiguration.java
===================================================================
RCS file: src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetProjectConfiguration.java
diff -N src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetProjectConfiguration.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetProjectConfiguration.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,170 @@
+/*******************************************************************************
+ * Copyright (c) 2009 QNX Software Systems 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:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.internal.ui.workingsets;
+
+import java.util.Collection;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+
+import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
+
+/**
+ *
+ * The protocol for project configurations in a working set configuration. At a minimum, the project
+ * configuration specifies which build configuration is {@linkplain #getSelectedConfigurationID() selected} to
+ * be set as the project's active configuration. Implementations are free to add more configuration
+ * information than the selected build configuration.
+ *
+ *
+ * Note that project configurations are owned by working set configurations. Thus, different configurations of
+ * the same (or different) working set may specify different settings for the same project.
+ *
+ *
+ * @author Christian W. Damus (cdamus)
+ *
+ * @since 6.0
+ */
+public interface IWorkingSetProjectConfiguration extends IWorkingSetConfigurationElement {
+ /**
+ * Obtains the working set configuration element that owns me.
+ *
+ * @return my working set configuration
+ */
+ IWorkingSetConfiguration getWorkingSetConfiguration();
+
+ /**
+ * Queries the name of the project that I configure.
+ *
+ * @return my project name
+ */
+ String getProjectName();
+
+ /**
+ * Resolves my project name to the actual project resource in the workspace.
+ *
+ * @return my referenced project, or null
if the project is not
+ * {@linkplain IResource#isAccessible() accessible} in the workspace
+ */
+ IProject resolveProject();
+
+ /**
+ * Queries the ID of the build configuration that is currently selected for my project.
+ *
+ * @return my selected build configuration ID
+ */
+ String getSelectedConfigurationID();
+
+ /**
+ * Sets the ID of the build configuration that is currently selected for my project.
+ *
+ * @param id
+ * my selected build configuration ID
+ */
+ void setSelectedConfigurationID(String id);
+
+ /**
+ *
+ * Resolves my selected configuration reference to the C model's description handle for it.
+ *
+ *
+ * Note that, in the general case, it is possible for the configuration to resolve to a different
+ * object from one call to the next, but always representing the same configuration. However, in the case
+ * of a working-copy {@linkplain IWorkingSetProjectConfiguration.ISnapshot snapshot} of me, the result
+ * will always be the same object.
+ *
+ *
+ * @return the C model representation of my selected build configuration
+ *
+ * @see #resolveConfigurations()
+ */
+ ICConfigurationDescription resolveSelectedConfiguration();
+
+ /**
+ *
+ * Resolves the set of available configurations of my project.
+ *
+ *
+ * Note that, in the general case, it is possible for these configurations to resolve to different
+ * objects from one call to the next, but always representing the same configurations. However, in the
+ * case of a working-copy {@linkplain IWorkingSetProjectConfiguration.ISnapshot snapshot} of me, the
+ * results will always be the same objects.
+ *
+ *
+ * @return the C model representation of my selected available build configurations
+ *
+ * @see #resolveSelectedConfiguration()
+ */
+ Collection resolveConfigurations();
+
+ /**
+ * Queries whether my project currently has my selected configuration active in the workspace.
+ *
+ * @return whether I am my project's active configuration
+ *
+ * @see #getSelectedConfigurationID()
+ * @see #activate()
+ */
+ boolean isActive();
+
+ /**
+ * Activates my selected configuration in the workspace, for my project.
+ *
+ * @see #getSelectedConfigurationID()
+ * @see #setSelectedConfigurationID(String)
+ * @see #isActive()
+ */
+ void activate();
+
+ /**
+ * Builds my selected configuration in the workspace, for my project. If building the configuration
+ * actually requires activating it, and it was not already active, then it would be a good idea to return
+ * a warning status indicating that the active configuration had to be changed in order to effect the
+ * build.
+ *
+ * @param monitor
+ * a progress monitor to report build progress
+ * @return a status indicating any error or warning conditions in the invocation of the build
+ */
+ IStatus build(IProgressMonitor monitor);
+
+ /**
+ * Creates a snapshot (also known as a "working copy") of myself, providing a mutable view suitable
+ * for editing.
+ *
+ * @param workingSetConfig
+ * my parent working set configuration snapshot
+ * @param workspace
+ * a workspace snapshot that captures the baseline state of the workspace and the working set
+ * configurations that are to be edited
+ *
+ * @return a working-copy snapshot of myself
+ */
+ ISnapshot createSnapshot(IWorkingSetConfiguration.ISnapshot workingSetConfig, WorkspaceSnapshot workspace);
+
+ //
+ // Nested types
+ //
+
+ /**
+ * The snapshot ("working copy") view of a working set project configuration.
+ *
+ * @author Christian W. Damus (cdamus)
+ *
+ * @since 6.0
+ */
+ interface ISnapshot extends IWorkingSetProjectConfiguration, IWorkingSetConfigurationElement.ISnapshot {
+ IWorkingSetConfiguration.ISnapshot getWorkingSetConfiguration();
+ }
+}
Index: src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfigsController.java
===================================================================
RCS file: src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfigsController.java
diff -N src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfigsController.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfigsController.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,460 @@
+/*******************************************************************************
+ * Copyright (c) 2009 QNX Software Systems 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:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.internal.ui.workingsets;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.ui.IWorkingSet;
+
+import org.eclipse.cdt.ui.CUIPlugin;
+
+/**
+ * The view controller for the working set configurations pane in the dialog. It takes care of coordinating
+ * the user gestures in the pane with the working set configuration model, and vice-versa. It also implements
+ * the handling of the action buttons.
+ *
+ * @author Christian W. Damus (cdamus)
+ *
+ * @since 6.0
+ *
+ */
+class WorkingSetConfigsController implements SelectionListener, ISelectionChangedListener {
+
+ private TreeViewer tree;
+ private Button addButton;
+ private Button removeButton;
+ private Button renameButton;
+ private Button activateButton;
+ private Button buildButton;
+
+ private IWorkingSetProxy.ISnapshot initialWorkingSet;
+ private IWorkingSetProxy.ISnapshot currentWorkingSet;
+ private IWorkingSetConfiguration.ISnapshot currentConfig;
+
+ private final WorkspaceSnapshot workspace;
+
+ private ProjectConfigsController projectsController;
+
+ /**
+ * Initializes me we an initial working set to select.
+ */
+ WorkingSetConfigsController(WorkspaceSnapshot workspace, IWorkingSetProxy.ISnapshot initialWorkingSet) {
+ this.workspace = workspace;
+
+ if (initialWorkingSet != null) {
+ this.initialWorkingSet = initialWorkingSet;
+ } else {
+ IWorkingSet[] recent = WorkingSetConfigurationManager.WS_MGR.getRecentWorkingSets();
+ if ((recent != null) && (recent.length > 0)) {
+ this.initialWorkingSet = workspace.getWorkingSet(recent[0].getName());
+ }
+ }
+ }
+
+ /**
+ * Initializes me.
+ */
+ WorkingSetConfigsController(WorkspaceSnapshot workspace) {
+ this(workspace, null);
+ }
+
+ /**
+ * Assigns the tree viewer that I control.
+ *
+ * @param tree
+ * my tree viewer
+ */
+ void setTreeViewer(final TreeViewer tree) {
+ if (this.tree != null) {
+ this.tree.removeSelectionChangedListener(this);
+ }
+
+ this.tree = tree;
+
+ if (this.tree != null) {
+ this.tree.addSelectionChangedListener(this);
+
+ this.tree.setInput(workspace.getWorkingSets());
+
+ if (!workspace.getWorkingSets().isEmpty()) {
+ tree.getTree().getDisplay().asyncExec(new Runnable() {
+
+ public void run() {
+ Object initialSelection;
+
+ ITreeContentProvider content = (ITreeContentProvider) tree.getContentProvider();
+
+ if ((initialWorkingSet != null)
+ && Arrays.asList(content.getElements(tree.getInput())).contains(
+ initialWorkingSet)) {
+ initialSelection = initialWorkingSet;
+ } else {
+ // we have a most-recently-used working set. Just
+ // take the first in tree order
+ initialSelection = tree.getTree().getItem(0).getData();
+ }
+
+ Object[] children = content.getChildren(initialSelection);
+ IStructuredSelection sel;
+
+ if ((children == null) || (children.length == 0)) {
+ // Shouldn't happen: there should at least be the
+ // read-only config.
+ // Can only select the initial working set
+ sel = new StructuredSelection(initialSelection);
+ } else {
+ Object[] toSort = new Object[children.length];
+ System.arraycopy(children, 0, toSort, 0, children.length);
+ tree.getComparator().sort(tree, toSort);
+ sel = new StructuredSelection(toSort[0]);
+ }
+
+ // make the selection
+ tree.setSelection(sel, true);
+ }
+ });
+ }
+ }
+ }
+
+ private Button updateButton(Button oldButton, Button newButton) {
+ if (oldButton != null) {
+ oldButton.removeSelectionListener(this);
+ }
+
+ if (newButton != null) {
+ newButton.addSelectionListener(this);
+ }
+
+ return newButton;
+ }
+
+ /**
+ * Assigns me my "Add..." button.
+ *
+ * @param addButton
+ * my add button
+ */
+ void setAddButton(Button addButton) {
+ this.addButton = updateButton(this.addButton, addButton);
+ }
+
+ /**
+ * Assigns me my "Remove" button.
+ *
+ * @param removeButton
+ * my remove button
+ */
+ void setRemoveButton(Button removeButton) {
+ this.removeButton = updateButton(this.removeButton, removeButton);
+ }
+
+ /**
+ * Assigns me my "Rename..." button.
+ *
+ * @param renameButton
+ * my rename button
+ */
+ void setRenameButton(Button renameButton) {
+ this.renameButton = updateButton(this.renameButton, renameButton);
+ }
+
+ /**
+ * Assigns me my "Activate" button.
+ *
+ * @param activateButton
+ * my activate button
+ */
+ void setActivateButton(Button activateButton) {
+ this.activateButton = updateButton(this.activateButton, activateButton);
+ }
+
+ /**
+ * Assigns me my "Build" button.
+ *
+ * @param buildButton
+ * my build button
+ */
+ void setBuildButton(Button buildButton) {
+ this.buildButton = updateButton(this.buildButton, buildButton);
+ }
+
+ /**
+ * Connects me to the controller for the project configurations pane, into which I inject the currently
+ * selected working set configuration.
+ *
+ * @param controller
+ * my project configurations controller
+ */
+ void setProjectConfigsController(ProjectConfigsController controller) {
+ this.projectsController = controller;
+
+ if (controller != null) {
+ controller.setWorkingSetConfiguration(currentConfig);
+ }
+ }
+
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // not interesting
+ }
+
+ /**
+ * Handles button presses in the working set configurations pane.
+ */
+ public void widgetSelected(SelectionEvent e) {
+ // handle button press
+ if (e.widget == addButton) {
+ addConfig();
+ } else if (e.widget == removeButton) {
+ removeConfig();
+ } else if (e.widget == renameButton) {
+ renameConfig();
+ } else if (e.widget == activateButton) {
+ activateConfig();
+ } else if (e.widget == buildButton) {
+ buildConfig();
+ }
+ }
+
+ /**
+ * Handles selection of working sets and their configurations. Among potentially other actions, this
+ * injects the working-set configuration selection into the project configurations controller and updates
+ * the enablement of the buttons.
+ */
+ public void selectionChanged(SelectionChangedEvent event) {
+ currentConfig = null;
+ currentWorkingSet = null;
+
+ if (event.getSelection() instanceof IStructuredSelection) {
+ IStructuredSelection sel = (IStructuredSelection) event.getSelection();
+
+ if (!sel.isEmpty()) {
+ Object first = sel.getFirstElement();
+
+ if (first instanceof IWorkingSetConfiguration) {
+ currentConfig = (IWorkingSetConfiguration.ISnapshot) first;
+ currentWorkingSet = currentConfig.getWorkingSet();
+ } else if (first instanceof IWorkingSetProxy) {
+ currentWorkingSet = (IWorkingSetProxy.ISnapshot) first;
+ }
+ }
+ }
+
+ if (projectsController != null) {
+ // tell the project controller
+ projectsController.setWorkingSetConfiguration(currentConfig);
+ }
+
+ updateButtons();
+ }
+
+ /**
+ * Handler for the "Add..." button.
+ */
+ private void addConfig() {
+ InputDialog dlg = new InputDialog(tree.getTree().getShell(),
+ WorkingSetMessages.WSConfigsController_addDlg_title,
+ WorkingSetMessages.WSConfigsController_addDlg_msg,
+ WorkingSetMessages.WSConfigsController_addDlg_defaultName, new IInputValidator() {
+
+ public String isValid(String newText) {
+ if (currentWorkingSet.getConfiguration(newText) != null) {
+ return WorkingSetMessages.WSConfigsController_addDlg_nameExists;
+ }
+ if (newText.length() == 0) {
+ return WorkingSetMessages.WSConfigsController_addDlg_emptyName;
+ }
+ return null;
+ }
+ });
+
+ if (dlg.open() == IDialogConstants.OK_ID) {
+ IWorkingSetConfiguration.ISnapshot newConfig = currentWorkingSet.createConfiguration(dlg
+ .getValue());
+ tree.refresh(currentWorkingSet);
+ tree.setSelection(new StructuredSelection(newConfig), true);
+ currentConfig = newConfig;
+ currentWorkingSet = currentConfig.getWorkingSet();
+
+ // this is a "recently used" working set
+ IWorkingSet ws = currentWorkingSet.resolve();
+ if (ws != null) {
+ WorkingSetConfigurationManager.WS_MGR.addRecentWorkingSet(ws);
+ }
+ }
+ }
+
+ /**
+ * Handler for the "Remove" button.
+ */
+ private void removeConfig() {
+ currentWorkingSet.removeConfiguration(currentConfig);
+ tree.refresh(currentWorkingSet);
+ }
+
+ /**
+ * Handler for the "Rename..." button.
+ */
+ private void renameConfig() {
+ InputDialog dlg = new InputDialog(tree.getTree().getShell(),
+ WorkingSetMessages.WSConfigsController_renameDlg_title,
+ WorkingSetMessages.WSConfigsController_renameDlg_msg, currentConfig.getName(),
+ new IInputValidator() {
+
+ public String isValid(String newText) {
+ if (newText.equals(currentConfig.getName())) {
+ return ""; //$NON-NLS-1$
+ }
+ if (currentWorkingSet.getConfiguration(newText) != null) {
+ return WorkingSetMessages.WSConfigsController_addDlg_nameExists;
+ }
+ if (newText.length() == 0) {
+ return WorkingSetMessages.WSConfigsController_addDlg_emptyName;
+ }
+ return null;
+ }
+ });
+
+ if (dlg.open() == IDialogConstants.OK_ID) {
+ currentConfig.setName(dlg.getValue());
+ tree.refresh(currentWorkingSet);
+ }
+ }
+
+ /**
+ * Handler for the "Activate" button.
+ */
+ private void activateConfig() {
+ currentConfig.activate();
+ projectsController.update();
+ updateForActivation();
+ }
+
+ /**
+ * Updates the display to reflect potential changes in project activation and the resulting changes in
+ * working-set config activation, if any.
+ */
+ private void updateForActivation() {
+ // update all working-set configs that intersect this config
+ Collection unaffectedWorkingSets = new java.util.HashSet(
+ workspace.getWorkingSets());
+
+ for (IProject project : currentConfig.getWorkingSet().resolveProjects()) {
+ for (Iterator iter = unaffectedWorkingSets.iterator(); iter.hasNext();) {
+ IWorkingSetProxy.ISnapshot next = iter.next();
+
+ if (next.resolveProjects().contains(project)) {
+ iter.remove();
+
+ if (next.updateActiveConfigurations()) {
+ // major change. Refresh it altogether
+ tree.refresh(next);
+ } else {
+ // lighter-weight updates of its configs
+ for (IWorkingSetConfiguration config : next.getConfigurations()) {
+ tree.update(config, null);
+ }
+ }
+ }
+ }
+ }
+
+ updateButtons();
+ }
+
+ /**
+ * Handler for the "Build" button.
+ */
+ private void buildConfig() {
+ final IStatus[] problem = new IStatus[1];
+
+ try {
+ ProgressMonitorDialog dlg = new ProgressMonitorDialog(tree.getControl().getShell());
+ dlg.run(true, true, new IRunnableWithProgress() {
+
+ public void run(IProgressMonitor monitor) {
+ IStatus status = currentConfig.build(monitor);
+ if (status.matches(IStatus.WARNING | IStatus.ERROR)) {
+ problem[0] = status;
+ }
+ }
+ });
+ } catch (Exception e) {
+ CUIPlugin.log(WorkingSetMessages.WSConfigsController_buildFailedLog, e);
+ }
+
+ // it is possible that some project configurations had to applied in
+ // order to effect a build. Refresh to handle that case
+ updateForActivation();
+
+ if (problem[0] != null) {
+ // show the problem
+ ErrorDialog.openError(tree.getControl().getShell(),
+ WorkingSetMessages.WSConfigsController_buildFailedDlgTitle,
+ WorkingSetMessages.WSConfigsController_buildFailedDlgMsg, problem[0]);
+ }
+ }
+
+ /**
+ * Updates the enablement state of the action buttons according to the current selection.
+ */
+ private void updateButtons() {
+ if (addButton != null) {
+ addButton.setEnabled(currentWorkingSet != null);
+ }
+ if (removeButton != null) {
+ removeButton.setEnabled((currentConfig != null) && !currentConfig.isReadOnly());
+ }
+ if (renameButton != null) {
+ renameButton.setEnabled((currentConfig != null) && !currentConfig.isReadOnly());
+ }
+ if (activateButton != null) {
+ activateButton.setEnabled((currentConfig != null) && !currentConfig.isActive());
+ }
+ if (buildButton != null) {
+ buildButton.setEnabled(currentConfig != null);
+ }
+ }
+
+ /**
+ * Notification that the selection of configuration(s) in some project in the current working set
+ * configuration has changed. I accordingly update the visuals of the working-set configuration to
+ * indicate whether it is active or not.
+ *
+ * @param project
+ * the project configuration whose active configuration selections have changed
+ */
+ void projectSelectionsChanged(IWorkingSetProjectConfiguration project) {
+ tree.update(currentConfig, null);
+ updateButtons(); // depends on whether the ws config is active
+ }
+}
\ No newline at end of file
Index: src/org/eclipse/cdt/internal/ui/workingsets/AbstractWorkingSetConfigsContribution.java
===================================================================
RCS file: src/org/eclipse/cdt/internal/ui/workingsets/AbstractWorkingSetConfigsContribution.java
diff -N src/org/eclipse/cdt/internal/ui/workingsets/AbstractWorkingSetConfigsContribution.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/internal/ui/workingsets/AbstractWorkingSetConfigsContribution.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2009 QNX Software Systems 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:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.internal.ui.workingsets;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.actions.CompoundContributionItem;
+
+import com.ibm.icu.text.Collator;
+
+import org.eclipse.cdt.ui.CUIPlugin;
+
+/**
+ * Common API of dynamic contribution of items to manipulate configurations of a working set.
+ *
+ * @author Christian W. Damus (cdamus)
+ *
+ * @since 6.0
+ */
+abstract class AbstractWorkingSetConfigsContribution extends CompoundContributionItem {
+
+ private IWorkingSetProxy workingSet;
+
+ private Comparator configOrdering = new Comparator() {
+ private Collator collator = Collator.getInstance();
+
+ public int compare(IWorkingSetConfiguration o1, IWorkingSetConfiguration o2) {
+ return collator.compare(o1.getName(), o2.getName());
+ }
+ };
+
+ /**
+ * Initializes me without a working set. I figure it out, later. This is only appropriate usage for
+ * context-menu contribution, where the workbench selection is obvious.
+ */
+ public AbstractWorkingSetConfigsContribution() {
+ super();
+ }
+
+ /**
+ * Initializes me with my working set.
+ *
+ * @param workingSet
+ * my working set
+ */
+ AbstractWorkingSetConfigsContribution(IWorkingSetProxy workingSet) {
+ super();
+
+ this.workingSet = workingSet;
+ }
+
+ @Override
+ protected IContributionItem[] getContributionItems() {
+ if (getWorkingSet() == null) {
+ return new IContributionItem[0];
+ }
+
+ // sort the configurations by name
+ List configs = new java.util.ArrayList(
+ getWorkingSet().getConfigurations());
+ Collections.sort(configs, configOrdering);
+
+ IContributionItem[] result = new IContributionItem[configs.size()];
+ int i = 0;
+ for (IWorkingSetConfiguration next : configs) {
+ result[i] = createContribution(next, i);
+ i++;
+ }
+
+ return result;
+ }
+
+ /**
+ * Creates a contribution item for a specific configuration of my working set.
+ *
+ * @param config
+ * a configuration of my working set
+ * @param index
+ * the index of the contribution in the composite
+ *
+ * @return the contribution
+ */
+ protected abstract IContributionItem createContribution(IWorkingSetConfiguration config, int index);
+
+ /**
+ * Obtains my working set. It may be lazily determined from the current workbench selection.
+ *
+ * @return my working set
+ */
+ protected IWorkingSetProxy getWorkingSet() {
+ if (workingSet == null) {
+ ISelection sel = CUIPlugin.getActivePage().getSelection();
+ if (sel instanceof IStructuredSelection) {
+ IStructuredSelection ssel = (IStructuredSelection) sel;
+
+ if (!ssel.isEmpty()) {
+ Object first = ssel.getFirstElement();
+ if (first instanceof IWorkingSet) {
+ workingSet = WorkingSetConfigurationManager.getDefault().getWorkingSet(
+ ((IWorkingSet) first).getName());
+ }
+ }
+ }
+ }
+
+ return workingSet;
+ }
+}
Index: src/org/eclipse/cdt/internal/ui/workingsets/BuildWorkingSetsContribution.java
===================================================================
RCS file: src/org/eclipse/cdt/internal/ui/workingsets/BuildWorkingSetsContribution.java
diff -N src/org/eclipse/cdt/internal/ui/workingsets/BuildWorkingSetsContribution.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/internal/ui/workingsets/BuildWorkingSetsContribution.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2009 QNX Software Systems 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:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.internal.ui.workingsets;
+
+import org.eclipse.jface.action.IContributionItem;
+
+/**
+ * A dynamic contribution of sub-menus to build working sets, with further sub-menus showing the
+ * configurations to choose from.
+ *
+ * @author Christian W. Damus (cdamus)
+ *
+ * @since 6.0
+ */
+public class BuildWorkingSetsContribution extends AbstractWorkingSetsContribution {
+
+ /**
+ * Initializes me.
+ */
+ public BuildWorkingSetsContribution() {
+ super();
+ }
+
+ @Override
+ protected IContributionItem createContribution(IWorkingSetProxy workingSet) {
+ return new BuildWorkingSetConfigsContribution(workingSet);
+ }
+}
Index: src/org/eclipse/cdt/internal/ui/workingsets/WorkspaceSnapshot.java
===================================================================
RCS file: src/org/eclipse/cdt/internal/ui/workingsets/WorkspaceSnapshot.java
diff -N src/org/eclipse/cdt/internal/ui/workingsets/WorkspaceSnapshot.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/internal/ui/workingsets/WorkspaceSnapshot.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,525 @@
+/*******************************************************************************
+ * Copyright (c) 2009 QNX Software Systems 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:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.internal.ui.workingsets;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.IWorkingSet;
+
+import org.eclipse.cdt.core.model.CoreModel;
+import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
+import org.eclipse.cdt.core.settings.model.ICProjectDescription;
+import org.eclipse.cdt.ui.CUIPlugin;
+
+/**
+ *
+ * A snapshot of the working set configurations and project configurations across the workspace at the time
+ * when it was created. The snapshot maintains a delta from that original state to the current state, for such
+ * comparison operations as determining which projects need to be re-built because their active configurations
+ * have changed. The snapshot provides mutable working-copy views of the working set configurations at the
+ * time of snapshot creation.
+ *
+ *
+ * To make changes to working set configurations, first
+ * {@linkplain WorkingSetConfigurationManager#createWorkspaceSnapshot() obtain a snapshot} from the
+ * {@link WorkingSetConfigurationManager}. Then make edits to the various snapshots of the configuration
+ * elements and {@linkplain #save() save} the snapshot
+ *
+ *
+ * @author Christian W. Damus (cdamus)
+ *
+ * @since 6.0
+ *
+ */
+public class WorkspaceSnapshot {
+ private Map workingSets = new java.util.HashMap();
+ private Map projectStates = new java.util.HashMap();
+
+ /**
+ * Initializes me. I capture the current C/C++ active configuration state of the projects in the
+ * workspace.
+ */
+ WorkspaceSnapshot() {
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+
+ for (IProject next : root.getProjects()) {
+ ICProjectDescription desc = CoreModel.getDefault().getProjectDescription(next);
+
+ if (desc != null) {
+ projectStates.put(next, createProjectState(next, desc));
+ }
+ }
+ }
+
+ /**
+ * Creates a project state using the registered factory, if possible.
+ *
+ * @param project
+ * a workspace project
+ * @param desc
+ * its CDT project description
+ *
+ * @return its state capture (will never be null
)
+ */
+ private static ProjectState createProjectState(IProject project, ICProjectDescription desc) {
+ ProjectState result = null;
+ IWorkingSetProjectConfigurationFactory factory = IWorkingSetProjectConfigurationFactory.Registry.INSTANCE
+ .getFactory(project);
+
+ if (factory != null) {
+ result = factory.createProjectState(project, desc);
+ }
+
+ if (result == null) {
+ // the default-default
+ result = new ProjectState(project, desc);
+ }
+
+ return result;
+ }
+
+ /**
+ * Initializes me with the specified working sets to copy for editing.
+ *
+ * @param workingSets
+ * the working sets to copy
+ * @return myself
+ */
+ WorkspaceSnapshot initialize(Map workingSets) {
+ for (IWorkingSet next : WorkingSetConfigurationManager.WS_MGR.getWorkingSets()) {
+ IWorkingSetProxy workingSet = workingSets.get(next.getName());
+
+ if (workingSet == null) {
+ workingSet = new WorkingSetProxy();
+ ((WorkingSetProxy) workingSet).setName(next.getName());
+ }
+
+ if (workingSet.isValid()) {
+ this.workingSets.put(workingSet.getName(), workingSet.createSnapshot(this));
+ }
+ }
+
+ return this;
+ }
+
+ /**
+ * Obtains a mutable snapshot of the named working set.
+ *
+ * @param name
+ * the working set to retrieve
+ *
+ * @return the working set snapshot, or null
if there is no working set by this name
+ *
+ * @see #getWorkingSets()
+ */
+ public IWorkingSetProxy.ISnapshot getWorkingSet(String name) {
+ return workingSets.get(name);
+ }
+
+ /**
+ * Obtains snapshots of all of the working sets currently defined by the workbench.
+ *
+ * @return the working set snapshots
+ *
+ * @see #getWorkingSet(String)
+ */
+ public Collection getWorkingSets() {
+ return workingSets.values();
+ }
+
+ /**
+ * Obtains the project state recording the initial configuration of the specified project at the
+ * time that this snapshot was taken.
+ *
+ * @param project
+ * a project
+ * @return its snapshot/delta state
+ */
+ public ProjectState getState(IProject project) {
+ return projectStates.get(project);
+ }
+
+ /**
+ * Queries the ID of the configuration of the specified project that was active when the workspace
+ * snapshot was taken.
+ *
+ * @param project
+ * a project
+ * @return its active configuration ID at the time of the snapshot
+ */
+ String getBaselineConfigurationID(IProject project) {
+ String result = null;
+ ProjectState state = getState(project);
+
+ if (state != null) {
+ result = state.getBaselineConfigurationID();
+ }
+
+ return result;
+ }
+
+ /**
+ * Queries the ID of the currently active configuration of the specified project.
+ *
+ * @param project
+ * a project
+ *
+ * @return the current active configuration ID
+ */
+ String getActiveConfigurationID(IProject project) {
+ String result = null;
+ ProjectState state = getState(project);
+
+ if (state != null) {
+ result = state.getActiveConfigurationID();
+ }
+
+ return result;
+ }
+
+ /**
+ * Queries whether the configuration selected by the given project in a working set configuration is
+ * currently active in the workspace.
+ *
+ * @param project
+ * a project configuration element in a working set configuration
+ *
+ * @return whether the project's selected configuration is active
+ *
+ * @see #activate(IProject, String)
+ */
+ boolean isActive(IWorkingSetProjectConfiguration project) {
+ boolean result = false;
+ ProjectState state = getState(project.resolveProject());
+
+ if (state != null) {
+ result = state.isActive(project.getSelectedConfigurationID());
+ }
+
+ return result;
+ }
+
+ /**
+ * Activates, in the workspace, the specified configuration of a project. This method has no effect if the
+ * given configuration is already active.
+ *
+ * @param project
+ * the project for which to set the active configuration
+ * @param configID
+ * the ID of the configuration to activate
+ *
+ * @see #isActive(IWorkingSetProjectConfiguration)
+ */
+ void activate(IProject project, String configID) {
+ ProjectState state = getState(project);
+
+ if (state != null) {
+ state.activate(configID);
+ }
+ }
+
+ IStatus build(IProject project, String configID, IProgressMonitor monitor) {
+ ProjectState state = getState(project);
+
+ if (state != null) {
+ return state.build(configID, monitor);
+ }
+
+ return new Status(IStatus.ERROR, CUIPlugin.PLUGIN_ID, NLS.bind(
+ WorkingSetMessages.WorkspaceSnapshot_buildNoProj, project.getName()));
+ }
+
+ /**
+ * Obtains the configurations of the specified project, as known at the time that this snapshot was taken.
+ *
+ * @param project
+ * a project
+ *
+ * @return its configurations, which may be an empty collection if the project is not a C/C++ project
+ */
+ public Collection getConfigurations(IProject project) {
+ Collection result;
+ ProjectState state = getState(project);
+
+ if (state == null) {
+ result = Collections.emptyList();
+ } else {
+ result = state.getConfigurations();
+ }
+
+ return result;
+ }
+
+ /**
+ * Obtains the specified configuration of a project, as known at the time that this snapshot was taken.
+ *
+ * @param project
+ * a project
+ * @param id
+ * the ID of a configuration
+ *
+ * @return the configuration, or null
if there is none such by this ID
+ */
+ public ICConfigurationDescription getConfiguration(IProject project, String id) {
+ ProjectState state = getState(project);
+ return (state == null) ? null : state.getConfiguration(id);
+ }
+
+ /**
+ * Queries the projects that need to be built because their active configurations have been changed since
+ * this snapshot was taken.
+ *
+ * @return the projects needing to be re-built
+ */
+ public Collection getProjectsToBuild() {
+ Collection result = new java.util.ArrayList();
+
+ for (ProjectState next : projectStates.values()) {
+ if (next.needsBuild()) {
+ result.add(next.getProject());
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Saves my working set configuration settings.
+ */
+ public void save() {
+ WorkingSetConfigurationManager.getDefault().save(this);
+ }
+
+ //
+ // Nested classes
+ //
+
+ /**
+ * Capture of the current state of a project at the time when a {@linkplain WorkspaceSnapshot workspace
+ * snapshot} was taken, and its delta from that original state. This tracks at least the C/C++ project
+ * description (if any) and the original active configuration. Subclasses may track additional
+ * configuration details.
+ *
+ * @author Christian W. Damus (cdamus)
+ *
+ * @since 6.0
+ */
+ public static class ProjectState {
+ private final IProject project;
+ private final ICProjectDescription projectDescription;
+ private final String baselineConfigID;
+ private String currentConfigID;
+ private String lastBuiltConfigID;
+
+ /**
+ * Initializes me with a project and its description.
+ *
+ * @param project
+ * the project whose state I track
+ * @param desc
+ * the project's description, from which I capture the initial state snapshot
+ */
+ protected ProjectState(IProject project, ICProjectDescription desc) {
+ this.project = project;
+ this.projectDescription = desc;
+
+ if (desc != null) {
+ ICConfigurationDescription config = desc.getActiveConfiguration();
+ this.baselineConfigID = (config == null) ? "" : config.getId(); //$NON-NLS-1$
+ } else {
+ this.baselineConfigID = ""; //$NON-NLS-1$
+ }
+
+ this.currentConfigID = this.baselineConfigID;
+ }
+
+ /**
+ * Obtains the project that I track.
+ *
+ * @return my project
+ */
+ public final IProject getProject() {
+ return project;
+ }
+
+ /**
+ * Obtains the project description that was current when the snapshot was taken.
+ *
+ * @return my project description
+ */
+ protected final ICProjectDescription getProjectDescription() {
+ return projectDescription;
+ }
+
+ /**
+ * Queries whether my project needs to be re-built because its active configuration has been changed
+ * since the snapshot was taken, and it hasn't been built already.
+ *
+ * @return whether I need to be re-built
+ */
+ public boolean needsBuild() {
+ return !currentConfigID.equals(baselineConfigID) && !currentConfigID.equals(lastBuiltConfigID);
+ }
+
+ /**
+ * Queries whether the specified configuration is currently active in the workspace for my project.
+ *
+ * @param configID
+ * the ID of a project build configuration
+ * @return whether it is my project's active configuration
+ */
+ public boolean isActive(String configID) {
+ return currentConfigID.equals(configID);
+ }
+
+ /**
+ * Queries the ID of the currently active configuration.
+ *
+ * @return the current active configuration ID
+ */
+ protected String getActiveConfigurationID() {
+ return currentConfigID;
+ }
+
+ /**
+ * Queries the ID of the configuration of my project that was active when the workspace snapshot was
+ * taken.
+ *
+ * @return its active configuration ID at the time of the snapshot
+ */
+ protected String getBaselineConfigurationID() {
+ return baselineConfigID;
+ }
+
+ /**
+ * Sets my project's active configuration to the specified configuration. This method has no effect if
+ * this configuration is already active.
+ *
+ * @param configID
+ * the ID of the configuration to activate
+ */
+ protected void activate(String configID) {
+ if (!currentConfigID.equals(configID) && (projectDescription != null)) {
+ try {
+ ICConfigurationDescription realConfig = projectDescription.getConfigurationById(configID);
+ realConfig.setActive();
+ CoreModel.getDefault().setProjectDescription(project, projectDescription);
+ currentConfigID = configID;
+ } catch (CoreException e) {
+ CUIPlugin.log(e);
+ }
+ }
+ }
+
+ /**
+ * Builds the specified configuration of my project. I update myself to record a new build baseline if
+ * the build succeeds.
+ *
+ * @param configID
+ * the configuration to build
+ * @param monitor
+ * a monitor to report build progress
+ *
+ * @return the status of the build
+ */
+ protected IStatus build(String configID, IProgressMonitor monitor) {
+ IStatus result = Status.OK_STATUS;
+
+ ICConfigurationDescription config = getConfiguration(configID);
+
+ if (config == null) {
+ result = new Status(IStatus.WARNING, CUIPlugin.PLUGIN_ID, NLS.bind(
+ WorkingSetMessages.WSProjConfig_noConfig, getProject().getName()));
+ } else {
+ if (!isActive(configID)) {
+ activate(configID);
+ result = new Status(IStatus.WARNING, CUIPlugin.PLUGIN_ID, NLS.bind(
+ WorkingSetMessages.WSProjConfig_activatedWarning, config.getName(), getProject()
+ .getName()));
+ }
+
+ monitor = SubMonitor.convert(monitor);
+
+ try {
+ getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, monitor);
+
+ // update the build baseline to this config, which is now active
+ built(configID);
+ } catch (CoreException e) {
+ if (result.isOK()) {
+ result = e.getStatus();
+ } else {
+ result = new MultiStatus(CUIPlugin.PLUGIN_ID, 0, new IStatus[] { result,
+ e.getStatus() }, NLS.bind(WorkingSetMessages.WSProjConfig_buildProblem,
+ getProject().getName()), null);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Records that we built the specified configuration ID. I will not {@linkplain #needsBuild() need a
+ * build} if the last build configuration is my active configuration.
+ *
+ * @param configID
+ * the configuration that was built (not null
)
+ */
+ protected void built(String configID) {
+ lastBuiltConfigID = configID;
+ }
+
+ /**
+ * Obtains the configurations of my project that were defined at the time that the snapshot was taken.
+ *
+ * @return my project's configurations, which may be empty if it is not a C/C++ project
+ */
+ protected Collection getConfigurations() {
+ Collection result;
+
+ if (projectDescription == null) {
+ result = Collections.emptyList();
+ } else {
+ result = Arrays.asList(projectDescription.getConfigurations());
+ }
+
+ return result;
+ }
+
+ /**
+ * Obtains the specified configuration of my project as it was defined at the time that the snapshot
+ * was taken.
+ *
+ * @param id
+ * a configuration ID
+ * @return the matching configuration, or null
if it did not exist
+ */
+ protected ICConfigurationDescription getConfiguration(String id) {
+ return (projectDescription == null) ? null : projectDescription.getConfigurationById(id);
+ }
+ }
+}
\ No newline at end of file
Index: src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfigurationManager.java
===================================================================
RCS file: src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfigurationManager.java
diff -N src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfigurationManager.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfigurationManager.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,415 @@
+/*******************************************************************************
+ * Copyright (c) 2009 QNX Software Systems 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:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.internal.ui.workingsets;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.IWorkingSetManager;
+import org.eclipse.ui.XMLMemento;
+
+import org.eclipse.cdt.ui.CUIPlugin;
+import org.eclipse.cdt.ui.newui.CDTPrefUtil;
+
+/**
+ * The purveyor of working set configurations. It provides a current view of the {@linkplain IWorkingSetProxy
+ * working set configurations} defined in the workspace, as well as a working-copy
+ * {@linkplain WorkspaceSnapshot snapshot} of the same for making modifications.
+ *
+ * @author Christian W. Damus (cdamus)
+ *
+ * @since 6.0
+ *
+ */
+public class WorkingSetConfigurationManager {
+
+ static final String TYPE_WORKING_SET_CONFIGS = "org.eclipse.cdt.ui.workingSetConfigurations"; //$NON-NLS-1$
+ static final String KEY_WORKING_SET = "workingSet"; //$NON-NLS-1$
+ static final String ATTR_NAME = "name"; //$NON-NLS-1$
+ static final String KEY_CONFIG = "config"; //$NON-NLS-1$
+ static final String KEY_PROJECT = "project"; //$NON-NLS-1$
+ static final String ATTR_CONFIG = "config"; //$NON-NLS-1$
+ static final String ATTR_FACTORY = "factory"; //$NON-NLS-1$
+
+ static IWorkingSetManager WS_MGR = CUIPlugin.getDefault().getWorkbench().getWorkingSetManager();
+
+ private static final WorkingSetConfigurationManager INSTANCE = new WorkingSetConfigurationManager();
+
+ private Map workingSets;
+
+ private final Object storeLock = new Object();
+ private IMemento store;
+
+ private final ISchedulingRule saveRule = new ISchedulingRule() {
+
+ public boolean isConflicting(ISchedulingRule rule) {
+ return rule == this;
+ }
+
+ public boolean contains(ISchedulingRule rule) {
+ return rule == this;
+ }
+ };
+
+ /**
+ * Not instantiable by clients.
+ */
+ private WorkingSetConfigurationManager() {
+ store = loadMemento();
+ new WorkingSetChangeTracker();
+ }
+
+ /**
+ * Obtains the default working set configuration manager.
+ *
+ * @return the working set configuration manager
+ */
+ public static WorkingSetConfigurationManager getDefault() {
+ return INSTANCE;
+ }
+
+ private Map getWorkingSetMap() {
+ Map result;
+
+ synchronized (storeLock) {
+ if (workingSets == null) {
+ load();
+ }
+ result = workingSets;
+ }
+
+ return result;
+ }
+
+ /**
+ * Obtains the current immutable view of the specified working set's configurations. These configurations
+ * may be {@linkplain IWorkingSetConfiguration#activate() activated} to apply their settings to the
+ * workspace, but they cannot be modified.
+ *
+ * @param name
+ * the name of the working set to retrieve
+ * @return the named working set, or null
if there is none available by that name
+ */
+ public IWorkingSetProxy getWorkingSet(String name) {
+ return getWorkingSetMap().get(name);
+ }
+
+ /**
+ * Obtains the current immutable view of all available working set configurations. These configurations
+ * may be {@linkplain IWorkingSetConfiguration#activate() activated} to apply their settings to the
+ * workspace, but they cannot be modified.
+ *
+ * @return the working set configurations
+ */
+ public Collection getWorkingSets() {
+ return getWorkingSetMap().values();
+ }
+
+ /**
+ * Creates a new mutable snapshot of the current working set configurations. This snapshot accepts
+ * modifications and can be {@linkplain WorkspaceSnapshot#save() saved} to persist the changes.
+ *
+ * @return a working-copy of the working set configurations
+ */
+ public WorkspaceSnapshot createWorkspaceSnapshot() {
+ return new WorkspaceSnapshot().initialize(getWorkingSetMap());
+ }
+
+ /**
+ *
+ * Loads the working set configurations from storage.
+ *
+ *
+ * Note that this method must only be called within the storeLock monitor.
+ *
+ */
+ private void load() {
+ workingSets = new java.util.HashMap();
+
+ for (IMemento next : store.getChildren(KEY_WORKING_SET)) {
+ WorkingSetProxy ws = new WorkingSetProxy();
+
+ ws.loadState(next);
+
+ if (ws.isValid()) {
+ workingSets.put(ws.getName(), ws);
+ }
+ }
+ }
+
+ /**
+ *
+ * Forgets the current view of the working set configurations.
+ *
+ *
+ * Note that this method must only be called within the storeLock monitor.
+ *
+ */
+ private void clear() {
+ workingSets = null;
+ }
+
+ /**
+ * Saves the working set configurations to storage.
+ *
+ * @param snapshot
+ * the snapshot to save
+ */
+ void save(WorkspaceSnapshot snapshot) {
+ final XMLMemento memento = XMLMemento.createWriteRoot(TYPE_WORKING_SET_CONFIGS);
+
+ for (IWorkingSetConfigurationElement next : snapshot.getWorkingSets()) {
+ next.saveState(memento.createChild(KEY_WORKING_SET));
+ }
+
+ save(memento);
+ }
+
+ /**
+ * Records the specified memento as our new store and asynchronously saves it in a job.
+ *
+ * @param memento
+ * the new store
+ */
+ private void save(final XMLMemento memento) {
+ synchronized (storeLock) {
+ store = memento;
+ clear();
+ }
+
+ new Job(WorkingSetMessages.WSConfigManager_save_job) {
+ {
+ setRule(saveRule);
+ setSystem(true);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+
+ File file = getStorage();
+ FileWriter writer = null;
+ try {
+ writer = new FileWriter(file);
+ memento.save(writer);
+ writer.close();
+ } catch (IOException e) {
+ if (writer != null) {
+ try {
+ writer.close();
+ } catch (IOException e2) {
+ // no recovery
+ CUIPlugin.log(WorkingSetMessages.WSConfigManager_closeFailed, e);
+ }
+ }
+
+ file.delete(); // it is corrupt; we won't be able to load it, later
+
+ CUIPlugin.log(WorkingSetMessages.WSConfigManager_saveFailed, e);
+ }
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ /**
+ * Gets the file in which we persist the working set configurations.
+ *
+ * @return the file store
+ */
+ private File getStorage() {
+ IPath path = CUIPlugin.getDefault().getStateLocation().append("workingSetConfigs.xml"); //$NON-NLS-1$
+ return path.toFile();
+ }
+
+ /**
+ * Loads the working set configurations from storage. For compatibility, if the XML file is not available,
+ * we load from the old preference setting format.
+ *
+ * @return the working set configuration store
+ */
+ private IMemento loadMemento() {
+ IMemento result = null;
+
+ File file = getStorage();
+
+ if (file.exists()) {
+ FileReader reader = null;
+ try {
+ reader = new FileReader(file);
+ result = XMLMemento.createReadRoot(reader);
+ reader.close();
+ } catch (Exception e) {
+ result = null;
+
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (IOException e2) {
+ // no recovery
+ CUIPlugin.log(WorkingSetMessages.WSConfigManager_closeFailed, e);
+ }
+ }
+
+ CUIPlugin.log(WorkingSetMessages.WSConfigManager_loadFailed, e);
+ }
+ }
+
+ if (result == null) {
+ // fake one from the old preference storage format. This also
+ // handles the case of no working set configurations ever being made
+ @SuppressWarnings("deprecation")
+ List configSetStrings = CDTPrefUtil.readConfigSets();
+ result = XMLMemento.createWriteRoot(TYPE_WORKING_SET_CONFIGS);
+
+ // collect the unordered entries by working set
+ Map configMap = new HashMap();
+ for (String next : configSetStrings) {
+ String[] bits = next.split(" "); //$NON-NLS-1$
+
+ if (bits.length >= 2) {
+ String configName = bits[0];
+ String wsName = bits[1];
+
+ IMemento workingSet = configMap.get(wsName);
+ if (workingSet == null) {
+ workingSet = result.createChild(KEY_WORKING_SET);
+ configMap.put(wsName, workingSet);
+ }
+
+ workingSet.putString(ATTR_NAME, wsName);
+
+ IMemento config = workingSet.createChild(KEY_CONFIG);
+ config.putString(ATTR_NAME, configName);
+
+ int limit = bits.length - (bits.length % 2);
+ for (int i = 2; i < limit; i += 2) {
+ IMemento project = config.createChild(KEY_PROJECT);
+ project.putString(ATTR_NAME, bits[i]);
+ project.putString(ATTR_CONFIG, bits[i + 1]);
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ //
+ // Nested classes
+ //
+
+ /**
+ * A working set manager listener that tracks name changes and removals of working sets to keep our
+ * configurations in synch as much as possible. It updates the memento store directly in response to
+ * changes in the working sets.
+ *
+ * @author Christian W. Damus (cdamus)
+ *
+ * @since 6.0
+ */
+ private class WorkingSetChangeTracker extends java.util.IdentityHashMap implements
+ IPropertyChangeListener {
+
+ WorkingSetChangeTracker() {
+ for (IWorkingSet next : WS_MGR.getWorkingSets()) {
+ put(next, next.getName());
+ }
+
+ WS_MGR.addPropertyChangeListener(this);
+ }
+
+ public void propertyChange(PropertyChangeEvent event) {
+ String property = event.getProperty();
+
+ if (IWorkingSetManager.CHANGE_WORKING_SET_NAME_CHANGE.equals(property)) {
+ handleNameChange((IWorkingSet) event.getNewValue());
+ } else if (IWorkingSetManager.CHANGE_WORKING_SET_REMOVE.equals(property)) {
+ handleRemove((IWorkingSet) event.getOldValue());
+ } else if (IWorkingSetManager.CHANGE_WORKING_SET_ADD.equals(property)) {
+ handleAdd((IWorkingSet) event.getNewValue());
+ }
+ }
+
+ private void handleNameChange(IWorkingSet workingSet) {
+ synchronized (storeLock) {
+ String oldName = get(workingSet);
+ IMemento wsMemento = null;
+ if (oldName != null) {
+ for (IMemento next : store.getChildren(KEY_WORKING_SET)) {
+ if (oldName.equals(next.getString(ATTR_NAME))) {
+ wsMemento = next;
+ break;
+ }
+ }
+ }
+
+ if (wsMemento != null) {
+ // update the memento with the new name
+ wsMemento.putString(ATTR_NAME, workingSet.getName());
+
+ // clone it
+ XMLMemento newStore = XMLMemento.createWriteRoot(TYPE_WORKING_SET_CONFIGS);
+ newStore.putMemento(store);
+
+ // save it asynchronously
+ save(newStore);
+ }
+
+ // and update our mapping
+ put(workingSet, workingSet.getName());
+ }
+ }
+
+ private void handleRemove(IWorkingSet workingSet) {
+ synchronized (storeLock) {
+ String name = get(workingSet);
+ if (name != null) {
+ // remove the memento from the store
+ XMLMemento newStore = XMLMemento.createWriteRoot(TYPE_WORKING_SET_CONFIGS);
+ for (IMemento next : store.getChildren(KEY_WORKING_SET)) {
+ if (!name.equals(next.getString(ATTR_NAME))) {
+ newStore.createChild(KEY_WORKING_SET).putMemento(next);
+ }
+ }
+
+ // save asynchronously
+ save(newStore);
+ }
+
+ // and update our mapping
+ remove(workingSet);
+ }
+ }
+
+ private void handleAdd(IWorkingSet workingSet) {
+ synchronized (storeLock) {
+ put(workingSet, workingSet.getName());
+ }
+ }
+ }
+}
Index: src/org/eclipse/cdt/internal/ui/workingsets/ActivateWorkingSetsContribution.java
===================================================================
RCS file: src/org/eclipse/cdt/internal/ui/workingsets/ActivateWorkingSetsContribution.java
diff -N src/org/eclipse/cdt/internal/ui/workingsets/ActivateWorkingSetsContribution.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/internal/ui/workingsets/ActivateWorkingSetsContribution.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2009 QNX Software Systems 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:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.internal.ui.workingsets;
+
+import org.eclipse.jface.action.IContributionItem;
+
+/**
+ * A dynamic contribution of sub-menus to activate working sets, with further sub-menus showing the
+ * configurations to choose from.
+ *
+ * @author Christian W. Damus (cdamus)
+ *
+ * @since 6.0
+ */
+public class ActivateWorkingSetsContribution extends AbstractWorkingSetsContribution {
+
+ /**
+ * Initializes me.
+ */
+ public ActivateWorkingSetsContribution() {
+ super();
+ }
+
+ @Override
+ protected IContributionItem createContribution(IWorkingSetProxy workingSet) {
+ return new ActivateWorkingSetConfigsContribution(workingSet);
+ }
+}
Index: src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetProxy.java
===================================================================
RCS file: src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetProxy.java
diff -N src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetProxy.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetProxy.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright (c) 2009 QNX Software Systems 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:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.internal.ui.workingsets;
+
+import java.util.Collection;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.ui.IWorkingSet;
+
+/**
+ * The protocol for elements representing working sets, providing proxies for the workbench's actual
+ * {@link IWorkingSet}s. A working set may have zero or more {@linkplain IWorkingSetConfiguration
+ * configurations} that aggregate configuration settings for the C/C++ projects in the working set.
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ *
+ * @author Christian W. Damus (cdamus)
+ *
+ * @since 6.0
+ *
+ */
+public interface IWorkingSetProxy extends IWorkingSetConfigurationElement {
+ /**
+ * Queries my name. This is the {@link IWorkingSet#getName() name} of my referenced working set, not its
+ * {@link IWorkingSet#getLabel() label}. As my referenced working set's name changes, so does my name.
+ *
+ * @return my working set's name
+ */
+ String getName();
+
+ /**
+ * Resolves me to the actual working set as maintained by the workbench.
+ *
+ * @return my referenced working set, or null
if it no longer exists
+ */
+ IWorkingSet resolve();
+
+ /**
+ * Resolves the actual existing projects in my working set, that are currently
+ * {@linkplain IResource#isAccessible() accessible} in the workspace.
+ *
+ * @return my projects
+ */
+ Collection resolveProjects();
+
+ /**
+ * Queries whether I am a valid working set proxy, to be displayed to and manipulated by the user. This
+ * should at least check that the proxy {@linkplain #resolve() resolves} to an existing working set and
+ * that it includes at least one {@linkplain #resolveProjects() project}.
+ *
+ * @return whether I am a valid working set proxy
+ */
+ boolean isValid();
+
+ /**
+ * Obtains the named configuration of my working set.
+ *
+ * @param name
+ * a configuration name
+ *
+ * @return the matching configuration, or null
if there is none such
+ */
+ IWorkingSetConfiguration getConfiguration(String name);
+
+ /**
+ * Obtains all of the configurations currently defined for my working set. If I am a working-copy
+ * {@linkplain IWorkingSetProxy.ISnapshot snapshot}, then these may include a special
+ * {@linkplain IWorkingSetConfiguration.ISnapshot#isReadOnly() read-only} configuration indicating the
+ * active configurations of my projects, if none of my named configurations is
+ * {@linkplain IWorkingSetConfiguration#isActive() active}.
+ *
+ * @return my configurations
+ */
+ Collection getConfigurations();
+
+ /**
+ * Creates a snapshot (also known as a "working copy") of myself, providing a mutable view suitable
+ * for editing.
+ *
+ * @param workspace
+ * a workspace snapshot that captures the baseline state of the workspace and the working set
+ * configurations that are to be edited
+ *
+ * @return a working-copy snapshot of myself
+ */
+ ISnapshot createSnapshot(WorkspaceSnapshot workspace);
+
+ //
+ // Nested types
+ //
+
+ /**
+ * The snapshot ("working copy") view of a working set proxy. It has additional API for modifying
+ * configurations, which can then be {@linkplain WorkspaceSnapshot#save() saved} for posterity.
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ *
+ * @author Christian W. Damus (cdamus)
+ *
+ * @since 6.0
+ */
+ interface ISnapshot extends IWorkingSetProxy, IWorkingSetConfigurationElement.ISnapshot {
+ /**
+ * Creates a new configuration with the specified name.
+ *
+ * @param name
+ * a new configuration name
+ *
+ * @return the new configuration
+ *
+ * @throws IllegalArgumentException
+ * if the new name is null
or empty, or if it is already used by another
+ * configuration of the same working set
+ */
+ IWorkingSetConfiguration.ISnapshot createConfiguration(String name);
+
+ /**
+ * Removes the specified configuration from me.
+ *
+ * @param config
+ * a configuration to remove
+ *
+ * @throws IllegalArgumentException
+ * if the configuration to be removed is
+ * {@linkplain IWorkingSetConfiguration.ISnapshot#isReadOnly() read-only}
+ */
+ void removeConfiguration(IWorkingSetConfiguration config);
+
+ /**
+ *
+ * Updates me according to the (assumed to have changed) activation state of my configurations. If any
+ * named configurations are active and I currently have a "fake"
+ * {@linkplain IWorkingSetConfiguration.ISnapshot#isReadOnly() read-only} configuration, then it is
+ * removed and I signal a "major change."
+ *
+ *
+ * If I have no named configurations that are active, and currently have not got a read-only
+ * configuration to show the active configuration, then I create it and signal a "major change."
+ *
+ *
+ * It is assumed that the UI will refresh the tree structure rooted in me when I signal a major
+ * change.
+ *
+ *
+ * @return whether this update results in a "major change" to my child configuration structure
+ */
+ boolean updateActiveConfigurations();
+ }
+}
Index: src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetProjectConfigurationFactory.java
===================================================================
RCS file: src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetProjectConfigurationFactory.java
diff -N src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetProjectConfigurationFactory.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetProjectConfigurationFactory.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,394 @@
+/*******************************************************************************
+ * Copyright (c) 2009 QNX Software Systems 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:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.internal.ui.workingsets;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectNatureDescriptor;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+
+import org.eclipse.cdt.core.settings.model.ICProjectDescription;
+import org.eclipse.cdt.ui.CUIPlugin;
+
+import org.eclipse.cdt.internal.ui.workingsets.WorkspaceSnapshot.ProjectState;
+
+/**
+ * Protocol for a factory of {@link IWorkingSetProjectConfiguration}s. Factories are {@linkplain Registry
+ * registered} against project natures.
+ *
+ * @author Christian W. Damus (cdamus)
+ *
+ * @since 6.0
+ */
+public interface IWorkingSetProjectConfigurationFactory {
+ /**
+ * Queries my factory ID. The ID is persisted in the working set configuration data so that the same
+ * factory can be used to reconstruct project configurations when loading the working set configurations.
+ *
+ * @return my unique identifier
+ */
+ String getID();
+
+ /**
+ * Creates a new project configuration element.
+ *
+ * @param parent
+ * the working set configuration that owns the new project configuration
+ * @param project
+ * the workspace project for which to create the configuration
+ *
+ * @return the new project configuration
+ */
+ IWorkingSetProjectConfiguration createProjectConfiguration(IWorkingSetConfiguration parent,
+ IProject project);
+
+ /**
+ * Creates a UI controller to support editing the specified project configuration snapshot, which should
+ * have been obtained from a configuration that I previously
+ * {@linkplain #createProjectConfiguration(org.eclipse.cdt.internal.ui.workingsets.IWorkingSetConfiguration, IProject)
+ * created}, myself.
+ *
+ * @param config
+ * a project configuration snapshot that I created
+ *
+ * @return a suitable controller for it. Must not be null
+ */
+ IWorkingSetProjectConfigurationController createProjectConfigurationController(
+ IWorkingSetProjectConfiguration.ISnapshot config);
+
+ /**
+ * Creates a snapshot of the configuration state of a project in the workspace. This may capture
+ * additional build meta-data beyond just the "active configuration."
+ *
+ * @param project
+ * a project to capture in a {@link WorkspaceSnapshot}
+ * @param desc
+ * the project description, from which to capture the initial configuration data
+ *
+ * @return the project state capture. Must not be null
+ */
+ WorkspaceSnapshot.ProjectState createProjectState(IProject project, ICProjectDescription desc);
+
+ //
+ // Nested types
+ //
+
+ /**
+ * A registry of {@linkplain IWorkingSetProjectConfigurationFactory project configuration factories}
+ * contributed on the org.eclipse.cdt.ui.workingSetConfigurations extension point.
+ *
+ * @author Christian W. Damus (cdamus)
+ *
+ * @since 6.0
+ */
+ class Registry {
+ private static final String EXT_PT_ID = "workingSetConfigurations"; //$NON-NLS-1$
+ private static final String E_FACTORY = "projectConfigurationFactory"; //$NON-NLS-1$
+ private static final String E_NATURE = "projectNature"; //$NON-NLS-1$
+ private static final String A_ID = "id"; //$NON-NLS-1$
+ private static final String A_CLASS = "class"; //$NON-NLS-1$
+
+ /**
+ * The shared project configuration factory registry.
+ */
+ public static Registry INSTANCE = new Registry();
+
+ private final IWorkingSetProjectConfigurationFactory defaultFactory = new Default();
+ private final Map factoriesByID = new java.util.HashMap();
+ private final Map factoriesByNature = new java.util.HashMap();
+
+ private Map> projectNaturePartOrdering;
+
+ private Registry() {
+ super();
+
+ projectNaturePartOrdering = computeProjectNaturePartOrdering();
+
+ loadExtensions();
+ }
+
+ public IWorkingSetProjectConfigurationFactory getFactory(String id) {
+ IWorkingSetProjectConfigurationFactory result = get(factoriesByID, id);
+
+ if (result == null) {
+ result = defaultFactory;
+ }
+
+ return result;
+ }
+
+ public IWorkingSetProjectConfigurationFactory getFactory(IProject project) {
+ IWorkingSetProjectConfigurationFactory result = null;
+
+ for (String nature : getPartOrderedNatureIDs(project)) {
+ result = get(factoriesByNature, nature);
+
+ if (result != null) {
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ private IWorkingSetProjectConfigurationFactory get(
+ Map, IWorkingSetProjectConfigurationFactory> map, Object key) {
+ return map.get(key);
+ }
+
+ private String[] getPartOrderedNatureIDs(IProject project) {
+ String[] result;
+
+ try {
+ result = project.getDescription().getNatureIds();
+ } catch (CoreException e) {
+ CUIPlugin.log(e.getStatus());
+ result = new String[0];
+ }
+
+ if (result.length > 0) {
+ Arrays.sort(result, new Comparator() {
+ public int compare(String nature1, String nature2) {
+ Set required1 = projectNaturePartOrdering.get(nature1);
+ Set required2 = projectNaturePartOrdering.get(nature2);
+
+ if (required1.contains(nature2)) {
+ return -1; // required1 precedes required2
+ } else if (required2.contains(nature1)) {
+ return +1; // required2 precedes required1
+ } else if (nature1.startsWith("org.eclipse.cdt.") //$NON-NLS-1$
+ && !nature2.startsWith("org.eclipse.cdt.")) { //$NON-NLS-1$
+ return +1; // lower priority to CDT natures
+ } else if (nature2.startsWith("org.eclipse.cdt.") //$NON-NLS-1$
+ && !nature1.startsWith("org.eclipse.cdt.")) { //$NON-NLS-1$
+ return -1; // lower priority to CDT natures
+ }
+
+ return 0; // not partially comparable
+ }
+ });
+ }
+
+ return result;
+ }
+
+ private Map> computeProjectNaturePartOrdering() {
+ Map> result = new java.util.HashMap>();
+
+ // first pass to populate the map with immediate requireds
+ IWorkspace ws = ResourcesPlugin.getWorkspace();
+ for (IProjectNatureDescriptor next : ws.getNatureDescriptors()) {
+ result.put(next.getNatureId(), new java.util.HashSet(Arrays.asList(next
+ .getRequiredNatureIds())));
+ }
+
+ // now, iterate to add transitive requireds
+ boolean loopAgain;
+ do {
+ loopAgain = false;
+
+ for (Map.Entry> next : result.entrySet()) {
+ Set requireds = next.getValue();
+ Set newRequireds = new java.util.HashSet(requireds);
+
+ boolean changed = false;
+
+ for (String required : requireds) {
+ changed |= newRequireds.addAll(result.get(required));
+ }
+
+ if (changed) {
+ loopAgain = true;
+ next.setValue(newRequireds);
+ }
+ }
+ } while (loopAgain);
+
+ return result;
+ }
+
+ private void loadExtensions() {
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ for (IExtension ext : registry.getExtensionPoint(CUIPlugin.PLUGIN_ID, EXT_PT_ID).getExtensions()) {
+ for (IConfigurationElement element : ext.getConfigurationElements()) {
+ if (E_FACTORY.equals(element.getName())) {
+ try {
+ Descriptor desc = new Descriptor(element);
+
+ synchronized (factoriesByID) {
+ factoriesByID.put(desc.getID(), desc);
+ }
+
+ synchronized (factoriesByNature) {
+ for (IConfigurationElement nature : element.getChildren(E_NATURE)) {
+ String natureID = nature.getAttribute(A_ID);
+
+ if (natureID != null) {
+ factoriesByNature.put(natureID, desc);
+ } else {
+ CUIPlugin.log(NLS.bind(
+ WorkingSetMessages.WSProjConfigFactory_noNatureID, ext
+ .getContributor().getName()), null);
+ }
+ }
+ }
+ } catch (CoreException e) {
+ CUIPlugin.log(e.getStatus());
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Nested classes
+ //
+
+ /**
+ * A self-resolving descriptor for lazy instantiation of a factory.
+ */
+ private class Descriptor implements IWorkingSetProjectConfigurationFactory {
+ private final IConfigurationElement extension;
+ private final String id;
+
+ Descriptor(IConfigurationElement extension) throws CoreException {
+ this.extension = extension;
+ id = extension.getAttribute(A_ID);
+
+ if (id == null) {
+ throw new CoreException(new Status(IStatus.ERROR, CUIPlugin.PLUGIN_ID, NLS.bind(
+ WorkingSetMessages.WSProjConfigFactory_noFactoryID, extension.getContributor()
+ .getName())));
+ }
+ }
+
+ public String getID() {
+ return id;
+ }
+
+ public IWorkingSetProjectConfiguration createProjectConfiguration(
+ IWorkingSetConfiguration parent, IProject project) {
+ return resolve().createProjectConfiguration(parent, project);
+ }
+
+ public IWorkingSetProjectConfigurationController createProjectConfigurationController(
+ IWorkingSetProjectConfiguration.ISnapshot config) {
+
+ return resolve().createProjectConfigurationController(config);
+ }
+
+ public ProjectState createProjectState(IProject project, ICProjectDescription desc) {
+ return resolve().createProjectState(project, desc);
+ }
+
+ private IWorkingSetProjectConfigurationFactory resolve() {
+ IWorkingSetProjectConfigurationFactory result = null;
+
+ try {
+ result = (IWorkingSetProjectConfigurationFactory) extension
+ .createExecutableExtension(A_CLASS);
+ } catch (ClassCastException e) {
+ CUIPlugin.log(NLS.bind(WorkingSetMessages.WSProjConfigFactory_badFactory, extension
+ .getContributor().getName()), e);
+ } catch (CoreException e) {
+ CUIPlugin.log(new MultiStatus(CUIPlugin.PLUGIN_ID, 0, new IStatus[] { e.getStatus() },
+ WorkingSetMessages.WSProjConfigFactory_factoryFailed, null));
+ }
+
+ if (result == null) {
+ result = defaultFactory;
+ }
+
+ // replace the descriptor in the maps
+ synchronized (factoriesByID) {
+ factoriesByID.put(getID(), result);
+ }
+ synchronized (factoriesByNature) {
+ for (Map.Entry next : factoriesByNature
+ .entrySet()) {
+ if (next.getValue().getID().equals(getID())) {
+ next.setValue(result);
+ }
+ }
+ }
+
+ return result;
+ }
+ }
+
+ /**
+ * The default project configuration factory. Clients may extend this class to implement custom
+ * factories for their project natures.
+ *
+ * @author Christian W. Damus (cdamus)
+ *
+ * @since 6.0
+ */
+ public static class Default implements IWorkingSetProjectConfigurationFactory, IExecutableExtension {
+
+ private String id;
+
+ public Default() {
+ super();
+ }
+
+ public IWorkingSetProjectConfiguration createProjectConfiguration(
+ IWorkingSetConfiguration parent, IProject project) {
+
+ WorkingSetProjectConfiguration result = createProjectConfiguration(parent);
+ result.setProjectName(project.getName());
+ return result;
+ }
+
+ protected WorkingSetProjectConfiguration createProjectConfiguration(
+ IWorkingSetConfiguration parent) {
+ return new WorkingSetProjectConfiguration(parent);
+ }
+
+ public IWorkingSetProjectConfigurationController createProjectConfigurationController(
+ IWorkingSetProjectConfiguration.ISnapshot config) {
+
+ return new ProjectConfigurationController(config);
+ }
+
+ public ProjectState createProjectState(IProject project, ICProjectDescription desc) {
+ return new WorkspaceSnapshot.ProjectState(project, desc);
+ }
+
+ public String getID() {
+ return id;
+ }
+
+ public void setInitializationData(IConfigurationElement config, String propertyName, Object data)
+ throws CoreException {
+
+ this.id = config.getAttribute(A_ID);
+ }
+
+ }
+ }
+}
#P org.eclipse.cdt.managedbuilder.ui
Index: plugin.xml
===================================================================
RCS file: /cvsroot/tools/org.eclipse.cdt/all/org.eclipse.cdt.managedbuilder.ui/plugin.xml,v
retrieving revision 1.117
diff -u -r1.117 plugin.xml
--- plugin.xml 14 Apr 2009 20:23:42 -0000 1.117
+++ plugin.xml 23 Apr 2009 13:28:25 -0000
@@ -675,7 +675,17 @@
class="org.eclipse.cdt.make.ui.dialogs.GCCPerProjectSCDProfilePage"
name="%MBSPerProjectProfile.name"
profileId="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"/>
-
+
+
+
+
+
+
+
Index: META-INF/MANIFEST.MF
===================================================================
RCS file: /cvsroot/tools/org.eclipse.cdt/all/org.eclipse.cdt.managedbuilder.ui/META-INF/MANIFEST.MF,v
retrieving revision 1.14
diff -u -r1.14 MANIFEST.MF
--- META-INF/MANIFEST.MF 13 Mar 2009 13:47:46 -0000 1.14
+++ META-INF/MANIFEST.MF 23 Apr 2009 13:28:25 -0000
@@ -6,7 +6,8 @@
Bundle-Activator: org.eclipse.cdt.managedbuilder.ui.properties.ManagedBuilderUIPlugin
Bundle-Vendor: %providerName
Bundle-Localization: plugin
-Export-Package: org.eclipse.cdt.managedbuilder.ui.actions,
+Export-Package: org.eclipse.cdt.managedbuilder.internal.ui.workingsets,
+ org.eclipse.cdt.managedbuilder.ui.actions,
org.eclipse.cdt.managedbuilder.ui.properties,
org.eclipse.cdt.managedbuilder.ui.wizards
Require-Bundle: org.eclipse.ui.ide;bundle-version="[3.2.0,4.0.0)",
Index: src/org/eclipse/cdt/managedbuilder/internal/ui/workingsets/MBSProjectState.java
===================================================================
RCS file: src/org/eclipse/cdt/managedbuilder/internal/ui/workingsets/MBSProjectState.java
diff -N src/org/eclipse/cdt/managedbuilder/internal/ui/workingsets/MBSProjectState.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/managedbuilder/internal/ui/workingsets/MBSProjectState.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2009 QNX Software Systems 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:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.internal.ui.workingsets;
+
+import org.eclipse.cdt.core.settings.model.ICProjectDescription;
+import org.eclipse.cdt.internal.ui.workingsets.WorkspaceSnapshot.ProjectState;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+
+/**
+ * A managed-build implementation of the workspace snapshot project state. It
+ * knows how to build the selected configuration without activating it.
+ *
+ * @author Christian W. Damus (cdamus)
+ *
+ * @since 6.0
+ */
+class MBSProjectState extends ProjectState {
+
+ /**
+ * Initializes me with my project and its description.
+ *
+ * @param project
+ * my project
+ * @param desc
+ * its description
+ */
+ public MBSProjectState(IProject project, ICProjectDescription desc) {
+ super(project, desc);
+ }
+
+ @Override
+ protected IStatus build(String configID, IProgressMonitor monitor) {
+ IStatus result = MBSProjectConfiguration.build(getProject(),
+ getConfiguration(configID), monitor);
+
+ if (result.isOK()) {
+ built(configID);
+ }
+
+ return result;
+ }
+}
Index: src/org/eclipse/cdt/managedbuilder/internal/ui/workingsets/MBSProjectConfiguration.java
===================================================================
RCS file: src/org/eclipse/cdt/managedbuilder/internal/ui/workingsets/MBSProjectConfiguration.java
diff -N src/org/eclipse/cdt/managedbuilder/internal/ui/workingsets/MBSProjectConfiguration.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/managedbuilder/internal/ui/workingsets/MBSProjectConfiguration.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2009 QNX Software Systems 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:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.internal.ui.workingsets;
+
+import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
+import org.eclipse.cdt.internal.ui.workingsets.IWorkingSetConfiguration;
+import org.eclipse.cdt.internal.ui.workingsets.WorkingSetProjectConfiguration;
+import org.eclipse.cdt.managedbuilder.core.IConfiguration;
+import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
+import org.eclipse.cdt.ui.CUIPlugin;
+import org.eclipse.core.resources.IProject;
+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.core.runtime.SubMonitor;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * A managed-build implementation of the working set project configuration. It
+ * knows how to build the selected configuration without activating it.
+ *
+ * @author Christian W. Damus (cdamus)
+ *
+ * @since 6.0
+ */
+class MBSProjectConfiguration extends WorkingSetProjectConfiguration {
+
+ /**
+ * Initializes me.
+ *
+ * @param parent
+ * my parent working set configuration
+ */
+ public MBSProjectConfiguration(IWorkingSetConfiguration parent) {
+ super(parent);
+ }
+
+ @Override
+ public IStatus build(IProgressMonitor monitor) {
+ return MBSProjectConfiguration.build(resolveProject(),
+ resolveSelectedConfiguration(), monitor);
+ }
+
+ /**
+ * Builds the MBS configuration selected by the specified working set
+ * project configuration.
+ *
+ * @param projectConfig
+ * a project configuration to build
+ * @param monitor
+ * for reporting build progress
+ *
+ * @return the result of the MBS build
+ */
+ static IStatus build(IProject project, ICConfigurationDescription config,
+ IProgressMonitor monitor) {
+
+ IStatus result = Status.OK_STATUS;
+
+ IConfiguration mbsConfig = (config == null) ? null
+ : ManagedBuildManager.getConfigurationForDescription(config);
+
+ if (mbsConfig == null) {
+ result = new Status(IStatus.WARNING, CUIPlugin.PLUGIN_ID, NLS.bind(
+ "No configuration selected for project \"{0}\".", project
+ .getName()));
+ } else {
+ monitor = SubMonitor.convert(monitor);
+
+ try {
+ ManagedBuildManager.buildConfigurations(
+ new IConfiguration[] { mbsConfig }, monitor);
+ } catch (CoreException e) {
+ result = e.getStatus();
+ }
+ }
+
+ return result;
+ }
+}
Index: src/org/eclipse/cdt/managedbuilder/internal/ui/workingsets/MBSProjectConfigurationFactory.java
===================================================================
RCS file: src/org/eclipse/cdt/managedbuilder/internal/ui/workingsets/MBSProjectConfigurationFactory.java
diff -N src/org/eclipse/cdt/managedbuilder/internal/ui/workingsets/MBSProjectConfigurationFactory.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/managedbuilder/internal/ui/workingsets/MBSProjectConfigurationFactory.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2009 QNX Software Systems 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:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.internal.ui.workingsets;
+
+import org.eclipse.cdt.core.settings.model.ICProjectDescription;
+import org.eclipse.cdt.internal.ui.workingsets.IWorkingSetConfiguration;
+import org.eclipse.cdt.internal.ui.workingsets.IWorkingSetProjectConfigurationFactory;
+import org.eclipse.cdt.internal.ui.workingsets.WorkingSetProjectConfiguration;
+import org.eclipse.cdt.internal.ui.workingsets.WorkspaceSnapshot.ProjectState;
+import org.eclipse.core.resources.IProject;
+
+/**
+ * Working set project configuration factory for MBS projects.
+ *
+ * @author Christian W. Damus (cdamus)
+ *
+ * @since 6.0
+ *
+ */
+public class MBSProjectConfigurationFactory extends
+ IWorkingSetProjectConfigurationFactory.Registry.Default {
+
+ /**
+ * Initializes me.
+ */
+ public MBSProjectConfigurationFactory() {
+ super();
+ }
+
+ @Override
+ protected WorkingSetProjectConfiguration createProjectConfiguration(
+ IWorkingSetConfiguration parent) {
+
+ return new MBSProjectConfiguration(parent);
+ }
+
+ @Override
+ public ProjectState createProjectState(IProject project,
+ ICProjectDescription desc) {
+
+ return new MBSProjectState(project, desc);
+ }
+}