### Eclipse Workspace Patch 1.0 #P org.eclipse.cdt.ui Index: plugin.properties =================================================================== RCS file: /cvsroot/tools/org.eclipse.cdt/all/org.eclipse.cdt.ui/plugin.properties,v retrieving revision 1.184 diff -u -r1.184 plugin.properties --- plugin.properties 15 Apr 2009 11:21:01 -0000 1.184 +++ plugin.properties 23 Apr 2009 13:28:23 -0000 @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2003, 2008 IBM Corporation and others. +# Copyright (c) 2003, 2009 IBM Corporation, 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 @@ -10,6 +10,7 @@ # Markus Schorn (Wind River Systems) # Anton Leherbauer (Wind River Systems) # Sergey Prigogin (Google) +# QNX Software Systems - [272416] Rework the working set configurations ############################################################################### pluginName=C/C++ Development Tools UI providerName=Eclipse.org @@ -508,7 +509,14 @@ cElementHyperlinkDetector= C/C++ Elements keybinding.MSVS= Microsoft Visual Studio -wsselection= Configs for Working set +wsselection= Manage &Working Sets... +workingSetConfigsPage=C/C++ Build +activateWorkingSetConfig.label=Set &Active by Working Set +activateWorkingSetConfig.context.label=Set &Active +buildWorkingSetConfig.label=&Build by Working Set +buildWorkingSetConfig.context.label=&Build +workingSetConfigs.context.label=&Build Configurations +workingSetConfigurationsExtensionPoint=Working Set Configurations # Keywords for Preferences preferenceKeywords.common=c cpp cplusplus cdt Index: plugin.xml =================================================================== RCS file: /cvsroot/tools/org.eclipse.cdt/all/org.eclipse.cdt.ui/plugin.xml,v retrieving revision 1.349 diff -u -r1.349 plugin.xml --- plugin.xml 15 Apr 2009 11:21:01 -0000 1.349 +++ plugin.xml 23 Apr 2009 13:28:24 -0000 @@ -24,6 +24,7 @@ + @@ -1116,6 +1117,77 @@ contentMergeViewerId="org.eclipse.cdt.ui.compare.AsmContentViewerCreator"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - @@ -2859,6 +2911,12 @@ namespace="org.eclipse.cdt.ui" properties="isSource" type="org.eclipse.core.resources.IFile"/> + @@ -3018,5 +3076,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetMessages.properties =================================================================== RCS file: /cvsroot/tools/org.eclipse.cdt/all/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetMessages.properties,v retrieving revision 1.8 diff -u -r1.8 WorkingSetMessages.properties --- src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetMessages.properties 25 Nov 2008 11:01:51 -0000 1.8 +++ src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetMessages.properties 23 Apr 2009 13:28:24 -0000 @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2000, 2008 IBM Corporation and others. +# Copyright (c) 2000, 2009 IBM Corporation, 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 @@ -8,6 +8,7 @@ # Contributors: # IBM Corporation - initial API and implementation # Anton Leherbauer (Wind River Systems) +# QNX Software Systems - [272416] Rework the working set configurations ############################################################################### CElementWorkingSetPage_title= C/C++ Working Set @@ -18,3 +19,53 @@ CElementWorkingSetPage_warning_nameMustNotBeEmpty= The name must not be empty. CElementWorkingSetPage_warning_workingSetExists= A working set with that name already exists. CElementWorkingSetPage_warning_resourceMustBeChecked= At least one resource must be checked. + +ProjConfigController_activeConfig={0} (active) + +WorkingSetMenus_enumPattern=&{0} {1} +WorkspaceSnapshot_buildNoProj=Attempt to build project that does not exist: {0} + +WSConfig_build_problems=Problems occurred in building the working set. +WSConfig_build_task=Building working set "{0}" + +WSConfigDialog_activate_label=&Set Active +WSConfigDialog_active_config={0} (active) +WSConfigDialog_add_label=&Add... +WSConfigDialog_build_label=&Build +WSConfigDialog_buildPrompt_message=Some projects have had their active configurations changed, and need to be re-built. Build them now? +WSConfigDialog_buildPrompt_title=Build New Configuration +WSConfigDialog_implicit_config=(active) +WSConfigDialog_projTree_accessible_name=Project configuration selection tree +WSConfigDialog_projTree_label=Project configurations: +WSConfigDialog_remove_label=&Remove +WSConfigDialog_rename_label=Re&name... +WSConfigDialog_title=Manage Working Set Configurations +WSConfigDialog_wsTree_accessible_name=Working sets and configurations tree +WSConfigDialog_wsTree_label=Working set configurations: + +WSConfigManager_closeFailed=Failed to close working set configurations file. +WSConfigManager_loadFailed=Failed to load working set configurations. +WSConfigManager_save_job=Saving working set configurations +WSConfigManager_saveFailed=Failed to save working set configurations. + +WSConfigsController_addDlg_defaultName=NewConfiguration +WSConfigsController_addDlg_emptyName=The name must not be empty. +WSConfigsController_addDlg_msg=Enter a name for the new configuration. +WSConfigsController_addDlg_nameExists=A configuration with that name already exists. +WSConfigsController_addDlg_title=Add Working Set Configuration +WSConfigsController_buildFailedDlgMsg=Problems occurred during the build. +WSConfigsController_buildFailedDlgTitle=Build Problems +WSConfigsController_buildFailedLog=Exception occurred in working-set build. +WSConfigsController_renameDlg_msg=Enter a new name for the configuration. +WSConfigsController_renameDlg_title=Rename Working Set Configuration + +WSetConfigsPage_noProjects=Working set does not include any C/C++ projects. + +WSProjConfig_activatedWarning=Set configuration "{0}" active in project "{1}". +WSProjConfig_buildProblem=Problems occurred in building project "{0}". +WSProjConfig_noConfig=No configuration selected for project "{0}". + +WSProjConfigFactory_badFactory=Invalid project configuration factory in plug-in {0}. Expected an IWorkingSetProjectConfigurationFactory. +WSProjConfigFactory_factoryFailed=Failed to create project configuration factory. +WSProjConfigFactory_noFactoryID=Missing ID in project configuration factory extension in plug-in {0} +WSProjConfigFactory_noNatureID=Missing nature ID in project configuration factory in plug-in {0}. Index: src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetMessages.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.cdt/all/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetMessages.java,v retrieving revision 1.7 diff -u -r1.7 WorkingSetMessages.java --- src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetMessages.java 25 Nov 2008 11:01:51 -0000 1.7 +++ src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetMessages.java 23 Apr 2009 13:28:24 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. + * Copyright (c) 2000, 2009 IBM Corporation, 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * QNX Software Systems - [272416] Rework the working set configurations *******************************************************************************/ package org.eclipse.cdt.internal.ui.workingsets; @@ -27,6 +28,56 @@ public static String CElementWorkingSetPage_warning_nameMustNotBeEmpty; public static String CElementWorkingSetPage_warning_workingSetExists; public static String CElementWorkingSetPage_warning_resourceMustBeChecked; + + public static String ProjConfigController_activeConfig; + + public static String WorkingSetMenus_enumPattern; + public static String WorkspaceSnapshot_buildNoProj; + + public static String WSConfig_build_problems; + public static String WSConfig_build_task; + + public static String WSConfigDialog_activate_label; + public static String WSConfigDialog_active_config; + public static String WSConfigDialog_add_label; + public static String WSConfigDialog_build_label; + public static String WSConfigDialog_buildPrompt_message; + public static String WSConfigDialog_buildPrompt_title; + public static String WSConfigDialog_implicit_config; + public static String WSConfigDialog_projTree_accessible_name; + public static String WSConfigDialog_projTree_label; + public static String WSConfigDialog_remove_label; + public static String WSConfigDialog_rename_label; + public static String WSConfigDialog_title; + public static String WSConfigDialog_wsTree_accessible_name; + public static String WSConfigDialog_wsTree_label; + + public static String WSConfigManager_closeFailed; + public static String WSConfigManager_loadFailed; + public static String WSConfigManager_save_job; + public static String WSConfigManager_saveFailed; + + public static String WSConfigsController_addDlg_defaultName; + public static String WSConfigsController_addDlg_emptyName; + public static String WSConfigsController_addDlg_msg; + public static String WSConfigsController_addDlg_nameExists; + public static String WSConfigsController_addDlg_title; + public static String WSConfigsController_buildFailedDlgMsg; + public static String WSConfigsController_buildFailedDlgTitle; + public static String WSConfigsController_buildFailedLog; + public static String WSConfigsController_renameDlg_msg; + public static String WSConfigsController_renameDlg_title; + + public static String WSetConfigsPage_noProjects; + + public static String WSProjConfig_activatedWarning; + public static String WSProjConfig_buildProblem; + public static String WSProjConfig_noConfig; + + public static String WSProjConfigFactory_badFactory; + public static String WSProjConfigFactory_factoryFailed; + public static String WSProjConfigFactory_noFactoryID; + public static String WSProjConfigFactory_noNatureID; static { NLS.initializeMessages(BUNDLE_NAME, WorkingSetMessages.class); Index: src/org/eclipse/cdt/ui/newui/CDTPrefUtil.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.cdt/all/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/CDTPrefUtil.java,v retrieving revision 1.19 diff -u -r1.19 CDTPrefUtil.java --- src/org/eclipse/cdt/ui/newui/CDTPrefUtil.java 3 Feb 2009 13:43:38 -0000 1.19 +++ src/org/eclipse/cdt/ui/newui/CDTPrefUtil.java 23 Apr 2009 13:28:24 -0000 @@ -7,6 +7,7 @@ * * Contributors: * Intel Corporation - initial API and implementation + * QNX Software Systems - [272416] Rework the working set configurations *******************************************************************************/ package org.eclipse.cdt.ui.newui; @@ -22,6 +23,8 @@ import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.cdt.internal.ui.workingsets.WorkingSetConfigurationManager; + /** * @noextend This class is not intended to be subclassed by clients. * @noinstantiate This class is not intended to be instantiated by clients. @@ -226,9 +229,18 @@ return s1; } + /** + * @deprecated Use the {@link WorkingSetConfigurationManager} class, instead. + */ + @Deprecated public static List readConfigSets() { return new LinkedList(Arrays.asList(getStr(KEY_CONFSET).split(CONFSETDEL))); } + + /** + * @deprecated Use the {@link WorkingSetConfigurationManager} class, instead. + */ + @Deprecated public static void saveConfigSets(List out) { StringBuilder b = new StringBuilder(); for (String s : out) { Index: src/org/eclipse/cdt/ui/newui/PluginResources.properties =================================================================== RCS file: /cvsroot/tools/org.eclipse.cdt/all/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/PluginResources.properties,v retrieving revision 1.72 diff -u -r1.72 PluginResources.properties --- src/org/eclipse/cdt/ui/newui/PluginResources.properties 28 Jan 2009 14:01:38 -0000 1.72 +++ src/org/eclipse/cdt/ui/newui/PluginResources.properties 23 Apr 2009 13:28:24 -0000 @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2000, 2008 IBM Corporation and others. +# Copyright (c) 2000, 2009 IBM Corporation, 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 @@ -7,6 +7,7 @@ # # Contributors: # IBM - Initial API and implementation +# QNX Software Systems - [272416] Rework the working set configurations ############################################################################### # ----------- Configuration Selection Page ----------- @@ -530,26 +531,5 @@ CDTMainWizardPage.1=Project category is selected. Expand the category and select a concrete project type. CProjectWizard.0=Add C Project Nature CCProjectWizard.0=Add CC Project Nature -WorkingSetConfigAction.0=Symbols ' -WorkingSetConfigAction.1=Choose active configs for Working Sets -WorkingSetConfigAction.10=-- CURRENT -- -WorkingSetConfigAction.11=Config Set Name: -WorkingSetConfigAction.12=Configuration set already exists: -WorkingSetConfigAction.13=Wrong configuration set data : -WorkingSetConfigAction.14=' should not be in the name -WorkingSetConfigAction.15=Config Set ' -WorkingSetConfigAction.16=' already exists \! -WorkingSetConfigAction.17=Configurations list -WorkingSetConfigAction.18=New... -WorkingSetConfigAction.19=Rename... -WorkingSetConfigAction.2=Working Sets -WorkingSetConfigAction.20=Save, Build and Exit WorkingSetConfigAction.21=Building project WorkingSetConfigAction.22=Build error -WorkingSetConfigAction.3=- NO WORKING SETS - -WorkingSetConfigAction.4=Config Sets -WorkingSetConfigAction.5=Projects and configurations -WorkingSetConfigAction.6=Update config set -WorkingSetConfigAction.7=Create config set -WorkingSetConfigAction.8=Rename config set -WorkingSetConfigAction.9=Delete config set Index: src/org/eclipse/cdt/ui/actions/WorkingSetConfigAction.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.cdt/all/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/WorkingSetConfigAction.java,v retrieving revision 1.4 diff -u -r1.4 WorkingSetConfigAction.java --- src/org/eclipse/cdt/ui/actions/WorkingSetConfigAction.java 11 Jun 2008 15:50:39 -0000 1.4 +++ src/org/eclipse/cdt/ui/actions/WorkingSetConfigAction.java 23 Apr 2009 13:28:24 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008 Intel Corporation and others. + * Copyright (c) 2008, 2009 Intel Corporation, 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 @@ -7,88 +7,33 @@ * * Contributors: * Intel Corporation - initial API and implementation + * QNX Software Systems - [272416] Rework the config sets dialog *******************************************************************************/ -/** - * - */ package org.eclipse.cdt.ui.actions; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.Map; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IncrementalProjectBuilder; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.action.IAction; -import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.jface.dialogs.IInputValidator; -import org.eclipse.jface.dialogs.InputDialog; -import org.eclipse.jface.dialogs.TrayDialog; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.window.Window; -import org.eclipse.swt.SWT; -import org.eclipse.swt.accessibility.AccessibleAdapter; -import org.eclipse.swt.accessibility.AccessibleEvent; -import org.eclipse.swt.custom.SashForm; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.events.TreeEvent; -import org.eclipse.swt.events.TreeListener; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.List; -import org.eclipse.swt.widgets.MessageBox; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.IWorkbenchWindowActionDelegate; import org.eclipse.ui.IWorkingSet; import org.eclipse.ui.IWorkingSetManager; -import org.eclipse.ui.PlatformUI; -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; -import org.eclipse.cdt.ui.newui.CDTHelpContextIds; -import org.eclipse.cdt.ui.newui.CDTPrefUtil; -import org.eclipse.cdt.ui.newui.UIMessages; -import org.eclipse.cdt.internal.ui.CPluginImages; +import org.eclipse.cdt.internal.ui.workingsets.WorkingSetConfigurationDialog; /** */ public class WorkingSetConfigAction implements IWorkbenchWindowActionDelegate, IPropertyChangeListener { - private static final String DELIMITER = " "; //$NON-NLS-1$ - private static final String EMPTY_STR = ""; //$NON-NLS-1$ - private static final String CURRENT = UIMessages.getString("WorkingSetConfigAction.10"); //$NON-NLS-1$ - public static final Image IMG_PROJ = CPluginImages.get(CPluginImages.IMG_OBJS_CFOLDER); - public static final Image IMG_CONF = CPluginImages.get(CPluginImages.IMG_OBJS_CONFIG); - private static final Shell sh = CUIPlugin.getDefault().getShell(); private static final IWorkingSetManager wsm = CUIPlugin.getDefault().getWorkbench().getWorkingSetManager(); - private LinkedHashMap workingSetsMap; - private LinkedHashMap configSetMap; private boolean enabled = true; + private IWorkbenchWindow window; + public void run(IAction action) { - LocalDialog dlg = new LocalDialog(sh); - dlg.open(); + new WorkingSetConfigurationDialog(window.getShell()).open(); } public void selectionChanged(IAction action, ISelection selection) { @@ -101,6 +46,7 @@ } public void init(IWorkbenchWindow window) { + this.window = window; wsm.addPropertyChangeListener(this); checkWS(); } @@ -112,516 +58,8 @@ enabled = w.length > 0; return w; } - - private String[] getWSnames() { - IWorkingSet[] w = checkWS(); - workingSetsMap = new LinkedHashMap(w.length); - for (IWorkingSet ws : w) - workingSetsMap.put(ws.getLabel(), ws); - return workingSetsMap.keySet().toArray(new String[w.length]); - } public void propertyChange(PropertyChangeEvent event) { checkWS(); } - - private class LocalDialog extends TrayDialog { - private List wsets; - private List csets; - private Tree tree; - private Button b1, b2, b3, b4, bb; - - LocalDialog(Shell parentShell) { - super(parentShell); - setHelpAvailable(false); - setShellStyle(getShellStyle()|SWT.RESIZE); - } - @Override - protected void buttonPressed(int buttonId) { - if (buttonId == IDialogConstants.OK_ID) { - saveConfigSets(); - saveActiveConfigs(); - } else {} - super.buttonPressed(buttonId); - } - - private void saveConfigSets() { - ArrayList out = new ArrayList(configSetMap.size()); - for (ConfigSet cs : configSetMap.values()) - if (cs.isValid() && !cs.name.equals(CURRENT)) - out.add(cs.toString()); - CDTPrefUtil.saveConfigSets(out); - } - - private void saveActiveConfigs() { - for (TreeItem ti : tree.getItems()) { - ICProjectDescription pd = (ICProjectDescription)ti.getData(); - for (TreeItem ti1: ti.getItems()) { - if (!ti1.getChecked()) - continue; - ((ICConfigurationDescription)ti1.getData()).setActive(); - break; - } - try { - CoreModel.getDefault().setProjectDescription(pd.getProject(), pd); - } catch (CoreException e) { - e.printStackTrace(); - CUIPlugin.log(e); - } - } - } - - @Override - protected void configureShell(Shell shell) { - super.configureShell(shell); - shell.setText(UIMessages.getString("WorkingSetConfigAction.1")); //$NON-NLS-1$ - } - - @Override - protected Control createDialogArea(Composite parent) { - PlatformUI.getWorkbench().getHelpSystem().setHelp( getShell(), CDTHelpContextIds.MAN_PROJ_BUILD_PROP); - - Composite comp = new Composite(parent, SWT.NULL); - comp.setFont(parent.getFont()); - comp.setLayout(new GridLayout(2, false)); - comp.setLayoutData(new GridData(GridData.FILL_BOTH)); - - // Create the sash form - SashForm sashForm = new SashForm(comp, SWT.NONE); - sashForm.setOrientation(SWT.VERTICAL); - GridData gd = new GridData(GridData.FILL_VERTICAL); - gd.verticalSpan = 3; - sashForm.setLayoutData(gd); - - Composite ws = new Composite(sashForm, SWT.NULL); - ws.setLayoutData(new GridData(GridData.FILL_BOTH)); - ws.setLayout(new GridLayout(1, false)); - Label l1 = new Label(ws, SWT.NONE); - l1.setText(UIMessages.getString("WorkingSetConfigAction.2")); //$NON-NLS-1$ - l1.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - wsets = new List(ws, SWT.SINGLE | SWT.BORDER); - wsets.setLayoutData(new GridData(GridData.FILL_BOTH)); - wsets.setItems(getWSnames()); - - wsets.addSelectionListener(new SelectionListener() { - public void widgetDefaultSelected(SelectionEvent e) { - workingSetChanged(); - } - public void widgetSelected(SelectionEvent e) { - workingSetChanged(); - }}); - - if (wsets.getItemCount() == 0) { - wsets.add(UIMessages.getString("WorkingSetConfigAction.3")); //$NON-NLS-1$ - wsets.setEnabled(false); - } else { - IWorkingSet[] w = wsm.getRecentWorkingSets(); - if (w == null || w.length == 0) - wsets.setSelection(0); - else { - String s = w[0].getLabel(); - String[] ss = wsets.getItems(); - for (int i=0; i 0) { - String oldS = csets.getItem(n); - String newS = getString(UIMessages.getString("WorkingSetConfigAction.19"), oldS); //$NON-NLS-1$ - if (newS == null) - return; - if (oldS.equals(newS)) // nothing to do - return; - String key = wsets.getSelection()[0] + DELIMITER + newS; - if (configSetMap.containsKey(key)) { - ExistsMessage(newS); - return; - } - ConfigSet cs = configSetMap.get(wsets.getSelection()[0] + DELIMITER + oldS); - configSetMap.remove(cs); - cs.name = newS; - configSetMap.put(key, cs); - csets.setItem(n, newS); - } - }}); - - b4 = new Button(c, SWT.PUSH); - b4.setText(UIMessages.getString("WorkingSetConfigAction.9")); //$NON-NLS-1$ - b4.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL)); - b4.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - String[] ss = csets.getSelection(); - if (ss != null && ss.length > 0) { - configSetMap.remove(wsets.getSelection()[0] + DELIMITER + ss[0]); - csets.remove(ss[0]); - csets.setSelection(0); - updateButtons(); - } - }}); - - bb = new Button(c, SWT.PUSH); - bb.setText(UIMessages.getString("WorkingSetConfigAction.20")); //$NON-NLS-1$ - gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 2; - bb.setLayoutData(gd); - bb.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - build(); - LocalDialog.this.close(); - }}); - - initData(); - return comp; - } - - private void initData() { - configSetMap = new LinkedHashMap(); - for (String s : CDTPrefUtil.readConfigSets()) { - ConfigSet cs = new ConfigSet(s); - if (cs.isValid()) - configSetMap.put(cs.workingSetLabel + DELIMITER + cs.name, cs); - } - workingSetChanged(); - } - - private void updateButtons() { - Button ok = this.getButton(IDialogConstants.OK_ID); - boolean en = csets.getSelectionIndex() > 0; - if (! wsets.getEnabled()) { - b2.setEnabled(false); // new - if (ok != null) - ok.setEnabled(false); // OK - en = false; - } - b1.setEnabled(en); // update - b3.setEnabled(en); // rename - b4.setEnabled(en); // delete - bb.setEnabled(wsets.getEnabled()); - } - private void workingSetChanged() { -// tree.setRedraw(false); - tree.removeAll(); - String[] ss = wsets.getSelection(); - if (ss == null || ss.length == 0) - return; - IWorkingSet ws = workingSetsMap.get(ss[0]); - fillTree(ws); - tree.setRedraw(true); -// csets.setRedraw(false); - csets.removeAll(); - csets.add(CURRENT); - csets.setSelection(0); - - configSetMap.remove(CURRENT); // previous default object, if any - for (Map.Entry me : configSetMap.entrySet()) { - if (me.getValue().workingSetLabel.equals(ws.getLabel())) - csets.add(me.getValue().name); - } - configSetMap.put(CURRENT, new ConfigSet(CURRENT, ws.getLabel(), tree)); - csets.setRedraw(true); - updateButtons(); - - // calls from FillTree does not work... - for (TreeItem ti : tree.getItems()) - ti.setExpanded(true); - } - - /** - * Update projects tree for selected working set. - * @param ws - working set selected. - */ - private void fillTree(IWorkingSet ws) { - if (ws == null) - return; - for (IAdaptable ad : ws.getElements()) { - IProject p = (IProject)ad.getAdapter(IProject.class); - if (p == null) - continue; - ICProjectDescription prjd = CoreModel.getDefault().getProjectDescription(p, true); - if (prjd == null) - continue; - ICConfigurationDescription[] cfgs = prjd.getConfigurations(); - if (cfgs == null || cfgs.length == 0) - continue; - TreeItem ti = new TreeItem(tree, SWT.NONE); - ti.setText(prjd.getName()); - ti.setImage(IMG_PROJ); - ti.setData(prjd); - for (ICConfigurationDescription c : cfgs) { - TreeItem ti1 = new TreeItem(ti, SWT.NONE); - ti1.setText(c.getName()); - ti1.setImage(IMG_CONF); - ti1.setChecked(c.isActive()); - ti1.setData(c); - } - } - } - - private void configSetChanged() { - int i = csets.getSelectionIndex(); - if (i >= 0) { - String key = (i == 0) ? CURRENT : wsets.getSelection()[0] + DELIMITER + csets.getItem(i); - ConfigSet cs = configSetMap.get(key); - if (cs != null && cs.isValid()) { - for (TreeItem ti : tree.getItems()) { - ICProjectDescription prjd = (ICProjectDescription)ti.getData(); - String cid = cs.data.get(prjd.getName()); - if (cid == null) - continue; // the project not in the list - for (TreeItem ti1 : ti.getItems()) { - ICConfigurationDescription cfg = (ICConfigurationDescription)ti1.getData(); - ti1.setChecked(cid.equals(cfg.getId())); - } - } - } - } - updateButtons(); - } - - private String getString(String title, String value) { - InputDialog d = new InputDialog(sh, title, - UIMessages.getString("WorkingSetConfigAction.11"), //$NON-NLS-1$ - value, new IInputValidator() { - public String isValid(String newText) { - if (newText.indexOf(CDTPrefUtil.CONFSETDEL) >= 0) - return UIMessages.getString("WorkingSetConfigAction.0") + CDTPrefUtil.CONFSETDEL + UIMessages.getString("WorkingSetConfigAction.14"); //$NON-NLS-1$ //$NON-NLS-2$ - if (configSetMap.containsKey(wsets.getSelection()[0] + DELIMITER + newText)) - return UIMessages.getString("WorkingSetConfigAction.15") + newText + UIMessages.getString("WorkingSetConfigAction.16"); //$NON-NLS-1$ //$NON-NLS-2$ - return null; - }}); - if (d.open() == Window.OK) - return d.getValue().replace(' ', '_'); // space is delimiter. - return null; - } - - private void ExistsMessage(String s) { - MessageBox box = new MessageBox(sh, SWT.ICON_ERROR); - box.setMessage(UIMessages.getString("WorkingSetConfigAction.12") + s); //$NON-NLS-1$ - box.open(); - } - - private void build() { - saveConfigSets(); - saveActiveConfigs(); - IProject[] ps = new IProject[tree.getItemCount()]; - int cnt = 0; - for (TreeItem ti : tree.getItems()) - ps[cnt++] = ((ICProjectDescription)ti.getData()).getProject(); - Job buildJob = new BuildJob(ps); - buildJob.schedule(); - } - } - - private static final class BuildJob extends Job { - IProject[] ps; - - BuildJob(IProject[] _ps) { - super(UIMessages.getString("WorkingSetConfigAction.21")); //$NON-NLS-1$ - ps = _ps; - } - - /* (non-Javadoc) - * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) - */ - @Override - protected IStatus run(IProgressMonitor monitor) { - for (IProject p:ps) - try { - setName(UIMessages.getString("WorkingSetConfigAction.21") + p.getName()); //$NON-NLS-1$ - p.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, monitor); - } catch (CoreException e) { - return new Status(IStatus.ERROR, UIMessages.getString("WorkingSetConfigAction.22"), e.getLocalizedMessage()); //$NON-NLS-1$ - } - if (monitor.isCanceled()) { - return Status.CANCEL_STATUS; - } - monitor.done(); - return Status.OK_STATUS; - } - - @Override - public boolean belongsTo(Object family) { - return ResourcesPlugin.FAMILY_MANUAL_BUILD == family; - } - - } - - private static class ConfigSet { - String name; - String workingSetLabel; - LinkedHashMap data; - - private ConfigSet(String s) { - data = new LinkedHashMap(); - String[] ss = s.split(DELIMITER); - if (ss == null || ss.length < 4 || ss.length %2 == 1) { - CUIPlugin.getDefault().logErrorMessage(UIMessages.getString("WorkingSetConfigAction.13") + s); //$NON-NLS-1$ - return; // not valid - } - name = ss[0]; - workingSetLabel = ss[1]; - int n = (ss.length - 2) / 2; - for (int i=0; i(); - name = n; - workingSetLabel = w; - for (TreeItem ti : t.getItems()) { - ICProjectDescription prjd = (ICProjectDescription)ti.getData(); - for (TreeItem ti1 : ti.getItems()) { - if (ti1.getChecked()) { - ICConfigurationDescription cfg = (ICConfigurationDescription)ti1.getData(); - data.put(prjd.getName(), cfg.getId()); - break; - } - } - } - - } - - private boolean isValid() { - return data.size() > 0; - } - - @Override - public String toString() { - if (!isValid()) - return EMPTY_STR; - StringBuilder b = new StringBuilder(); - b.append(name); - b.append(DELIMITER); - b.append(workingSetLabel); - b.append(DELIMITER); - for (Map.Entry me : data.entrySet()) { - b.append(me.getKey()); - b.append(DELIMITER); - b.append(me.getValue()); - b.append(DELIMITER); - } - return b.toString().trim(); - } - } } Index: src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetPropertyTester.java =================================================================== RCS file: src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetPropertyTester.java diff -N src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetPropertyTester.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetPropertyTester.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,79 @@ +/******************************************************************************* + * 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.core.expressions.PropertyTester; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.ui.IWorkingSet; + +import org.eclipse.cdt.core.model.CoreModel; + +/** + * Property tester for working sets that CDT can manipulate in cool ways, such + * as managing build configurations. + * + * @author Christian W. Damus (cdamus) + * + * @since 6.0 + * + */ +public class WorkingSetPropertyTester extends PropertyTester { + + private static final String P_HAS_C_PROJECTS = "hasCProjects"; //$NON-NLS-1$ + + /** + * Initializes me. + */ + public WorkingSetPropertyTester() { + super(); + } + + public boolean test(Object receiver, String property, Object[] args, Object expectedValue) { + if (P_HAS_C_PROJECTS.equals(property)) { + return hasCProjects(getWorkingSet(receiver)); + } + + return false; + } + + private IWorkingSet getWorkingSet(Object object) { + IWorkingSet result = null; + + if (object instanceof IWorkingSet) { + result = (IWorkingSet) object; + } else if (object instanceof IAdaptable) { + result = (IWorkingSet) ((IAdaptable) object).getAdapter(IWorkingSet.class); + } + + return result; + } + + private boolean hasCProjects(IWorkingSet workingSet) { + boolean result = false; + + if (workingSet != null) { + IAdaptable[] members = workingSet.getElements(); + + for (IAdaptable next : members) { + IProject project = (IProject) next.getAdapter(IProject.class); + + if ((project != null) && CoreModel.hasCNature(project)) { + result = true; + break; + } + } + } + + return result; + } +} Index: src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetProxy.java =================================================================== RCS file: src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetProxy.java diff -N src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetProxy.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetProxy.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,328 @@ +/******************************************************************************* + * 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 static org.eclipse.cdt.internal.ui.workingsets.WorkingSetConfigurationManager.ATTR_NAME; +import static org.eclipse.cdt.internal.ui.workingsets.WorkingSetConfigurationManager.KEY_CONFIG; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.ui.IMemento; +import org.eclipse.ui.IWorkingSet; + +import com.ibm.icu.text.UCharacterIterator; + +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; + +/** + * Default implementation of the {@link IWorkingSetProxy} interface. + * + * @noextend This class is not intended to be subclassed by clients. + * + * @author Christian W. Damus (cdamus) + * + * @since 6.0 + */ +public class WorkingSetProxy implements IWorkingSetProxy { + private String name; + private Map configurations; + + /** + * Initializes me. + */ + public WorkingSetProxy() { + super(); + } + + public String getName() { + return name; + } + + /** + * Sets my name. This does not change the name of the working set that I represent. Rather, it + * changes which working set I represent. + * + * @param name + * my new name + */ + void setName(String name) { + this.name = name; + } + + public IWorkingSet resolve() { + return WorkingSetConfigurationManager.WS_MGR.getWorkingSet(name); + } + + public Collection resolveProjects() { + Set result = new java.util.HashSet(); + + IWorkingSet resolvedWS = resolve(); + if (resolvedWS != null) { + for (IAdaptable next : resolvedWS.getElements()) { + IProject proj = (IProject) next.getAdapter(IProject.class); + + if (proj != null) { + result.add(proj); + } + } + } + + return result; + } + + public boolean isValid() { + return !resolveProjects().isEmpty(); + } + + private Map getConfigurationsMap() { + if (configurations == null) { + configurations = new java.util.HashMap(); + } + + return configurations; + } + + public IWorkingSetConfiguration getConfiguration(String name) { + return getConfigurationsMap().get(name); + } + + public Collection getConfigurations() { + return getConfigurationsMap().values(); + } + + public void saveState(IMemento memento) { + memento.putString(ATTR_NAME, getName()); + + for (IWorkingSetConfiguration next : getConfigurations()) { + if (!isTransient(next)) { + next.saveState(memento.createChild(KEY_CONFIG)); + } + } + } + + /** + * Queries whether the specified configuration is transient, meaning that it should not be persisted in + * the working set configuration store. The default implementation just returns false; + * subclasses may redefine as required. + * + * @param config + * a working set configuration + * @return whether it should be omitted from persistence + */ + protected boolean isTransient(IWorkingSetConfiguration config) { + return false; + } + + public void loadState(IMemento memento) { + setName(memento.getString(ATTR_NAME)); + + for (IMemento next : memento.getChildren(KEY_CONFIG)) { + IWorkingSetConfiguration config = createWorkingSetConfiguration(); + config.loadState(next); + getConfigurationsMap().put(config.getName(), config); + } + } + + /** + * Creates a new child working set configuration element. Subclasses may override to create custom + * implementations. + * + * @return the new working set configuration + */ + protected IWorkingSetConfiguration createWorkingSetConfiguration() { + return new WorkingSetConfiguration(this); + } + + /** + * Provides simple access to the child configurations, to remove the specified configuration. + * + * @param config + * a configuration to remove + */ + protected void basicRemoveConfiguration(IWorkingSetConfiguration config) { + getConfigurationsMap().remove(config.getName()); + } + + /** + * Provides simple access to the child configurations, to add the specified configuration. + * + * @param config + * a configuration to add + */ + protected void basicAddConfiguration(IWorkingSetConfiguration config) { + getConfigurationsMap().put(config.getName(), config); + } + + public ISnapshot createSnapshot(WorkspaceSnapshot workspace) { + Snapshot result = new Snapshot(this, workspace); + + result.updateActiveConfigurations(); + + return result; + } + + // + // Nested classes + // + + /** + * The default implementation of a mutable working set snapshot. + * + * @noextend This class is not intended to be subclassed by clients. + * + * @author Christian W. Damus (cdamus) + * + * @since 6.0 + */ + public static class Snapshot extends WorkingSetProxy implements IWorkingSetProxy.ISnapshot { + private final WorkspaceSnapshot workspace; + private IWorkingSetConfiguration.ISnapshot readOnlyConfig; + + /** + * Initializes me with the current workspace snapshot. + * + * @param workingSet + * the original working set element to copy + * @param workspace + * the workspace snapshot + */ + protected Snapshot(IWorkingSetProxy workingSet, WorkspaceSnapshot workspace) { + super(); + + this.workspace = workspace; + + setName(workingSet.getName()); + + for (IWorkingSetConfiguration next : workingSet.getConfigurations()) { + basicAddConfiguration(next.createSnapshot(this, workspace)); + } + } + + public final WorkspaceSnapshot getWorkspaceSnapshot() { + return workspace; + } + + public IWorkingSetConfiguration.ISnapshot createConfiguration(String name) { + if ((name == null) || (name.length() == 0)) { + throw new IllegalArgumentException("name is empty"); //$NON-NLS-1$ + } + if (getConfiguration(name) != null) { + throw new IllegalArgumentException("name is already in use"); //$NON-NLS-1$ + } + + IWorkingSetConfiguration.ISnapshot result = createWorkingSetConfiguration(); + result.setName(name); + + heuristicSelectProjectConfigurations(result); + + basicAddConfiguration(result); + updateActiveConfigurations(); + + return result; + } + + /** + * Heuristically attempts to select reasonable default project configurations for a new working-set + * configuration. This implementation does a best-effort match of project configuration names against + * the working set configuration name. + * + * @param newConfig + * the new working set configuration + */ + protected void heuristicSelectProjectConfigurations(IWorkingSetConfiguration.ISnapshot newConfig) { + String nameToSearch = getSearchKey(newConfig.getName()); + + for (IWorkingSetProjectConfiguration next : newConfig.getProjectConfigurations()) { + IWorkingSetProjectConfiguration.ISnapshot project = (IWorkingSetProjectConfiguration.ISnapshot) next; + + for (ICConfigurationDescription config : project.resolveConfigurations()) { + if (nameToSearch.equalsIgnoreCase(getSearchKey(config.getName()))) { + // a match! Select this config + project.setSelectedConfigurationID(config.getId()); + break; + } + } + } + + } + + private String getSearchKey(String configurationName) { + StringBuilder result = new StringBuilder(configurationName.length()); + + UCharacterIterator iter = UCharacterIterator.getInstance(configurationName); + for (int cp = iter.nextCodePoint(); cp != UCharacterIterator.DONE; cp = iter.nextCodePoint()) { + if (Character.isLetterOrDigit(cp)) { + result.appendCodePoint(cp); + } + } + + return result.toString(); + } + + /** + * I create working-set configuration snapshots that are mutable, as I am. + */ + @Override + protected IWorkingSetConfiguration.ISnapshot createWorkingSetConfiguration() { + return new WorkingSetConfiguration.Snapshot(this, workspace); + } + + public void removeConfiguration(IWorkingSetConfiguration config) { + if (WorkingSetConfiguration.isReadOnly(config)) { + throw new IllegalArgumentException("config is read-only"); //$NON-NLS-1$ + } + + basicRemoveConfiguration(config); + } + + public boolean updateActiveConfigurations() { + boolean result = getConfigurations().isEmpty(); + + boolean hasActiveConfig = false; + for (IWorkingSetConfiguration next : getConfigurations()) { + if (next.isActive() && !WorkingSetConfiguration.isReadOnly(next)) { + hasActiveConfig = true; + break; + } + } + + if (hasActiveConfig) { + if (readOnlyConfig != null) { + basicRemoveConfiguration(readOnlyConfig); + result = true; + } + readOnlyConfig = null; + } else { + WorkingSetConfiguration.Snapshot ro = new WorkingSetConfiguration.Snapshot(this, workspace, + true); + ro.basicSetName(""); // don't want to validate this name //$NON-NLS-1$ + readOnlyConfig = ro; + basicAddConfiguration(readOnlyConfig); + result = true; + } + + return result; + } + + /** + * Read-only working set configuration snapshots are transient. + */ + @Override + protected boolean isTransient(IWorkingSetConfiguration config) { + return WorkingSetConfiguration.isReadOnly(config); + } + } +} \ No newline at end of file Index: src/org/eclipse/cdt/internal/ui/workingsets/BuildWorkingSetConfigsContribution.java =================================================================== RCS file: src/org/eclipse/cdt/internal/ui/workingsets/BuildWorkingSetConfigsContribution.java diff -N src/org/eclipse/cdt/internal/ui/workingsets/BuildWorkingSetConfigsContribution.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/cdt/internal/ui/workingsets/BuildWorkingSetConfigsContribution.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 build configurations of a working set. + * + * @author Christian W. Damus (cdamus) + * + * @since 6.0 + */ +public class BuildWorkingSetConfigsContribution 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 BuildWorkingSetConfigsContribution() { + super(); + } + + /** + * Initializes me with my working set. + * + * @param workingSet + * my working set + */ + BuildWorkingSetConfigsContribution(IWorkingSetProxy workingSet) { + super(workingSet); + } + + @Override + protected IContributionItem createContribution(IWorkingSetConfiguration config, int index) { + return new ActionContributionItem(new BuildConfigAction(config, index + 1)); + } + + // + // Nested classes + // + + private static class BuildConfigAction extends Action { + private IWorkingSetConfiguration workingSetConfig; + + BuildConfigAction(IWorkingSetConfiguration workingSetConfig, int ordinal) { + super(NLS.bind(WorkingSetMessages.WorkingSetMenus_enumPattern, ordinal, workingSetConfig + .getName())); + + this.workingSetConfig = workingSetConfig; + } + + @Override + public void run() { + new BuildJob(workingSetConfig).schedule(); + } + } +} Index: src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetProjectConfigurationController.java =================================================================== RCS file: src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetProjectConfigurationController.java diff -N src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetProjectConfigurationController.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetProjectConfigurationController.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,176 @@ +/******************************************************************************* + * 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.viewers.IBaseLabelProvider; +import org.eclipse.jface.viewers.IColorProvider; +import org.eclipse.jface.viewers.IContentProvider; +import org.eclipse.jface.viewers.IFontProvider; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.Viewer; + +/** + * Protocol for the view controller for the project configurations pane of the working set configurations + * dialog. It takes care of coordinating the user gestures in that pane with the working-set configuration + * model and vice-versa. + * + * @author Christian W. Damus (cdamus) + * + * @since 6.0 + * + */ +public interface IWorkingSetProjectConfigurationController { + /** + * Queries the project configuration in the Working Set Configurations pane that I control. + * + * @return the new working set configuration selection. May be null if there is no selection + */ + IWorkingSetProjectConfiguration.ISnapshot getProjectConfiguration(); + + /** + * Notifies me that the check state of some element that I control in the sub-tree of my + * {@linkplain #getProjectConfiguration() project configuration} has changed its check-state. The + * controller context can be used to pass back reactions such as to veto the check-state change or to + * signal that some level of UI refresh is required. + * + * @param element + * an element that has been checked or unchecked + * @param checked + * whether the element is now checked + * @param context + * the controller context, used to communicate vetos, refreshes, etc. + */ + void checkStateChanged(Object element, boolean checked, IControllerContext context); + + /** + * Computes the initial check-box settings for my tree according to the current state of my + * {@linkplain #getProjectConfiguration() project configuration}. + * + * @param context + * context in which I can set initial check-states of my elements + */ + void updateCheckState(IControllerContext context); + + /** + * Obtains a content provider for the structure rooted at my {@linkplain #getProjectConfiguration() + * project configuration}. Note that this method will only be called once, and that the caller takes + * responsibility for {@linkplain IContentProvider#dispose() disposing} the content provider. + * + * @return my content provider + */ + ITreeContentProvider getContentProvider(); + + /** + *

+ * Obtains a label provider for the structure rooted at my {@linkplain #getProjectConfiguration() project + * configuration}. Note that this method will only be called once, and that the caller takes + * responsibility for {@linkplain IBaseLabelProvider#dispose() disposing} the label provider. + *

+ *

+ * The viewer argument is useful to obtain information about default font and colors, for label providers + * that implement the optional {@link IFontProvider} and/or {@link IColorProvider} interfaces. + *

+ * + * @param viewer + * the viewer for which I will provide labels + * + * @return my label provider + */ + ILabelProvider getLabelProvider(Viewer viewer); + + // + // Nested types + // + + /** + * An interface provided by the Manage Working Set Configurations dialog infrastructure to + * {@link IWorkingSetProjectConfigurationController}s for communication of state changes back to the UI. + * + * @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 (damus) + * + * @since 6.0 + */ + interface IControllerContext { + /** + * Queries whether the current working set configuration context is a read-only one. In such cases, I + * should probably disallow check-state changes and other editing. + * + * @return whether the current working set configuration is read-only + * + * @see IWorkingSetConfiguration.ISnapshot#isReadOnly() + */ + boolean isReadOnly(); + + /** + * Sets the check state of an element in the Project Configurations pane under the authority of the + * controller. This is particularly useful for setting the + * {@linkplain IWorkingSetProjectConfigurationController#updateCheckState(IControllerContext) initial + * check state} of a controller and for + * {@linkplain IWorkingSetProjectConfigurationController#checkStateChanged(Object, boolean, IControllerContext) + * vetoing check state changes}. + * + * @param element + * the element to update checked + * @param checked + * whether the element should be checked + * + * @see IWorkingSetProjectConfigurationController#checkStateChanged(Object, boolean, + * IControllerContext) + * @see IWorkingSetProjectConfigurationController#updateCheckState(IControllerContext) + * @see #setGrayed(Object, boolean) + */ + void setChecked(Object element, boolean checked); + + /** + * Sets the gray state of an element in the Project Configurations pane under the authority of the + * controller. This is particularly useful for setting the + * {@linkplain IWorkingSetProjectConfigurationController#updateCheckState(IControllerContext) initial + * check state} of a controller and for + * {@linkplain IWorkingSetProjectConfigurationController#checkStateChanged(Object, boolean, IControllerContext) + * responding to check state changes}. + * + * @param element + * the element to update checked + * @param checked + * whether the element should be checked + * + * @see IWorkingSetProjectConfigurationController#checkStateChanged(Object, boolean, + * IControllerContext) + * @see IWorkingSetProjectConfigurationController#updateCheckState(IControllerContext) + * @see #setChecked(Object, boolean) + */ + void setGrayed(Object element, boolean grayed); + + /** + * Requests an update of the visual appearance of the specified element. The element may be any + * element under my control, or even the {@link IWorkingSetConfiguration} or {@link IWorkingSetProxy} + * that owns my project configuration. + * + * @param element + * an element to update + */ + void update(Object element); + + /** + * Notifies that the specified project configuration's activation state has changed. That is, that it + * is now activated when previously it was not, or vice-versa. + * + * @param project + * configuration the project configuration that changed + */ + void activationStateChanged(IWorkingSetProjectConfiguration projectConfiguration); + } +} \ No newline at end of file Index: src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfiguration.java =================================================================== RCS file: src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfiguration.java diff -N src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfiguration.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfiguration.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,384 @@ +/******************************************************************************* + * 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 static org.eclipse.cdt.internal.ui.workingsets.WorkingSetConfigurationManager.ATTR_NAME; +import static org.eclipse.cdt.internal.ui.workingsets.WorkingSetConfigurationManager.KEY_PROJECT; + +import java.util.List; +import java.util.Map; + +import org.eclipse.core.resources.IProject; +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.IMemento; +import org.eclipse.ui.IWorkingSet; + +import org.eclipse.cdt.ui.CUIPlugin; + +/** + * Default implementation of the {@link IWorkingSetConfiguration} interface. + * + * @noextend This class is not intended to be subclassed by clients. + * + * @author Christian W. Damus (cdamus) + * + * @since 6.0 + * + */ +public class WorkingSetConfiguration implements IWorkingSetConfiguration { + private final IWorkingSetProxy workingSet; + private String name; + + private Map projects; + + /** + * Initializes me with my parent working set. + * + * @param workingSet + * my parent working set + */ + protected WorkingSetConfiguration(IWorkingSetProxy workingSet) { + this.workingSet = workingSet; + } + + /** + * Obtains my parent working set. + * + * @return my parent + */ + public IWorkingSetProxy getWorkingSet() { + return workingSet; + } + + /** + * Obtains my name. + * + * @return my name + */ + public String getName() { + return name; + } + + /** + * Sets my name. + * + * @param name + * my new name + * + * @throws IllegalArgumentException + * if the specified name is null or empty, or if it is already used by another + * configuration in my warking set + */ + void setName(String name) { + if ((name == null) || (name.length() == 0)) { + throw new IllegalArgumentException("name is empty"); //$NON-NLS-1$ + } + + if (!name.equals(getName())) { + if (getWorkingSet().getConfiguration(name) != null) { + throw new IllegalArgumentException("name is already in use"); //$NON-NLS-1$ + } + + basicSetName(name); + } + } + + /** + * Provides simple access to the name for setting it. + * + * @param name + * my new name + */ + protected void basicSetName(String name) { + this.name = name; + } + + private Map getProjects() { + if (projects == null) { + projects = new java.util.HashMap(); + + for (IProject next : workingSet.resolveProjects()) { + IWorkingSetProjectConfiguration child = createProjectConfiguration(next); + + // the project may not be a C/C++ project + if (child != null) { + basicAddProjectConfiguration(child); + } + } + } + + return projects; + } + + protected void basicAddProjectConfiguration(IWorkingSetProjectConfiguration projectConfig) { + if (projects == null) { + projects = new java.util.HashMap(); + } + + projects.put(projectConfig.getProjectName(), projectConfig); + } + + public IWorkingSetProjectConfiguration getProjectConfiguration(String projectName) { + return getProjects().get(projectName); + } + + public java.util.Collection getProjectConfigurations() { + return getProjects().values(); + } + + public boolean isActive() { + boolean result = !getProjects().isEmpty(); + + if (result) { + for (IWorkingSetProjectConfiguration next : getProjectConfigurations()) { + if (!next.isActive()) { + result = false; + break; + } + } + } + + return result; + } + + public void activate() { + if (!isActive()) { + for (IWorkingSetProjectConfiguration next : getProjectConfigurations()) { + next.activate(); + } + } + + // this is a "recently used" working set + IWorkingSet ws = getWorkingSet().resolve(); + if (ws != null) { + WorkingSetConfigurationManager.WS_MGR.addRecentWorkingSet(ws); + } + } + + public IStatus build(IProgressMonitor monitor) { + MultiStatus result = new MultiStatus(CUIPlugin.PLUGIN_ID, 0, + WorkingSetMessages.WSConfig_build_problems, null); + + List toBuild = new java.util.ArrayList( + getProjectConfigurations().size()); + for (IWorkingSetProjectConfiguration next : getProjectConfigurations()) { + IProject project = next.resolveProject(); + + if ((project != null) && (project.isAccessible())) { + toBuild.add(next); + } + } + + SubMonitor progress = SubMonitor.convert(monitor, NLS.bind(WorkingSetMessages.WSConfig_build_task, + getWorkingSet().getName()), toBuild.size()); + + try { + for (IWorkingSetProjectConfiguration next : toBuild) { + if (progress.isCanceled()) { + result.add(Status.CANCEL_STATUS); + break; + } + + IStatus status = next.build(progress.newChild(1)); + + if ((status != null && !status.isOK())) { + result.add(status); + } + } + } finally { + if (monitor != null) { + monitor.done(); + } + } + + return result.isOK() ? Status.OK_STATUS : result; + } + + public void saveState(IMemento memento) { + memento.putString(ATTR_NAME, getName()); + + for (IWorkingSetProjectConfiguration next : getProjectConfigurations()) { + next.saveState(memento.createChild(KEY_PROJECT)); + } + } + + public void loadState(IMemento memento) { + setName(memento.getString(ATTR_NAME)); + + Map projectMementos = new java.util.HashMap(); + for (IMemento next : memento.getChildren(KEY_PROJECT)) { + projectMementos.put(next.getString(ATTR_NAME), next); + } + + for (IWorkingSetProjectConfiguration next : getProjectConfigurations()) { + IMemento state = projectMementos.get(next.getProjectName()); + if (state != null) { + next.loadState(state); + } + } + } + + /** + * Creates a new project configuration for the specified project. May be overridden by subclasses to + * create a different implementation. + * + * @param project + * a workspace project + * @return a new project configuration element for it + */ + protected IWorkingSetProjectConfiguration createProjectConfiguration(IProject project) { + IWorkingSetProjectConfiguration result = null; + + IWorkingSetProjectConfigurationFactory factory = IWorkingSetProjectConfigurationFactory.Registry.INSTANCE + .getFactory(project); + if (factory != null) { + result = factory.createProjectConfiguration(this, project); + } + + return result; + } + + public ISnapshot createSnapshot(IWorkingSetProxy.ISnapshot workingSet, WorkspaceSnapshot workspace) { + + return new Snapshot(workingSet, this, workspace); + } + + /** + * Utility method to query whether the specified configuration is a read-only snapshot. + * + * @param config + * a working set configuration + * @return whether it is a read-only snapshot + * + * @see IWorkingSetConfiguration.ISnapshot#isReadOnly() + */ + static boolean isReadOnly(IWorkingSetConfiguration config) { + return (config instanceof WorkingSetConfiguration.Snapshot) + && ((WorkingSetConfiguration.Snapshot) config).isReadOnly(); + } + + // + // Nested classes + // + + /** + * Default implementation of the mutable working set configuration snapshot. + * + * @author Christian W. Damus (cdamus) + * + * @noextend This class is not intended to be subclassed by clients. + * + * @since 6.0 + */ + public static class Snapshot extends WorkingSetConfiguration implements + IWorkingSetConfiguration.ISnapshot { + + private final boolean readOnly; + private final WorkspaceSnapshot workspace; + + /** + * Initializes me with the current workspace snapshot. + * + * @param workingSet + * my parent working set + * @param workspace + * the current workspace snapshot + */ + protected Snapshot(IWorkingSetProxy workingSet, WorkspaceSnapshot workspace) { + this(workingSet, workspace, false); + } + + /** + * Initializes me as a special read-only configuration that shows what is the current active + * configuration of the projects in a working set when none of its named configurations is active. + * + * @param workingSet + * my parent working set + * @param workspace + * the current workspace snapshot + * @param readOnly + * whether I am read-only. A read-only configuration cannot be modified in the dialog + */ + protected Snapshot(IWorkingSetProxy workingSet, WorkspaceSnapshot workspace, boolean readOnly) { + super(workingSet); + + this.readOnly = readOnly; + this.workspace = workspace; + } + + /** + * Initializes me with the current workspace snapshot. + * + * @param workingSet + * my parent working set + * @param config + * the working set configuration that I copy + * @param workspace + * the current workspace snapshot + */ + protected Snapshot(IWorkingSetProxy workingSet, IWorkingSetConfiguration config, + WorkspaceSnapshot workspace) { + this(workingSet, workspace); + + setName(config.getName()); + + for (IWorkingSetProjectConfiguration next : config.getProjectConfigurations()) { + basicAddProjectConfiguration(next.createSnapshot(this, workspace)); + } + } + + @Override + public final IWorkingSetProxy.ISnapshot getWorkingSet() { + return (IWorkingSetProxy.ISnapshot) super.getWorkingSet(); + } + + public final WorkspaceSnapshot getWorkspaceSnapshot() { + return workspace; + } + + /** + * Queries whether I am a read-only view of the current active configurations of my working set's + * projects. + * + * @return whether I am read-only + */ + public final boolean isReadOnly() { + return readOnly; + } + + @Override + public void setName(String name) { + super.setName(name); + } + + /** + * I create project configurations that are mutable, as I am. + */ + @Override + protected IWorkingSetProjectConfiguration createProjectConfiguration(IProject project) { + IWorkingSetProjectConfiguration result = null; + + IWorkingSetProjectConfigurationFactory factory = IWorkingSetProjectConfigurationFactory.Registry.INSTANCE + .getFactory(project); + if (factory != null) { + result = factory.createProjectConfiguration(this, project).createSnapshot(this, workspace); + } + + return result; + } + } +} \ No newline at end of file Index: schema/workingSetConfigurations.exsd =================================================================== RCS file: schema/workingSetConfigurations.exsd diff -N schema/workingSetConfigurations.exsd --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ schema/workingSetConfigurations.exsd 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,149 @@ + + + + + + + + + <p> +<b>This extension point is internal to the CDT plug-in family.</b> +</p><p> +Extension point for registration of project configuration factories for handling extended configuration options for custom project natures, in working set configurations. These factories are responsible for creating the project configuration elements and the UI controllers for the Manage Working Set Configurations dialog. +</p> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Registration of a factory for project configuration elements in working set configurations. Factories are registered against project natures via nested <tt>&lt;nature&gt;</tt> elements. + + + + + + + + + + A unique identifier for the project configuration factory. + + + + + + + Fully qualified name of the factory class. It must implement the <tt>IWorkingSetProjectConfigurationFactory</tt> interface. + + + + + + + + + + + + + A reference to a project nature. + + + + + + + The referenced project nature ID. + + + + + + + + + + + + + + + 6.0 + + + + + + + + + <pre> +<extension point="org.eclipse.cdt.ui.workingSetConfigurations"> + <projectConfigurationFactory + id="org.example.myProject" + class="org.example.MyProjectConfigurationFactory"> + <nature id="org.example.myProjectNature"/> + </projectConfigurationFactory> +</extension> +</pre> + + + + + + + + + Registered project configuration factories are required to implement the <tt>org.eclipse.cdt.internal.ui.workingsets.IWorkingSetProjectConfigurationFactory</tt> interface. + + + + + + + + + + Copyright (c) 2009 QNX Software Systems and others. All rights reserved. + + + + Index: src/org/eclipse/cdt/internal/ui/workingsets/BuildJob.java =================================================================== RCS file: src/org/eclipse/cdt/internal/ui/workingsets/BuildJob.java diff -N src/org/eclipse/cdt/internal/ui/workingsets/BuildJob.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/cdt/internal/ui/workingsets/BuildJob.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2008, 2009 Intel Corporation, 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: + * Intel Corporation - initial API and implementation + * QNX Software Systems - [272416] Rework the working set configurations + *******************************************************************************/ + +package org.eclipse.cdt.internal.ui.workingsets; + +import java.util.Collection; + +import org.eclipse.core.resources.IProject; +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.jobs.Job; + +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.cdt.ui.newui.UIMessages; + +/** + * A job that builds a bunch of workspace projects or a working set configuration. + */ +public final class BuildJob extends Job { + private Collection projects; + private IWorkingSetConfiguration workingSetConfig; + + /** + * Initializes me with a bunch projects to build in their active configurations. + * + * @param projects + * the projects to build + */ + public BuildJob(Collection projects) { + super(UIMessages.getString("WorkingSetConfigAction.21")); //$NON-NLS-1$ + this.projects = new java.util.ArrayList(projects); + } + + /** + * Initializes me with a working set configuration to build. + * + * @param workingSetConfig + * the working set configuration to build + */ + public BuildJob(IWorkingSetConfiguration workingSetConfig) { + super(UIMessages.getString("WorkingSetConfigAction.21")); //$NON-NLS-1$ + this.workingSetConfig = workingSetConfig; + } + + @Override + protected IStatus run(IProgressMonitor monitor) { + if (projects != null) { + return buildProjects(monitor); + } else { + return buildWorkingSetConfig(monitor); + } + } + + private IStatus buildProjects(IProgressMonitor monitor) { + try { + for (IProject p : projects) { + try { + setName(UIMessages.getString("WorkingSetConfigAction.21") + p.getName()); //$NON-NLS-1$ + p.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, monitor); + } catch (CoreException e) { + return new MultiStatus(CUIPlugin.PLUGIN_ID, 0, new IStatus[] { e.getStatus() }, + UIMessages.getString("WorkingSetConfigAction.22"), //$NON-NLS-1$ + null); + } + if (monitor.isCanceled()) { + return Status.CANCEL_STATUS; + } + } + } finally { + monitor.done(); + } + return Status.OK_STATUS; + } + + private IStatus buildWorkingSetConfig(IProgressMonitor monitor) { + try { + return workingSetConfig.build(monitor); + } finally { + monitor.done(); + } + } + + @Override + public boolean belongsTo(Object family) { + return ResourcesPlugin.FAMILY_MANUAL_BUILD == family; + } + +} \ No newline at end of file Index: src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfigurationDialog.java =================================================================== RCS file: src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfigurationDialog.java diff -N src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfigurationDialog.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfigurationDialog.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,92 @@ +/******************************************************************************* + * 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.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.TrayDialog; +import org.eclipse.jface.window.IShellProvider; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; + +/** + * A dialog for management of working set configurations. These collect the selection of project + * configurations for the member projects of the working sets into named presets. + * + * @author Christian W. Damus (cdamus) + * + * @since 6.0 + */ +public class WorkingSetConfigurationDialog extends TrayDialog { + + private WorkingSetConfigurationBlock block; + + /** + * Initializes me with my shell. + * + * @param shell + */ + public WorkingSetConfigurationDialog(Shell shell) { + super(shell); + } + + /** + * Initializes me with my shell provider. + * + * @param parentShell + */ + public WorkingSetConfigurationDialog(IShellProvider parentShell) { + super(parentShell); + } + + @Override + protected boolean isResizable() { + return true; + } + + @Override + protected void configureShell(Shell newShell) { + setHelpAvailable(false); + + super.configureShell(newShell); + + newShell.setText(WorkingSetMessages.WSConfigDialog_title); + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite result = (Composite) super.createDialogArea(parent); + + block = new WorkingSetConfigurationBlock(WorkingSetConfigurationManager.getDefault() + .createWorkspaceSnapshot()); + Control contents = block.createContents(result); + contents.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + return result; + } + + @Override + protected void buttonPressed(int buttonId) { + if (buttonId == IDialogConstants.OK_ID) { + if (!block.build()) { + // user cancelled: don't save, and don't close the dialog + return; + } + + block.save(); + } + + super.buttonPressed(buttonId); + } +} Index: src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetConfigurationElement.java =================================================================== RCS file: src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetConfigurationElement.java diff -N src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetConfigurationElement.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetConfigurationElement.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,57 @@ +/******************************************************************************* + * 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.ui.IMemento; +import org.eclipse.ui.IPersistable; + +/** + * The protocol for elements of the working-set configuration model, which can be persisted via + * {@linkplain IMemento mementos}. + * + * @author Christian W. Damus (cdamus) + * + * @since 6.0 + * + */ +public interface IWorkingSetConfigurationElement extends IPersistable { + /** + * Loads me from the specified memento. + * + * @param memento + * a memento in which I am persisted + */ + void loadState(IMemento memento); + + // + // Nested types + // + + /** + * The protocol for mutable working-copies ("snapshots") of working set configuration model elements. + * + * @author Christian W. Damus (cdamus) + * + * @since 6.0 + * + * @see WorkspaceSnapshot + */ + interface ISnapshot { + /** + * Obtains the workspace snapshot that describes the baseline state of the working-set configuration + * editing session of which I am a part. + * + * @return my base workspace snapshot + */ + WorkspaceSnapshot getWorkspaceSnapshot(); + } +} Index: src/org/eclipse/cdt/internal/ui/workingsets/AbstractWorkingSetsContribution.java =================================================================== RCS file: src/org/eclipse/cdt/internal/ui/workingsets/AbstractWorkingSetsContribution.java diff -N src/org/eclipse/cdt/internal/ui/workingsets/AbstractWorkingSetsContribution.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/cdt/internal/ui/workingsets/AbstractWorkingSetsContribution.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,108 @@ +/******************************************************************************* + * 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 java.util.List; + +import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.osgi.util.NLS; +import org.eclipse.ui.IWorkingSet; +import org.eclipse.ui.IWorkingSetManager; +import org.eclipse.ui.actions.CompoundContributionItem; + +import org.eclipse.cdt.ui.CUIPlugin; + +/** + * A dynamic contribution of sub-menus for working set configuration actions, with further sub-menus showing + * the configurations to choose from. + * + * @author Christian W. Damus (cdamus) + * + * @since 6.0 + */ +abstract class AbstractWorkingSetsContribution extends CompoundContributionItem { + + private IWorkingSetManager workingSetManager; + + /** + * Initializes me without an identifier. + */ + public AbstractWorkingSetsContribution() { + super(); + } + + /** + * Initializes me with my identifier. + * + * @param id + * my identifier + */ + public AbstractWorkingSetsContribution(String id) { + super(id); + } + + @Override + protected IContributionItem[] getContributionItems() { + // at most 5 recent working sets + List result = new java.util.ArrayList(5); + + int i = 0; + for (IWorkingSet recent : getWorkingsetManager().getRecentWorkingSets()) { + IWorkingSetProxy proxy = WorkingSetConfigurationManager.getDefault().getWorkingSet( + recent.getName()); + + if (proxy != null) { + IContributionItem item = createMenu(proxy, i++); + if (item != null) { + result.add(item); + } + } + } + + return result.toArray(new IContributionItem[result.size()]); + } + + private IWorkingSetManager getWorkingsetManager() { + if (workingSetManager == null) { + workingSetManager = CUIPlugin.getDefault().getWorkbench().getWorkingSetManager(); + } + + return workingSetManager; + } + + private IContributionItem createMenu(IWorkingSetProxy workingSet, int index) { + IContributionItem result = null; + IWorkingSet ws = workingSet.resolve(); + String label = NLS.bind(WorkingSetMessages.WorkingSetMenus_enumPattern, index + 1, ws.getLabel()); + Collection configs = workingSet.getConfigurations(); + + if (!configs.isEmpty()) { + MenuManager submenu = new MenuManager(label, ws.getName()); + result = submenu; + + submenu.add(createContribution(workingSet)); + } + + return result; + } + + /** + * Creates a contribution item for a working set. + * + * @param workingSet + * a working set + * @return the contribution + */ + protected abstract IContributionItem createContribution(IWorkingSetProxy workingSet); +} Index: src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetConfiguration.java =================================================================== RCS file: src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetConfiguration.java diff -N src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetConfiguration.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/cdt/internal/ui/workingsets/IWorkingSetConfiguration.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,181 @@ +/******************************************************************************* + * 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.IResource; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; + +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; + +/** + *

+ * The protocol for working set configurations. A working set configuration specifies, at a minimum, a + * {@linkplain ICConfigurationDescription build configuration} for each C/C++ project in the working set. + * {@linkplain #activate() activating} the configuration applies these build configurations to the respective + * projects as their active build configurations. + *

+ *

+ * Implementations of this interface may choose to manage more configuration settings than are captured by the + * active build configuration. They are, then, responsible for persistence, editing, and application of these + * settings. + *

+ *

+ * A working set configuration is considered to be {@linkplain #isActive() active} if all of the projects in + * the working set are configured to build according to the configuration specified by the working set + * configuration. It is an implementation detail (i.e., unspecified) what it means for a working set that has + * recorded settings for projects that are not currently {@linkplain IResource#isAccessible() accessible} in + * the workspace. However, for projects that are accessible and are included in the working set, but for which + * the working set configuration has no settings, such projects are implicitly in the working set + * configuration and it specifies their current configuration settings. Thus, in the extreme case, a + * working-set configuration that includes none of the projects that currently are members of the working set, + * is active. + *

+ * + * @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 IWorkingSetConfiguration extends IWorkingSetConfigurationElement { + /** + * Obtains the working set element that contains me. + * + * @return my working set + */ + IWorkingSetProxy getWorkingSet(); + + /** + * Queries my name. + * + * @return my name + */ + String getName(); + + /** + * Obtains the project configuration element for the specified project. + * + * @param projectName + * a project name + * + * @return that project's configuration element + * + * @throws IllegalArgumentException + * if the specified project is not a member of my working set + * + * @see #getProjectConfigurations() + */ + IWorkingSetProjectConfiguration getProjectConfiguration(String projectName); + + /** + * Obtains the configuration elements for all of the projects in my working set. These include any + * projects that were not in my working set when I was last updated, and does not include any projects + * that were in my working set when I was last updated but that no longer are. + * + * @return my project configuration elements + */ + Collection getProjectConfigurations(); + + /** + * Queries whether I am currently active in the workspace. I am active if and only if for every the + * projects in my working set, its active configuration is the one that I specify for it. As a special + * case, the configurations of an empty working set can never be active. + * + * @return whether I am currently active in the workspace + * + * @see #activate() + */ + boolean isActive(); + + /** + * Updates the workspace to set, for each project in my working set, the active configuration that I + * specify for it. This method has no effect if I am already active. + * + * @see #isActive() + */ + void activate(); + + /** + * Builds my project configurations in the workspace. + * + * @param monitor + * for reporting progress of the working-set build + * @return the aggregate status of the individual + * {@linkplain IWorkingSetProjectConfiguration#build(IProgressMonitor) project builds} + */ + IStatus build(IProgressMonitor monitor); + + /** + * Creates a snapshot (also known as a "working copy") of myself, providing a mutable view suitable + * for editing. + * + * @param workingSet + * my parent working set 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(IWorkingSetProxy.ISnapshot workingSet, WorkspaceSnapshot workspace); + + // + // Nested types + // + + /** + * The snapshot ("working copy") view of a working set configuration. It defines additional API for the + * manipulation of working set configurations. + * + * @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 IWorkingSetConfiguration, IWorkingSetConfigurationElement.ISnapshot { + IWorkingSetProxy.ISnapshot getWorkingSet(); + + /** + *

+ * Queries whether I am read-only. Read-only working set configurations are used for the special case + * of showing what is the active configuration of the projects in a working set when none of the named + * working set configurations is active. Thus, a working set that has no user-defined named + * configurations does, at least, have its read-only active configuration. + *

+ *

+ * A working set only ever has at most one read-only configuration, though it may have multiple active + * configurations if some of its configurations are equivalent. + *

+ * + * @return whether I am the read-only active configuration of my working set + */ + boolean isReadOnly(); + + /** + * Sets my name, which must be unique amongst the configurations in my working set. + * + * @param name + * my new, unique name + * + * @throws IllegalArgumentException + * if the new name is null or empty, or if it is already used by another + * configuration of the same working set + */ + void setName(String name); + } +} Index: src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfigurationsPage.java =================================================================== RCS file: src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfigurationsPage.java diff -N src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfigurationsPage.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfigurationsPage.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,96 @@ +/******************************************************************************* + * 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.layout.GridLayoutFactory; +import org.eclipse.jface.viewers.IFilter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.ui.IWorkingSet; +import org.eclipse.ui.dialogs.PropertyPage; + +/** + * Property page for the configurations of a working set. + * + * @author Christian W. Damus (cdamus) + * + * @since 6.0 + */ +public class WorkingSetConfigurationsPage extends PropertyPage { + + private WorkingSetConfigurationBlock block; + + /** + * Initializes me. + */ + public WorkingSetConfigurationsPage() { + super(); + + noDefaultAndApplyButton(); + } + + @Override + protected Control createContents(Composite parent) { + Composite result = new Composite(parent, SWT.NONE); + GridLayoutFactory.fillDefaults().margins(5, 5).applyTo(result); + + final WorkspaceSnapshot workspace = WorkingSetConfigurationManager.getDefault() + .createWorkspaceSnapshot(); + final IWorkingSetProxy.ISnapshot workingSet = getWorkingSet(workspace); + + if (workingSet == null) { + new Label(result, SWT.NONE).setText(WorkingSetMessages.WSetConfigsPage_noProjects); + } else { + block = new WorkingSetConfigurationBlock(workspace, workingSet); + block.setWorkingSetFilter(new IFilter() { + + public boolean select(Object toTest) { + return toTest == workingSet; + } + }); + + Control contents = block.createContents(result); + contents.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + } + + return result; + } + + private IWorkingSetProxy.ISnapshot getWorkingSet(WorkspaceSnapshot workspace) { + IWorkingSetProxy.ISnapshot result = null; + IWorkingSet realWorkingSet = (IWorkingSet) getElement().getAdapter(IWorkingSet.class); + + if (realWorkingSet != null) { + result = workspace.getWorkingSet(realWorkingSet.getName()); + if ((result != null) && result.resolveProjects().isEmpty()) { + // no C/C++ projects to configure + result = null; + } + } + + return result; + } + + @Override + public boolean performOk() { + if (!block.build()) { + // user cancelled: don't save, and don't close the property page + return false; + } + + block.save(); + return true; + } +} Index: src/org/eclipse/cdt/internal/ui/workingsets/ProjectConfigurationController.java =================================================================== RCS file: src/org/eclipse/cdt/internal/ui/workingsets/ProjectConfigurationController.java diff -N src/org/eclipse/cdt/internal/ui/workingsets/ProjectConfigurationController.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/cdt/internal/ui/workingsets/ProjectConfigurationController.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,220 @@ +/******************************************************************************* + * 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.Set; + +import org.eclipse.jface.resource.FontDescriptor; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.resource.LocalResourceManager; +import org.eclipse.jface.resource.ResourceManager; +import org.eclipse.jface.viewers.IFontProvider; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Image; +import org.eclipse.ui.model.WorkbenchLabelProvider; + +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; + +import org.eclipse.cdt.internal.ui.CPluginImages; +import org.eclipse.cdt.internal.ui.workingsets.IWorkingSetProjectConfiguration.ISnapshot; + +/** + * Default implementation of the working set project configuration controller protocol. + * + * @author Christian W. Damus (cdamus) + * + * @since 6.0 + * + */ +public class ProjectConfigurationController implements IWorkingSetProjectConfigurationController { + + private IWorkingSetProjectConfiguration.ISnapshot config; + + /** + * Initializes me with my project configuration. + * + * @param config + * my project configuration + */ + public ProjectConfigurationController(IWorkingSetProjectConfiguration.ISnapshot config) { + this.config = config; + } + + public ISnapshot getProjectConfiguration() { + return config; + } + + public void checkStateChanged(Object element, boolean checked, IControllerContext context) { + if (!context.isReadOnly() && (element instanceof ICConfigurationDescription)) { + + ICConfigurationDescription newSel = (ICConfigurationDescription) element; + ICConfigurationDescription oldSel = getProjectConfiguration().resolveSelectedConfiguration(); + + boolean oldActive = getProjectConfiguration().isActive(); + + if (checked) { + if (newSel != oldSel) { + getProjectConfiguration().setSelectedConfigurationID(newSel.getId()); + + if (oldSel != null) { + context.setChecked(oldSel, false); + } + } + } else if (newSel == oldSel) { + // cannot just uncheck the current selection + context.setChecked(oldSel, true); + } + + boolean newActive = getProjectConfiguration().isActive(); + if (oldActive != newActive) { + context.activationStateChanged(getProjectConfiguration()); + } + } else { + // cannot change the check-state of these nodes + context.setChecked(element, !checked); + } + } + + public void updateCheckState(IControllerContext context) { + ICConfigurationDescription sel = getProjectConfiguration().resolveSelectedConfiguration(); + + if (sel != null) { + context.setChecked(sel, true); + } + + // gray the project node + context.setGrayed(getProjectConfiguration(), true); + } + + public ITreeContentProvider getContentProvider() { + return new ContentProvider(getProjectConfiguration()); + } + + public ILabelProvider getLabelProvider(Viewer viewer) { + return new LabelProvider(viewer, getProjectConfiguration()); + } + + // + // Nested classes + // + + private static class ContentProvider implements ITreeContentProvider { + private static final Object[] NO_OBJECTS = new Object[0]; + + private IWorkingSetProjectConfiguration project; + private Set configs; + + ContentProvider(IWorkingSetProjectConfiguration project) { + this.project = project; + this.configs = new java.util.HashSet(project.resolveConfigurations()); + } + + public Object[] getChildren(Object parentElement) { + return (parentElement == project) ? project.resolveConfigurations().toArray() : NO_OBJECTS; + } + + public Object getParent(Object element) { + return (element == project) ? null : configs.contains(element) ? project : null; + } + + public boolean hasChildren(Object element) { + return element == project; + } + + public Object[] getElements(Object inputElement) { + return new Object[] { project }; + } + + public void dispose() { + // nothing to dispose + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + // nothing to do + } + + } + + private static class LabelProvider extends org.eclipse.jface.viewers.LabelProvider implements + IFontProvider { + + private IWorkingSetProjectConfiguration.ISnapshot projectConfig; + private WorkbenchLabelProvider wbLabels = new WorkbenchLabelProvider(); + private Image configImage = CPluginImages.get(CPluginImages.IMG_OBJS_CONFIG); + + private Font defaultFont; + private ResourceManager fonts = new LocalResourceManager(JFaceResources.getResources()); + + LabelProvider(Viewer viewer, IWorkingSetProjectConfiguration.ISnapshot projectConfig) { + this.projectConfig = projectConfig; + this.defaultFont = viewer.getControl().getFont(); + } + + @Override + public String getText(Object element) { + if (element instanceof ICConfigurationDescription) { + ICConfigurationDescription config = (ICConfigurationDescription) element; + + return isActiveInWorkspace(config) ? NLS.bind( + WorkingSetMessages.ProjConfigController_activeConfig, config.getName()) : config + .getName(); + } else if (element instanceof IWorkingSetProjectConfiguration) { + return wbLabels.getText(((IWorkingSetProjectConfiguration) element).resolveProject()); + } + + return wbLabels.getText(element); + } + + @Override + public Image getImage(Object element) { + if (element instanceof ICConfigurationDescription) { + return configImage; + } else if (element instanceof IWorkingSetProjectConfiguration) { + return wbLabels.getImage(((IWorkingSetProjectConfiguration) element).resolveProject()); + } + + return wbLabels.getImage(element); + } + + public Font getFont(Object element) { + if (element instanceof ICConfigurationDescription) { + ICConfigurationDescription config = (ICConfigurationDescription) element; + + if (isActiveInWorkspace(config)) { + FontDescriptor desc = FontDescriptor.createFrom(defaultFont); + return (Font) fonts.get(desc.withStyle(SWT.BOLD)); + } + } + + return wbLabels.getFont(element); + } + + private boolean isActiveInWorkspace(ICConfigurationDescription config) { + WorkspaceSnapshot workspace = projectConfig.getWorkspaceSnapshot(); + + return workspace.getState(projectConfig.resolveProject()).isActive(config.getId()); + } + + @Override + public void dispose() { + wbLabels.dispose(); + fonts.dispose(); + super.dispose(); + } + } + +} \ No newline at end of file Index: src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfigurationBlock.java =================================================================== RCS file: src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfigurationBlock.java diff -N src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfigurationBlock.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetConfigurationBlock.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,450 @@ +/******************************************************************************* + * 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.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.jface.resource.FontDescriptor; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.resource.LocalResourceManager; +import org.eclipse.jface.resource.ResourceManager; +import org.eclipse.jface.viewers.CheckboxTreeViewer; +import org.eclipse.jface.viewers.IFilter; +import org.eclipse.jface.viewers.IFontProvider; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerComparator; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.accessibility.AccessibleAdapter; +import org.eclipse.swt.accessibility.AccessibleEvent; +import org.eclipse.swt.custom.SashForm; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.ui.model.WorkbenchLabelProvider; + +import org.eclipse.cdt.internal.ui.CPluginImages; +import org.eclipse.cdt.internal.ui.dialogs.OptionalMessageDialog; + +/** + * A block of UI controls for management of working set configurations. These collect the selection of project + * configurations for the member projects of the working sets into named presets. + * + * @author Christian W. Damus (cdamus) + * + * @since 6.0 + */ +public class WorkingSetConfigurationBlock { + + private static final String BUILD_PROMPT_DIALOG_ID = "workingsets.build.prompt"; //$NON-NLS-1$ + private static final int BUILD_PROMPT_DIALOG_NO = 0; + private static final int BUILD_PROMPT_DIALOG_CANCEL = 1; + private static final int BUILD_PROMPT_DIALOG_YES = 2; + + private WorkspaceSnapshot workspace; + private WorkingSetConfigsController controller; + + private IWorkingSetProxy.ISnapshot initialSelection; + private IFilter workingSetFilter; + + private Control contents; + + /** + * Initializes me. I take the most recently used working set as my initial selection. + * + * @param workspace + * the workspace snapshot to edit + */ + public WorkingSetConfigurationBlock(WorkspaceSnapshot workspace) { + this(workspace, null); + } + + /** + * Initializes me with my initial selection. + * + * @param workspace + * the workspace snapshot to edit + * @param initialSelection + * my initial selection + */ + public WorkingSetConfigurationBlock(WorkspaceSnapshot workspace, + IWorkingSetProxy.ISnapshot initialSelection) { + + this.workspace = workspace; + this.initialSelection = initialSelection; + } + + /** + * Queries the working set filter, if any, that restricts the display of working sets. + * + * @return my working-set filter + */ + public IFilter getWorkingSetFilter() { + return workingSetFilter; + } + + /** + * Assigns a filter to restrict the working sets that are shown. + * + * @param filter + * a working-set filter + */ + public void setWorkingSetFilter(IFilter filter) { + this.workingSetFilter = filter; + } + + /** + * Creates the contents of the working set configuration management control block. + * + * @param parent + * the parent composite in which to create my controls + * + * @return my controls + */ + public Control createContents(Composite parent) { + SashForm sashForm = new SashForm(parent, SWT.VERTICAL | SWT.SMOOTH); + + GridLayoutFactory layoutFactory = GridLayoutFactory.fillDefaults(); + createWorkingSetConfigsArea(sashForm, layoutFactory.extendedMargins(0, 0, 0, 15)); + createProjectConfigsArea(sashForm, layoutFactory.extendedMargins(0, 0, 15, 0)); + + sashForm.setWeights(new int[] { 1, 1 }); + + contents = sashForm; + + return sashForm; + } + + /** + * Creates the "working set configurations" pane in the upper part of the sash form. + * + * @param parent + * the parent composite + * @param layoutFactory + * a layout-factory to use to lay out the composite in a grid, possibly pre-configured. Its use + * is optional + * + * @return the working set configurations pane + */ + protected Composite createWorkingSetConfigsArea(Composite parent, GridLayoutFactory layoutFactory) { + Composite result = new Composite(parent, SWT.NONE); + layoutFactory.numColumns(2).applyTo(result); + + GridDataFactory layoutDataFactory = GridDataFactory.fillDefaults(); + + Label label = new Label(result, SWT.NONE); + label.setText(WorkingSetMessages.WSConfigDialog_wsTree_label); + layoutDataFactory.span(2, 1).applyTo(label); + + controller = new WorkingSetConfigsController(workspace, initialSelection); + + TreeViewer tree = new TreeViewer(result); + layoutDataFactory.span(1, 1).align(SWT.FILL, SWT.FILL).grab(true, true).hint(250, SWT.DEFAULT) + .applyTo(tree.getControl()); + + tree.setContentProvider(new WSConfigsContentProvider()); + tree.setLabelProvider(new WSConfigsLabelProvider(tree)); + controller.setTreeViewer(tree); + + tree.setComparator(new ViewerComparator() { + @Override + public int category(Object element) { + if (element instanceof IWorkingSetConfiguration.ISnapshot) { + IWorkingSetConfiguration.ISnapshot config = (IWorkingSetConfiguration.ISnapshot) element; + if (config.isReadOnly()) { + return 0; + } + } + return 1; + } + }); + + tree.getTree().getAccessible().addAccessibleListener(new AccessibleAdapter() { + @Override + public void getName(AccessibleEvent e) { + e.result = WorkingSetMessages.WSConfigDialog_wsTree_accessible_name; + } + }); + + Composite buttons = new Composite(result, SWT.NONE); + layoutDataFactory.grab(false, false).hint(SWT.DEFAULT, SWT.DEFAULT).applyTo(buttons); + layoutFactory.numColumns(1).extendedMargins(0, 0, 0, 0).applyTo(buttons); + + Button button = new Button(buttons, SWT.PUSH); + layoutDataFactory.align(SWT.FILL, SWT.BEGINNING).applyTo(button); + button.setText(WorkingSetMessages.WSConfigDialog_add_label); + controller.setAddButton(button); + + button = new Button(buttons, SWT.PUSH); + layoutDataFactory.applyTo(button); + button.setText(WorkingSetMessages.WSConfigDialog_remove_label); + controller.setRemoveButton(button); + + button = new Button(buttons, SWT.PUSH); + layoutDataFactory.applyTo(button); + button.setText(WorkingSetMessages.WSConfigDialog_rename_label); + controller.setRenameButton(button); + + button = new Button(buttons, SWT.PUSH); + layoutDataFactory.applyTo(button); + button.setText(WorkingSetMessages.WSConfigDialog_activate_label); + controller.setActivateButton(button); + + button = new Button(buttons, SWT.PUSH); + layoutDataFactory.applyTo(button); + button.setText(WorkingSetMessages.WSConfigDialog_build_label); + controller.setBuildButton(button); + + return result; + } + + /** + * Creates the "project configurations" pane in the lower part of the sash form. + * + * @param parent + * the parent composite + * @param layoutFactory + * a layout-factory to use to lay out the composite in a grid, possibly pre-configured. Its use + * is optional + * + * @return the project configurations pane + */ + protected Composite createProjectConfigsArea(Composite parent, GridLayoutFactory layoutFactory) { + Composite result = new Composite(parent, SWT.NONE); + layoutFactory.numColumns(1).applyTo(result); + + GridDataFactory layoutDataFactory = GridDataFactory.fillDefaults(); + + Label label = new Label(result, SWT.NONE); + label.setText(WorkingSetMessages.WSConfigDialog_projTree_label); + layoutDataFactory.applyTo(label); + + ProjectConfigsController projectsController = new ProjectConfigsController(); + CheckboxTreeViewer tree = new CheckboxTreeViewer(result); + layoutDataFactory.span(1, 1).align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(tree.getControl()); + + controller.setProjectConfigsController(projectsController); + projectsController.setWorkingSetConfigurationsController(controller); + + projectsController.setTreeViewer(tree); + + tree.setComparator(new ViewerComparator()); + + tree.getTree().getAccessible().addAccessibleListener(new AccessibleAdapter() { + @Override + public void getName(AccessibleEvent e) { + e.result = WorkingSetMessages.WSConfigDialog_projTree_accessible_name; + } + }); + + return result; + } + + /** + * Saves the working set configurations to storage. + */ + public void save() { + workspace.save(); + } + + /** + * Builds the projects that were reconfigured by the dialog, if any. The user is prompted (if prompting is + * not disabled via the preference) before building. The user has the options to build, not build, or + * cancel. The result indicates cancellation. + * + * @return true if the user opted to save changes and exit the dialog (with or without + * build); false if the user cancelled and the dialog should remain open and unsaved + */ + public boolean build() { + boolean result = true; + Collection projects = workspace.getProjectsToBuild(); + + if (!projects.isEmpty()) { + int defaultButton = OptionalMessageDialog.getDialogDetail(BUILD_PROMPT_DIALOG_ID); + if (defaultButton == OptionalMessageDialog.NO_DETAIL) { + defaultButton = BUILD_PROMPT_DIALOG_YES; // yes button is the default-default + } + + int button = OptionalMessageDialog.open(BUILD_PROMPT_DIALOG_ID, contents.getShell(), + WorkingSetMessages.WSConfigDialog_buildPrompt_title, null, + WorkingSetMessages.WSConfigDialog_buildPrompt_message, MessageDialog.QUESTION, + new String[] { IDialogConstants.NO_LABEL, IDialogConstants.CANCEL_LABEL, + IDialogConstants.YES_LABEL }, defaultButton); + + if (button == OptionalMessageDialog.NOT_SHOWN) { + // handle the case where the dialog was suppressed. Get the current default + button = defaultButton; + } else if (button != BUILD_PROMPT_DIALOG_CANCEL) { + // store non-cancel selection as the new default answer + OptionalMessageDialog.setDialogDetail(BUILD_PROMPT_DIALOG_ID, button); + } + + switch (button) { + case BUILD_PROMPT_DIALOG_YES: + // do the build + new BuildJob(projects).schedule(); + break; + case BUILD_PROMPT_DIALOG_NO: + // just don't build + break; + default: // BUILD_PROMPT_DIALOG_CANCEL + result = false; + break; + } + } + + return result; + } + + // + // Nested classes + // + + /** + * Simple content provider for the working set configurations tree. + * + * @author Christian W. Damus (cdamus) + */ + private class WSConfigsContentProvider implements ITreeContentProvider { + private Collection workingSets; + + public Object[] getChildren(Object parentElement) { + if (parentElement == workingSets) { + Collection filtered = filterWorkingSets(workingSets); + return filtered.toArray(); + } else if (parentElement instanceof IWorkingSetProxy) { + return ((IWorkingSetProxy) parentElement).getConfigurations().toArray(); + } else { + return new Object[0]; + } + } + + private Collection filterWorkingSets(Collection workingSets) { + if (workingSetFilter == null) { + return workingSets; + } + + Collection result = new java.util.ArrayList(); + + for (IWorkingSetProxy next : workingSets) { + if (workingSetFilter.select(next)) { + result.add(next); + } + } + + return result; + } + + public Object getParent(Object element) { + return (element instanceof IWorkingSetConfiguration) ? ((IWorkingSetConfiguration) element) + .getWorkingSet() : null; + } + + public boolean hasChildren(Object element) { + return (element != null) && !(element instanceof IWorkingSetConfiguration); + } + + public Object[] getElements(Object inputElement) { + return getChildren(inputElement); + } + + public void dispose() { + // nothing to dispose + } + + @SuppressWarnings("unchecked") + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + workingSets = (Collection) newInput; + } + + } + + /** + * Label provider for working sets and their configurations. The active configuration is highlighted in + * bold and affixed with an "(active)" decoration. The special read-only configuration is further + * differentiated with an italic font. + * + * @author Christian W. Damus (cdamus) + */ + private class WSConfigsLabelProvider extends LabelProvider implements IFontProvider { + private WorkbenchLabelProvider wbLabels = new WorkbenchLabelProvider(); + private Image configImage = CPluginImages.get(CPluginImages.IMG_OBJS_CONFIG); + private Font defaultFont; + private ResourceManager fonts = new LocalResourceManager(JFaceResources.getResources()); + + WSConfigsLabelProvider(Viewer viewer) { + defaultFont = viewer.getControl().getFont(); + } + + @Override + public String getText(Object element) { + if (element instanceof IWorkingSetConfiguration) { + IWorkingSetConfiguration config = (IWorkingSetConfiguration) element; + + if (config.isActive()) { + return WorkingSetConfiguration.isReadOnly(config) + ? WorkingSetMessages.WSConfigDialog_implicit_config : NLS.bind( + WorkingSetMessages.WSConfigDialog_active_config, config.getName()); + } + return config.getName(); + } else if (element instanceof IWorkingSetProxy) { + return ((IWorkingSetProxy) element).resolve().getLabel(); + } + + return wbLabels.getText(element); + } + + @Override + public Image getImage(Object element) { + if (element instanceof IWorkingSetConfiguration) { + return configImage; + } else if (element instanceof IWorkingSetProxy) { + return wbLabels.getImage(((IWorkingSetProxy) element).resolve()); + } + + return wbLabels.getImage(element); + } + + @Override + public void dispose() { + wbLabels.dispose(); + fonts.dispose(); + super.dispose(); + } + + public Font getFont(Object element) { + if (element instanceof IWorkingSetConfiguration) { + IWorkingSetConfiguration config = (IWorkingSetConfiguration) element; + if (config.isActive()) { + FontDescriptor desc = FontDescriptor.createFrom(defaultFont); + + desc = WorkingSetConfiguration.isReadOnly(config) ? desc.withStyle(SWT.BOLD | SWT.ITALIC) + : desc.withStyle(SWT.BOLD); + return (Font) fonts.get(desc); + } + } + + return wbLabels.getFont(element); + } + } +} Index: src/org/eclipse/cdt/internal/ui/workingsets/ProjectConfigsController.java =================================================================== RCS file: src/org/eclipse/cdt/internal/ui/workingsets/ProjectConfigsController.java diff -N src/org/eclipse/cdt/internal/ui/workingsets/ProjectConfigsController.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/cdt/internal/ui/workingsets/ProjectConfigsController.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,386 @@ +/******************************************************************************* + * 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.Map; + +import org.eclipse.jface.viewers.CheckStateChangedEvent; +import org.eclipse.jface.viewers.CheckboxTreeViewer; +import org.eclipse.jface.viewers.ICheckStateListener; +import org.eclipse.jface.viewers.IColorProvider; +import org.eclipse.jface.viewers.IFontProvider; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Image; + +/** + * View controller for the project configurations pane of the working set configurations dialog. It takes care + * of coordinating the user gestures in that pane with the working-set configuration model and vice-versa. + * + * @author Christian W. Damus (cdamus) + * + * @since 6.0 + * + */ +class ProjectConfigsController implements ICheckStateListener, DisposeListener { + private CheckboxTreeViewer tree; + + private IWorkingSetConfiguration.ISnapshot workingSet; + private WorkingSetConfigsController workingSetController; + + private ControllerContext controllerContext; + + private ILabelProvider labelProvider = new DelegatingLabelProvider(); + private ITreeContentProvider contentProvider = new DelegatingContentProvider(); + + /** + * Initializes me. + */ + ProjectConfigsController() { + super(); + } + + /** + * Assigns the tree viewer that I control. + * + * @param tree + * my tree viewer + */ + void setTreeViewer(CheckboxTreeViewer tree) { + if (this.tree != null) { + this.tree.getTree().removeDisposeListener(this); + this.tree.removeCheckStateListener(this); + this.tree.setLabelProvider(null); + this.tree.setContentProvider(null); + } + + this.tree = tree; + + if (this.tree != null) { + this.tree.setUseHashlookup(true); + this.tree.setContentProvider(contentProvider); + this.tree.setLabelProvider(labelProvider); + this.tree.addCheckStateListener(this); + this.tree.getTree().addDisposeListener(this); + } + } + + /** + * Injects the current selection of a working set from the Working Set Configurations pane. This changes + * the project configurations that I show in my own tree. + * + * @param config + * the new working set configuration selection. May be null if there is no + * selection + */ + void setWorkingSetConfiguration(IWorkingSetConfiguration.ISnapshot config) { + if ((tree != null) && (config != workingSet)) { + this.workingSet = config; + + tree.setSelection(new StructuredSelection()); + + if (config != null) { + controllerContext = new ControllerContext(tree); + tree.setInput(config); + tree.getTree().setEnabled(true); + updateCheckState(config); + tree.expandToLevel(2); + } else { + tree.getTree().setEnabled(false); + tree.setInput(config); + controllerContext.dispose(); + controllerContext = null; + } + } + } + + /** + * Queries the current working set configuration that I show in my tree. + * + * @return the working set configuration, or null if none + */ + IWorkingSetConfiguration.ISnapshot getWorkingSetConfiguration() { + return workingSet; + } + + public void checkStateChanged(CheckStateChangedEvent event) { + Object element = event.getElement(); + IWorkingSetProjectConfigurationController controller = controllerContext + .controllerForElement(element); + + if (controller != null) { + controller.checkStateChanged(element, event.getChecked(), controllerContext); + + } else { + // controller unknown? Cannot change the check-state + tree.setChecked(element, !event.getChecked()); + } + } + + public void widgetDisposed(DisposeEvent e) { + dispose(); + } + + /** + * Computes the initial check-box settings for my tree according to the current state of the specified + * working set configuration. + * + * @param config + * a working set configuration that I am now showing + */ + private void updateCheckState(IWorkingSetConfiguration.ISnapshot config) { + for (IWorkingSetProjectConfiguration project : config.getProjectConfigurations()) { + IWorkingSetProjectConfigurationController controller = controllerContext + .controllerForElement(project); + + if (controller != null) { + controller.updateCheckState(controllerContext); + } + } + } + + void update() { + if (tree != null) { + tree.refresh(true); + } + } + + /** + * Connects me to the controller of the working set configurations pane. + * + * @param controller + * the working-set configs controller + */ + void setWorkingSetConfigurationsController(WorkingSetConfigsController controller) { + workingSetController = controller; + } + + void dispose() { + if (controllerContext != null) { + controllerContext.dispose(); + controllerContext = null; + } + } + + // + // Nested classes + // + + private class ControllerContext implements IWorkingSetProjectConfigurationController.IControllerContext { + + private Map elementToControllerMap; + + private Map contentProviders; + private Map labelProviders; + + ControllerContext(Viewer viewer) { + elementToControllerMap = new java.util.IdentityHashMap(); + contentProviders = new java.util.HashMap(); + labelProviders = new java.util.HashMap(); + + for (IWorkingSetProjectConfiguration next : getWorkingSetConfiguration() + .getProjectConfigurations()) { + + IWorkingSetProjectConfiguration.ISnapshot project = (IWorkingSetProjectConfiguration.ISnapshot) next; + + IWorkingSetProjectConfigurationController controller = IWorkingSetProjectConfigurationFactory.Registry.INSTANCE + .getFactory(project.resolveProject()).createProjectConfigurationController(project); + + if (controller == null) { + // can only supply the default behaviour, then + controller = new ProjectConfigurationController(project); + } + + elementToControllerMap.put(project, controller); + contentProviders.put(controller, controller.getContentProvider()); + labelProviders.put(controller, controller.getLabelProvider(viewer)); + + discoverElements(controller, project, contentProviders.get(controller)); + } + } + + private void discoverElements(IWorkingSetProjectConfigurationController controller, Object element, + ITreeContentProvider provider) { + Object[] children = provider.getChildren(element); + + for (Object next : children) { + elementToControllerMap.put(next, controller); + discoverElements(controller, next, provider); + } + } + + IWorkingSetProjectConfigurationController controllerForElement(Object element) { + return elementToControllerMap.get(element); + } + + ITreeContentProvider contentProviderForElement(Object element) { + return contentProviders.get(elementToControllerMap.get(element)); + } + + ILabelProvider labelProviderForElement(Object element) { + return labelProviders.get(elementToControllerMap.get(element)); + } + + public void activationStateChanged(IWorkingSetProjectConfiguration projectConfiguration) { + workingSetController.projectSelectionsChanged(projectConfiguration); + } + + public boolean isReadOnly() { + return getWorkingSetConfiguration().isReadOnly(); + } + + public void setChecked(Object element, boolean checked) { + tree.setChecked(element, checked); + } + + public void setGrayed(Object element, boolean grayed) { + tree.setGrayChecked(element, grayed); + } + + public void update(Object element) { + if ((element instanceof IWorkingSetConfiguration) || (element instanceof IWorkingSetProxy)) { + // TODO: Talk to the WS controller + } else if (controllerForElement(element) != null) { + // only need to update if we have actually accessed this + // element, yet, in order to display it + tree.update(element, null); + } + } + + public void dispose() { + elementToControllerMap = null; + + if (contentProviders != null) { + for (ITreeContentProvider next : contentProviders.values()) { + next.dispose(); + } + contentProviders = null; + } + + if (labelProviders != null) { + for (ILabelProvider next : labelProviders.values()) { + next.dispose(); + } + labelProviders = null; + } + } + } + + private class DelegatingLabelProvider extends LabelProvider implements IFontProvider, IColorProvider { + private final NullLabelProvider defaultLabels = new NullLabelProvider(); + + @Override + public String getText(Object element) { + return delegateFor(element, ILabelProvider.class).getText(element); + } + + @Override + public Image getImage(Object element) { + return delegateFor(element, ILabelProvider.class).getImage(element); + } + + public Font getFont(Object element) { + return delegateFor(element, IFontProvider.class).getFont(element); + } + + public Color getBackground(Object element) { + return delegateFor(element, IColorProvider.class).getBackground(element); + } + + public Color getForeground(Object element) { + return delegateFor(element, IColorProvider.class).getForeground(element); + } + + @SuppressWarnings("unchecked") + private T delegateFor(Object element, Class expectedType) { + if (controllerContext == null) { + return (T) defaultLabels; + } else { + T result = (T) controllerContext.labelProviderForElement(element); + + if (!expectedType.isInstance(result)) { + return (T) defaultLabels; + } + + return result; + } + } + } + + private class DelegatingContentProvider implements ITreeContentProvider { + private final Object[] NO_OBJECTS = new Object[0]; + + public Object[] getChildren(Object parentElement) { + ITreeContentProvider delegate = delegateFor(parentElement); + + return (delegate != null) ? delegate.getChildren(parentElement) : NO_OBJECTS; + } + + public Object getParent(Object element) { + ITreeContentProvider delegate = delegateFor(element); + + return (delegate != null) ? delegate.getParent(element) : null; + } + + public boolean hasChildren(Object element) { + ITreeContentProvider delegate = delegateFor(element); + + return (delegate != null) && delegate.hasChildren(element); + } + + public Object[] getElements(Object inputElement) { + return getWorkingSetConfiguration().getProjectConfigurations().toArray(); + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + // nothing to do + } + + public void dispose() { + // nothing of my own to dispose + } + + private ITreeContentProvider delegateFor(Object element) { + return (controllerContext == null) ? null : controllerContext.contentProviderForElement(element); + } + } + + /** + * A useful empty implementation of the extended label-provider protocol. + * + * @author Christian W. Damus (cdamus) + * + * @since 6.0 + */ + private static class NullLabelProvider extends LabelProvider implements IFontProvider, IColorProvider { + + public Font getFont(Object element) { + return null; + } + + public Color getBackground(Object element) { + return null; + } + + public Color getForeground(Object element) { + return null; + } + + } +} \ No newline at end of file Index: src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetProjectConfiguration.java =================================================================== RCS file: src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetProjectConfiguration.java diff -N src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetProjectConfiguration.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/cdt/internal/ui/workingsets/WorkingSetProjectConfiguration.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,293 @@ +/******************************************************************************* + * 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 static org.eclipse.cdt.internal.ui.workingsets.WorkingSetConfigurationManager.ATTR_CONFIG; +import static org.eclipse.cdt.internal.ui.workingsets.WorkingSetConfigurationManager.ATTR_NAME; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +import org.eclipse.core.resources.IProject; +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.IMemento; + +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; + +/** + * Default implementation of the {@link IWorkingSetProjectConfiguration} interface. Clients may extend this + * class to implement additional project configuration settings. + * + * @author Christian W. Damus (cdamus) + * + * @since 6.0 + * + */ +public class WorkingSetProjectConfiguration implements IWorkingSetProjectConfiguration { + private final IWorkingSetConfiguration workingSetConfig; + private String projectName; + private String selectedConfiguration; + + /** + * Initializes me with my parent working set configuration. + * + * @param parent + * my parent working set configuration + */ + protected WorkingSetProjectConfiguration(IWorkingSetConfiguration parent) { + this.workingSetConfig = parent; + } + + public IWorkingSetConfiguration getWorkingSetConfiguration() { + return workingSetConfig; + } + + public String getProjectName() { + return projectName; + } + + /** + * Sets my project name. Note that this does not change the name of the project that I represent. + * Rather, it changes which project I represent. + * + * @param projectName + * my new project name + */ + protected void setProjectName(String projectName) { + this.projectName = projectName; + } + + public IProject resolveProject() { + IProject result = ResourcesPlugin.getWorkspace().getRoot().getProject(getProjectName()); + + if ((result != null) && !result.isAccessible()) { + result = null; + } + + return result; + } + + public String getSelectedConfigurationID() { + return selectedConfiguration; + } + + public void setSelectedConfigurationID(String id) { + this.selectedConfiguration = id; + } + + public ICConfigurationDescription resolveSelectedConfiguration() { + ICConfigurationDescription result = null; + + IProject project = resolveProject(); + if (project != null) { + ICProjectDescription desc = CoreModel.getDefault().getProjectDescription(project); + + if (desc != null) { + result = desc.getConfigurationById(getSelectedConfigurationID()); + } + } + + return result; + } + + public Collection resolveConfigurations() { + ICConfigurationDescription[] result = null; + + IProject project = resolveProject(); + if (project != null) { + ICProjectDescription desc = CoreModel.getDefault().getProjectDescription(project); + + if (desc != null) { + result = desc.getConfigurations(); + } + } + + return (result == null) ? Collections. emptyList() : Arrays + .asList(result); + } + + public boolean isActive() { + ICConfigurationDescription desc = resolveSelectedConfiguration(); + + return (desc != null) && desc.isActive(); + } + + public void activate() { + ICConfigurationDescription config = resolveSelectedConfiguration(); + + if (config != null) { + ICProjectDescription desc = config.getProjectDescription(); + + if (desc.getActiveConfiguration() != config) { + try { + IProject project = desc.getProject(); + desc.setActiveConfiguration(config); + CoreModel.getDefault().setProjectDescription(project, desc); + } catch (CoreException e) { + CUIPlugin.log(e); + } + } + } + } + + public IStatus build(IProgressMonitor monitor) { + IStatus result = Status.OK_STATUS; + + ICConfigurationDescription config = resolveSelectedConfiguration(); + + if (config == null) { + result = new Status(IStatus.WARNING, CUIPlugin.PLUGIN_ID, NLS.bind( + WorkingSetMessages.WSProjConfig_noConfig, getProjectName())); + } else { + if (!isActive()) { + activate(); + result = new Status(IStatus.WARNING, CUIPlugin.PLUGIN_ID, NLS.bind( + WorkingSetMessages.WSProjConfig_activatedWarning, config.getName(), getProjectName())); + } + + monitor = SubMonitor.convert(monitor); + + try { + resolveProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, monitor); + } 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, getProjectName()), null); + } + } + } + + return result; + } + + public void saveState(IMemento memento) { + memento.putString(ATTR_NAME, getProjectName()); + + if (getSelectedConfigurationID() != null) { + memento.putString(ATTR_CONFIG, getSelectedConfigurationID()); + } + } + + public void loadState(IMemento memento) { + projectName = memento.getString(ATTR_NAME); + selectedConfiguration = memento.getString(ATTR_CONFIG); + } + + public ISnapshot createSnapshot(IWorkingSetConfiguration.ISnapshot workingSetConfig, + WorkspaceSnapshot workspace) { + + return new Snapshot(workingSetConfig, this, workspace); + } + + // + // Nested classes + // + + /** + * Default implementation of the mutable project configuration snapshot. + * + * @author Christian W. Damus (cdamus) + * + * @since 6.0 + */ + public static class Snapshot extends WorkingSetProjectConfiguration implements + IWorkingSetProjectConfiguration.ISnapshot { + + private final IProject project; + private final WorkspaceSnapshot workspace; + + /** + * Initializes me with the project that I represent and the workspace snapshot. I discover the + * currently defined configurations for my project and initially select the one that is currently + * active, or the first available if none is active (which would be odd). + * + * @param parent + * my parent working set configuration + * @param projectConfig + * the project configuration to copy + * @param workspace + * the current workspace snapshot + */ + protected Snapshot(IWorkingSetConfiguration parent, IWorkingSetProjectConfiguration projectConfig, + WorkspaceSnapshot workspace) { + + super(parent); + + this.project = projectConfig.resolveProject(); + this.workspace = workspace; + + String selected = projectConfig.getSelectedConfigurationID(); + if (selected == null) { + selected = workspace.getActiveConfigurationID(project); + } + setSelectedConfigurationID(selected); + } + + @Override + public IWorkingSetConfiguration.ISnapshot getWorkingSetConfiguration() { + return (IWorkingSetConfiguration.ISnapshot) super.getWorkingSetConfiguration(); + } + + public final WorkspaceSnapshot getWorkspaceSnapshot() { + return workspace; + } + + @Override + public final IProject resolveProject() { + return project; + } + + @Override + public final String getProjectName() { + return resolveProject().getName(); + } + + @Override + public boolean isActive() { + return workspace.isActive(this); + } + + @Override + public void activate() { + workspace.activate(resolveProject(), getSelectedConfigurationID()); + } + + @Override + public IStatus build(IProgressMonitor monitor) { + return workspace.build(resolveProject(), getSelectedConfigurationID(), monitor); + } + + @Override + public Collection 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 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); + } +}