Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 112305 Details for
Bug 229633
Better Support for Linked Resources: Need for Virtual folders and project level variable relative path resolution.
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
[patch]
CVS Patch file for the independent path feature only
independent_path.patch (text/plain), 242.87 KB, created by
Serge Beauchamp
on 2008-09-11 08:37:32 EDT
(
hide
)
Description:
CVS Patch file for the independent path feature only
Filename:
MIME Type:
Creator:
Serge Beauchamp
Created:
2008-09-11 08:37:32 EDT
Size:
242.87 KB
patch
obsolete
>### Eclipse Workspace Patch 1.0 >#P org.eclipse.cdt.ui >Index: src/org/eclipse/cdt/internal/ui/dnd/ResourceTransferDropAdapter.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.cdt/all/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/dnd/ResourceTransferDropAdapter.java,v >retrieving revision 1.5 >diff -u -r1.5 ResourceTransferDropAdapter.java >--- src/org/eclipse/cdt/internal/ui/dnd/ResourceTransferDropAdapter.java 10 Apr 2008 10:03:27 -0000 1.5 >+++ src/org/eclipse/cdt/internal/ui/dnd/ResourceTransferDropAdapter.java 11 Sep 2008 12:30:17 -0000 >@@ -8,6 +8,7 @@ > * Contributors: > * QNX Software Systems - Initial API and implementation > * Anton Leherbauer (Wind River Systems) - 151571 DND move on GTK >+ * Serge Beauchamp (Freescale Semiconductor) > *******************************************************************************/ > > package org.eclipse.cdt.internal.ui.dnd; >@@ -18,6 +19,7 @@ > import org.eclipse.core.resources.IContainer; > import org.eclipse.core.resources.IResource; > import org.eclipse.core.runtime.IAdaptable; >+import org.eclipse.jface.dialogs.MessageDialog; > import org.eclipse.jface.viewers.ISelection; > import org.eclipse.jface.viewers.IStructuredSelection; > import org.eclipse.jface.viewers.StructuredViewer; >@@ -33,6 +35,8 @@ > > import org.eclipse.cdt.core.model.ICElement; > >+import org.eclipse.cdt.internal.ui.dialogs.ImportTypeDialog; >+ > /** > * ResourceTransferDropAdapter > */ >@@ -104,6 +108,27 @@ > IResource[] sources = (IResource[])data; > if (op == DND.DROP_COPY) { > CopyFilesAndFoldersOperation operation = new CopyFilesAndFoldersOperation(getShell()); >+ boolean allSourceAreLinks = true; >+ for (int i = 0; i < sources.length; i++) { >+ if (!sources[0].isLinked()) { >+ allSourceAreLinks = false; >+ break; >+ } >+ } >+ // if all sources are links , copy them normally, >+ // don't show the dialog >+ if (!allSourceAreLinks) { >+ int mask = ImportTypeDialog.IMPORT_LINK | ImportTypeDialog.IMPORT_COPY; >+ ImportTypeDialog dialog = new ImportTypeDialog(getShell(), mask); >+ dialog.setProject(target.getProject()); >+ if (dialog.open() == MessageDialog.OK) { >+ if (dialog.getSelection() == ImportTypeDialog.IMPORT_LINK) >+ operation.setCreateLinks(true); >+ if (dialog.getVariable() != null) >+ operation.setRelativeVariable(dialog.getVariable()); >+ } else >+ return; >+ } > operation.copyResources(sources, target); > } else { > ReadOnlyStateChecker checker = new ReadOnlyStateChecker( >Index: src/org/eclipse/cdt/internal/ui/dnd/FileTransferDropAdapter.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.cdt/all/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/dnd/FileTransferDropAdapter.java,v >retrieving revision 1.3 >diff -u -r1.3 FileTransferDropAdapter.java >--- src/org/eclipse/cdt/internal/ui/dnd/FileTransferDropAdapter.java 9 Apr 2008 11:24:24 -0000 1.3 >+++ src/org/eclipse/cdt/internal/ui/dnd/FileTransferDropAdapter.java 11 Sep 2008 12:30:16 -0000 >@@ -7,15 +7,18 @@ > * > * Contributors: > * QNX Software Systems - Initial API and implementation >+ * Serge Beauchamp (Freescale Semiconductor) > *******************************************************************************/ > > package org.eclipse.cdt.internal.ui.dnd; > > import org.eclipse.cdt.core.model.ICElement; >+import org.eclipse.cdt.internal.ui.dialogs.ImportTypeDialog; > import org.eclipse.core.resources.IContainer; > import org.eclipse.core.resources.IResource; > import org.eclipse.core.resources.ResourceAttributes; > import org.eclipse.core.runtime.IAdaptable; >+import org.eclipse.jface.dialogs.MessageDialog; > import org.eclipse.jface.viewers.AbstractTreeViewer; > import org.eclipse.swt.dnd.DND; > import org.eclipse.swt.dnd.DropTargetEvent; >@@ -90,7 +93,32 @@ > Display.getCurrent().asyncExec(new Runnable() { > public void run() { > getShell().forceActive(); >- new CopyFilesAndFoldersOperation(getShell()).copyFiles((String[]) data, target); >+ >+ String files[] = (String[]) data; >+ >+ CopyFilesAndFoldersOperation op = new CopyFilesAndFoldersOperation(getShell()); >+ // if the target is a group and all sources are files, then >+ // automatically create links >+ int type; >+ int mask = ImportTypeDialog.IMPORT_LINK | ImportTypeDialog.IMPORT_COPY; >+ ImportTypeDialog dialog = new ImportTypeDialog(getShell(), mask); >+ dialog.setProject(target.getProject()); >+ if (dialog.open() == MessageDialog.OK) >+ type = dialog.getSelection(); >+ else >+ type = ImportTypeDialog.IMPORT_NONE; >+ switch (type) { >+ case ImportTypeDialog.IMPORT_COPY: >+ op.copyFiles(files, target); >+ break; >+ case ImportTypeDialog.IMPORT_LINK: >+ if (dialog.getVariable() != null) >+ op.setRelativeVariable(dialog.getVariable()); >+ op.linkFiles(files, target); >+ break; >+ case ImportTypeDialog.IMPORT_NONE: >+ break; >+ } > // Import always performs a copy. > event.detail= DND.DROP_COPY; > } >Index: src/org/eclipse/cdt/internal/ui/dialogs/ImportTypeDialog.java >=================================================================== >RCS file: src/org/eclipse/cdt/internal/ui/dialogs/ImportTypeDialog.java >diff -N src/org/eclipse/cdt/internal/ui/dialogs/ImportTypeDialog.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/cdt/internal/ui/dialogs/ImportTypeDialog.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,262 @@ >+package org.eclipse.cdt.internal.ui.dialogs; >+ >+ >+import org.eclipse.cdt.ui.PreferenceConstants; >+import org.eclipse.core.resources.IPathVariableManager; >+import org.eclipse.core.resources.IProject; >+import org.eclipse.core.resources.ResourcesPlugin; >+import org.eclipse.jface.dialogs.IDialogConstants; >+import org.eclipse.jface.dialogs.MessageDialog; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.events.SelectionEvent; >+import org.eclipse.swt.events.SelectionListener; >+import org.eclipse.swt.layout.GridData; >+import org.eclipse.swt.layout.GridLayout; >+import org.eclipse.swt.widgets.Button; >+import org.eclipse.swt.widgets.Combo; >+import org.eclipse.swt.widgets.Composite; >+import org.eclipse.swt.widgets.Control; >+import org.eclipse.swt.widgets.Label; >+import org.eclipse.swt.widgets.Shell; >+import org.eclipse.ui.ide.dialogs.PathVariableEditDialog; >+ >+public class ImportTypeDialog extends MessageDialog implements >+ SelectionListener { >+ >+ private static final String PREF_IMPORT_FILES_AND_FOLDERS_TYPE = "import_files_and_folders_type"; //$NON-NLS-1$ >+ private static final String PREF_IMPORT_FILES_AND_FOLDERS_VARIABLE = "import_files_and_folders_variable"; //$NON-NLS-1$ >+ public static final String ABSOLUTE_PATH = "default"; //$NON-NLS-1$ >+ >+ public ImportTypeDialog(Shell parentShell, int operationMask) { >+ super( >+ parentShell, >+ "File and Folder Import", >+ null, >+ "Select how files and folders should be imported in the project:", >+ MessageDialog.QUESTION, new String[] { "OK", "Cancel" }, 0); >+ >+ this.operationMask = operationMask; >+ currentSelection = PreferenceConstants.getPreferenceStore().getInt(PREF_IMPORT_FILES_AND_FOLDERS_TYPE); >+ currentSelection = currentSelection & operationMask; >+ if (currentSelection == 0) { >+ if ((operationMask & IMPORT_COPY) != 0) >+ currentSelection = IMPORT_COPY; >+ else >+ currentSelection = IMPORT_MOVE; >+ } >+ } >+ >+ public String getVariable() { >+ if (variable.equals(ABSOLUTE_PATH)) >+ return null; >+ return variable; >+ } >+ >+ public final static int IMPORT_COPY = 1; >+ public final static int IMPORT_GROUPS_AND_LINKS = 2; >+ public final static int IMPORT_LINK = 4; >+ public final static int IMPORT_MOVE = 8; >+ public final static int IMPORT_NONE = 0; >+ >+ public int getSelection() { >+ return currentSelection; >+ } >+ >+ int operationMask; >+ int currentSelection; >+ Button copyButton = null; >+ Button shadowCopyButton = null; >+ Button linkButton = null; >+ Button moveButton = null; >+ Combo variableCombo = null; >+ Label variableLabel = null; >+ String variable = ABSOLUTE_PATH; >+ IProject receivingProject = null; >+ >+ protected Control createCustomArea(Composite parent) { >+ Composite composite = new Composite(parent, 0); >+ GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); >+ composite.setLayoutData(gridData); >+ >+ GridLayout layout = new GridLayout(); >+ layout.numColumns = 1; >+ layout.verticalSpacing = 9; >+ layout.marginLeft = 32; >+ composite.setLayout(layout); >+ >+ if ((operationMask & IMPORT_COPY) != 0) { >+ copyButton = new Button(composite, SWT.RADIO); >+ copyButton.setText("Copy the files and directories."); >+ gridData = new GridData(GridData.FILL_HORIZONTAL); >+ copyButton.setLayoutData(gridData); >+ copyButton.setData(new Integer(IMPORT_COPY)); >+ copyButton.addSelectionListener(this); >+ } >+ >+ if ((operationMask & IMPORT_MOVE) != 0) { >+ moveButton = new Button(composite, SWT.RADIO); >+ moveButton.setText("Move the files and directories."); >+ gridData = new GridData(GridData.FILL_HORIZONTAL); >+ moveButton.setLayoutData(gridData); >+ moveButton.setData(new Integer(IMPORT_MOVE)); >+ moveButton.addSelectionListener(this); >+ } >+ >+ if ((operationMask & IMPORT_GROUPS_AND_LINKS) != 0) { >+ shadowCopyButton = new Button(composite, SWT.RADIO); >+ shadowCopyButton.setText("Recreate the files and directories hierarchy with groups and links."); >+ gridData = new GridData(GridData.FILL_HORIZONTAL); >+ shadowCopyButton.setLayoutData(gridData); >+ shadowCopyButton.setData(new Integer(IMPORT_GROUPS_AND_LINKS)); >+ shadowCopyButton.addSelectionListener(this); >+ } >+ if ((operationMask & IMPORT_LINK) != 0) { >+ linkButton = new Button(composite, SWT.RADIO); >+ linkButton.setText("Create links for each files and directories."); >+ gridData = new GridData(GridData.FILL_HORIZONTAL); >+ linkButton.setLayoutData(gridData); >+ linkButton.setData(new Integer(IMPORT_LINK)); >+ linkButton.addSelectionListener(this); >+ } >+ >+ if ((operationMask & (IMPORT_GROUPS_AND_LINKS | IMPORT_LINK)) != 0) { >+ Composite variableGroup = new Composite(composite, 0); >+ gridData = new GridData(SWT.FILL, SWT.FILL, true, true); >+ variableGroup.setLayoutData(gridData); >+ >+ layout = new GridLayout(); >+ layout.numColumns = 2; >+ layout.verticalSpacing = 9; >+ variableGroup.setLayout(layout); >+ >+ variableLabel = new Label(variableGroup, 0); >+ variableLabel.setText("Import paths as:"); >+ gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); >+ variableLabel.setLayoutData(gridData); >+ >+ variableCombo = new Combo(variableGroup, SWT.DROP_DOWN >+ | SWT.READ_ONLY); >+ gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); // GridData.FILL_HORIZONTAL); >+ variableCombo.setLayoutData(gridData); >+ variableCombo.addSelectionListener(new SelectionListener() { >+ public void widgetDefaultSelected(SelectionEvent e) { >+ if (variableCombo.getSelectionIndex() == (variableCombo >+ .getItemCount() - 1)) >+ editVariables(); >+ else >+ selectVariable(variableCombo.getItem(variableCombo >+ .getSelectionIndex())); >+ } >+ >+ public void widgetSelected(SelectionEvent e) { >+ if (variableCombo.getSelectionIndex() == (variableCombo >+ .getItemCount() - 1)) >+ editVariables(); >+ else >+ selectVariable(variableCombo.getItem(variableCombo >+ .getSelectionIndex())); >+ } >+ }); >+ setupVariableContent(); >+ selectVariable(PreferenceConstants.getPreferenceStore().getString( >+ PREF_IMPORT_FILES_AND_FOLDERS_VARIABLE)); >+ } >+ >+ refreshSelection(); >+ return composite; >+ } >+ >+ private void editVariables() { >+ PathVariableEditDialog dialog = new PathVariableEditDialog(getShell()); >+ dialog.setProject(receivingProject); >+ if (dialog.open() == IDialogConstants.OK_ID) { >+ String[] variableNames = (String[]) dialog.getResult(); >+ if (variableNames != null && variableNames.length >= 1) { >+ variable = variableNames[0]; >+ } >+ } >+ setupVariableContent(); >+ selectVariable(variable); >+ } >+ >+ private void selectVariable(String var) { >+ if (var.equals(ABSOLUTE_PATH)) { >+ variableCombo.select(0); >+ variable = var; >+ } else { >+ String[] items = variableCombo.getItems(); >+ for (int i = 0; i < items.length; i++) { >+ if (var.equals(items[i])) { >+ variableCombo.select(i); >+ if (i == 0) >+ variable = ABSOLUTE_PATH; >+ else >+ variable = items[i]; >+ return; >+ } >+ } >+ variableCombo.select(0); >+ variable = ABSOLUTE_PATH; >+ } >+ } >+ >+ private void setupVariableContent() { >+ String[] items; >+ IPathVariableManager pathVariableManager; >+ if (receivingProject != null) >+ pathVariableManager = receivingProject.getPathVariableManager(); >+ else >+ pathVariableManager = ResourcesPlugin.getWorkspace() >+ .getPathVariableManager(); >+ String[] variables = pathVariableManager.getPathVariableNames(); >+ items = new String[variables.length + 2]; >+ items[0] = "Absolute path"; >+ for (int i = 0; i < variables.length; i++) >+ items[i + 1] = variables[i]; >+ items[items.length - 1] = "Edit Variables..."; >+ variableCombo.setItems(items); >+ super.getShell().layout(true); >+ } >+ >+ protected void buttonPressed(int buttonId) { >+ if (buttonId == IDialogConstants.OK_ID) { >+ PreferenceConstants.getPreferenceStore().setValue( >+ PREF_IMPORT_FILES_AND_FOLDERS_TYPE, >+ currentSelection); >+ PreferenceConstants.getPreferenceStore().setValue( >+ PREF_IMPORT_FILES_AND_FOLDERS_VARIABLE, >+ variable); >+ } >+ super.buttonPressed(buttonId); >+ } >+ >+ public void widgetDefaultSelected(SelectionEvent e) { >+ currentSelection = ((Integer) e.widget.getData()).intValue(); >+ refreshSelection(); >+ } >+ >+ public void widgetSelected(SelectionEvent e) { >+ currentSelection = ((Integer) e.widget.getData()).intValue(); >+ refreshSelection(); >+ } >+ >+ void refreshSelection() { >+ if (copyButton != null) >+ copyButton.setSelection(currentSelection == IMPORT_COPY); >+ if (shadowCopyButton != null) >+ shadowCopyButton.setSelection(currentSelection == IMPORT_GROUPS_AND_LINKS); >+ if (linkButton != null) >+ linkButton.setSelection(currentSelection == IMPORT_LINK); >+ if (moveButton != null) >+ moveButton.setSelection(currentSelection == IMPORT_MOVE); >+ if (variableCombo != null) >+ variableCombo.setEnabled((currentSelection & (IMPORT_GROUPS_AND_LINKS | IMPORT_LINK)) != 0); >+ if (variableLabel != null) >+ variableLabel.setEnabled((currentSelection & (IMPORT_GROUPS_AND_LINKS | IMPORT_LINK)) != 0); >+ >+ } >+ >+ public void setProject(IProject project) { >+ receivingProject = project; >+ } >+} >#P org.eclipse.core.resources >Index: src/org/eclipse/core/resources/ResourcesPlugin.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/resources/ResourcesPlugin.java,v >retrieving revision 1.50 >diff -u -r1.50 ResourcesPlugin.java >--- src/org/eclipse/core/resources/ResourcesPlugin.java 7 Apr 2008 08:55:44 -0000 1.50 >+++ src/org/eclipse/core/resources/ResourcesPlugin.java 11 Sep 2008 12:30:32 -0000 >@@ -94,7 +94,15 @@ > * @since 3.2 > */ > public static final String PT_MODEL_PROVIDERS = "modelProviders"; //$NON-NLS-1$ >- >+ >+ /** >+ * Simple identifier constant (value <code>"variableProviders"</code>) >+ * for the variable providers extension point. >+ * >+ * @since 3.5 >+ */ >+ public static final String PT_VARIABLE_PROVIDERS = "variableProviders"; //$NON-NLS-1$ >+ > /** > * Constant identifying the job family identifier for the background autobuild job. > * >Index: src/org/eclipse/core/resources/IPathVariableManager.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/resources/IPathVariableManager.java,v >retrieving revision 1.17 >diff -u -r1.17 IPathVariableManager.java >--- src/org/eclipse/core/resources/IPathVariableManager.java 7 Apr 2008 08:55:44 -0000 1.17 >+++ src/org/eclipse/core/resources/IPathVariableManager.java 11 Sep 2008 12:30:29 -0000 >@@ -7,6 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Serge Beauchamp (Freescale Semiconductor) > *******************************************************************************/ > > package org.eclipse.core.resources; >@@ -199,4 +200,31 @@ > * @see IStatus#OK > */ > public IStatus validateValue(IPath path); >+ >+ /** Convert an absolute path to path variable relative path. >+ * For example, converts "C:/foo/bar.txt" into "FOO/bar.txt", >+ * granted that the path variable "FOO" value is "C:/foo". >+ * >+ * The "force" argument allows intermediate path variable to >+ * be created if for a given path can be relative only to a parent >+ * of an existing path variable. >+ * >+ * For example, if the path "C:/other/file.txt" is to be converted >+ * and no path variables point to "C:/" or "C:/other" but "FOO" >+ * points to "C:/foo", an intermediate "OTHER" variable will be >+ * created relative to "FOO" containing the value "${PARENT-1-FOO}" >+ * so that the final path returned will be "OTHER/file.txt". >+ * >+ * The argument "variableHint" can be used to specify to which >+ * path variable the path should be made relative to. >+ * >+ * @param path The absolute path to be converted >+ * @param force Set to true if intermediate path variables need to be created if the path is relative only to a parent of an existing path variable. >+ * @param variableHint The name of the variable to which the path should be relative to, or null for the nearest one. >+ * @return The converted path >+ * @exception CoreException if this method fails. Reasons include: >+ * <ul> >+ * <li>The variable name is not valid</li> >+ */ >+ public IPath convertToRelative(IPath path, boolean force, String variableHint) throws CoreException; > } >Index: src/org/eclipse/core/resources/IProject.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/resources/IProject.java,v >retrieving revision 1.44 >diff -u -r1.44 IProject.java >--- src/org/eclipse/core/resources/IProject.java 7 Apr 2008 08:55:44 -0000 1.44 >+++ src/org/eclipse/core/resources/IProject.java 11 Sep 2008 12:30:29 -0000 >@@ -842,4 +842,27 @@ > * @since 2.0 > */ > public void setDescription(IProjectDescription description, int updateFlags, IProgressMonitor monitor) throws CoreException; >+ >+ /** >+ * Returns the path variable manager for this project. >+ * >+ * @return the path variable manager >+ * @see IPathVariableManager >+ * @since 3.3 (Freescale) >+ */ >+ public IPathVariableManager getPathVariableManager(); >+ >+ /** >+ * Returns a variable relative path equivalent to an absolute path for a >+ * file or folder in the file system, according to the variables defined in >+ * this project PathVariableManager. The file or folder need not to exist. >+ * <p> >+ * >+ * @param location >+ * a path in the local file system >+ * @return the corresponding variable relative path, or <code>null</code> >+ * if no such path is available >+ * @since 3.3 (Freescale) >+ */ >+ public IPath getVariableRelativePathLocation(IPath location); > } >Index: src/org/eclipse/core/resources/IResource.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/resources/IResource.java,v >retrieving revision 1.100 >diff -u -r1.100 IResource.java >--- src/org/eclipse/core/resources/IResource.java 7 Apr 2008 08:55:44 -0000 1.100 >+++ src/org/eclipse/core/resources/IResource.java 11 Sep 2008 12:30:32 -0000 >@@ -9,6 +9,7 @@ > * IBM Corporation - initial API and implementation > * Red Hat Incorporated - get/setResourceAttribute code > * Oakland Software Incorporated - added getSessionProperties and getPersistentProperties >+ * Serge Beauchamp (Freescale Semiconductor) > *******************************************************************************/ > package org.eclipse.core.resources; > >@@ -2540,6 +2541,40 @@ > * @see IResourceDelta#DESCRIPTION > */ > public void touch(IProgressMonitor monitor) throws CoreException; >+ >+ /** >+ * Sets the value of the link location for a linked resource. >+ * >+ * @param location >+ * the new location of the target link resource >+ * @param updateFlags >+ * bit-wise or of update flag constants ({@link #FORCE}, >+ * {@link #KEEP_HISTORY}, {@link #SHALLOW}, >+ * {@link #BACKGROUND_REFRESH} and {@link #REPLACE}). >+ * @param monitor >+ * a progress monitor, or <code>null</code> if progress >+ * reporting is not desired >+ * @exception CoreException >+ * if isLinked() returns false. >+ */ >+ public void setLinkLocation(URI location, int updateFlags, IProgressMonitor monitor) throws CoreException; >+ >+ /** >+ * Sets the value of the link location for a linked resource. >+ * >+ * @param location >+ * the new location of the target link resource >+ * @param updateFlags >+ * bit-wise or of update flag constants ({@link #FORCE}, >+ * {@link #KEEP_HISTORY}, {@link #SHALLOW}, >+ * {@link #BACKGROUND_REFRESH} and {@link #REPLACE}). >+ * @param monitor >+ * a progress monitor, or <code>null</code> if progress >+ * reporting is not desired >+ * @exception CoreException >+ * if isLinked() returns false. >+ */ >+ public void setLinkLocation(IPath location, int updateFlags, IProgressMonitor monitor) throws CoreException; > > > } >Index: plugin.properties >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/plugin.properties,v >retrieving revision 1.21 >diff -u -r1.21 plugin.properties >--- plugin.properties 3 Jun 2008 12:34:52 -0000 1.21 >+++ plugin.properties 11 Sep 2008 12:30:19 -0000 >@@ -21,6 +21,7 @@ > modelProviders=Model Providers > preferencesExtPtName=Resource Preferences > resourceModelName=File System Resources >+variableProviders=Variable Providers > > markerName = Marker > problemName = Problem >Index: plugin.xml >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/plugin.xml,v >retrieving revision 1.79 >diff -u -r1.79 plugin.xml >--- plugin.xml 25 Sep 2006 14:58:50 -0000 1.79 >+++ plugin.xml 11 Sep 2008 12:30:19 -0000 >@@ -10,6 +10,7 @@ > <extension-point id="teamHook" name="%teamHookName" schema="schema/teamHook.exsd"/> > <extension-point id="refreshProviders" name="%refreshProvidersName" schema="schema/refreshProviders.exsd"/> > <extension-point id="modelProviders" name="%modelProviders" schema="schema/modelProviders.exsd"/> >+ <extension-point id="variableProviders" name="%variableProviders" schema="schema/variableProviders.exsd"/> > > <extension id="preferences" point="org.eclipse.core.runtime.preferences" name="%preferencesExtPtName"> > <scope name="project" class="org.eclipse.core.internal.resources.ProjectPreferences"/> >@@ -189,4 +190,24 @@ > id="org.eclipse.core.resources.mappingPropertyTester"/> > </extension> > >+ <extension >+ point="org.eclipse.core.resources.variableProviders"> >+ <variableProvider >+ class="org.eclipse.core.internal.resources.projectVariables.EclipseHomeProjectVariable" >+ name="ECLIPSE_HOME"> >+ </variableProvider> >+ <variableProvider >+ class="org.eclipse.core.internal.resources.projectVariables.ProjectLocationProjectVariable" >+ name="PROJECT_LOC"> >+ </variableProvider> >+ <variableProvider >+ class="org.eclipse.core.internal.resources.projectVariables.WorkspaceLocationProjectVariable" >+ name="WORKSPACE_LOC"> >+ </variableProvider> >+ <variableProvider >+ class="org.eclipse.core.internal.resources.projectVariables.ParentVariableProvider" >+ name="PARENT"> >+ </variableProvider> >+ </extension> >+ > </plugin> >Index: src/org/eclipse/core/internal/resources/LocationValidator.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/LocationValidator.java,v >retrieving revision 1.16 >diff -u -r1.16 LocationValidator.java >--- src/org/eclipse/core/internal/resources/LocationValidator.java 3 Jun 2008 12:34:50 -0000 1.16 >+++ src/org/eclipse/core/internal/resources/LocationValidator.java 11 Sep 2008 12:30:21 -0000 >@@ -7,6 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Serge Beauchamp (Freescale Semiconductor) > *******************************************************************************/ > package org.eclipse.core.internal.resources; > >@@ -63,7 +64,11 @@ > * @see IWorkspace#validateLinkLocation(IResource, IPath) > */ > public IStatus validateLinkLocation(IResource resource, IPath unresolvedLocation) { >- IPath location = workspace.getPathVariableManager().resolvePath(unresolvedLocation); >+ IPath location; >+ if (resource.getProject() != null) >+ location = resource.getProject().getPathVariableManager().resolvePath(unresolvedLocation); >+ else >+ location = workspace.getPathVariableManager().resolvePath(unresolvedLocation); > if (location.isEmpty()) > return new ResourceStatus(IResourceStatus.INVALID_VALUE, resource.getFullPath(), Messages.links_noPath); > //check that the location is absolute >@@ -96,7 +101,11 @@ > message = NLS.bind(Messages.links_parentNotAccessible, resource.getFullPath()); > return new ResourceStatus(IResourceStatus.INVALID_VALUE, resource.getFullPath(), message); > } >- URI location = workspace.getPathVariableManager().resolveURI(unresolvedLocation); >+ URI location; >+ if (resource.getProject() != null) >+ location = resource.getProject().getPathVariableManager().resolveURI(unresolvedLocation); >+ else >+ location = workspace.getPathVariableManager().resolveURI(unresolvedLocation); > //check nature veto > String[] natureIds = ((Project) resource.getProject()).internalGetDescription().getNatureIds(); > >@@ -286,8 +295,11 @@ > public IStatus validateProjectLocation(IProject context, IPath unresolvedLocation) { > if (unresolvedLocation == null) > return validateProjectLocationURI(context, null); >- >- IPath location = workspace.getPathVariableManager().resolvePath(unresolvedLocation); >+ IPath location; >+ if (context != null) >+ location = context.getPathVariableManager().resolvePath(unresolvedLocation); >+ else >+ location = workspace.getPathVariableManager().resolvePath(unresolvedLocation); > //check that the location is absolute > if (!location.isAbsolute()) { > String message; >@@ -327,8 +339,11 @@ > // the default is ok for all other projects > if (unresolvedLocation == null) > return Status.OK_STATUS; >- >- URI location = workspace.getPathVariableManager().resolveURI(unresolvedLocation); >+ URI location; >+ if (context != null) >+ location = context.getPathVariableManager().resolveURI(unresolvedLocation); >+ else >+ location = workspace.getPathVariableManager().resolveURI(unresolvedLocation); > //check the standard path name restrictions > IStatus result = validateSegments(location); > if (!result.isOK()) >Index: src/org/eclipse/core/internal/resources/IModelObjectConstants.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/IModelObjectConstants.java,v >retrieving revision 1.17 >diff -u -r1.17 IModelObjectConstants.java >--- src/org/eclipse/core/internal/resources/IModelObjectConstants.java 4 Apr 2006 20:53:46 -0000 1.17 >+++ src/org/eclipse/core/internal/resources/IModelObjectConstants.java 11 Sep 2008 12:30:21 -0000 >@@ -44,4 +44,6 @@ > public static final String WORKSPACE_DESCRIPTION = "workspaceDescription"; //$NON-NLS-1$ > public static final String LINKED_RESOURCES = "linkedResources"; //$NON-NLS-1$ > public static final String LINK = "link"; //$NON-NLS-1$ >+ public static final String VARIABLE = "variable"; //$NON-NLS-1$ >+ public static final String VARIABLE_LIST = "variableList"; //$NON-NLS-1$ > } >Index: src/org/eclipse/core/internal/resources/Workspace.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Workspace.java,v >retrieving revision 1.219 >diff -u -r1.219 Workspace.java >--- src/org/eclipse/core/internal/resources/Workspace.java 8 May 2008 10:21:55 -0000 1.219 >+++ src/org/eclipse/core/internal/resources/Workspace.java 11 Sep 2008 12:30:28 -0000 >@@ -8,9 +8,14 @@ > * Contributors: > * IBM Corporation - initial API and implementation > * Red Hat Incorporated - loadProjectDescription(InputStream) >+ * Serge Beauchamp (Freescale Semiconductor) > *******************************************************************************/ > package org.eclipse.core.internal.resources; > >+import java.net.URISyntaxException; >+ >+import org.eclipse.core.filesystem.URIUtil; >+ > import java.io.IOException; > import java.io.InputStream; > import java.net.URI; >@@ -697,7 +702,14 @@ > } > } > >- protected void copyTree(IResource source, IPath destination, int depth, int updateFlags, boolean keepSyncInfo) throws CoreException { >+ protected void copyTree(IResource source, IPath destination, int depth, >+ int updateFlags, boolean keepSyncInfo) throws CoreException { >+ copyTree(source, destination, depth, updateFlags, keepSyncInfo, false); >+ } >+ >+ protected void copyTree(IResource source, IPath destination, int depth, >+ int updateFlags, boolean keepSyncInfo, boolean moveResources) >+ throws CoreException { > // retrieve the resource at the destination if there is one (phantoms included). > // if there isn't one, then create a new handle based on the type that we are > // trying to copy >@@ -736,18 +748,22 @@ > // update link locations in project descriptions > if (source.isLinked()) { > LinkDescription linkDescription; >+ URI sourceLocationURI = transferVariableDefinition(source, destinationResource, source.getLocationURI()); > if ((updateFlags & IResource.SHALLOW) != 0) { > //for shallow move the destination is a linked resource with the same location > newInfo.set(ICoreConstants.M_LINK); >- linkDescription = new LinkDescription(destinationResource, source.getLocationURI()); >+ linkDescription = new LinkDescription(destinationResource, sourceLocationURI); > } else { > //for deep move the destination is not a linked resource > newInfo.clear(ICoreConstants.M_LINK); > linkDescription = null; > } >+ if (moveResources) >+ ((Project) source.getProject()).internalGetDescription().setLinkLocation(source.getProjectRelativePath(), null); > Project project = (Project) destinationResource.getProject(); > project.internalGetDescription().setLinkLocation(destinationResource.getProjectRelativePath(), linkDescription); > project.writeDescription(updateFlags); >+ newInfo.setFileStoreRoot(null); > } > > // do the recursion. if we have a file then it has no members so return. otherwise >@@ -761,16 +777,120 @@ > if (projectCopy) { > IResource dotProject = ((Project) source).findMember(IProjectDescription.DESCRIPTION_FILE_NAME); > if (dotProject != null) >- copyTree(dotProject, destination.append(dotProject.getName()), depth, updateFlags, keepSyncInfo); >+ copyTree(dotProject, destination.append(dotProject.getName()), depth, updateFlags, keepSyncInfo, moveResources); > } > IResource[] children = ((IContainer) source).members(IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS | IContainer.INCLUDE_HIDDEN); > for (int i = 0, imax = children.length; i < imax; i++) { > String childName = children[i].getName(); > if (!projectCopy || !childName.equals(IProjectDescription.DESCRIPTION_FILE_NAME)) { > IPath childPath = destination.append(childName); >- copyTree(children[i], childPath, depth, updateFlags, keepSyncInfo); >+ copyTree(children[i], childPath, depth, updateFlags, keepSyncInfo, moveResources); >+ } >+ } >+ } >+ >+ private URI transferVariableDefinition(IResource source, IResource dest, >+ URI sourceURI) throws CoreException { >+ IPath srcLoc = source.getLocation(); >+ IPath srcRawLoc = source.getRawLocation(); >+ if (!srcRawLoc.equals(srcLoc)) { >+ // the location is variable relative >+ if (!source.getProject().equals(dest.getProject())) { >+ String variable = srcRawLoc.segment(0); >+ variable = copyVariable(source.getProject(), dest.getProject(), >+ variable); >+ IPath newLocation = Path.fromPortableString(variable).append( >+ srcRawLoc.removeFirstSegments(1)); >+ sourceURI = toURI(newLocation); >+ } else { >+ sourceURI = toURI(srcRawLoc); >+ } >+ } >+ return sourceURI; >+ } >+ >+ URI toURI(IPath path) { >+ if (path.isAbsolute()) >+ return URIUtil.toURI(path); >+ else >+ try { >+ return new URI(null, null, path.toPortableString(), null); >+ } catch (URISyntaxException e) { >+ return URIUtil.toURI(path); > } >+ } >+ >+ String copyVariable(IProject source, IProject dest, String variable) >+ throws CoreException { >+ IPathVariableManager destPathVariableManager = dest >+ .getPathVariableManager(); >+ IPathVariableManager srcPathVariableManager = source >+ .getPathVariableManager(); >+ >+ IPath srcValue = srcPathVariableManager.getValue(variable); >+ if (srcValue == null) // if the variable doesn't exist, return another >+ // variable that doesn't exist either >+ return getUniqueVariableName(variable, destPathVariableManager); >+ IPath resolvedSrcValue = srcPathVariableManager.resolvePath(srcValue); >+ >+ // look if the exact same variable exists >+ if (destPathVariableManager.isDefined(variable)) { >+ if (destPathVariableManager.resolvePath( >+ destPathVariableManager.getValue(variable)).equals( >+ resolvedSrcValue)) >+ return variable; >+ } >+ // look if one variable in the destination project matches >+ String[] variables = destPathVariableManager.getPathVariableNames(); >+ for (int i = 0; i < variables.length; i++) { >+ IPath resolveDestVariable = destPathVariableManager >+ .resolvePath(destPathVariableManager.getValue(variables[i])); >+ if (resolveDestVariable.equals(resolvedSrcValue)) { >+ return variables[i]; >+ } >+ } >+ // if the variable doesn't exist in the dest project, or >+ // if the value is different than the source project, we have to create >+ // an equivalent. >+ String destVariable = getUniqueVariableName(variable, >+ destPathVariableManager); >+ >+ if (!srcValue.equals(resolvedSrcValue)) { >+ // the variable content contains references to more variables >+ String[] segments = ProjectPathVariableManager >+ .splitVariablesAndContent(srcValue.toPortableString()); >+ StringBuffer result = new StringBuffer(); >+ for (int i = 0; i < segments.length; i++) { >+ String var = ProjectPathVariableManager >+ .extractVariable(segments[i]); >+ if (var.length() > 0) { >+ String copiedVariable = copyVariable(source, dest, var); >+ int index = segments[i].indexOf(var); >+ if (index != -1) { >+ result.append(segments[i].substring(0, index)); >+ result.append(copiedVariable); >+ int start = index + var.length(); >+ int end = segments[i].length(); >+ result.append(segments[i].substring(start, end)); >+ } >+ } else >+ result.append(segments[i]); >+ } >+ srcValue = Path.fromPortableString(result.toString()); >+ } >+ destPathVariableManager.setValue(destVariable, srcValue); >+ return destVariable; >+ } >+ >+ private String getUniqueVariableName(String variable, >+ IPathVariableManager destPathVariableManager) { >+ int index = 1; >+ String destVariable = variable; >+ while (destPathVariableManager.isDefined(destVariable)) { >+ destVariable = variable + index; >+ index++; > } >+ return destVariable; > } > > /** >@@ -1583,7 +1703,7 @@ > void move(Resource source, IPath destination, int depth, int updateFlags, boolean keepSyncInfo) throws CoreException { > // overlay the tree at the destination path, preserving any important info > // in any already existing resource information >- copyTree(source, destination, depth, updateFlags, keepSyncInfo); >+ copyTree(source, destination, depth, updateFlags, keepSyncInfo, true); > source.fixupAfterMoveSource(); > } > >Index: src/org/eclipse/core/internal/resources/AliasManager.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/AliasManager.java,v >retrieving revision 1.41 >diff -u -r1.41 AliasManager.java >--- src/org/eclipse/core/internal/resources/AliasManager.java 3 Jun 2008 12:34:51 -0000 1.41 >+++ src/org/eclipse/core/internal/resources/AliasManager.java 11 Sep 2008 12:30:21 -0000 >@@ -94,13 +94,15 @@ > break; > } > if (aliasPath != null) >- if (aliasType == IResource.FILE) { >- aliases.add(workspace.getRoot().getFile(aliasPath)); >- } else { >- if (aliasPath.segmentCount() == 1) >- aliases.add(workspace.getRoot().getProject(aliasPath.lastSegment())); >- else >- aliases.add(workspace.getRoot().getFolder(aliasPath)); >+ synchronized(aliases) { >+ if (aliasType == IResource.FILE) { >+ aliases.add(workspace.getRoot().getFile(aliasPath)); >+ } else { >+ if (aliasPath.segmentCount() == 1) >+ aliases.add(workspace.getRoot().getProject(aliasPath.lastSegment())); >+ else >+ aliases.add(workspace.getRoot().getFolder(aliasPath)); >+ } > } > } > >@@ -423,12 +425,14 @@ > if (hasNoAliases(resource)) > return null; > >- aliases.clear(); >- internalComputeAliases(resource, location); >- int size = aliases.size(); >- if (size == 0) >- return null; >- return (IResource[]) aliases.toArray(new IResource[size]); >+ synchronized(aliases) { >+ aliases.clear(); >+ internalComputeAliases(resource, location); >+ int size = aliases.size(); >+ if (size == 0) >+ return null; >+ return (IResource[]) aliases.toArray(new IResource[size]); >+ } > } > > /** >@@ -442,7 +446,9 @@ > //get the normal aliases (resources rooted in parent locations) > internalComputeAliases(resource, location); > //get all resources rooted below this resource's location >- addToCollection.setCollection(aliases); >+ synchronized(aliases) { >+ addToCollection.setCollection(aliases); >+ } > locationsMap.matchingPrefixDo(location, addToCollection); > //if this is a project, get all resources rooted below links in this project > if (resource.getType() == IResource.PROJECT) { >@@ -656,23 +662,25 @@ > public void updateAliases(IResource resource, IFileStore location, int depth, IProgressMonitor monitor) throws CoreException { > if (hasNoAliases(resource)) > return; >- aliases.clear(); >- if (depth == IResource.DEPTH_ZERO) >- internalComputeAliases(resource, location); >- else >- computeDeepAliases(resource, location); >- if (aliases.size() == 0) >- return; >- FileSystemResourceManager localManager = workspace.getFileSystemManager(); >- for (Iterator it = aliases.iterator(); it.hasNext();) { >- IResource alias = (IResource) it.next(); >- monitor.subTask(NLS.bind(Messages.links_updatingDuplicate, alias.getFullPath())); >- if (alias.getType() == IResource.PROJECT) { >- if (checkDeletion((Project) alias, location)) >- continue; >- //project did not require deletion, so fall through below and refresh it >+ synchronized(aliases) { >+ aliases.clear(); >+ if (depth == IResource.DEPTH_ZERO) >+ internalComputeAliases(resource, location); >+ else >+ computeDeepAliases(resource, location); >+ if (aliases.size() == 0) >+ return; >+ FileSystemResourceManager localManager = workspace.getFileSystemManager(); >+ for (Iterator it = aliases.iterator(); it.hasNext();) { >+ IResource alias = (IResource) it.next(); >+ monitor.subTask(NLS.bind(Messages.links_updatingDuplicate, alias.getFullPath())); >+ if (alias.getType() == IResource.PROJECT) { >+ if (checkDeletion((Project) alias, location)) >+ continue; >+ //project did not require deletion, so fall through below and refresh it >+ } >+ localManager.refresh(alias, IResource.DEPTH_INFINITE, false, null); > } >- localManager.refresh(alias, IResource.DEPTH_INFINITE, false, null); > } > } > >Index: src/org/eclipse/core/internal/resources/PathVariableManager.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/PathVariableManager.java,v >retrieving revision 1.32 >diff -u -r1.32 PathVariableManager.java >--- src/org/eclipse/core/internal/resources/PathVariableManager.java 3 Jun 2008 12:34:50 -0000 1.32 >+++ src/org/eclipse/core/internal/resources/PathVariableManager.java 11 Sep 2008 12:30:22 -0000 >@@ -7,6 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Serge Beauchamp (Freescale Semiconductor) > *******************************************************************************/ > package org.eclipse.core.internal.resources; > >@@ -264,4 +265,13 @@ > } > return Status.OK_STATUS; > } >+ >+ /** >+ * @throws CoreException >+ * @see IPathVariableManager#convertToRelative(IPath, boolean, String) >+ */ >+ public IPath convertToRelative(IPath path, boolean force, String variableHint) throws CoreException { >+ // the workspace path variable manager doesn't have the PARENT variable to support the "force" flag. >+ return PathVariableUtil.convertToRelative(this, path, false, variableHint); >+ } > } >Index: src/org/eclipse/core/internal/resources/ProjectDescriptionReader.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/ProjectDescriptionReader.java,v >retrieving revision 1.36 >diff -u -r1.36 ProjectDescriptionReader.java >--- src/org/eclipse/core/internal/resources/ProjectDescriptionReader.java 25 Jan 2008 23:09:37 -0000 1.36 >+++ src/org/eclipse/core/internal/resources/ProjectDescriptionReader.java 11 Sep 2008 12:30:24 -0000 >@@ -7,6 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Serge Beauchamp (Freescale Semiconductor) > *******************************************************************************/ > package org.eclipse.core.internal.resources; > >@@ -51,6 +52,10 @@ > protected static final int S_PROJECT_NAME = 19; > protected static final int S_PROJECTS = 20; > protected static final int S_REFERENCED_PROJECT_NAME = 21; >+ protected static final int S_VARIABLE_LIST = 25; >+ protected static final int S_VARIABLE = 26; >+ protected static final int S_VARIABLE_NAME = 27; >+ protected static final int S_VARIABLE_VALUE = 28; > > /** > * Singleton sax parser factory >@@ -299,9 +304,15 @@ > case S_LINK : > endLinkElement(elementName); > break; >+ case S_VARIABLE : >+ endVariableElement(elementName); >+ break; > case S_LINKED_RESOURCES : > endLinkedResourcesElement(elementName); > return; >+ case S_VARIABLE_LIST : >+ endVariableListElement(elementName); >+ return; > case S_PROJECT_COMMENT : > if (elementName.equals(COMMENT)) { > projectDescription.setComment(charBuffer.toString()); >@@ -354,6 +365,12 @@ > case S_LINK_LOCATION_URI : > endLinkLocationURI(elementName); > break; >+ case S_VARIABLE_NAME : >+ endVariableName(elementName); >+ break; >+ case S_VARIABLE_VALUE : >+ endVariableValue(elementName); >+ break; > } > charBuffer.setLength(0); > } >@@ -372,6 +389,20 @@ > } > > /** >+ * End this group of group resources and add them to the project >+ * description. >+ */ >+ private void endVariableListElement(String elementName) { >+ if (elementName.equals(VARIABLE_LIST)) { >+ HashMap variableList = (HashMap) objectStack.pop(); >+ state = S_PROJECT_DESC; >+ if (variableList.isEmpty()) >+ return; >+ projectDescription.setVariableDescriptions(variableList); >+ } >+ } >+ >+ /** > * End a single linked resource and add it to the HashMap. > */ > private void endLinkElement(String elementName) { >@@ -402,6 +433,26 @@ > } > > /** >+ * End a single group resource and add it to the HashMap. >+ */ >+ private void endVariableElement(String elementName) { >+ if (elementName.equals(VARIABLE)) { >+ state = S_VARIABLE_LIST; >+ // Pop off the link description >+ VariableDescription desc = (VariableDescription) objectStack.pop(); >+ // Make sure that you have something reasonable >+ if (desc.getName().length() == 0) { >+ parseProblem(NLS.bind(Messages.projRead_emptyVariableName, >+ project.getName())); >+ return; >+ } >+ >+ // The HashMap of variables is the next thing on the stack >+ ((HashMap) objectStack.peek()).put(desc.getName(), desc); >+ } >+ } >+ >+ /** > * For backwards compatibility, link locations in the local file system are represented > * in the project description under the "location" tag. > * @param elementName >@@ -461,6 +512,26 @@ > } > } > >+ private void endVariableName(String elementName) { >+ if (elementName.equals(NAME)) { >+ String value = charBuffer.toString(); >+ // objectStack has a VariableDescription on it. Set the value >+ // on this ValueDescription. >+ ((VariableDescription) objectStack.peek()).setName(value); >+ state = S_VARIABLE; >+ } >+ } >+ >+ private void endVariableValue(String elementName) { >+ if (elementName.equals(VALUE)) { >+ String value = charBuffer.toString(); >+ // objectStack has a VariableDescription on it. Set the value >+ // on this ValueDescription. >+ ((VariableDescription) objectStack.peek()).setValue(value); >+ state = S_VARIABLE; >+ } >+ } >+ > private void endLinkType(String elementName) { > if (elementName.equals(TYPE)) { > //FIXME we should handle this case by removing the entire link >@@ -589,6 +660,12 @@ > state = S_LINKED_RESOURCES; > return; > } >+ if (elementName.equals(VARIABLE_LIST)) { >+ // Push a HashMap to collect all the variables. >+ objectStack.push(new HashMap()); >+ state = S_VARIABLE_LIST; >+ return; >+ } > } > > public ProjectDescription read(InputSource input) { >@@ -713,6 +790,14 @@ > objectStack.push(new LinkDescription()); > } > break; >+ case S_VARIABLE_LIST: >+ if (elementName.equals(VARIABLE)) { >+ state = S_VARIABLE; >+ // Push place holders for the name, type and location of >+ // this link. >+ objectStack.push(new VariableDescription()); >+ } >+ break; > case S_LINK : > if (elementName.equals(NAME)) { > state = S_LINK_PATH; >@@ -724,6 +809,13 @@ > state = S_LINK_LOCATION_URI; > } > break; >+ case S_VARIABLE: >+ if (elementName.equals(NAME)) { >+ state = S_VARIABLE_NAME; >+ } else if (elementName.equals(VALUE)) { >+ state = S_VARIABLE_VALUE; >+ } >+ break; > } > } > >Index: src/org/eclipse/core/internal/resources/ModelObjectWriter.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/ModelObjectWriter.java,v >retrieving revision 1.29 >diff -u -r1.29 ModelObjectWriter.java >--- src/org/eclipse/core/internal/resources/ModelObjectWriter.java 3 Jun 2008 12:34:51 -0000 1.29 >+++ src/org/eclipse/core/internal/resources/ModelObjectWriter.java 11 Sep 2008 12:30:22 -0000 >@@ -7,6 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Serge Beauchamp (Freescale Semiconductor) > *******************************************************************************/ > package org.eclipse.core.internal.resources; > >@@ -91,6 +92,15 @@ > writer.endTag(LINK); > } > >+ protected void write(VariableDescription description, XMLWriter writer) { >+ writer.startTag(VARIABLE, null); >+ if (description != null) { >+ writer.printSimpleTag(NAME, description.getName()); >+ writer.printSimpleTag(VALUE, description.getValue()); >+ } >+ writer.endTag(VARIABLE); >+ } >+ > /** > * Writes a location to the XML writer. For backwards compatibility, > * local file system locations are written and read using a different tag >@@ -153,6 +163,10 @@ > write((LinkDescription) obj, writer); > return; > } >+ if (obj instanceof VariableDescription) { >+ write((VariableDescription) obj, writer); >+ return; >+ } > writer.printTabulation(); > writer.println(obj.toString()); > } >@@ -173,6 +187,9 @@ > Collections.sort(sorted); > write(LINKED_RESOURCES, sorted, writer); > } >+ HashMap variables = description.getVariables(); >+ if (variables != null) >+ write(VARIABLE_LIST, variables.values(), writer); > } > writer.endTag(PROJECT_DESCRIPTION); > } >Index: src/org/eclipse/core/internal/resources/ProjectDescription.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/ProjectDescription.java,v >retrieving revision 1.41 >diff -u -r1.41 ProjectDescription.java >--- src/org/eclipse/core/internal/resources/ProjectDescription.java 3 Jun 2008 12:34:50 -0000 1.41 >+++ src/org/eclipse/core/internal/resources/ProjectDescription.java 11 Sep 2008 12:30:23 -0000 >@@ -7,6 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Serge Beauchamp (Freescale Semiconductor) > *******************************************************************************/ > package org.eclipse.core.internal.resources; > >@@ -46,6 +47,12 @@ > */ > protected HashMap linkDescriptions = null; > >+ /** >+ * Map of (String -> VariableDescription) pairs for each variable in this >+ * project, where String is the name of the variable. >+ */ >+ protected HashMap variableDescriptions = null; >+ > // fields > protected URI location = null; > protected String[] natures = EMPTY_STRING_ARRAY; >@@ -59,6 +66,8 @@ > ProjectDescription clone = (ProjectDescription) super.clone(); > //don't want the clone to have access to our internal link locations table or builders > clone.linkDescriptions = null; >+ if (variableDescriptions != null) >+ clone.variableDescriptions = (HashMap) variableDescriptions.clone(); > clone.buildSpec = getBuildSpec(true); > return clone; > } >@@ -171,6 +180,15 @@ > } > > /** >+ * Returns the map of variable descriptions (String (variable name) -> >+ * VariableDescription). Since this method is only used internally, it never >+ * creates a copy. Returns null if the project does not have any variables. >+ */ >+ public HashMap getVariables() { >+ return variableDescriptions; >+ } >+ >+ /** > * @see IProjectDescription#getLocation() > * @deprecated > */ >@@ -256,9 +274,14 @@ > if (!Arrays.equals(natures, description.getNatureIds(false))) > return true; > HashMap otherLinks = description.getLinks(); >- if (linkDescriptions == null) >- return otherLinks != null; >- return !linkDescriptions.equals(otherLinks); >+ if ((linkDescriptions == null) && (otherLinks != null)) >+ return true; >+ if ((linkDescriptions != null) && !linkDescriptions.equals(otherLinks)) >+ return true; >+ HashMap otherVariables = description.getVariables(); >+ if (variableDescriptions == null) >+ return otherVariables != null; >+ return !variableDescriptions.equals(otherVariables); > } > > /* (non-Javadoc) >@@ -315,6 +338,15 @@ > } > > /** >+ * Sets the map of variable descriptions (String name -> >+ * VariableDescription). Since this method is only used internally, it never >+ * creates a copy. May pass null if this project does not have any variables >+ */ >+ public void setVariableDescriptions(HashMap variableDescriptions) { >+ this.variableDescriptions = variableDescriptions; >+ } >+ >+ /** > * Sets the description of a link. Setting to a description of null will > * remove the link from the project description. > */ >@@ -340,6 +372,33 @@ > } > } > >+ /** >+ * Sets the description of a variable. Setting to a description of null will >+ * remove the variable from the project description. >+ */ >+ public void setVariableDescription(String name, >+ VariableDescription description) { >+ HashMap tempMap = variableDescriptions; >+ if (description != null) { >+ // addition or modification >+ if (tempMap == null) >+ tempMap = new HashMap(10); >+ else >+ // copy on write to protect against concurrent read >+ tempMap = (HashMap) tempMap.clone(); >+ tempMap.put(name, description); >+ variableDescriptions = tempMap; >+ } else { >+ // removal >+ if (tempMap != null) { >+ // copy on write to protect against concurrent access >+ HashMap newMap = (HashMap) tempMap.clone(); >+ newMap.remove(name); >+ variableDescriptions = newMap.size() == 0 ? null : newMap; >+ } >+ } >+ } >+ > /* (non-Javadoc) > * @see IProjectDescription#setLocation(IPath) > */ >Index: src/org/eclipse/core/internal/resources/Project.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Project.java,v >retrieving revision 1.150 >diff -u -r1.150 Project.java >--- src/org/eclipse/core/internal/resources/Project.java 9 May 2008 18:26:14 -0000 1.150 >+++ src/org/eclipse/core/internal/resources/Project.java 11 Sep 2008 12:30:23 -0000 >@@ -7,6 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Serge Beauchamp (Freescale Semiconductor) > *******************************************************************************/ > package org.eclipse.core.internal.resources; > >@@ -24,8 +25,11 @@ > > public class Project extends Container implements IProject { > >+ protected ProjectPathVariableManager pathVariableManager; >+ > protected Project(IPath path, Workspace container) { > super(path, container); >+ pathVariableManager = new ProjectPathVariableManager(this); > } > > protected void assertCreateRequirements(IProjectDescription description) throws CoreException { >@@ -1134,4 +1138,29 @@ > ProjectDescription.isWriting = false; > } > } >+ >+ /* >+ * (non-Javadoc) >+ * >+ * @see IProject#getPathVariableManager() >+ */ >+ public IPathVariableManager getPathVariableManager() { >+ return pathVariableManager; >+ } >+ >+ /* >+ * (non-Javadoc) >+ * >+ * @see IProject#getVariableRelativePathLocation(IPath) >+ */ >+ public IPath getVariableRelativePathLocation(IPath location) { >+ try { >+ IPath result = getPathVariableManager().convertToRelative(location, false, null); >+ if (!result.equals(location)) >+ return result; >+ } catch (CoreException e) { >+ // handled by returning null >+ } >+ return null; >+ } > } >Index: src/org/eclipse/core/internal/resources/Resource.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Resource.java,v >retrieving revision 1.163 >diff -u -r1.163 Resource.java >--- src/org/eclipse/core/internal/resources/Resource.java 21 Aug 2008 11:01:10 -0000 1.163 >+++ src/org/eclipse/core/internal/resources/Resource.java 11 Sep 2008 12:30:25 -0000 >@@ -11,9 +11,12 @@ > * Red Hat Incorporated - get/setResourceAttribute code > * Oakland Software Incorporated - added getSessionProperties and getPersistentProperties > * Holger Oehm <holger.oehm@sap.com> - [226264] race condition in Workspace.isTreeLocked()/setTreeLocked() >+ * Serge Beauchamp (Freescale Semiconductor) > *******************************************************************************/ > package org.eclipse.core.internal.resources; > >+import java.net.URISyntaxException; >+ > import java.net.URI; > import java.util.*; > import org.eclipse.core.filesystem.*; >@@ -165,7 +168,11 @@ > if (variableUndefined) > return null; > //check if the file exists >- URI resolved = workspace.getPathVariableManager().resolveURI(localLocation); >+ URI resolved; >+ if (parent.getProject() != null) >+ resolved = parent.getProject().getPathVariableManager().resolveURI(localLocation); >+ else >+ resolved = workspace.getPathVariableManager().resolveURI(localLocation); > IFileStore store = EFS.getStore(resolved); > IFileInfo fileInfo = store.fetchInfo(); > boolean localExists = fileInfo.exists(); >@@ -1799,4 +1806,69 @@ > break; > } > } >+ >+ /* >+ * (non-Javadoc) >+ * >+ * @see IResource#setLinkLocation(IPath) >+ */ >+ public void setLinkLocation(URI location, int updateFlags, >+ IProgressMonitor monitor) throws CoreException { >+ if (!isLinked()) { >+ String message = NLS.bind(Messages.links_resourceIsNotALink, getFullPath()); >+ throw new ResourceException(IResourceStatus.INVALID_VALUE, getFullPath(), message, null); >+ } >+ >+ final ISchedulingRule rule = workspace.getRuleFactory().modifyRule(this); >+ try { >+ String message = NLS.bind(Messages.links_setLocation, getFullPath()); >+ monitor.beginTask(message, Policy.totalWork); >+ >+ workspace.prepareOperation(rule, monitor); >+ workspace.beginOperation(true); >+ >+ LinkDescription linkDescription; >+ linkDescription = new LinkDescription(this, location); >+ Project project = (Project) getProject(); >+ project.internalGetDescription().setLinkLocation(getProjectRelativePath(), linkDescription); >+ project.writeDescription(updateFlags); >+ >+ ResourceInfo info = workspace.getResourceInfo(getFullPath(), true, false); >+ getLocalManager().setLocation(this, info, location); >+ } finally { >+ workspace.endOperation(rule, true, Policy.subMonitorFor(monitor, Policy.endOpWork)); >+ } >+ >+ final ISchedulingRule rule2 = workspace.getRuleFactory().refreshRule(this); >+ try { >+ workspace.prepareOperation(rule2, monitor); >+ workspace.beginOperation(true); >+ // refresh either in background or foreground >+ if ((updateFlags & IResource.BACKGROUND_REFRESH) != 0) { >+ workspace.refreshManager.refresh(this); >+ monitor.worked(Policy.opWork * 90 / 100); >+ } else { >+ refreshLocal(DEPTH_INFINITE, Policy.subMonitorFor(monitor, Policy.opWork * 90 / 100)); >+ } >+ } finally { >+ workspace.endOperation(rule2, true, Policy.subMonitorFor(monitor, Policy.endOpWork)); >+ monitor.done(); >+ } >+ } >+ >+ /* >+ * (non-Javadoc) >+ * >+ * @see IResource#setLinkLocation(URI) >+ */ >+ public void setLinkLocation(IPath location, int updateFlags, IProgressMonitor monitor) throws CoreException { >+ if (location.isAbsolute()) >+ setLinkLocation(URIUtil.toURI(location.toPortableString()), updateFlags, monitor); >+ else >+ try { >+ setLinkLocation(new URI(null, null, location.toPortableString(), null), updateFlags, monitor); >+ } catch (URISyntaxException e) { >+ setLinkLocation(URIUtil.toURI(location.toPortableString()), updateFlags, monitor); >+ } >+ } > } >Index: src/org/eclipse/core/internal/resources/ResourceTree.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/ResourceTree.java,v >retrieving revision 1.76 >diff -u -r1.76 ResourceTree.java >--- src/org/eclipse/core/internal/resources/ResourceTree.java 10 Dec 2007 18:44:00 -0000 1.76 >+++ src/org/eclipse/core/internal/resources/ResourceTree.java 11 Sep 2008 12:30:26 -0000 >@@ -692,6 +692,8 @@ > try { > //moving linked resources may have modified the description in memory > ((ProjectDescription) destDescription).setLinkDescriptions(destination.internalGetDescription().getLinks()); >+ // moving variables may have modified the description in memory >+ ((ProjectDescription) destDescription).setVariableDescriptions(destination.internalGetDescription().getVariables()); > destination.internalSetDescription(destDescription, true); > destination.writeDescription(IResource.FORCE); > } catch (CoreException e) { >Index: src/org/eclipse/core/internal/localstore/FileSystemResourceManager.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/FileSystemResourceManager.java,v >retrieving revision 1.113 >diff -u -r1.113 FileSystemResourceManager.java >--- src/org/eclipse/core/internal/localstore/FileSystemResourceManager.java 2 Sep 2008 17:14:15 -0000 1.113 >+++ src/org/eclipse/core/internal/localstore/FileSystemResourceManager.java 11 Sep 2008 12:30:20 -0000 >@@ -58,7 +58,6 @@ > results.add(Path.ROOT); > return results; > } >- IPathVariableManager varMan = workspace.getPathVariableManager(); > IProject[] projects = root.getProjects(); > for (int i = 0; i < projects.length; i++) { > IProject project = projects[i]; >@@ -84,7 +83,7 @@ > continue; > for (Iterator it = links.values().iterator(); it.hasNext();) { > LinkDescription link = (LinkDescription) it.next(); >- testLocation = varMan.resolveURI(link.getLocationURI()); >+ testLocation = project.getPathVariableManager().resolveURI(link.getLocationURI()); > // if we are looking for file: locations try to get a file: location for this link > if (isFileLocation && !EFS.SCHEME_FILE.equals(testLocation.getScheme())) > testLocation = getFileURI(testLocation); >Index: src/org/eclipse/core/internal/localstore/FileStoreRoot.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/FileStoreRoot.java,v >retrieving revision 1.16 >diff -u -r1.16 FileStoreRoot.java >--- src/org/eclipse/core/internal/localstore/FileStoreRoot.java 25 Sep 2006 21:46:18 -0000 1.16 >+++ src/org/eclipse/core/internal/localstore/FileStoreRoot.java 11 Sep 2008 12:30:20 -0000 >@@ -10,6 +10,12 @@ > *******************************************************************************/ > package org.eclipse.core.internal.localstore; > >+import org.eclipse.core.resources.IProject; >+ >+import org.eclipse.core.resources.IResource; >+ >+import org.eclipse.core.resources.IWorkspaceRoot; >+ > import java.io.File; > import java.net.URI; > import org.eclipse.core.filesystem.EFS; >@@ -39,8 +45,6 @@ > > private URI root; > >- private final IPathVariableManager variableManager; >- > /** > * Defines the root of a file system within the workspace tree. > * @param rootURI The virtual file representing the root of the file >@@ -51,12 +55,25 @@ > FileStoreRoot(URI rootURI, IPath workspacePath) { > Assert.isNotNull(rootURI); > Assert.isNotNull(workspacePath); >- this.variableManager = ResourcesPlugin.getWorkspace().getPathVariableManager(); > this.root = rootURI; > this.chop = workspacePath.segmentCount(); > this.localRoot = toLocalPath(root); > } > >+ private IPathVariableManager getManager(IPath workspacePath) { >+ if (workspacePath.segmentCount() > 0) { >+ IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace() >+ .getRoot(); >+ if (workspacePath.segmentCount() > 1) >+ workspacePath = workspacePath.removeLastSegments(workspacePath >+ .segmentCount() - 1); >+ IResource resource = workspaceRoot.findMember(workspacePath); >+ if (resource != null && resource.getType() == IResource.PROJECT) >+ return ((IProject) resource).getPathVariableManager(); >+ } >+ return ResourcesPlugin.getWorkspace().getPathVariableManager(); >+ } >+ > /** > * Returns the resolved, absolute file system location of the resource > * corresponding to the given workspace path, or null if none could >@@ -64,7 +81,7 @@ > */ > public URI computeURI(IPath workspacePath) { > IPath childPath = workspacePath.removeFirstSegments(chop); >- final URI rootURI = variableManager.resolveURI(root); >+ final URI rootURI = getManager(workspacePath).resolveURI(root); > if (childPath.segmentCount() == 0) > return rootURI; > try { >@@ -81,7 +98,7 @@ > IFileStore createStore(IPath workspacePath) throws CoreException { > IPath childPath = workspacePath.removeFirstSegments(chop); > IFileStore rootStore; >- final URI uri = variableManager.resolveURI(root); >+ final URI uri = getManager(workspacePath).resolveURI(root); > if (!uri.isAbsolute()) { > //handles case where resource location cannot be resolved > //such as unresolved path variable or invalid file system scheme >@@ -105,7 +122,7 @@ > location = localRoot; > else > location = localRoot.append(workspacePath.removeFirstSegments(chop)); >- location = variableManager.resolvePath(location); >+ location = getManager(workspacePath).resolvePath(location); > //if path is still relative then path variable could not be resolved > if (!location.isAbsolute()) > return null; >Index: src/org/eclipse/core/internal/utils/messages.properties >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/messages.properties,v >retrieving revision 1.127 >diff -u -r1.127 messages.properties >--- src/org/eclipse/core/internal/utils/messages.properties 29 Apr 2008 16:57:09 -0000 1.127 >+++ src/org/eclipse/core/internal/utils/messages.properties 11 Sep 2008 12:30:28 -0000 >@@ -52,6 +52,8 @@ > links_vetoNature = Cannot add nature because project ''{0}'' contains linked resources, and nature ''{1}'' does not allow it. > links_workspaceVeto = Linked resources are not supported by this application. > links_wrongLocalType = Cannot create linked resource ''{0}''. Files cannot be linked to folders. >+links_resourceIsNotALink=Resource ''{0}'' must be a linked resource to change its linked location. >+links_setLocation=Changing link location. > > ### local store > localstore_copying = Copying ''{0}''. >@@ -117,6 +119,8 @@ > projRead_notProjectDescription = Encountered element name ''{0}'' instead of \"project\" when trying to read a project description file. > projRead_failureReadingProjectDesc = Failure occurred reading .project file. > >+projRead_emptyVariableName = Empty variable name detected in project "{0}\". >+ > properties_qualifierIsNull = Qualifier part of property key cannot be null. > properties_readProperties = Failure while reading persistent properties for resource ''{0}'', file was corrupt. Some properties may have been lost. > properties_valueTooLong = Could not set property: {0} {1}. Value is too long. >@@ -265,6 +269,8 @@ > > synchronizer_partnerNotRegistered = Sync partner: {0} not registered with the synchronizer. > >+parentVariableProvider_noVariableSpecified=< Specify a variable using the syntax "${PARENT-COUNT-MyVariable}" where COUNT is a digit larger than 0 > >+ > ### URL > url_badVariant = Unsupported \"platform:\" protocol variation {0}. > url_couldNotResolve = Project ''{0}'' does not exist. Could not resolve URL: {1}. >Index: src/org/eclipse/core/internal/utils/Messages.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/Messages.java,v >retrieving revision 1.34 >diff -u -r1.34 Messages.java >--- src/org/eclipse/core/internal/utils/Messages.java 29 Apr 2008 16:57:09 -0000 1.34 >+++ src/org/eclipse/core/internal/utils/Messages.java 11 Sep 2008 12:30:28 -0000 >@@ -57,6 +57,8 @@ > public static String links_vetoNature; > public static String links_workspaceVeto; > public static String links_wrongLocalType; >+ public static String links_resourceIsNotALink; >+ public static String links_setLocation; > > // local store > public static String localstore_copying; >@@ -121,6 +123,8 @@ > public static String projRead_whichKey; > public static String projRead_whichValue; > >+ public static String projRead_emptyVariableName; >+ > public static String properties_couldNotClose; > public static String properties_qualifierIsNull; > public static String properties_readProperties; >@@ -269,6 +273,8 @@ > > public static String synchronizer_partnerNotRegistered; > >+ public static String parentVariableProvider_noVariableSpecified; >+ > // URL > public static String url_badVariant; > public static String url_couldNotResolve; >Index: src/org/eclipse/core/internal/refresh/MonitorManager.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/internal/refresh/MonitorManager.java,v >retrieving revision 1.26 >diff -u -r1.26 MonitorManager.java >--- src/org/eclipse/core/internal/refresh/MonitorManager.java 3 Jun 2008 12:34:52 -0000 1.26 >+++ src/org/eclipse/core/internal/refresh/MonitorManager.java 11 Sep 2008 12:30:20 -0000 >@@ -114,7 +114,11 @@ > case LifecycleEvent.PRE_PROJECT_CLOSE: > case LifecycleEvent.PRE_PROJECT_DELETE: > unmonitor(event.resource); >+ if (event.resource.getType() == IResource.PROJECT) >+ ((IProject) event.resource).getPathVariableManager().removeChangeListener(this); > break; >+ case LifecycleEvent.PRE_PROJECT_OPEN: >+ ((IProject) event.resource).getPathVariableManager().addChangeListener(this); > } > } > >Index: src/org/eclipse/core/internal/resources/ProjectPathVariableManager.java >=================================================================== >RCS file: src/org/eclipse/core/internal/resources/ProjectPathVariableManager.java >diff -N src/org/eclipse/core/internal/resources/ProjectPathVariableManager.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/resources/ProjectPathVariableManager.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,469 @@ >+/******************************************************************************* >+ * Copyright (c) 2008 IBM Corporation 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: >+ * IBM Corporation - initial API and implementation >+ *******************************************************************************/ >+package org.eclipse.core.internal.resources; >+ >+import java.net.URI; >+import java.util.*; >+import org.eclipse.core.filesystem.URIUtil; >+import org.eclipse.core.internal.events.PathVariableChangeEvent; >+import org.eclipse.core.internal.utils.*; >+import org.eclipse.core.resources.*; >+import org.eclipse.core.runtime.*; >+import org.eclipse.core.runtime.jobs.ISchedulingRule; >+import org.eclipse.osgi.util.NLS; >+ >+/** >+ * >+ */ >+public class ProjectPathVariableManager implements IPathVariableManager, >+ IManager { >+ >+ private Set listeners; >+ >+ private Project project; >+ private ProjectVariableProviderManager.Descriptor variableProviders[] = null; >+ >+ /** >+ * Constructor for the class. >+ */ >+ public ProjectPathVariableManager(Project project) { >+ this.listeners = Collections.synchronizedSet(new HashSet()); >+ this.project = project; >+ variableProviders = ProjectVariableProviderManager.getDefault() >+ .getDescriptors(); >+ } >+ >+ /** >+ * @see org.eclipse.core.resources. >+ * IPathVariableManager#addChangeListener(IPathVariableChangeListener) >+ */ >+ public void addChangeListener(IPathVariableChangeListener listener) { >+ listeners.add(listener); >+ } >+ >+ PathVariableManager getWorkspaceManager() { >+ return (PathVariableManager) project.getWorkspace() >+ .getPathVariableManager(); >+ } >+ >+ /** >+ * Throws a runtime exception if the given name is not valid as a path >+ * variable name. >+ */ >+ private void checkIsValidName(String name) throws CoreException { >+ IStatus status = validateName(name); >+ if (!status.isOK()) >+ throw new CoreException(status); >+ } >+ >+ /** >+ * Throws an exception if the given path is not valid as a path variable >+ * value. >+ */ >+ private void checkIsValidValue(IPath newValue) throws CoreException { >+ IStatus status = validateValue(newValue); >+ if (!status.isOK()) >+ throw new CoreException(status); >+ } >+ >+ /** >+ * Fires a property change event corresponding to a change to the current >+ * value of the variable with the given name. >+ * >+ * @param name >+ * the name of the variable, to be used as the variable in the >+ * event object >+ * @param value >+ * the current value of the path variable or <code>null</code> >+ * if the variable was deleted >+ * @param type >+ * one of <code>IPathVariableChangeEvent.VARIABLE_CREATED</code>, >+ * <code>IPathVariableChangeEvent.VARIABLE_CHANGED</code>, or >+ * <code>IPathVariableChangeEvent.VARIABLE_DELETED</code> >+ * @see IPathVariableChangeEvent >+ * @see IPathVariableChangeEvent#VARIABLE_CREATED >+ * @see IPathVariableChangeEvent#VARIABLE_CHANGED >+ * @see IPathVariableChangeEvent#VARIABLE_DELETED >+ */ >+ private void fireVariableChangeEvent(String name, IPath value, int type) { >+ if (this.listeners.size() == 0) >+ return; >+ // use a separate collection to avoid interference of simultaneous >+ // additions/removals >+ Object[] listenerArray = this.listeners.toArray(); >+ final PathVariableChangeEvent pve = new PathVariableChangeEvent(this, >+ name, value, type); >+ for (int i = 0; i < listenerArray.length; ++i) { >+ final IPathVariableChangeListener l = (IPathVariableChangeListener) listenerArray[i]; >+ ISafeRunnable job = new ISafeRunnable() { >+ public void handleException(Throwable exception) { >+ // already being logged in SafeRunner#run() >+ } >+ >+ public void run() throws Exception { >+ l.pathVariableChanged(pve); >+ } >+ }; >+ SafeRunner.run(job); >+ } >+ } >+ >+ /** >+ * @see org.eclipse.core.resources.IPathVariableManager#getPathVariableNames() >+ */ >+ public String[] getPathVariableNames() { >+ List result = new LinkedList(); >+ HashMap map; >+ try { >+ map = ((ProjectDescription) project.getDescription()) >+ .getVariables(); >+ } catch (CoreException e) { >+ return new String[0]; >+ } >+ for (int i = 0; i < variableProviders.length; i++) { >+ result.add(variableProviders[i].getName()); >+ } >+ if (map != null) >+ result.addAll(map.keySet()); >+ result.addAll(Arrays.asList(getWorkspaceManager() >+ .getPathVariableNames())); >+ return (String[]) result.toArray(new String[0]); >+ } >+ >+ /** >+ * If the variable is not listed in the project description, we fall back on >+ * the workspace variables. >+ * >+ * @see org.eclipse.core.resources.IPathVariableManager#getValue(String) >+ */ >+ public IPath getValue(String varName) { >+ String value = internalGetValue(varName); >+ if (value != null) { >+ if (value.indexOf("..") != -1) { //$NON-NLS-1$ >+ // if the path is 'reducible', lets resolve it first. >+ int index = value.indexOf(Path.SEPARATOR); >+ if (index > 0) { // if its the first character, its an >+ // absolute path on unix, so we don't >+ // resolve it >+ IPath resolved = resolveVariable(value); >+ if (resolved != null) >+ return resolved; >+ } >+ } >+ return Path.fromPortableString(value); >+ } >+ return getWorkspaceManager().getValue(varName); >+ } >+ >+ public String internalGetValue(String varName) { >+ HashMap map; >+ try { >+ map = ((ProjectDescription) project.getDescription()) >+ .getVariables(); >+ } catch (CoreException e) { >+ return null; >+ } >+ if (map != null && map.containsKey(varName)) >+ return ((VariableDescription) map.get(varName)).getValue(); >+ >+ String name; >+ int index = varName.indexOf('-'); >+ if (index != -1) >+ name = varName.substring(0, index); >+ else >+ name = varName; >+ for (int i = 0; i < variableProviders.length; i++) { >+ if (variableProviders[i].getName().equals(name)) >+ return variableProviders[i].getValue(varName, project); >+ } >+ return null; >+ } >+ >+ /** >+ * @see org.eclipse.core.resources.IPathVariableManager#isDefined(String) >+ */ >+ public boolean isDefined(String varName) { >+ return getValue(varName) != null; >+ } >+ >+ /** >+ * @see org.eclipse.core.resources. >+ * IPathVariableManager#removeChangeListener(IPathVariableChangeListener) >+ */ >+ public void removeChangeListener(IPathVariableChangeListener listener) { >+ listeners.remove(listener); >+ } >+ >+ /** >+ * @see org.eclipse.core.resources.IPathVariableManager#resolvePath(IPath) >+ */ >+ public IPath resolvePath(IPath path) { >+ if (path == null || path.segmentCount() == 0 || path.isAbsolute() >+ || path.getDevice() != null) >+ return path; >+ IPath value = resolveVariable(path.segment(0)); >+ return value == null ? path : value.append(path.removeFirstSegments(1)); >+ } >+ >+ public IPath resolveVariable(String variable) { >+ LinkedList variableStack = new LinkedList(); >+ >+ String value = resolveVariable(variable, variableStack); >+ if (value != null) >+ return Path.fromPortableString(value); >+ return null; >+ } >+ >+ /* >+ * Splits a value (returned by this.getValue(variable) in an array of >+ * string, where the array is divided between the value content and the >+ * value variables. >+ * >+ * For example, if the value is "${ECLIPSE_HOME}/plugins", the value >+ * returned will be {"${ECLIPSE_HOME}" "/plugins"} >+ */ >+ static public String[] splitVariablesAndContent(String value) { >+ LinkedList result = new LinkedList(); >+ while (true) { >+ // we check if the value contains referenced variables with ${VAR} >+ int index = value.indexOf("${"); //$NON-NLS-1$ >+ if (index != -1) { >+ int endIndex = getMatchingBrace(value, index); >+ if (index > 0) >+ result.add(value.substring(0, index)); >+ result.add(value.substring(index, endIndex + 1)); >+ value = value.substring(endIndex + 1); >+ } else >+ break; >+ } >+ if (value.length() > 0) >+ result.add(value); >+ return (String[]) result.toArray(new String[0]); >+ } >+ >+ /* >+ * Extracts the variable name from a variable segment. >+ * >+ * For example, if the value is "${ECLIPSE_HOME}", the value returned will >+ * be "ECLIPSE_HOME". If the segment doesn't contain any variable, the value >+ * returned will be "". >+ */ >+ static public String extractVariable(String segment) { >+ int index = segment.indexOf("${"); //$NON-NLS-1$ >+ if (index != -1) { >+ int endIndex = getMatchingBrace(segment, index); >+ return segment.substring(index + 2, endIndex); >+ } >+ return ""; //$NON-NLS-1$ >+ } >+ >+ public String resolveVariable(String value, LinkedList variableStack) { >+ if (variableStack == null) >+ variableStack = new LinkedList(); >+ >+ String tmp = internalGetValue(value); >+ if (tmp == null) { >+ IPath result = getWorkspaceManager().getValue(value); >+ if (result != null) >+ return result.toPortableString(); >+ } else >+ value = tmp; >+ >+ while (true) { >+ // we check if the value contains referenced variables with ${VAR} >+ int index = value.indexOf("${"); //$NON-NLS-1$ >+ if (index != -1) { >+ int endIndex = getMatchingBrace(value, index); >+ String macro = value.substring(index + 2, endIndex); >+ String resolvedMacro = ""; //$NON-NLS-1$ >+ if (!variableStack.contains(macro)) { >+ variableStack.add(macro); >+ resolvedMacro = resolveVariable(macro, variableStack); >+ if (resolvedMacro == null) >+ resolvedMacro = ""; //$NON-NLS-1$ >+ } >+ if (value.length() > endIndex) >+ value = value.substring(0, index) + resolvedMacro >+ + value.substring(endIndex + 1); >+ else >+ value = resolvedMacro; >+ } else >+ break; >+ } >+ return value; >+ } >+ >+ // getMatchingBrace("${FOO}/something") returns 5 >+ // getMatchingBrace("${${OTHER}}/something") returns 10 >+ // getMatchingBrace("${FOO") returns 5 >+ static int getMatchingBrace(String value, int index) { >+ int scope = 0; >+ for (int i = index + 1; i < value.length(); i++) { >+ char c = value.charAt(i); >+ if (c == '}') { >+ if (scope == 0) >+ return i; >+ scope--; >+ } >+ if (c == '$') { >+ if ((i + 1 < value.length()) && (value.charAt(i + 1) == '{')) >+ scope++; >+ } >+ } >+ return value.length(); >+ } >+ >+ public URI resolveURI(URI uri) { >+ if (uri == null || uri.isAbsolute()) >+ return uri; >+ IPath raw = new Path(uri.getSchemeSpecificPart()); >+ IPath resolved = resolvePath(raw); >+ return raw == resolved ? uri : URIUtil.toURI(resolved); >+ } >+ >+ /** >+ * @see org.eclipse.core.resources.IPathVariableManager#setValue(String, >+ * IPath) >+ */ >+ public void setValue(String varName, IPath newValue) throws CoreException { >+ checkIsValidName(varName); >+ // if the location doesn't have a device, see if the OS will assign one >+ if (newValue != null && newValue.isAbsolute() >+ && newValue.getDevice() == null) >+ newValue = new Path(newValue.toFile().getAbsolutePath()); >+ checkIsValidValue(newValue); >+ int eventType = 0; >+ // read previous value and set new value atomically in order to generate >+ // the right event >+ boolean changeWorkspaceValue = false; >+ synchronized (this) { >+ String value = internalGetValue(varName); >+ IPath currentValue = null; >+ if (value == null) >+ currentValue = getWorkspaceManager().getValue(varName); >+ else >+ currentValue = Path.fromPortableString(value); >+ boolean variableExists = currentValue != null; >+ if (!variableExists && newValue == null) >+ return; >+ if (variableExists && currentValue.equals(newValue)) >+ return; >+ >+ for (int i = 0; i < variableProviders.length; i++) { >+ if (variableProviders[i].getName().equals(varName)) >+ return; >+ } >+ >+ if (value == null && variableExists) >+ changeWorkspaceValue = true; >+ else { >+ IProgressMonitor monitor = new NullProgressMonitor(); >+ final ISchedulingRule rule = project; // project.workspace.getRuleFactory().modifyRule(project); >+ try { >+ project.workspace.prepareOperation(rule, monitor); >+ project.workspace.beginOperation(true); >+ // save the location in the project description >+ ProjectDescription description = project >+ .internalGetDescription(); >+ if (newValue == null) { >+ description.setVariableDescription(varName, null); >+ eventType = IPathVariableChangeEvent.VARIABLE_DELETED; >+ } else { >+ description.setVariableDescription(varName, >+ new VariableDescription(varName, newValue >+ .toPortableString())); >+ eventType = variableExists ? IPathVariableChangeEvent.VARIABLE_CHANGED >+ : IPathVariableChangeEvent.VARIABLE_CREATED; >+ } >+ project.writeDescription(IResource.NONE); >+ } finally { >+ project.workspace.endOperation(rule, true, Policy >+ .subMonitorFor(monitor, Policy.endOpWork)); >+ } >+ } >+ } >+ if (!changeWorkspaceValue) { >+ // notify listeners from outside the synchronized block to avoid >+ // deadlocks >+ fireVariableChangeEvent(varName, newValue, eventType); >+ } else >+ getWorkspaceManager().setValue(varName, newValue); >+ } >+ >+ /** >+ * @see org.eclipse.core.internal.resources.IManager#shutdown(IProgressMonitor) >+ */ >+ public void shutdown(IProgressMonitor monitor) { >+ // nothing to do here >+ } >+ >+ /** >+ * @see org.eclipse.core.internal.resources.IManager#startup(IProgressMonitor) >+ */ >+ public void startup(IProgressMonitor monitor) { >+ // nothing to do here >+ } >+ >+ /** >+ * @see org.eclipse.core.resources.IPathVariableManager#validateName(String) >+ */ >+ public IStatus validateName(String name) { >+ String message = null; >+ if (name.length() == 0) { >+ message = Messages.pathvar_length; >+ return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, >+ message); >+ } >+ >+ char first = name.charAt(0); >+ if (!Character.isLetter(first) && first != '_') { >+ message = NLS.bind(Messages.pathvar_beginLetter, String >+ .valueOf(first)); >+ return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, >+ message); >+ } >+ >+ for (int i = 1; i < name.length(); i++) { >+ char following = name.charAt(i); >+ if (Character.isWhitespace(following)) >+ return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, >+ Messages.pathvar_whitespace); >+ if (!Character.isLetter(following) && !Character.isDigit(following) >+ && following != '_') { >+ message = NLS.bind(Messages.pathvar_invalidChar, String >+ .valueOf(following)); >+ return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, >+ message); >+ } >+ } >+ // check >+ >+ return Status.OK_STATUS; >+ } >+ >+ /** >+ * @see IPathVariableManager#validateValue(IPath) >+ */ >+ public IStatus validateValue(IPath value) { >+ // accept any format >+ return Status.OK_STATUS; >+ } >+ >+ >+ /** >+ * @throws CoreException >+ * @see IPathVariableManager#convertToRelative(IPath, boolean, String) >+ */ >+ public IPath convertToRelative(IPath path, boolean force, String variableHint) throws CoreException { >+ return PathVariableUtil.convertToRelative(this, path, force, variableHint); >+ } >+ >+} >Index: src/org/eclipse/core/internal/resources/projectVariables/ProjectLocationProjectVariable.java >=================================================================== >RCS file: src/org/eclipse/core/internal/resources/projectVariables/ProjectLocationProjectVariable.java >diff -N src/org/eclipse/core/internal/resources/projectVariables/ProjectLocationProjectVariable.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/resources/projectVariables/ProjectLocationProjectVariable.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,33 @@ >+/******************************************************************************* >+ * Copyright (c) 2008 IBM Corporation 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: >+ * IBM Corporation - initial API and implementation >+ *******************************************************************************/ >+package org.eclipse.core.internal.resources.projectVariables; >+ >+import org.eclipse.core.resources.IProject; >+import org.eclipse.core.resources.IProjectVariableProvider; >+ >+/** >+ * >+ */ >+public class ProjectLocationProjectVariable implements IProjectVariableProvider { >+ >+ public ProjectLocationProjectVariable() { >+ // nothing >+ } >+ >+ public String getValue(String variable, IProject project) { >+ return project.getLocation().toPortableString(); >+ } >+ >+ public Object[] getExtensions(String variable, IProject project) { >+ return null; >+ } >+ >+} >Index: src/org/eclipse/core/internal/resources/projectVariables/ParentVariableProvider.java >=================================================================== >RCS file: src/org/eclipse/core/internal/resources/projectVariables/ParentVariableProvider.java >diff -N src/org/eclipse/core/internal/resources/projectVariables/ParentVariableProvider.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/resources/projectVariables/ParentVariableProvider.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,63 @@ >+package org.eclipse.core.internal.resources.projectVariables; >+ >+import java.util.*; >+import org.eclipse.core.internal.utils.Messages; >+import org.eclipse.core.resources.IProject; >+import org.eclipse.core.resources.IProjectVariableProvider; >+import org.eclipse.core.runtime.IPath; >+ >+/** >+ * Path Variable representing the parent directory of the variable provided >+ * in argument, following the syntax: >+ * >+ * "${PARENT-COUNT-MyVariable}" >+ * >+ */ >+public class ParentVariableProvider implements IProjectVariableProvider { >+ >+ public ParentVariableProvider() { >+ // nothing >+ } >+ >+ public Object[] getExtensions(String variable, IProject project) { >+ LinkedList result = new LinkedList(); >+ Iterator it = Arrays.asList(project.getPathVariableManager().getPathVariableNames()).iterator(); >+ while(it.hasNext()) { >+ String value = (String) it.next(); >+ if (!value.equals("PARENT")) //$NON-NLS-1$ >+ result.add("1-" + value); //$NON-NLS-1$ >+ } >+ return result.toArray(); >+ } >+ >+ public String getValue(String variable, IProject project) { >+ int index = variable.indexOf('-'); >+ if (index == -1 || index == (variable.length() -1)) >+ return Messages.parentVariableProvider_noVariableSpecified; >+ >+ String countRemaining = variable.substring(index + 1); >+ index = countRemaining.indexOf('-'); >+ if (index == -1 || index == (variable.length() -1)) >+ return Messages.parentVariableProvider_noVariableSpecified; >+ >+ String countString = countRemaining.substring(0, index); >+ int count = 0; >+ try { >+ count = Integer.parseInt(countString); >+ if (count < 0) >+ return Messages.parentVariableProvider_noVariableSpecified; >+ }catch (NumberFormatException e) { >+ return Messages.parentVariableProvider_noVariableSpecified; >+ } >+ String argument = countRemaining.substring(index + 1); >+ >+ IPath value = project.getPathVariableManager().getValue(argument); >+ if (value == null) >+ return ""; //$NON-NLS-1$ >+ value = project.getPathVariableManager().resolvePath(value); >+ value = value.removeLastSegments(count); >+ >+ return value.toPortableString(); >+ } >+ >+} >Index: src/org/eclipse/core/internal/resources/projectVariables/EclipseHomeProjectVariable.java >=================================================================== >RCS file: src/org/eclipse/core/internal/resources/projectVariables/EclipseHomeProjectVariable.java >diff -N src/org/eclipse/core/internal/resources/projectVariables/EclipseHomeProjectVariable.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/resources/projectVariables/EclipseHomeProjectVariable.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,38 @@ >+/******************************************************************************* >+ * Copyright (c) 2008 IBM Corporation 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: >+ * IBM Corporation - initial API and implementation >+ *******************************************************************************/ >+package org.eclipse.core.internal.resources.projectVariables; >+ >+import java.net.URL; >+import org.eclipse.core.resources.IProject; >+import org.eclipse.core.resources.IProjectVariableProvider; >+import org.eclipse.core.runtime.*; >+ >+/** >+ * ECLIPSE_HOME project variable, pointing to the location of the eclipse home >+ * >+ */ >+public class EclipseHomeProjectVariable implements IProjectVariableProvider { >+ >+ public EclipseHomeProjectVariable() { >+ // nothing to do. >+ } >+ >+ public String getValue(String variable, IProject project) { >+ URL installURL = Platform.getInstallLocation().getURL(); >+ IPath ppath = new Path(installURL.getFile()).removeTrailingSeparator(); >+ return ppath.toPortableString(); >+ } >+ >+ public Object[] getExtensions(String variable, IProject project) { >+ return null; >+ } >+ >+} >Index: src/org/eclipse/core/internal/resources/VariableDescription.java >=================================================================== >RCS file: src/org/eclipse/core/internal/resources/VariableDescription.java >diff -N src/org/eclipse/core/internal/resources/VariableDescription.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/resources/VariableDescription.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,71 @@ >+/******************************************************************************* >+ * Copyright (c) 2008 IBM Corporation 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: >+ * IBM Corporation - initial API and implementation >+ *******************************************************************************/ >+package org.eclipse.core.internal.resources; >+ >+import org.eclipse.core.runtime.*; >+ >+/** >+ * >+ */ >+public class VariableDescription implements Comparable { >+ >+ private String name; >+ private String value; >+ >+ public VariableDescription() { >+ this.name = ""; //$NON-NLS-1$ >+ this.value = ""; //$NON-NLS-1$ >+ } >+ >+ public VariableDescription(String name, String value) { >+ super(); >+ Assert.isNotNull(name); >+ Assert.isNotNull(value); >+ this.name = name; >+ this.value = value; >+ } >+ >+ public boolean equals(Object o) { >+ if (!(o.getClass() == VariableDescription.class)) >+ return false; >+ VariableDescription other = (VariableDescription) o; >+ return name.equals(other.name) && value == other.value; >+ } >+ >+ public String getName() { >+ return name; >+ } >+ >+ public String getValue() { >+ return value; >+ } >+ >+ public int hashCode() { >+ return name.hashCode() + value.hashCode(); >+ } >+ >+ public void setName(String name) { >+ this.name = name; >+ } >+ >+ public void setValue(String value) { >+ this.value = value; >+ } >+ >+ /** >+ * Compare string descriptions in a way that sorts them topologically by >+ * name. >+ */ >+ public int compareTo(Object o) { >+ VariableDescription that = (VariableDescription) o; >+ return name.compareTo(that.name); >+ } >+} >Index: schema/variableProviders.exsd >=================================================================== >RCS file: schema/variableProviders.exsd >diff -N schema/variableProviders.exsd >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ schema/variableProviders.exsd 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,126 @@ >+<?xml version='1.0' encoding='UTF-8'?> >+<!-- Schema file written by PDE --> >+<schema targetNamespace="org.eclipse.core.resources" xmlns="http://www.w3.org/2001/XMLSchema"> >+<annotation> >+ <appinfo> >+ <meta.schema plugin="org.eclipse.core.resources" id="variableProviders" name="variable Providers"/> >+ </appinfo> >+ <documentation> >+ A variable provider provides additional projects variables that can be used to specify the location of a linked resource. >+ </documentation> >+ </annotation> >+ >+ <include schemaLocation="schema://org.eclipse.core.expressions/schema/expressionLanguage.exsd"/> >+ >+ <element name="extension"> >+ <annotation> >+ <appinfo> >+ <meta.element /> >+ </appinfo> >+ </annotation> >+ <complexType> >+ <sequence> >+ <element ref="variableProvider" minOccurs="1" maxOccurs="unbounded"/> >+ </sequence> >+ <attribute name="point" type="string" use="required"> >+ <annotation> >+ <documentation> >+ >+ </documentation> >+ </annotation> >+ </attribute> >+ <attribute name="id" type="string"> >+ <annotation> >+ <documentation> >+ >+ </documentation> >+ </annotation> >+ </attribute> >+ <attribute name="name" type="string"> >+ <annotation> >+ <documentation> >+ >+ </documentation> >+ <appinfo> >+ <meta.attribute translatable="true"/> >+ </appinfo> >+ </annotation> >+ </attribute> >+ </complexType> >+ </element> >+ >+ <element name="variableProvider"> >+ <complexType> >+ <attribute name="class" type="string"> >+ <annotation> >+ <documentation> >+ A class providing dynamically the value of the variable. >+ </documentation> >+ <appinfo> >+ <meta.attribute kind="java" basedOn=":org.eclipse.core.resources.IProjectVariableProvider"/> >+ </appinfo> >+ </annotation> >+ </attribute> >+ <attribute name="value" type="string"> >+ <annotation> >+ <documentation> >+ The value of the variable, either as refering another variable or an absolute path. >+ </documentation> >+ </annotation> >+ </attribute> >+ <attribute name="name" type="string" use="required"> >+ <annotation> >+ <documentation> >+ The name of the variable. >+ </documentation> >+ </annotation> >+ </attribute> >+ </complexType> >+ </element> >+ >+ <annotation> >+ <appinfo> >+ <meta.section type="since"/> >+ </appinfo> >+ <documentation> >+ 3.5 (Freescale) >+ </documentation> >+ </annotation> >+ >+ <annotation> >+ <appinfo> >+ <meta.section type="apiInfo"/> >+ </appinfo> >+ <documentation> >+ The value of the class attribute must represent an implementation of <tt>org.eclipse.core.resources.mapping.variableProvider</tt>. >+ </documentation> >+ </annotation> >+ >+ >+ <annotation> >+ <appinfo> >+ <meta.section type="implementation"/> >+ </appinfo> >+ <documentation> >+ The platform itself does not have any predefined >+variable providers. Particular product installs may include >+variable providers as required. >+ </documentation> >+ </annotation> >+ >+ <annotation> >+ <appinfo> >+ <meta.section type="copyright"/> >+ </appinfo> >+ <documentation> >+ Copyright (c) 2007 Freescame Semiconductor and others.<br> >+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 >+<a >+href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> >+ </documentation> >+ </annotation> >+ >+</schema> >Index: src/org/eclipse/core/resources/ProjectVariableProviderManager.java >=================================================================== >RCS file: src/org/eclipse/core/resources/ProjectVariableProviderManager.java >diff -N src/org/eclipse/core/resources/ProjectVariableProviderManager.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/resources/ProjectVariableProviderManager.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,118 @@ >+/******************************************************************************* >+ * Copyright (c) 2008 IBM Corporation 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: >+ * IBM Corporation - initial API and implementation >+ *******************************************************************************/ >+package org.eclipse.core.resources; >+ >+import java.util.*; >+import org.eclipse.core.internal.resources.ResourceException; >+import org.eclipse.core.internal.utils.Messages; >+import org.eclipse.core.internal.utils.Policy; >+import org.eclipse.core.runtime.*; >+import org.eclipse.osgi.util.NLS; >+ >+/** >+ * >+ */ >+public class ProjectVariableProviderManager { >+ >+ public static class Descriptor { >+ IProjectVariableProvider provider = null; >+ String name = null; >+ String value = null; >+ >+ public Descriptor(IExtension extension, IConfigurationElement element) >+ throws RuntimeException, CoreException { >+ name = element.getAttribute("name"); //$NON-NLS-1$ >+ value = element.getAttribute("value"); //$NON-NLS-1$ >+ try { >+ provider = (IProjectVariableProvider) element >+ .createExecutableExtension("class"); //$NON-NLS-1$ >+ } catch (CoreException t) { >+ } >+ if (name == null) >+ fail(NLS.bind(Messages.mapping_invalidDef, extension >+ .getUniqueIdentifier())); >+ } >+ >+ protected void fail(String reason) throws CoreException { >+ throw new ResourceException(new Status(IStatus.ERROR, >+ ResourcesPlugin.PI_RESOURCES, 1, reason, null)); >+ } >+ >+ public String getName() { >+ return name; >+ } >+ >+ public String getValue(String variable, IProject project) { >+ if (value != null) >+ return value; >+ return provider.getValue(variable, project); >+ } >+ >+ public Object[] getExtensions(String variable, IProject project) { >+ if (provider != null) >+ return provider.getExtensions(variable, project); >+ else >+ return null; >+ } >+ } >+ >+ private static Map descriptors; >+ private static ProjectVariableProviderManager instance; >+ >+ public synchronized static ProjectVariableProviderManager getDefault() { >+ if (instance == null) { >+ instance = new ProjectVariableProviderManager(); >+ } >+ return instance; >+ } >+ >+ public Descriptor[] getDescriptors() { >+ lazyInitialize(); >+ return (Descriptor[]) descriptors.values().toArray( >+ new Descriptor[descriptors.size()]); >+ } >+ >+ protected void lazyInitialize() { >+ if (descriptors != null) >+ return; >+ IExtensionPoint point = Platform.getExtensionRegistry() >+ .getExtensionPoint(ResourcesPlugin.PI_RESOURCES, >+ ResourcesPlugin.PT_VARIABLE_PROVIDERS); >+ IExtension[] extensions = point.getExtensions(); >+ descriptors = new HashMap(extensions.length * 2 + 1); >+ for (int i = 0, imax = extensions.length; i < imax; i++) { >+ IConfigurationElement[] elements = extensions[i] >+ .getConfigurationElements(); >+ int count = elements.length; >+ for (int j = 0; j < count; j++) { >+ IConfigurationElement element = elements[j]; >+ String elementName = element.getName(); >+ if (elementName.equalsIgnoreCase("variableProvider")) { //$NON-NLS-1$ >+ Descriptor desc = null; >+ try { >+ desc = new Descriptor(extensions[i], element); >+ } catch (CoreException e) { >+ Policy.log(e); >+ } >+ if (desc != null) >+ descriptors.put(desc.getName(), desc); >+ } >+ } >+ } >+ } >+ >+ public Descriptor findDescriptor(String name) { >+ Object result = descriptors.get(name); >+ if (result != null) >+ return (Descriptor) result; >+ return null; >+ } >+} >Index: src/org/eclipse/core/resources/IProjectVariableProvider.java >=================================================================== >RCS file: src/org/eclipse/core/resources/IProjectVariableProvider.java >diff -N src/org/eclipse/core/resources/IProjectVariableProvider.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/resources/IProjectVariableProvider.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,41 @@ >+/******************************************************************************* >+ * Copyright (c) 2008 IBM Corporation 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: >+ * IBM Corporation - initial API and implementation >+ *******************************************************************************/ >+package org.eclipse.core.resources; >+ >+/** >+ * >+ */ >+public interface IProjectVariableProvider { >+ >+ /** >+ * Returns a variable value >+ * >+ * @param variable >+ * The current variable name. >+ * @param project >+ * The project that the variable is being resolved for. >+ * @return the variable value. >+ */ >+ public String getValue(String variable, IProject project); >+ >+ /** >+ * If the variable supports extensions (specified as >+ * "${VARNAME-EXTENSIONNAME}"), this method can return the list of possible >+ * extensions, or null if none are supported. >+ * >+ * @param variable >+ * The current variable name. >+ * @param project >+ * The project that the variable is being resolved for. >+ * @return the possible variable extensions or null if none are supported. >+ */ >+ public Object[] getExtensions(String variable, IProject project); >+} >Index: src/org/eclipse/core/internal/resources/PathVariableUtil.java >=================================================================== >RCS file: src/org/eclipse/core/internal/resources/PathVariableUtil.java >diff -N src/org/eclipse/core/internal/resources/PathVariableUtil.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/resources/PathVariableUtil.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,140 @@ >+package org.eclipse.core.internal.resources; >+ >+import java.util.Arrays; >+import java.util.List; >+import org.eclipse.core.resources.IPathVariableManager; >+import org.eclipse.core.runtime.*; >+ >+public class PathVariableUtil { >+ >+ static public IPath convertToRelative(IPathVariableManager pathVariableManager, IPath originalPath, boolean force, String variableHint) throws CoreException { >+ if (variableHint != null) >+ return makeRelativeToVariable(pathVariableManager, originalPath, force, variableHint); >+ IPath path = convertToProperCase(originalPath); >+ IPath newPath = null; >+ int maxMatchLength = -1; >+ String[] existingVariables = pathVariableManager.getPathVariableNames(); >+ for (int i = 0; i < existingVariables.length; i++) { >+ String variable = existingVariables[i]; >+ // find closest path to the original path >+ IPath value = pathVariableManager.getValue(variable); >+ value = convertToProperCase(pathVariableManager.resolvePath(value)); >+ if (value.isPrefixOf(path)) { >+ int matchLength = value.segmentCount(); >+ if (matchLength > maxMatchLength) { >+ maxMatchLength = matchLength; >+ newPath = makeRelativeToVariable(pathVariableManager, originalPath, force, variable); >+ } >+ } >+ } >+ if (newPath != null) >+ return newPath; >+ >+ if (force) { >+ int originalSegmentCount = originalPath.segmentCount(); >+ for (int j = 1; j < originalSegmentCount; j++) { >+ IPath matchingPath = path.removeLastSegments(j); >+ int minDifference = Integer.MAX_VALUE; >+ for (int i = 0; i < existingVariables.length; i++) { >+ String variable = existingVariables[i]; >+ IPath value = pathVariableManager.getValue(variable); >+ value = convertToProperCase(pathVariableManager.resolvePath(value)); >+ if (matchingPath.isPrefixOf(value)) { >+ int difference = value.segmentCount() - originalSegmentCount; >+ if (difference < minDifference) { >+ minDifference = difference; >+ newPath = makeRelativeToVariable(pathVariableManager, originalPath, force, variable); >+ } >+ } >+ } >+ if (newPath != null) >+ return newPath; >+ } >+ } >+ >+ return originalPath; >+ } >+ >+ private static IPath makeRelativeToVariable(IPathVariableManager pathVariableManager, IPath originalPath, boolean force, String variableHint) throws CoreException { >+ IPath path = convertToProperCase(originalPath); >+ IPath value = pathVariableManager.getValue(variableHint); >+ value = convertToProperCase(pathVariableManager.resolvePath(value)); >+ int valueSegmentCount = value.segmentCount(); >+ if (value.isPrefixOf(path)) { >+ // transform "c:/foo/bar" into "FOO/bar" >+ IPath tmp = Path.fromOSString(variableHint); >+ for (int j = valueSegmentCount;j < originalPath.segmentCount(); j++) { >+ tmp = tmp.append(originalPath.segment(j)); >+ } >+ return tmp; >+ } >+ >+ if (force) { >+ // transform "c:/foo/bar/other_child/file.txt" into "${PARENT-1-BAR_CHILD}/other_child/file.txt" >+ int matchingFirstSegments = path.matchingFirstSegments(value); >+ if (matchingFirstSegments > 0) { >+ String newValue = buildParentPathVariable(variableHint, valueSegmentCount - matchingFirstSegments); >+ String originalName = getExistingVariable(newValue, pathVariableManager); >+ if (originalName == null) { >+ originalName = getOriginalName(originalPath.segment(matchingFirstSegments - 1), pathVariableManager); >+ pathVariableManager.setValue(originalName, Path.fromOSString(newValue)); >+ } >+ IPath tmp = Path.fromOSString(originalName); >+ for (int j = matchingFirstSegments ;j < originalPath.segmentCount(); j++) { >+ tmp = tmp.append(originalPath.segment(j)); >+ } >+ return tmp; >+ } >+ } >+ return originalPath; >+ } >+ >+ private static String getExistingVariable(String newValue, IPathVariableManager pathVariableManager) { >+ String[] existingVariables = pathVariableManager.getPathVariableNames(); >+ for (int i = 0; i < existingVariables.length; i++) { >+ String variable = existingVariables[i]; >+ IPath value = pathVariableManager.getValue(variable); >+ if (value.toOSString().equals(newValue)) >+ return variable; >+ } >+ return null; >+ } >+ >+ private static String getOriginalName(String name, IPathVariableManager pathVariableManager) { >+ // standardize the variable name >+ name = name.trim().toUpperCase(); >+ char first = name.charAt(0); >+ if (!Character.isLetter(first) && first != '_') { >+ name = 'A' + name; >+ } >+ >+ StringBuffer builder = new StringBuffer(); >+ for (int i = 0; i < name.length(); i++) { >+ char c = name.charAt(i); >+ if ((Character.isLetter(c) || Character.isDigit(c) || c != '_') && >+ !Character.isWhitespace(c)) >+ builder.append(c); >+ } >+ name = builder.toString(); >+ String[] existingVariables = pathVariableManager.getPathVariableNames(); >+ List existingNames = Arrays.asList(existingVariables); >+ String originalName = name; >+ int index = 1; >+ while (existingNames.contains(name)) { >+ name = originalName + "_" + index; //$NON-NLS-1$ >+ index++; >+ } >+ return name; >+ } >+ >+ static private IPath convertToProperCase(IPath path) { >+ if (Platform.getOS().equals(Platform.OS_WIN32)) >+ return Path.fromPortableString(path.toPortableString().toLowerCase()); >+ return path; >+ } >+ >+ static private String buildParentPathVariable(String variable, int difference) { >+ String newString = "${PARENT" + "-" + difference + "-" + variable + "}"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$//$NON-NLS-4$ >+ return newString; >+ } >+} >Index: src/org/eclipse/core/internal/resources/projectVariables/WorkspaceLocationProjectVariable.java >=================================================================== >RCS file: src/org/eclipse/core/internal/resources/projectVariables/WorkspaceLocationProjectVariable.java >diff -N src/org/eclipse/core/internal/resources/projectVariables/WorkspaceLocationProjectVariable.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/resources/projectVariables/WorkspaceLocationProjectVariable.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,35 @@ >+/******************************************************************************* >+ * Copyright (c) 2008 IBM Corporation 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: >+ * IBM Corporation - initial API and implementation >+ *******************************************************************************/ >+package org.eclipse.core.internal.resources.projectVariables; >+ >+import org.eclipse.core.resources.IProject; >+import org.eclipse.core.resources.IProjectVariableProvider; >+ >+/** >+ * >+ */ >+public class WorkspaceLocationProjectVariable implements >+ IProjectVariableProvider { >+ >+ public WorkspaceLocationProjectVariable() { >+ // nothing to do >+ } >+ >+ public String getValue(String variable, IProject project) { >+ return project.getWorkspace().getRoot().getLocation() >+ .toPortableString(); >+ } >+ >+ public Object[] getExtensions(String variable, IProject project) { >+ return null; >+ } >+ >+} >#P org.eclipse.ui.ide >Index: src/org/eclipse/ui/ide/undo/CopyResourcesOperation.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide/src/org/eclipse/ui/ide/undo/CopyResourcesOperation.java,v >retrieving revision 1.15 >diff -u -r1.15 CopyResourcesOperation.java >--- src/org/eclipse/ui/ide/undo/CopyResourcesOperation.java 24 Mar 2008 19:13:36 -0000 1.15 >+++ src/org/eclipse/ui/ide/undo/CopyResourcesOperation.java 11 Sep 2008 12:30:42 -0000 >@@ -154,7 +154,7 @@ > new IResource[] { resources[i] }, getDestinationPath( > resources[i], i), resourcesAtDestination, > new SubProgressMonitor(monitor, 1000 / resources.length), >- uiInfo, true); >+ uiInfo, true, fCreateLinks, fRelativeToVariable); > // Accumulate the overwrites into the full list > for (int j = 0; j < overwrites.length; j++) { > overwrittenResources.add(overwrites[j]); >Index: src/org/eclipse/ui/ide/undo/AbstractCopyOrMoveResourcesOperation.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide/src/org/eclipse/ui/ide/undo/AbstractCopyOrMoveResourcesOperation.java,v >retrieving revision 1.12 >diff -u -r1.12 AbstractCopyOrMoveResourcesOperation.java >--- src/org/eclipse/ui/ide/undo/AbstractCopyOrMoveResourcesOperation.java 11 Apr 2007 15:09:35 -0000 1.12 >+++ src/org/eclipse/ui/ide/undo/AbstractCopyOrMoveResourcesOperation.java 11 Sep 2008 12:30:42 -0000 >@@ -39,6 +39,10 @@ > // Used when all resources are going to the same container (no name changes) > protected IPath destination = null; > >+ protected boolean fCreateLinks = false; >+ >+ protected String fRelativeToVariable = null; >+ > /** > * Create an AbstractCopyOrMoveResourcesOperation that moves or copies all > * of the specified resources to the specified paths. The destination paths >@@ -256,4 +260,13 @@ > } > return status; > } >+ >+ >+ public void setCreateLinks(boolean value) { >+ fCreateLinks = value; >+ } >+ >+ public void setRelativeVariable(String value) { >+ fRelativeToVariable = value; >+ } > } >Index: src/org/eclipse/ui/ide/undo/WorkspaceUndoUtil.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide/src/org/eclipse/ui/ide/undo/WorkspaceUndoUtil.java,v >retrieving revision 1.16 >diff -u -r1.16 WorkspaceUndoUtil.java >--- src/org/eclipse/ui/ide/undo/WorkspaceUndoUtil.java 16 Mar 2007 19:52:55 -0000 1.16 >+++ src/org/eclipse/ui/ide/undo/WorkspaceUndoUtil.java 11 Sep 2008 12:30:43 -0000 >@@ -7,17 +7,22 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Serge Beauchamp (Freescale Semiconductor) > *******************************************************************************/ > > package org.eclipse.ui.ide.undo; > >+import java.net.URI; > import java.util.ArrayList; > import java.util.List; > > import org.eclipse.core.commands.operations.IUndoContext; > import org.eclipse.core.commands.operations.ObjectUndoContext; >+import org.eclipse.core.filesystem.URIUtil; > import org.eclipse.core.resources.IContainer; > import org.eclipse.core.resources.IFile; >+import org.eclipse.core.resources.IFolder; >+import org.eclipse.core.resources.IPathVariableManager; > import org.eclipse.core.resources.IProject; > import org.eclipse.core.resources.IResource; > import org.eclipse.core.resources.IResourceStatus; >@@ -246,6 +251,59 @@ > static ResourceDescription[] copy(IResource[] resources, IPath destination, > List resourcesAtDestination, IProgressMonitor monitor, > IAdaptable uiInfo, boolean pathIncludesName) throws CoreException { >+ return copy(resources, destination, resourcesAtDestination, monitor, >+ uiInfo, pathIncludesName, false, null); >+ } >+ >+ /** >+ * Copies the resources to the given destination. This method can be called >+ * recursively to merge folders during folder copy. >+ * >+ * @param resources >+ * the resources to be copied >+ * @param destination >+ * the destination path for the resources, relative to the >+ * workspace >+ * @param resourcesAtDestination >+ * A list used to record the new copies. >+ * @param monitor >+ * the progress monitor used to show progress >+ * @param uiInfo >+ * the IAdaptable (or <code>null</code>) provided by the >+ * caller in order to supply UI information for prompting the >+ * user if necessary. When this parameter is not >+ * <code>null</code>, it contains an adapter for the >+ * org.eclipse.swt.widgets.Shell.class >+ * @param pathIncludesName >+ * a boolean that indicates whether the specified path includes >+ * the resource's name at the destination. If this value is >+ * <code>true</code>, the destination will contain the desired >+ * name of the resource (usually only desired when only one >+ * resource is being copied). If this value is <code>false</code>, >+ * each resource's name will be appended to the destination. >+ * @param createGroups >+ * a boolean that indicates whether groups resources should be >+ * created instead of folders when a hierarchy of files is >+ * copied. >+ * @param createLinks >+ * a boolean that indicates whether linked resources should be >+ * created instead of files and folders (if createGroups is >+ * false) when copied. >+ * @param relativeToVariable >+ * a String that indicates relative to which variable linked >+ * resources should be created, if createLinks is set to true. >+ * Absolute linked resources will be created if null is passed >+ * otherwise (and createLinks is set to true). >+ * @return an array of ResourceDescriptions describing any resources that >+ * were overwritten by the copy operation >+ * @throws CoreException >+ * propagates any CoreExceptions thrown from the resources API >+ */ >+ static ResourceDescription[] copy(IResource[] resources, IPath destination, >+ List resourcesAtDestination, IProgressMonitor monitor, >+ IAdaptable uiInfo, boolean pathIncludesName, >+ boolean createLinks, String relativeToVariable) >+ throws CoreException { > > monitor.beginTask("", resources.length); //$NON-NLS-1$ > monitor >@@ -264,11 +322,13 @@ > if (source.getType() == IResource.FOLDER && existing != null) { > // The resource is a folder and it exists in the destination. > // Copy its children to the existing destination. >- if (source.isLinked() == existing.isLinked()) { >+ if ((source.isLinked() && existing.isLinked()) >+ || (!source.isLinked() && !existing.isLinked())) { > IResource[] children = ((IContainer) source).members(); > ResourceDescription[] overwritten = copy(children, > destinationPath, resourcesAtDestination, >- new SubProgressMonitor(monitor, 1), uiInfo, false); >+ new SubProgressMonitor(monitor, 1), uiInfo, false, >+ createLinks, relativeToVariable); > // We don't record the copy since this recursive call will > // do so. Just record the overwrites. > for (int j = 0; j < overwritten.length; j++) { >@@ -280,8 +340,16 @@ > ResourceDescription[] deleted = delete( > new IResource[] { existing }, > new SubProgressMonitor(monitor, 0), uiInfo, false); >- source.copy(destinationPath, IResource.SHALLOW, >- new SubProgressMonitor(monitor, 1)); >+ if (createLinks >+ && (source.isLinked() == false)) { >+ IFolder folder = workspaceRoot.getFolder(destinationPath); >+ folder.createLink(createRelativePath( >+ folder.getProject().getPathVariableManager(), source >+ .getLocationURI(), relativeToVariable), 0, >+ new SubProgressMonitor(monitor, 1)); >+ } else >+ source.copy(destinationPath, IResource.SHALLOW, >+ new SubProgressMonitor(monitor, 1)); > // Record the copy > resourcesAtDestination.add(getWorkspace().getRoot() > .findMember(destinationPath)); >@@ -291,29 +359,61 @@ > } > } else { > if (existing != null) { >- if (source.isLinked() == existing.isLinked()) { >- overwrittenResources.add(copyOverExistingResource( >- source, existing, new SubProgressMonitor( >- monitor, 1), uiInfo, false)); >- // Record the "copy" >- resourcesAtDestination.add(existing); >- } else { >- // Copying a linked resource over unlinked or vice >- // versa. Can't use setContents here. Fixes bug 28772. >+ // source is a FILE and destination EXISTS >+ if (createLinks >+ && (source.isLinked() == false)) { >+ // we create a linked file, and overwrite the >+ // destination > ResourceDescription[] deleted = delete( > new IResource[] { existing }, > new SubProgressMonitor(monitor, 0), uiInfo, > false); >- source.copy(destinationPath, IResource.SHALLOW, >- new SubProgressMonitor(monitor, 1)); >- // Record the copy >+ if (source.getType() == IResource.FILE) { >+ IFile file = workspaceRoot.getFile(destinationPath); >+ file.createLink(createRelativePath( >+ file.getProject().getPathVariableManager(), source >+ .getLocationURI(), relativeToVariable), 0, >+ new SubProgressMonitor(monitor, 1)); >+ } else { >+ IFolder folder = workspaceRoot >+ .getFolder(destinationPath); >+ folder.createLink(createRelativePath( >+ folder.getProject().getPathVariableManager(), >+ source.getLocationURI(), relativeToVariable), >+ 0, new SubProgressMonitor(monitor, 1)); >+ } > resourcesAtDestination.add(getWorkspace().getRoot() > .findMember(destinationPath)); > for (int j = 0; j < deleted.length; j++) { > overwrittenResources.add(deleted[j]); > } >+ } else { >+ if (source.isLinked() == existing.isLinked()) { >+ overwrittenResources.add(copyOverExistingResource( >+ source, existing, new SubProgressMonitor( >+ monitor, 1), uiInfo, false)); >+ // Record the "copy" >+ resourcesAtDestination.add(existing); >+ } else { >+ // Copying a linked resource over unlinked or vice >+ // versa. Can't use setContents here. Fixes bug >+ // 28772. >+ ResourceDescription[] deleted = delete( >+ new IResource[] { existing }, >+ new SubProgressMonitor(monitor, 0), uiInfo, >+ false); >+ source.copy(destinationPath, IResource.SHALLOW, >+ new SubProgressMonitor(monitor, 1)); >+ // Record the copy >+ resourcesAtDestination.add(getWorkspace().getRoot() >+ .findMember(destinationPath)); >+ for (int j = 0; j < deleted.length; j++) { >+ overwrittenResources.add(deleted[j]); >+ } >+ } > } > } else { >+ // source is a FILE or FOLDER > // no resources are being overwritten > // ensure the destination path exists > IPath parentPath = destination; >@@ -321,8 +421,25 @@ > parentPath = destination.removeLastSegments(1); > } > IContainer generatedParent = generateContainers(parentPath); >- source.copy(destinationPath, IResource.SHALLOW, >- new SubProgressMonitor(monitor, 1)); >+ if ((createLinks) >+ && (source.isLinked() == false)) { >+ if (source.getType() == IResource.FILE) { >+ IFile file = workspaceRoot.getFile(destinationPath); >+ file.createLink(createRelativePath( >+ file.getProject().getPathVariableManager(), >+ source.getLocationURI(), relativeToVariable), 0, >+ new SubProgressMonitor(monitor, 1)); >+ } else { >+ IFolder folder = workspaceRoot >+ .getFolder(destinationPath); >+ folder.createLink(createRelativePath( >+ folder.getProject().getPathVariableManager(), >+ source.getLocationURI(), relativeToVariable), >+ 0, new SubProgressMonitor(monitor, 1)); >+ } >+ } else >+ source.copy(destinationPath, IResource.SHALLOW, >+ new SubProgressMonitor(monitor, 1)); > // Record the copy. If we had to generate a parent > // folder, that should be recorded as part of the copy > if (generatedParent == null) { >@@ -341,7 +458,28 @@ > monitor.done(); > return (ResourceDescription[]) overwrittenResources > .toArray(new ResourceDescription[overwrittenResources.size()]); >+ } > >+ /** >+ * Transform an absolute path URI to a relative path one (i.e. from >+ * "C:\foo\bar\file.txt" to "VAR\file.txt" granted that the relativeVariable >+ * is "VAR" and points to "C:\foo\bar\"). >+ * >+ * @param locationURI >+ * @param pvm the IPathVariableManager to use for resolving variables >+ * @return an URI that was made relative to a variable >+ */ >+ static private URI createRelativePath(IPathVariableManager pvm, URI locationURI, String relativeVariable) { >+ if (relativeVariable == null) >+ return locationURI; >+ IPath location = URIUtil.toPath(locationURI); >+ IPath result; >+ try { >+ result = pvm.convertToRelative(location, true, relativeVariable); >+ } catch (CoreException e) { >+ return locationURI; >+ } >+ return URIUtil.toURI(result); > } > > /** >Index: extensions/org/eclipse/ui/dialogs/NewFolderDialog.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide/extensions/org/eclipse/ui/dialogs/NewFolderDialog.java,v >retrieving revision 1.22 >diff -u -r1.22 NewFolderDialog.java >--- extensions/org/eclipse/ui/dialogs/NewFolderDialog.java 9 May 2008 14:13:07 -0000 1.22 >+++ extensions/org/eclipse/ui/dialogs/NewFolderDialog.java 11 Sep 2008 12:30:40 -0000 >@@ -104,6 +104,7 @@ > super(parentShell); > this.container = container; > setTitle(IDEWorkbenchMessages.NewFolderDialog_title); >+ setShellStyle(getShellStyle() | SWT.RESIZE); > setStatusLineAboveButtons(true); > } > >@@ -183,6 +184,10 @@ > public String getValue() { > return folderNameField.getText(); > } >+ >+ public IProject getProject() { >+ return container.getProject(); >+ } > }); > } > >Index: extensions/org/eclipse/ui/dialogs/WizardNewFolderMainPage.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide/extensions/org/eclipse/ui/dialogs/WizardNewFolderMainPage.java,v >retrieving revision 1.22 >diff -u -r1.22 WizardNewFolderMainPage.java >--- extensions/org/eclipse/ui/dialogs/WizardNewFolderMainPage.java 3 Nov 2006 22:07:02 -0000 1.22 >+++ extensions/org/eclipse/ui/dialogs/WizardNewFolderMainPage.java 11 Sep 2008 12:30:41 -0000 >@@ -17,6 +17,7 @@ > import java.util.Iterator; > import org.eclipse.core.commands.ExecutionException; > import org.eclipse.core.resources.IFolder; >+import org.eclipse.core.resources.IProject; > import org.eclipse.core.resources.IResource; > import org.eclipse.core.resources.IResourceStatus; > import org.eclipse.core.resources.IWorkspaceRoot; >@@ -163,6 +164,16 @@ > public void setValue(String string) { > resourceGroup.setResource(string); > } >+ >+ public IProject getProject() { >+ IPath path = resourceGroup.getContainerFullPath(); >+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace() >+ .getRoot(); >+ IResource res = root.findMember(path); >+ if (res != null) >+ return res.getProject(); >+ return null; >+ } > }); > } > >Index: extensions/org/eclipse/ui/dialogs/WizardNewFileCreationPage.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide/extensions/org/eclipse/ui/dialogs/WizardNewFileCreationPage.java,v >retrieving revision 1.24 >diff -u -r1.24 WizardNewFileCreationPage.java >--- extensions/org/eclipse/ui/dialogs/WizardNewFileCreationPage.java 11 Oct 2007 17:24:09 -0000 1.24 >+++ extensions/org/eclipse/ui/dialogs/WizardNewFileCreationPage.java 11 Sep 2008 12:30:41 -0000 >@@ -20,6 +20,7 @@ > import org.eclipse.core.commands.ExecutionException; > import org.eclipse.core.resources.IFile; > import org.eclipse.core.resources.IFolder; >+import org.eclipse.core.resources.IProject; > import org.eclipse.core.resources.IResource; > import org.eclipse.core.resources.IResourceStatus; > import org.eclipse.core.resources.IWorkspace; >@@ -190,6 +191,21 @@ > public String getValue() { > return resourceGroup.getResource(); > } >+ >+ public IProject getProject() { >+ IPath path; >+ if (resourceGroup == null) { >+ path = initialContainerFullPath; >+ } else { >+ path = resourceGroup.getContainerFullPath(); >+ } >+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace() >+ .getRoot(); >+ IResource res = root.findMember(path); >+ if (res != null) >+ return res.getProject(); >+ return null; >+ } > }); > } > >Index: src/org/eclipse/ui/internal/ide/messages.properties >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties,v >retrieving revision 1.158 >diff -u -r1.158 messages.properties >--- src/org/eclipse/ui/internal/ide/messages.properties 18 Jun 2008 18:39:04 -0000 1.158 >+++ src/org/eclipse/ui/internal/ide/messages.properties 11 Sep 2008 12:30:45 -0000 >@@ -466,10 +466,13 @@ > # and should be removed. > PathVariableDialog_shellTitle_newVariable = New Variable > PathVariableDialog_shellTitle_existingVariable = Edit Variable >+PathVariableDialog_shellTitle_editLocation = Edit Link Location > PathVariableDialog_dialogTitle_newVariable = Define a New Path Variable > PathVariableDialog_dialogTitle_existingVariable = Edit an Existing Path Variable >+PathVariableDialog_dialogTitle_editLinkLocation = Edit a Link Location > PathVariableDialog_message_newVariable = Enter a new variable name and its associated location. > PathVariableDialog_message_existingVariable = Edit variable's name and path value. >+PathVariableDialog_message_editLocation = Edit link location. > > PathVariableDialog_variableName = &Name: > PathVariableDialog_variableValue = &Location: >@@ -478,12 +481,15 @@ > PathVariableDialog_variableValueInvalidMessage = The provided value is not a valid path. > PathVariableDialog_file = &File... > PathVariableDialog_folder = F&older... >+PathVariableDialog_variable = &Variable... > PathVariableDialog_selectFileTitle = File selection > PathVariableDialog_selectFolderTitle = Folder selection > PathVariableDialog_selectFolderMessage = Specify the folder to be represented by the variable. > PathVariableDialog_variableAlreadyExistsMessage = This variable name is already in use. > PathVariableDialog_pathIsRelativeMessage = Path must be absolute. > PathVariableDialog_pathDoesNotExistMessage = Path does not exist. >+PathVariableDialog_variableValueIsWrongTypeFolder = Path target is of wrong type. The path must point to a folder. >+PathVariableDialog_variableValueIsWrongTypeFile = Path target is of wrong type. The path must point to a file. > > # --- Local History --- > FileHistory_longevity = Days to &keep files: >@@ -547,10 +553,14 @@ > ResourceInfo_fileContainerEncodingFormat = Default (&inherited from container: {0}) > ResourceInfo_containerEncodingFormat = &Inherited from container ({0}) > ResourceInfo_exWarning= Removing the executable flag on a directory will cause its children to become unreadable. >+ResourceInfo_edit=Edit... > > # --- Project References --- > ProjectReferencesPage_label = Projects may refer to other projects in the workspace.\nUse this page to specify what other projects are referenced by the project.\n\n&Project references for ''{0}'': > >+# --- Project Linked Resources References --- >+ProjectLinkedResourcePage_description=Path variables specify locations in the file system, including other path variables with the syntax "${VAR}".\nThe locations of linked resources may be specified relative to these path variables. >+ > # ============================================================================== > # Editors > # ============================================================================== >@@ -643,6 +653,7 @@ > CreateLinkedResourceGroup_unableToValidateLinkTarget = Unable to validate link target. > > PathVariablesBlock_variablesLabel = &Defined path variables: >+PathVariablesBlock_variablesLabelForProject = &Defined path variables for project ''{0}'': > PathVariablesBlock_addVariableButton = &New... > PathVariablesBlock_editVariableButton = Edi&t... > PathVariablesBlock_removeVariableButton = &Remove >Index: src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java,v >retrieving revision 1.55 >diff -u -r1.55 IDEWorkbenchMessages.java >--- src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java 28 Apr 2008 15:20:16 -0000 1.55 >+++ src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java 11 Sep 2008 12:30:44 -0000 >@@ -446,10 +446,13 @@ > // and should be removed. > public static String PathVariableDialog_shellTitle_newVariable; > public static String PathVariableDialog_shellTitle_existingVariable; >+ public static String PathVariableDialog_shellTitle_editLocation; > public static String PathVariableDialog_dialogTitle_newVariable; > public static String PathVariableDialog_dialogTitle_existingVariable; >+ public static String PathVariableDialog_dialogTitle_editLinkLocation; > public static String PathVariableDialog_message_newVariable; > public static String PathVariableDialog_message_existingVariable; >+ public static String PathVariableDialog_message_editLocation; > > public static String PathVariableDialog_variableName; > public static String PathVariableDialog_variableValue; >@@ -458,12 +461,15 @@ > public static String PathVariableDialog_variableValueInvalidMessage; > public static String PathVariableDialog_file; > public static String PathVariableDialog_folder; >+ public static String PathVariableDialog_variable; > public static String PathVariableDialog_selectFileTitle; > public static String PathVariableDialog_selectFolderTitle; > public static String PathVariableDialog_selectFolderMessage; > public static String PathVariableDialog_variableAlreadyExistsMessage; > public static String PathVariableDialog_pathIsRelativeMessage; > public static String PathVariableDialog_pathDoesNotExistMessage; >+ public static String PathVariableDialog_variableValueIsWrongTypeFolder; >+ public static String PathVariableDialog_variableValueIsWrongTypeFile; > > // --- Local History --- > public static String FileHistory_longevity; >@@ -526,10 +532,14 @@ > public static String ResourceInfo_fileContainerEncodingFormat; > public static String ResourceInfo_containerEncodingFormat; > public static String ResourceInfo_exWarning; >+ public static String ResourceInfo_edit; > > // --- Project References --- > public static String ProjectReferencesPage_label; > >+ // --- Project Linked Resources References --- >+ public static String ProjectLinkedResourcePage_description; >+ > // ============================================================================== > // Editors > // ============================================================================== >@@ -621,6 +631,7 @@ > public static String CreateLinkedResourceGroup_unableToValidateLinkTarget; > > public static String PathVariablesBlock_variablesLabel; >+ public static String PathVariablesBlock_variablesLabelForProject; > public static String PathVariablesBlock_addVariableButton; > public static String PathVariablesBlock_editVariableButton; > public static String PathVariablesBlock_removeVariableButton; >Index: src/org/eclipse/ui/internal/ide/dialogs/PathVariableDialog.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/dialogs/PathVariableDialog.java,v >retrieving revision 1.15 >diff -u -r1.15 PathVariableDialog.java >--- src/org/eclipse/ui/internal/ide/dialogs/PathVariableDialog.java 31 Jul 2008 18:04:37 -0000 1.15 >+++ src/org/eclipse/ui/internal/ide/dialogs/PathVariableDialog.java 11 Sep 2008 12:30:47 -0000 >@@ -14,8 +14,11 @@ > > import java.util.Set; > >+import org.eclipse.core.filesystem.IFileInfo; > import org.eclipse.core.resources.IPathVariableManager; >+import org.eclipse.core.resources.IProject; > import org.eclipse.core.resources.IResource; >+import org.eclipse.core.runtime.IPath; > import org.eclipse.core.runtime.IStatus; > import org.eclipse.core.runtime.Path; > import org.eclipse.jface.dialogs.Dialog; >@@ -37,6 +40,7 @@ > import org.eclipse.swt.widgets.Label; > import org.eclipse.swt.widgets.Shell; > import org.eclipse.swt.widgets.Text; >+import org.eclipse.ui.ide.dialogs.PathVariableSelectionDialog; > import org.eclipse.ui.internal.ide.IDEWorkbenchMessages; > > /** >@@ -62,6 +66,7 @@ > > private Button folderButton; > >+ private Button variableButton; > /** > * This dialog type: <code>NEW_VARIABLE</code> or > * <code>EXISTING_VARIABLE</code>. >@@ -94,7 +99,7 @@ > * Used to select the proper message depending on the current mode > * (new/existing variable). > */ >- private boolean newVariable; >+ private int operationMode = 0; > > /** > * Reference to the path variable manager. It is used for validating >@@ -153,6 +158,14 @@ > public final static int EXISTING_VARIABLE = 2; > > /** >+ * Constant for defining this dialog as intended to edit an existing link >+ * location (value = 3). >+ */ >+ public final static int EDIT_LINK_LOCATION = 3; >+ >+ private IProject currentProject = null; >+ >+ /** > * Constructs a dialog for editing a new/existing path variable. > * > * @param parentShell the parent shell >@@ -166,19 +179,21 @@ > public PathVariableDialog(Shell parentShell, int type, int variableType, > IPathVariableManager pathVariableManager, Set namesInUse) { > super(parentShell); >+ setShellStyle(getShellStyle() | SWT.RESIZE); > this.type = type; >- this.newVariable = type == NEW_VARIABLE; >+ this.operationMode = type; > this.variableName = ""; //$NON-NLS-1$ > this.variableValue = ""; //$NON-NLS-1$ > this.variableType = variableType; > this.pathVariableManager = pathVariableManager; > this.namesInUse = namesInUse; > >- if (newVariable) { >- this.standardMessage = IDEWorkbenchMessages.PathVariableDialog_message_newVariable; >- } else { >- this.standardMessage = IDEWorkbenchMessages.PathVariableDialog_message_existingVariable; >- } >+ if (operationMode == NEW_VARIABLE) >+ this.standardMessage = IDEWorkbenchMessages.PathVariableDialog_message_newVariable; >+ else if (operationMode == EXISTING_VARIABLE) >+ this.standardMessage = IDEWorkbenchMessages.PathVariableDialog_message_existingVariable; >+ else >+ this.standardMessage = IDEWorkbenchMessages.PathVariableDialog_message_editLocation; > } > > /** >@@ -188,12 +203,12 @@ > */ > protected void configureShell(Shell shell) { > super.configureShell(shell); >- if (newVariable) { >- shell.setText(IDEWorkbenchMessages.PathVariableDialog_shellTitle_newVariable); >- } else { >- shell >- .setText(IDEWorkbenchMessages.PathVariableDialog_shellTitle_existingVariable); >- } >+ if (operationMode == NEW_VARIABLE) >+ shell.setText(IDEWorkbenchMessages.PathVariableDialog_shellTitle_newVariable); >+ else if (operationMode == EXISTING_VARIABLE) >+ shell.setText(IDEWorkbenchMessages.PathVariableDialog_shellTitle_existingVariable); >+ else >+ shell.setText(IDEWorkbenchMessages.PathVariableDialog_shellTitle_editLocation); > } > > /** >@@ -237,11 +252,12 @@ > contents.setLayout(new GridLayout(4, false)); > contents.setLayoutData(new GridData(GridData.FILL_BOTH)); > >- if (newVariable) { >- setTitle(IDEWorkbenchMessages.PathVariableDialog_dialogTitle_newVariable); >- } else { >- setTitle(IDEWorkbenchMessages.PathVariableDialog_dialogTitle_existingVariable); >- } >+ if (operationMode == NEW_VARIABLE) >+ setTitle(IDEWorkbenchMessages.PathVariableDialog_dialogTitle_newVariable); >+ else if (operationMode == EXISTING_VARIABLE) >+ setTitle(IDEWorkbenchMessages.PathVariableDialog_dialogTitle_existingVariable); >+ else >+ setTitle(IDEWorkbenchMessages.PathVariableDialog_dialogTitle_editLinkLocation); > setMessage(standardMessage); > return contents; > } >@@ -255,20 +271,22 @@ > String nameLabelText = IDEWorkbenchMessages.PathVariableDialog_variableName; > String valueLabelText = IDEWorkbenchMessages.PathVariableDialog_variableValue; > >- // variable name label >- variableNameLabel = new Label(contents, SWT.LEAD); >- variableNameLabel.setText(nameLabelText); >- >- // variable name field. Attachments done after all widgets created. >- variableNameField = new Text(contents, SWT.SINGLE | SWT.BORDER); >- variableNameField.setText(variableName); >- variableNameField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, >- false, 3, 1)); >- variableNameField.addModifyListener(new ModifyListener() { >- public void modifyText(ModifyEvent event) { >- variableNameModified(); >- } >- }); >+ if (operationMode != EDIT_LINK_LOCATION) { >+ // variable name label >+ variableNameLabel = new Label(contents, SWT.LEAD); >+ variableNameLabel.setText(nameLabelText); >+ >+ // variable name field. Attachments done after all widgets created. >+ variableNameField = new Text(contents, SWT.SINGLE | SWT.BORDER); >+ variableNameField.setText(variableName); >+ variableNameField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, >+ false, 3, 1)); >+ variableNameField.addModifyListener(new ModifyListener() { >+ public void modifyText(ModifyEvent event) { >+ variableNameModified(); >+ } >+ }); >+ } > > // variable value label > variableValueLabel = new Label(contents, SWT.LEAD); >@@ -288,7 +306,7 @@ > Composite buttonsComposite = new Composite(contents, SWT.NONE); > buttonsComposite.setLayoutData(new GridData(SWT.END, SWT.CENTER, false, > false, 2, 1)); >- GridLayout layout = new GridLayout(2, true); >+ GridLayout layout = new GridLayout((operationMode == EDIT_LINK_LOCATION) ? 3:2, true); > layout.marginWidth = 0; > layout.marginHeight = 0; > buttonsComposite.setLayout(layout); >@@ -308,6 +326,20 @@ > } > }); > >+ if (operationMode == EDIT_LINK_LOCATION) { >+ variableButton = new Button(buttonsComposite, SWT.PUSH); >+ variableButton.setText(IDEWorkbenchMessages.PathVariableDialog_variable); >+ >+ variableButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, >+ false)); >+ >+ variableButton.addSelectionListener(new SelectionAdapter() { >+ public void widgetSelected(SelectionEvent e) { >+ selectVariable(); >+ } >+ }); >+ } >+ > // select folder path button > folderButton = new Button(buttonsComposite, SWT.PUSH); > folderButton.setText(IDEWorkbenchMessages.PathVariableDialog_folder); >@@ -377,6 +409,30 @@ > } > } > >+ private void selectVariable() { >+ PathVariableSelectionDialog dialog = new PathVariableSelectionDialog( >+ getShell(), IResource.FILE | IResource.FOLDER); >+ dialog.setProject(currentProject); >+ if (dialog.open() == IDialogConstants.OK_ID) { >+ String[] variableNames = (String[]) dialog.getResult(); >+ if (variableNames != null && variableNames.length == 1) { >+ // what we do is try to resolve and replace the value by its >+ // variable >+ String newValue = variableNames[0]; >+ IPath resolved = pathVariableManager.resolvePath(Path >+ .fromPortableString(variableValue)); >+ IPath existingValue = Path.fromPortableString(variableValue); >+ int count = existingValue.matchingFirstSegments(resolved); >+ if (count > 0) >+ newValue = Path.fromPortableString(variableValue).append( >+ existingValue.removeFirstSegments(count)) >+ .toPortableString(); >+ variableValue = newValue; >+ variableValueField.setText(newValue); >+ } >+ } >+ } >+ > /** > * Adds buttons to this dialog's button bar. > * >@@ -399,6 +455,9 @@ > private boolean validateVariableName() { > boolean allowFinish = false; > >+ if (operationMode == EDIT_LINK_LOCATION) >+ return true; >+ > // if the current validationStatus is ERROR, no additional validation applies > if (validationStatus == IMessageProvider.ERROR) { > return false; >@@ -470,6 +529,29 @@ > newValidationStatus = IMessageProvider.ERROR; > message = IDEWorkbenchMessages.PathVariableDialog_variableValueEmptyMessage; > } >+ } >+ if (currentProject != null) { >+ // While editing project path variables, the variable value can >+ // contain macros such as "${foo}\etc" >+ allowFinish = true; >+ IPath resolvedPath = currentProject.getPathVariableManager() >+ .resolvePath(Path.fromPortableString(variableValue)); >+ if (!IDEResourceInfoUtils.exists(resolvedPath.toOSString())) { >+ // the path does not exist (warning) >+ message = IDEWorkbenchMessages.PathVariableDialog_pathDoesNotExistMessage; >+ newValidationStatus = IMessageProvider.WARNING; >+ } else { >+ IFileInfo info = IDEResourceInfoUtils.getFileInfo(resolvedPath >+ .toOSString()); >+ if (info.isDirectory() != ((variableType & IResource.FOLDER) != 0)) { >+ allowFinish = false; >+ newValidationStatus = IMessageProvider.ERROR; >+ if (((variableType & IResource.FOLDER) != 0)) >+ message = IDEWorkbenchMessages.PathVariableDialog_variableValueIsWrongTypeFolder; >+ else >+ message = IDEWorkbenchMessages.PathVariableDialog_variableValueIsWrongTypeFile; >+ } >+ } > } else if (!Path.EMPTY.isValidPath(variableValue)) { > // the variable value is an invalid path > message = IDEWorkbenchMessages.PathVariableDialog_variableValueInvalidMessage; >@@ -534,7 +616,21 @@ > public void setVariableValue(String variableValue) { > this.variableValue = variableValue; > } >- >+ >+ /** >+ * @param project >+ */ >+ public void setProject(IProject project) { >+ currentProject = project; >+ } >+ >+ /** >+ * @param location >+ */ >+ public void setLinkLocation(IPath location) { >+ this.variableValue = location.toPortableString(); >+ } >+ > /* > * (non-Javadoc) > * @see org.eclipse.jface.dialogs.Dialog#isResizable() >Index: src/org/eclipse/ui/internal/ide/dialogs/IDEResourceInfoUtils.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/dialogs/IDEResourceInfoUtils.java,v >retrieving revision 1.17 >diff -u -r1.17 IDEResourceInfoUtils.java >--- src/org/eclipse/ui/internal/ide/dialogs/IDEResourceInfoUtils.java 24 Mar 2008 19:13:35 -0000 1.17 >+++ src/org/eclipse/ui/internal/ide/dialogs/IDEResourceInfoUtils.java 11 Sep 2008 12:30:46 -0000 >@@ -227,7 +227,9 @@ > return NOT_EXIST_TEXT; > } > >- IFileStore store = getFileStore(location); >+ IFileStore store = null; >+ if (resolvedLocation.equals(location)) >+ store = getFileStore(location); > // don't access the file system for closed projects (bug 151089) > if (isProjectAccessible(resource) && resolvedLocation != null > && !isPathVariable(resource)) { >@@ -243,7 +245,11 @@ > if (store != null) { > return store.toString(); > } >- return location.toString(); >+ final String scheme = location.getScheme(); >+ // null scheme represents path variable >+ if (scheme == null || EFS.SCHEME_FILE.equals(scheme)) >+ return new Path(location.getSchemeSpecificPart()).toPortableString(); >+ return location.toASCIIString(); > } > > /** >Index: src/org/eclipse/ui/internal/ide/dialogs/ResourceInfoPage.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/dialogs/ResourceInfoPage.java,v >retrieving revision 1.36 >diff -u -r1.36 ResourceInfoPage.java >--- src/org/eclipse/ui/internal/ide/dialogs/ResourceInfoPage.java 25 Sep 2006 14:49:33 -0000 1.36 >+++ src/org/eclipse/ui/internal/ide/dialogs/ResourceInfoPage.java 11 Sep 2008 12:30:48 -0000 >@@ -13,6 +13,7 @@ > import java.net.URI; > > import org.eclipse.core.filesystem.EFS; >+import org.eclipse.core.filesystem.IFileInfo; > import org.eclipse.core.filesystem.IFileSystem; > import org.eclipse.core.resources.IContainer; > import org.eclipse.core.resources.IFile; >@@ -21,13 +22,19 @@ > import org.eclipse.core.resources.ResourceAttributes; > import org.eclipse.core.runtime.CoreException; > import org.eclipse.core.runtime.IPath; >+import org.eclipse.core.runtime.NullProgressMonitor; >+import org.eclipse.core.runtime.Path; > import org.eclipse.core.runtime.content.IContentDescription; > import org.eclipse.jface.dialogs.ErrorDialog; > import org.eclipse.jface.preference.FieldEditor; > import org.eclipse.jface.util.IPropertyChangeListener; > import org.eclipse.jface.util.PropertyChangeEvent; >+import org.eclipse.jface.window.Window; >+import org.eclipse.osgi.util.NLS; > import org.eclipse.osgi.util.TextProcessor; > import org.eclipse.swt.SWT; >+import org.eclipse.swt.events.SelectionEvent; >+import org.eclipse.swt.events.SelectionListener; > import org.eclipse.swt.graphics.Font; > import org.eclipse.swt.layout.GridData; > import org.eclipse.swt.layout.GridLayout; >@@ -95,6 +102,13 @@ > > private static String CONTAINER_ENCODING_TITLE = IDEWorkbenchMessages.ResourceInfo_fileEncodingTitle; > >+ private static String EDIT_TITLE = IDEWorkbenchMessages.ResourceInfo_edit; >+ >+ private Text resolvedLocationValue = null; >+ private Text locationValue = null; >+ private Text sizeValue = null; >+ private IPath newResourceLocation = null; >+ > // Max value width in characters before wrapping > private static final int MAX_VALUE_WIDTH = 80; > >@@ -158,29 +172,61 @@ > SWT.COLOR_WIDGET_BACKGROUND)); > typeValue.setFont(font); > >- // The group for location >- Label locationTitle = new Label(basicInfoComposite, SWT.LEFT); >- locationTitle.setText(LOCATION_TITLE); >- gd = new GridData(); >- gd.verticalAlignment = SWT.TOP; >- locationTitle.setLayoutData(gd); >- locationTitle.setFont(font); >+ if (resource.isLinked()) { >+ // The group for location >+ Label locationTitle = new Label(basicInfoComposite, SWT.LEFT); >+ locationTitle.setText(LOCATION_TITLE); >+ gd = new GridData(); >+ gd.verticalAlignment = SWT.TOP; >+ locationTitle.setLayoutData(gd); >+ locationTitle.setFont(font); > >- Text locationValue = new Text(basicInfoComposite, SWT.WRAP >- | SWT.READ_ONLY); >- String locationStr = TextProcessor.process(IDEResourceInfoUtils >- .getLocationText(resource)); >- locationValue.setText(locationStr); >- gd = new GridData(); >- gd.widthHint = convertWidthInCharsToPixels(MAX_VALUE_WIDTH); >- gd.grabExcessHorizontalSpace = true; >- gd.horizontalAlignment = GridData.FILL; >- locationValue.setLayoutData(gd); >- locationValue.setFont(font); >- locationValue.setBackground(locationValue.getDisplay().getSystemColor( >- SWT.COLOR_WIDGET_BACKGROUND)); >+ Composite locationComposite = new Composite(basicInfoComposite, >+ SWT.NULL); >+ layout = new GridLayout(); >+ layout.numColumns = 2; >+ layout.marginWidth = 0; >+ layout.marginHeight = 0; >+ locationComposite.setLayout(layout); >+ gd = new GridData(); >+ gd.widthHint = convertWidthInCharsToPixels(MAX_VALUE_WIDTH); >+ gd.grabExcessHorizontalSpace = true; >+ gd.horizontalAlignment = GridData.FILL; >+ locationComposite.setLayoutData(gd); >+ >+ locationValue = new Text(locationComposite, SWT.WRAP >+ | SWT.READ_ONLY); >+ String locationStr = TextProcessor.process(IDEResourceInfoUtils >+ .getLocationText(resource)); >+ locationValue.setText(locationStr); >+ gd = new GridData(); >+ gd.widthHint = convertWidthInCharsToPixels(MAX_VALUE_WIDTH); >+ gd.grabExcessHorizontalSpace = true; >+ gd.horizontalAlignment = GridData.FILL; >+ locationValue.setLayoutData(gd); >+ locationValue.setFont(font); >+ locationValue.setBackground(locationValue.getDisplay() >+ .getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)); >+ >+ Button editButton = new Button(locationComposite, SWT.PUSH); >+ editButton.setText(EDIT_TITLE); >+ gd = new GridData(); >+ gd.widthHint = convertWidthInCharsToPixels(EDIT_TITLE >+ .length()) * 2 + 40; >+ gd.grabExcessHorizontalSpace = true; >+ gd.horizontalAlignment = GridData.FILL; >+ editButton.setLayoutData(gd); >+ editButton.setFont(font); >+ editButton.addSelectionListener(new SelectionListener() { >+ public void widgetDefaultSelected(SelectionEvent e) { >+ editLinkLocation(); >+ } >+ >+ public void widgetSelected(SelectionEvent e) { >+ editLinkLocation(); >+ } >+ }); > >- if (isPathVariable(resource)) { > Label resolvedLocationTitle = new Label(basicInfoComposite, > SWT.LEFT); > resolvedLocationTitle.setText(RESOLVED_LOCATION_TITLE); >@@ -189,7 +235,7 @@ > resolvedLocationTitle.setLayoutData(gd); > resolvedLocationTitle.setFont(font); > >- Text resolvedLocationValue = new Text(basicInfoComposite, SWT.WRAP >+ resolvedLocationValue = new Text(basicInfoComposite, SWT.WRAP > | SWT.READ_ONLY); > resolvedLocationValue.setText(IDEResourceInfoUtils > .getResolvedLocationText(resource)); >@@ -201,6 +247,27 @@ > resolvedLocationValue.setFont(font); > resolvedLocationValue.setBackground(resolvedLocationValue > .getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)); >+ } else { >+ Label locationTitle = new Label(basicInfoComposite, SWT.LEFT); >+ locationTitle.setText(LOCATION_TITLE); >+ gd = new GridData(); >+ gd.verticalAlignment = SWT.TOP; >+ locationTitle.setLayoutData(gd); >+ locationTitle.setFont(font); >+ >+ Text locationValue = new Text(basicInfoComposite, SWT.WRAP >+ | SWT.READ_ONLY); >+ String locationStr = TextProcessor.process(IDEResourceInfoUtils >+ .getLocationText(resource)); >+ locationValue.setText(locationStr); >+ gd = new GridData(); >+ gd.widthHint = convertWidthInCharsToPixels(MAX_VALUE_WIDTH); >+ gd.grabExcessHorizontalSpace = true; >+ gd.horizontalAlignment = GridData.FILL; >+ locationValue.setLayoutData(gd); >+ locationValue.setFont(font); >+ locationValue.setBackground(locationValue.getDisplay() >+ .getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)); > } > if (resource.getType() == IResource.FILE) { > // The group for size >@@ -208,8 +275,7 @@ > sizeTitle.setText(SIZE_TITLE); > sizeTitle.setFont(font); > >- Text sizeValue = new Text(basicInfoComposite, SWT.LEFT >- | SWT.READ_ONLY); >+ sizeValue = new Text(basicInfoComposite, SWT.LEFT | SWT.READ_ONLY); > sizeValue.setText(IDEResourceInfoUtils.getSizeString(resource)); > gd = new GridData(); > gd.widthHint = convertWidthInCharsToPixels(MAX_VALUE_WIDTH); >@@ -224,6 +290,54 @@ > return basicInfoComposite; > } > >+ protected void editLinkLocation() { >+ IResource resource = (IResource) getElement().getAdapter( >+ IResource.class); >+ IPath location = resource.getRawLocation(); >+ >+ PathVariableDialog dialog = new PathVariableDialog(getShell(), >+ PathVariableDialog.EDIT_LINK_LOCATION, resource.getType(), >+ resource.getProject().getPathVariableManager(), null); >+ dialog.setLinkLocation(location); >+ dialog.setProject(resource.getProject()); >+ // opens the dialog - just returns if the user cancels it >+ if (dialog.open() == Window.CANCEL) { >+ return; >+ } >+ location = Path.fromOSString(dialog.getVariableValue()); >+ newResourceLocation = location; >+ refreshLinkLocation(); >+ } >+ >+ private void refreshLinkLocation() { >+ IResource resource = (IResource) getElement().getAdapter( >+ IResource.class); >+ >+ locationValue.setText(newResourceLocation.toPortableString()); >+ >+ IPath resolved = resource.getProject().getPathVariableManager() >+ .resolvePath(newResourceLocation); >+ if (!IDEResourceInfoUtils.exists(resolved.toOSString())) { >+ resolvedLocationValue >+ .setText(IDEWorkbenchMessages.ResourceInfo_undefinedPathVariable); >+ if (sizeValue != null) >+ sizeValue.setText(IDEWorkbenchMessages.ResourceInfo_notExist); >+ } else { >+ resolvedLocationValue.setText(resolved.toPortableString()); >+ if (sizeValue != null) { >+ IFileInfo info = IDEResourceInfoUtils.getFileInfo(resolved >+ .toPortableString()); >+ if (info != null) >+ sizeValue.setText(NLS.bind( >+ IDEWorkbenchMessages.ResourceInfo_bytes, Long >+ .toString(info.getLength()))); >+ else >+ sizeValue >+ .setText(IDEWorkbenchMessages.ResourceInfo_unknown); >+ } >+ } >+ } >+ > protected Control createContents(Composite parent) { > > PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), >@@ -508,24 +622,18 @@ > * resource is either not a linked resource or it is not using a > * path variable. > */ >- private boolean isPathVariable(IResource resource) { >- if (!resource.isLinked()) { >- return false; >- } >- >- IPath resolvedLocation = resource.getLocation(); >- if (resolvedLocation == null) { >- // missing path variable >- return true; >- } >- IPath rawLocation = resource.getRawLocation(); >- if (resolvedLocation.equals(rawLocation)) { >- return false; >- } >- >- return true; >- } >- >+ /* >+ * Now shows the same widgets for all linked files. private boolean >+ * isPathVariable(IResource resource) { if (!resource.isLinked()) { return >+ * false; } >+ * >+ * IPath resolvedLocation = resource.getLocation(); if (resolvedLocation == >+ * null) { // missing path variable return true; } IPath rawLocation = >+ * resource.getRawLocation(); if (resolvedLocation.equals(rawLocation)) { >+ * return false; } >+ * >+ * return true; } >+ */ > /** > * Reset the editableBox to the false. > */ >@@ -537,6 +645,20 @@ > if (resource == null) > return; > >+ if (newResourceLocation != null) { >+ newResourceLocation = null; >+ >+ resolvedLocationValue.setText(IDEResourceInfoUtils >+ .getResolvedLocationText(resource)); >+ >+ String locationStr = TextProcessor.process(IDEResourceInfoUtils >+ .getLocationText(resource)); >+ locationValue.setText(locationStr); >+ >+ if (sizeValue != null) >+ sizeValue.setText(IDEResourceInfoUtils.getSizeString(resource)); >+ } >+ > // Nothing to update if we never made the box > if (this.editableBox != null) { > this.editableBox.setSelection(false); >@@ -578,6 +700,11 @@ > } > > try { >+ if (newResourceLocation != null) { >+ resource.setLinkLocation(newResourceLocation, 0, >+ new NullProgressMonitor()); >+ } >+ > ResourceAttributes attrs = resource.getResourceAttributes(); > if (attrs != null) { > boolean hasChange = false; >Index: src/org/eclipse/ui/internal/ide/dialogs/CreateLinkedResourceGroup.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/dialogs/CreateLinkedResourceGroup.java,v >retrieving revision 1.29 >diff -u -r1.29 CreateLinkedResourceGroup.java >--- src/org/eclipse/ui/internal/ide/dialogs/CreateLinkedResourceGroup.java 9 May 2008 14:13:06 -0000 1.29 >+++ src/org/eclipse/ui/internal/ide/dialogs/CreateLinkedResourceGroup.java 11 Sep 2008 12:30:46 -0000 >@@ -18,6 +18,7 @@ > import org.eclipse.core.filesystem.IFileStore; > import org.eclipse.core.filesystem.URIUtil; > import org.eclipse.core.resources.IPathVariableManager; >+import org.eclipse.core.resources.IProject; > import org.eclipse.core.resources.IResource; > import org.eclipse.core.resources.IWorkspace; > import org.eclipse.core.resources.ResourcesPlugin; >@@ -27,6 +28,7 @@ > import org.eclipse.core.runtime.Status; > import org.eclipse.jface.dialogs.Dialog; > import org.eclipse.jface.dialogs.IDialogConstants; >+import org.eclipse.jface.fieldassist.FieldAssistColors; > import org.eclipse.swt.SWT; > import org.eclipse.swt.events.ModifyEvent; > import org.eclipse.swt.events.ModifyListener; >@@ -106,6 +108,13 @@ > * @return the current value, or <code>null</code> > */ > String getValue(); >+ >+ /** >+ * Gets the project to which the resource will belong >+ * >+ * @return the IProject object, or <code>null</code> >+ */ >+ IProject getProject(); > } > > private String lastUpdatedValue; >@@ -171,6 +180,12 @@ > browseButton.setEnabled(createLink); > variablesButton.setEnabled(createLink); > // Set the required field color if the field is enabled >+ if (createLink) { >+ linkTargetField.setBackground(FieldAssistColors >+ .getRequiredFieldBackgroundColor(linkTargetField)); >+ } else { >+ linkTargetField.setBackground(null); >+ } > linkTargetField.setEnabled(createLink); > if (fileSystemSelectionArea != null) > fileSystemSelectionArea.setEnabled(createLink); >@@ -220,6 +235,10 @@ > data.horizontalSpan = 2; > linkTargetField.setLayoutData(data); > linkTargetField.setEnabled(enabled); >+ if (enabled) { >+ linkTargetField.setBackground(FieldAssistColors >+ .getRequiredFieldBackgroundColor(linkTargetField)); >+ } > linkTargetField.addModifyListener(new ModifyListener() { > public void modifyText(ModifyEvent e) { > linkTarget = linkTargetField.getText(); >@@ -353,9 +372,13 @@ > if (!createLink) > return null; > // resolve path variable if we have a relative path >- if (!linkTarget.startsWith("/")) { //$NON-NLS-1$ >- IPathVariableManager pathVariableManager = ResourcesPlugin >- .getWorkspace().getPathVariableManager(); >+ if (!Path.fromPortableString(linkTarget).isAbsolute()) { >+ IPathVariableManager pathVariableManager; >+ >+ if (updatableResourceName.getProject() != null) >+ pathVariableManager = updatableResourceName.getProject().getPathVariableManager(); >+ else >+ pathVariableManager = ResourcesPlugin.getWorkspace().getPathVariableManager(); > try { > > URI path = new URI(linkTarget.replace(java.io.File.separatorChar, '/')); >@@ -475,6 +498,7 @@ > > PathVariableSelectionDialog dialog = new PathVariableSelectionDialog( > linkTargetField.getShell(), variableTypes); >+ dialog.setProject(updatableResourceName.getProject()); > if (dialog.open() == IDialogConstants.OK_ID) { > String[] variableNames = (String[]) dialog.getResult(); > if (variableNames != null && variableNames.length == 1) { >@@ -616,9 +640,14 @@ > return locationStatus; > } > >+ IPathVariableManager pathVariableManager; > // use the resolved link target name >- URI resolved = workspace.getPathVariableManager().resolveURI( >- locationURI); >+ if (updatableResourceName.getProject() != null) >+ pathVariableManager = updatableResourceName.getProject().getPathVariableManager(); >+ else >+ pathVariableManager = workspace.getPathVariableManager(); >+ >+ URI resolved = pathVariableManager.resolveURI(locationURI); > IFileInfo linkTargetFile = IDEResourceInfoUtils.getFileInfo(resolved); > if (linkTargetFile != null && linkTargetFile.exists()) { > IStatus fileTypeStatus = validateFileType(linkTargetFile); >Index: src/org/eclipse/ui/internal/ide/dialogs/PathVariablesGroup.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/dialogs/PathVariablesGroup.java,v >retrieving revision 1.10 >diff -u -r1.10 PathVariablesGroup.java >--- src/org/eclipse/ui/internal/ide/dialogs/PathVariablesGroup.java 8 May 2006 20:54:08 -0000 1.10 >+++ src/org/eclipse/ui/internal/ide/dialogs/PathVariablesGroup.java 11 Sep 2008 12:30:48 -0000 >@@ -7,6 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Serge Beauchamp (Freescale Semiconductor) > *******************************************************************************/ > package org.eclipse.ui.internal.ide.dialogs; > >@@ -19,7 +20,9 @@ > > import org.eclipse.core.filesystem.IFileInfo; > import org.eclipse.core.resources.IPathVariableManager; >+import org.eclipse.core.resources.IProject; > import org.eclipse.core.resources.IResource; >+import org.eclipse.core.resources.ProjectVariableProviderManager; > import org.eclipse.core.resources.ResourcesPlugin; > import org.eclipse.core.runtime.CoreException; > import org.eclipse.core.runtime.IPath; >@@ -29,6 +32,7 @@ > import org.eclipse.jface.dialogs.IDialogConstants; > import org.eclipse.jface.resource.ImageDescriptor; > import org.eclipse.jface.window.Window; >+import org.eclipse.osgi.util.NLS; > import org.eclipse.swt.SWT; > import org.eclipse.swt.events.SelectionAdapter; > import org.eclipse.swt.events.SelectionEvent; >@@ -120,9 +124,15 @@ > private final Image FOLDER_IMG = PlatformUI.getWorkbench() > .getSharedImages().getImage(ISharedImages.IMG_OBJ_FOLDER); > >+ private final Image BUILTIN_IMG = PlatformUI.getWorkbench() >+ .getSharedImages().getImage(ISharedImages.IMG_OBJ_FOLDER); > // unknown (non-existent) image. created locally, dispose locally > private Image imageUnkown; > >+ // current project for which the variables are being edited. >+ // If null, the workspace variables are being edited instead. >+ private IProject currentProject = null; >+ > /** > * Creates a new PathVariablesGroup. > * >@@ -167,6 +177,7 @@ > PathVariableDialog.NEW_VARIABLE, variableType, > pathVariableManager, tempPathVariables.keySet()); > >+ dialog.setProject(currentProject); > // opens the dialog - just returns if the user cancels it > if (dialog.open() == Window.CANCEL) { > return; >@@ -217,7 +228,13 @@ > > // layout the table & its buttons > variableLabel = new Label(pageComponent, SWT.LEFT); >- variableLabel.setText(IDEWorkbenchMessages.PathVariablesBlock_variablesLabel); >+ if (currentProject == null) >+ variableLabel.setText(IDEWorkbenchMessages.PathVariablesBlock_variablesLabel); >+ else >+ variableLabel.setText(NLS.bind( >+ IDEWorkbenchMessages.PathVariablesBlock_variablesLabelForProject, >+ currentProject.getName())); >+ > data = new GridData(); > data.horizontalAlignment = GridData.FILL; > data.horizontalSpan = 2; >@@ -277,6 +294,7 @@ > pathVariableManager, tempPathVariables.keySet()); > dialog.setVariableName(variableName); > dialog.setVariableValue(variableValue.toOSString()); >+ dialog.setProject(currentProject); > > // opens the dialog - just returns if the user cancels it > if (dialog.open() == Window.CANCEL) { >@@ -432,8 +450,8 @@ > */ > private void updateEnabledState() { > int itemsSelectedCount = variableTable.getSelectionCount(); >- editButton.setEnabled(itemsSelectedCount == 1); >- removeButton.setEnabled(itemsSelectedCount > 0); >+ editButton.setEnabled(itemsSelectedCount == 1 && canChangeSelection()); >+ removeButton.setEnabled(itemsSelectedCount > 0 && canChangeSelection()); > } > > /** >@@ -455,13 +473,21 @@ > TableItem item = new TableItem(variableTable, SWT.NONE); > String varName = (String) varNames.next(); > IPath value = (IPath) tempPathVariables.get(varName); >- IFileInfo file = IDEResourceInfoUtils.getFileInfo(value); > > item.setText(varName + " - " + value.toOSString()); //$NON-NLS-1$ >+ >+ if (currentProject != null) >+ value = currentProject.getPathVariableManager().resolvePath( >+ value); >+ IFileInfo file = IDEResourceInfoUtils.getFileInfo(value); >+ > // the corresponding variable name is stored in each table widget item > item.setData(varName); >- item.setImage(file.exists() ? (file.isDirectory() ? FOLDER_IMG >- : FILE_IMG ) : imageUnkown); >+ if (!isBuiltInVariable(varName)) { >+ item.setImage(file.exists() ? (file.isDirectory() ? FOLDER_IMG : FILE_IMG) : imageUnkown); >+ } else >+ item.setImage(BUILTIN_IMG); >+ > if (varName.equals(selectedVarName)) { > selectedVarIndex = variableTable.getItemCount() - 1; > } >@@ -501,7 +527,8 @@ > Map.Entry entry = (Map.Entry) current.next(); > String variableName = (String) entry.getKey(); > IPath variableValue = (IPath) entry.getValue(); >- pathVariableManager.setValue(variableName, variableValue); >+ if (!isBuiltInVariable(variableName)) >+ pathVariableManager.setValue(variableName, variableValue); > } > // re-initialize temporary state > initTemporaryState(); >@@ -529,6 +556,35 @@ > updateWidgetState(null); > } > >+ private boolean canChangeSelection() { >+ int[] selectedIndices = variableTable.getSelectionIndices(); >+ for (int i = 0; i < selectedIndices.length; i++) { >+ TableItem selectedItem = variableTable.getItem(selectedIndices[i]); >+ String varName = (String) selectedItem.getData(); >+ if (isBuiltInVariable(varName)) >+ return false; >+ } >+ return true; >+ } >+ >+ /** >+ * @param varName >+ * the variable name to test >+ */ >+ private boolean isBuiltInVariable(String varName) { >+ if (currentProject != null) { >+ ProjectVariableProviderManager.Descriptor descriptors[] = ProjectVariableProviderManager >+ .getDefault().getDescriptors(); >+ if (descriptors != null) { >+ for (int j = 0; j < descriptors.length; j++) { >+ if (varName.equals(descriptors[j].getName())) >+ return true; >+ } >+ } >+ } >+ return false; >+ } >+ > /** > * Sets the <code>GridData</code> on the specified button to > * be one that is spaced for the current dialog page units. The >@@ -580,4 +636,16 @@ > updateVariableTable(selectedVarName); > updateEnabledState(); > } >+ >+ /** >+ * @param receivingProject >+ */ >+ public void setProject(IProject project) { >+ currentProject = project; >+ pathVariableManager = project.getPathVariableManager(); >+ removedVariableNames = new HashSet(); >+ tempPathVariables = new TreeMap(); >+ // initialize internal model >+ initTemporaryState(); >+ } > } >Index: plugin.properties >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide/plugin.properties,v >retrieving revision 1.141 >diff -u -r1.141 plugin.properties >--- plugin.properties 9 May 2008 18:52:05 -0000 1.141 >+++ plugin.properties 11 Sep 2008 12:30:37 -0000 >@@ -282,3 +282,5 @@ > menu.mnemonic.0 = I > menu.showIn.label = Show In > menu.showIn.mnemonic = I >+ >+linked_resources = Linked Resources >Index: plugin.xml >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide/plugin.xml,v >retrieving revision 1.278 >diff -u -r1.278 plugin.xml >--- plugin.xml 9 May 2008 17:05:06 -0000 1.278 >+++ plugin.xml 11 Sep 2008 12:30:39 -0000 >@@ -636,6 +636,15 @@ > </adapt> > </enabledWhen> > </page> >+ <page >+ class="org.eclipse.ui.internal.ide.dialogs.ProjectLinkedResourcePage" >+ id="org.eclipse.ui.propertypages.project.linkedResourcesPage" >+ name="%linked_resources" >+ > >+ <enabledWhen> >+ <adapt type="org.eclipse.core.resources.IProject"/> >+ </enabledWhen> >+ </page> > </extension> > <extension > point="org.eclipse.ui.commands"> >Index: src/org/eclipse/ui/wizards/datatransfer/ImportOperation.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide/src/org/eclipse/ui/wizards/datatransfer/ImportOperation.java,v >retrieving revision 1.16 >diff -u -r1.16 ImportOperation.java >--- src/org/eclipse/ui/wizards/datatransfer/ImportOperation.java 9 May 2008 14:13:07 -0000 1.16 >+++ src/org/eclipse/ui/wizards/datatransfer/ImportOperation.java 11 Sep 2008 12:30:49 -0000 >@@ -8,6 +8,7 @@ > * Contributors: > * IBM Corporation - initial API and implementation > * Red Hat, Inc - changed TarFileStructureProvider to TarLeveledStructureProvider >+ * Serge Beauchamp (Freescale Semiconductor) > *******************************************************************************/ > package org.eclipse.ui.wizards.datatransfer; > >@@ -22,6 +23,8 @@ > import org.eclipse.core.resources.IContainer; > import org.eclipse.core.resources.IFile; > import org.eclipse.core.resources.IFolder; >+import org.eclipse.core.resources.IPathVariableManager; >+import org.eclipse.core.resources.IProject; > import org.eclipse.core.resources.IResource; > import org.eclipse.core.resources.IWorkspace; > import org.eclipse.core.resources.IWorkspaceRoot; >@@ -82,6 +85,10 @@ > > private List errorTable = new ArrayList(); > >+ private boolean createLinks = false; >+ >+ private String relativeVariable = null; >+ > private boolean createContainerStructure = true; > > //The constants for the overwrite 3 state >@@ -304,8 +311,12 @@ > for (int i = 0; i < segmentCount; i++) { > currentFolder = currentFolder.getFolder(new Path(path.segment(i))); > if (!currentFolder.exists()) { >- ((IFolder) currentFolder).create(false, true, null); >- } >+ if (createLinks) >+ ((IFolder) currentFolder).createLink(createRelativePath( >+ currentFolder.getProject(), path), 0, null); >+ else >+ ((IFolder) currentFolder).create(false, true, null); >+ } > } > > return currentFolder; >@@ -551,11 +562,16 @@ > if (targetResource.exists()) { > targetResource.setContents(contentStream, > IResource.KEEP_HISTORY, null); >- } else { >- targetResource.create(contentStream, false, null); >- } >- setResourceAttributes(targetResource,fileObject); >- >+ } else { >+ if (createLinks) >+ targetResource.createLink(createRelativePath( >+ containerResource.getProject(), new Path(provider >+ .getFullPath(fileObject))), 0, null); >+ else >+ targetResource.create(contentStream, false, null); >+ } >+ setResourceAttributes(targetResource, fileObject); >+ > if (provider instanceof TarLeveledStructureProvider) { > try { > targetResource.setResourceAttributes(((TarLeveledStructureProvider) provider).getResourceAttributes(fileObject)); >@@ -607,7 +623,7 @@ > * (element type: <code>Object</code>) > * @exception OperationCanceledException if canceled > */ >- void importFileSystemObjects(List filesToImport) { >+ void importFileSystemObjects(List filesToImport) throws CoreException { > Iterator filesEnum = filesToImport.iterator(); > while (filesEnum.hasNext()) { > Object fileSystemObject = filesEnum.next(); >@@ -639,7 +655,7 @@ > * @param policy determines how the folder object and children are imported > * @return the policy to use to import the folder's children > */ >- int importFolder(Object folderObject, int policy) { >+ int importFolder(Object folderObject, int policy) throws CoreException { > IContainer containerResource; > try { > containerResource = getDestinationContainerFor(folderObject); >@@ -669,12 +685,22 @@ > return POLICY_SKIP_CHILDREN; > } > >- return POLICY_FORCE_OVERWRITE; >+ IFolder folder = workspace.getRoot().getFolder(resourcePath); >+ if (createLinks || folder.isLinked()) { >+ folder.delete(true, null); >+ } else >+ return POLICY_FORCE_OVERWRITE; > } > > try { >- workspace.getRoot().getFolder(resourcePath).create(false, true, >- null); >+ if (createLinks) { >+ workspace.getRoot().getFolder(resourcePath).createLink( >+ createRelativePath(containerResource.getProject(), >+ new Path(provider.getFullPath(folderObject))), >+ 0, null); >+ policy = POLICY_SKIP_CHILDREN; >+ } else >+ workspace.getRoot().getFolder(resourcePath).create(false, true, null); > } catch (CoreException e) { > errorTable.add(e.getStatus()); > } >@@ -683,6 +709,25 @@ > } > > /** >+ * Transform an absolute path URI to a relative path one (i.e. from >+ * "C:\foo\bar\file.txt" to "VAR\file.txt" granted that the relativeVariable >+ * is "VAR" and points to "C:\foo\bar\"). >+ * >+ * @param locationURI >+ * @return an URI that was made relative to a variable >+ */ >+ private IPath createRelativePath(IProject project, IPath location) { >+ if (relativeVariable == null) >+ return location; >+ IPathVariableManager pathVariableManager = project.getPathVariableManager(); >+ try { >+ return pathVariableManager.convertToRelative(location, true, relativeVariable); >+ } catch (CoreException e) { >+ return location; >+ } >+ } >+ >+ /** > * Imports the specified file system object recursively into the workspace. > * If the import fails, adds a status object to the list to be returned by > * <code>getStatus</code>. >@@ -691,7 +736,7 @@ > * @param policy determines how the file system object and children are imported > * @exception OperationCanceledException if canceled > */ >- void importRecursivelyFrom(Object fileSystemObject, int policy) { >+ void importRecursivelyFrom(Object fileSystemObject, int policy) throws CoreException { > if (monitor.isCanceled()) { > throw new OperationCanceledException(); > } >@@ -864,4 +909,22 @@ > rejectedFiles = validateEdit(overwriteReadonly); > rejectedFiles.addAll(noOverwrite); > } >+ >+ /** >+ * Set Whether links will be created instead of files and folders >+ * >+ * @param links >+ */ >+ public void setCreateLinks(boolean links) { >+ createLinks = links; >+ } >+ >+ /** >+ * Set a variable relative to which the links are created >+ * >+ * @param variable >+ */ >+ public void setRelativeVariable(String variable) { >+ relativeVariable = variable; >+ } > } >Index: extensions/org/eclipse/ui/actions/CopyFilesAndFoldersOperation.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide/extensions/org/eclipse/ui/actions/CopyFilesAndFoldersOperation.java,v >retrieving revision 1.31 >diff -u -r1.31 CopyFilesAndFoldersOperation.java >--- extensions/org/eclipse/ui/actions/CopyFilesAndFoldersOperation.java 2 May 2008 19:37:07 -0000 1.31 >+++ extensions/org/eclipse/ui/actions/CopyFilesAndFoldersOperation.java 11 Sep 2008 12:30:40 -0000 >@@ -22,9 +22,11 @@ > import org.eclipse.core.filesystem.EFS; > import org.eclipse.core.filesystem.IFileInfo; > import org.eclipse.core.filesystem.IFileStore; >+import org.eclipse.core.filesystem.URIUtil; > import org.eclipse.core.resources.IContainer; > import org.eclipse.core.resources.IFile; > import org.eclipse.core.resources.IFolder; >+import org.eclipse.core.resources.IPathVariableManager; > import org.eclipse.core.resources.IProject; > import org.eclipse.core.resources.IResource; > import org.eclipse.core.resources.IWorkspace; >@@ -92,6 +94,13 @@ > private boolean canceled = false; > > /** >+ * Whether or not the operation creates links instead of folders and files. >+ */ >+ private boolean createLinks = false; >+ >+ private String relativeVariable = null; >+ >+ /** > * Overwrite all flag. > */ > private boolean alwaysOverwrite = false; >@@ -426,22 +435,33 @@ > new SubProgressMonitor(subMonitor, 1)); > } > } else { >- if (existing != null) { >- if (homogenousResources(source, existing)) { >- copyExisting(source, existing, new SubProgressMonitor( >- subMonitor, 1)); >- } else { >+ if (existing != null && homogenousResources(source, existing)) { >+ copyExisting(source, existing, new SubProgressMonitor( >+ subMonitor, 1)); >+ } else { >+ if (existing != null) { > // Copying a linked resource over unlinked or vice > // versa. > // Can't use setContents here. Fixes bug 28772. > delete(existing, new SubProgressMonitor(subMonitor, 0)); >- source.copy(destinationPath, IResource.SHALLOW, >- new SubProgressMonitor(subMonitor, 1)); > } >- } else { >- source.copy(destinationPath, IResource.SHALLOW, >- new SubProgressMonitor(subMonitor, 1)); > >+ if (createLinks && (source.isLinked() == false)) { >+ if (source.getType() == IResource.FILE) { >+ IFile file = workspaceRoot.getFile(destinationPath); >+ file.createLink(createRelativePath(file.getProject().getPathVariableManager(), >+ source.getLocationURI()), 0, >+ new SubProgressMonitor(subMonitor, 1)); >+ } else { >+ IFolder folder = workspaceRoot >+ .getFolder(destinationPath); >+ folder.createLink(createRelativePath(folder.getProject().getPathVariableManager(), >+ source.getLocationURI()), 0, >+ new SubProgressMonitor(subMonitor, 1)); >+ } >+ } else >+ source.copy(destinationPath, IResource.SHALLOW, >+ new SubProgressMonitor(subMonitor, 1)); > } > > if (subMonitor.isCanceled()) { >@@ -452,6 +472,27 @@ > } > > /** >+ * Transform an absolute path URI to a relative path one (i.e. from >+ * "C:\foo\bar\file.txt" to "VAR\file.txt" granted that the relativeVariable >+ * is "VAR" and points to "C:\foo\bar\"). >+ * >+ * @param locationURI >+ * @return an URI that was made relative to a variable >+ */ >+ private URI createRelativePath(IPathVariableManager pvm, URI locationURI) { >+ if (relativeVariable == null) >+ return locationURI; >+ IPath location = URIUtil.toPath(locationURI); >+ IPath result; >+ try { >+ result = pvm.convertToRelative(location, true, relativeVariable); >+ } catch (CoreException e) { >+ return locationURI; >+ } >+ return URIUtil.toURI(result); >+ } >+ >+ /** > * Sets the content of the existing file to the source file content. > * > * @param source >@@ -1155,6 +1196,11 @@ > AbstractWorkspaceOperation op = getUndoableCopyOrMoveOperation( > resources, destination); > op.setModelProviderIds(getModelProviderIds()); >+ if (op instanceof CopyResourcesOperation) { >+ CopyResourcesOperation copyMoveOp = (CopyResourcesOperation) op; >+ copyMoveOp.setCreateLinks(createLinks); >+ copyMoveOp.setRelativeVariable(relativeVariable); >+ } > PlatformUI.getWorkbench().getOperationSupport() > .getOperationHistory().execute(op, monitor, > WorkspaceUndoUtil.getUIInfoAdapter(messageShell)); >@@ -1274,6 +1320,8 @@ > query, Arrays.asList(stores)); > op.setContext(messageShell); > op.setCreateContainerStructure(false); >+ op.setCreateLinks(createLinks); >+ op.setRelativeVariable(relativeVariable); > try { > op.run(monitor); > } catch (InterruptedException e) { >@@ -1703,6 +1751,49 @@ > } > > /** >+ * Create links of the given files and folders to the destination. The >+ * current Thread is halted while the resources are copied using a >+ * WorkspaceModifyOperation. This method should be called from the UI >+ * Thread. >+ * >+ * @param fileNames >+ * names of the files to copy >+ * @param destination >+ * destination to which files will be copied >+ * @see WorkspaceModifyOperation >+ * @see Display#getThread() >+ * @see Thread#currentThread() >+ * @since 3.2 >+ */ >+ public void linkFiles(final String[] fileNames, IContainer destination) { >+ IFileStore[] stores = buildFileStores(fileNames); >+ if (stores == null) { >+ return; >+ } >+ >+ createLinks = true; >+ copyFileStores(destination, stores, true, null); >+ } >+ >+ /** >+ * Set whether or not links will be created under the destination container. >+ * >+ * @param value >+ */ >+ public void setCreateLinks(boolean value) { >+ createLinks = value; >+ } >+ >+ /** >+ * Set a variable relative to which the links are created >+ * >+ * @param variable >+ */ >+ public void setRelativeVariable(String variable) { >+ relativeVariable = variable; >+ } >+ >+ /** > * Returns an AbstractWorkspaceOperation suitable for performing the move or > * copy operation that will move or copy the given resources to the given > * destination path. >Index: src/org/eclipse/ui/ide/dialogs/PathVariableSelectionDialog.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide/src/org/eclipse/ui/ide/dialogs/PathVariableSelectionDialog.java,v >retrieving revision 1.9 >diff -u -r1.9 PathVariableSelectionDialog.java >--- src/org/eclipse/ui/ide/dialogs/PathVariableSelectionDialog.java 24 Mar 2008 19:13:35 -0000 1.9 >+++ src/org/eclipse/ui/ide/dialogs/PathVariableSelectionDialog.java 11 Sep 2008 12:30:42 -0000 >@@ -7,6 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Serge Beauchamp (Freescale Semiconductor) > *******************************************************************************/ > > package org.eclipse.ui.ide.dialogs; >@@ -15,13 +16,25 @@ > import org.eclipse.core.filesystem.IFileInfo; > import org.eclipse.core.filesystem.IFileStore; > import org.eclipse.core.filesystem.URIUtil; >+import org.eclipse.core.resources.IProject; >+import org.eclipse.core.resources.ProjectVariableProviderManager; > import org.eclipse.core.runtime.CoreException; > import org.eclipse.core.runtime.IPath; > import org.eclipse.core.runtime.Path; > import org.eclipse.jface.dialogs.ErrorDialog; > import org.eclipse.jface.dialogs.IDialogConstants; >+import org.eclipse.jface.viewers.DoubleClickEvent; >+import org.eclipse.jface.viewers.IDoubleClickListener; >+import org.eclipse.jface.viewers.ISelectionChangedListener; >+import org.eclipse.jface.viewers.IStructuredSelection; >+import org.eclipse.jface.viewers.LabelProvider; >+import org.eclipse.jface.viewers.ListViewer; >+import org.eclipse.jface.viewers.SelectionChangedEvent; >+import org.eclipse.jface.viewers.StructuredSelection; > import org.eclipse.jface.window.Window; > import org.eclipse.osgi.util.NLS; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.layout.GridData; > import org.eclipse.swt.widgets.Button; > import org.eclipse.swt.widgets.Composite; > import org.eclipse.swt.widgets.Control; >@@ -35,6 +48,7 @@ > import org.eclipse.ui.internal.ide.dialogs.FileFolderSelectionDialog; > import org.eclipse.ui.internal.ide.dialogs.IDEResourceInfoUtils; > import org.eclipse.ui.internal.ide.dialogs.PathVariablesGroup; >+import org.eclipse.ui.internal.ide.dialogs.SimpleListContentProvider; > > /** > * A selection dialog which shows the path variables defined in the >@@ -61,6 +75,8 @@ > > private PathVariablesGroup pathVariablesGroup; > >+ private IProject currentProject = null; >+ > private int variableType; > > /** >@@ -84,6 +100,7 @@ > updateExtendButtonState(); > } > }); >+ setShellStyle(getShellStyle() | SWT.RESIZE); > } > > >@@ -92,23 +109,48 @@ > */ > protected void buttonPressed(int buttonId) { > if (buttonId == EXTEND_ID) { >- FileFolderSelectionDialog dialog = new FileFolderSelectionDialog( >- getShell(), false, variableType); >- PathVariablesGroup.PathVariableElement selection = pathVariablesGroup >- .getSelection()[0]; >- dialog.setTitle(IDEWorkbenchMessages.PathVariableSelectionDialog_ExtensionDialog_title); >- dialog.setMessage(NLS.bind(IDEWorkbenchMessages.PathVariableSelectionDialog_ExtensionDialog_description, selection.name)); >- //XXX This only works for variables that refer to local file system locations >- try { >- dialog.setInput(EFS.getStore(URIUtil.toURI(selection.path))); >- } catch (CoreException e) { >- ErrorDialog.openError(getShell(), null, null, e.getStatus()); >+ PathVariablesGroup.PathVariableElement selection = pathVariablesGroup >+ .getSelection()[0]; >+ ProjectVariableProviderManager.Descriptor desc = ProjectVariableProviderManager >+ .getDefault().findDescriptor(selection.name); >+ if (desc != null >+ && desc.getExtensions(selection.name, currentProject) != null) { >+ EnvSelectionDialog dialog = new EnvSelectionDialog(getShell(), >+ desc.getExtensions(selection.name, currentProject)); >+ dialog.setTitle(IDEWorkbenchMessages.PathVariableSelectionDialog_ExtensionDialog_title); >+ dialog.setMessage(NLS.bind(IDEWorkbenchMessages.PathVariableSelectionDialog_ExtensionDialog_description, selection.name)); >+ if (dialog.open() == Window.OK >+ && pathVariablesGroup.performOk()) { >+ setSelectionResult(new String[] { "${" + selection.name + "-" + dialog.getResult()[0] + "}" }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ >+ super.okPressed(); >+ } >+ } else { >+ FileFolderSelectionDialog dialog = new FileFolderSelectionDialog( >+ getShell(), false, variableType); >+ dialog >+ .setTitle(IDEWorkbenchMessages.PathVariableSelectionDialog_ExtensionDialog_title); >+ dialog >+ .setMessage(NLS >+ .bind( >+ IDEWorkbenchMessages.PathVariableSelectionDialog_ExtensionDialog_description, >+ selection.name)); >+ // XXX This only works for variables that refer to local file >+ // system locations >+ IPath selectionPath = selection.path; >+ if (currentProject != null) >+ selectionPath = currentProject.getPathVariableManager() >+ .resolvePath(selectionPath); >+ try { >+ dialog.setInput(EFS.getStore(URIUtil.toURI(selectionPath))); >+ } catch (CoreException e) { >+ ErrorDialog.openError(getShell(), null, null, e.getStatus()); >+ } >+ if (dialog.open() == Window.OK >+ && pathVariablesGroup.performOk()) { >+ setExtensionResult(selection, (IFileStore) dialog.getResult()[0]); >+ super.okPressed(); >+ } > } >- if (dialog.open() == Window.OK >- && pathVariablesGroup.performOk()) { >- setExtensionResult(selection, (IFileStore) dialog.getResult()[0]); >- super.okPressed(); >- } > } else { > super.buttonPressed(buttonId); > } >@@ -186,13 +228,16 @@ > private void setExtensionResult( > PathVariablesGroup.PathVariableElement variable, IFileStore extensionFile) { > IPath extensionPath = new Path(extensionFile.toString()); >- int matchCount = extensionPath.matchingFirstSegments(variable.path); >- IPath resultPath = new Path(variable.name); >+ IPath selectionPath = variable.path; >+ if (currentProject != null) >+ selectionPath = currentProject.getPathVariableManager().resolvePath(selectionPath); >+ int matchCount = extensionPath.matchingFirstSegments(selectionPath); >+ IPath resultPath = new Path(variable.name); > > extensionPath = extensionPath.removeFirstSegments(matchCount); > resultPath = resultPath.append(extensionPath); >- setSelectionResult(new String[] { resultPath.toOSString() }); >- } >+ setSelectionResult(new String[] { resultPath.toPortableString() }); >+ } > > /** > * Updates the enabled state of the Extend button based on the >@@ -207,8 +252,15 @@ > return; > } > if (selection.length == 1) { >- IFileInfo info = IDEResourceInfoUtils.getFileInfo(selection[0].path); >- if (info.exists() && info.isDirectory()) { >+ IPath selectionPath = selection[0].path; >+ if (currentProject != null) >+ selectionPath = currentProject.getPathVariableManager().resolvePath(selectionPath); >+ IFileInfo info = IDEResourceInfoUtils.getFileInfo(selectionPath); >+ ProjectVariableProviderManager.Descriptor desc = ProjectVariableProviderManager >+ .getDefault().findDescriptor(selection[0].name); >+ if (info.exists() && info.isDirectory() >+ || (desc != null && desc.getExtensions(selection[0].name, >+ currentProject) != null)) { > extendButton.setEnabled(true); > } else { > extendButton.setEnabled(false); >@@ -219,4 +271,88 @@ > } > } > >+ /** >+ * Sets the project for which the path variable is being edited. >+ * >+ * @param project >+ */ >+ public void setProject(IProject project) { >+ currentProject = project; >+ pathVariablesGroup.setProject(project); >+ } >+ >+ class EnvSelectionDialog extends SelectionDialog { >+ >+ ListViewer viewer; >+ Object[] extensions; >+ >+ protected EnvSelectionDialog(Shell parentShell, Object[] ext) { >+ super(parentShell); >+ setShellStyle(getShellStyle() | SWT.RESIZE); >+ extensions = ext; >+ } >+ >+ protected Control createDialogArea(Composite parent) { >+ Composite composite = (Composite) super.createDialogArea(parent); >+ >+ // Create label >+ createMessageArea(composite); >+ // Create list viewer >+ viewer = new ListViewer(composite, SWT.SINGLE | SWT.H_SCROLL >+ | SWT.V_SCROLL | SWT.BORDER); >+ GridData data = new GridData(GridData.FILL_BOTH); >+ data.heightHint = convertHeightInCharsToPixels(10); >+ data.widthHint = convertWidthInCharsToPixels(30); >+ viewer.getList().setLayoutData(data); >+ viewer.getList().setFont(parent.getFont()); >+ // Set the label provider >+ viewer.setLabelProvider(new LabelProvider() { >+ public String getText(Object element) { >+ if (element instanceof String) >+ return (String) element; >+ return null; >+ } >+ }); >+ >+ // Set the content provider >+ SimpleListContentProvider cp = new SimpleListContentProvider(); >+ cp.setElements(extensions); >+ viewer.setContentProvider(cp); >+ viewer.setInput(new Object()); >+ // it is ignored but must be non-null >+ >+ // Set the initial selection >+ viewer.setSelection(new StructuredSelection( >+ getInitialElementSelections()), true); >+ >+ // Add a selection change listener >+ viewer.addSelectionChangedListener(new ISelectionChangedListener() { >+ public void selectionChanged(SelectionChangedEvent event) { >+ // Update OK button enablement >+ getOkButton().setEnabled(!event.getSelection().isEmpty()); >+ } >+ }); >+ >+ // Add double-click listener >+ viewer.addDoubleClickListener(new IDoubleClickListener() { >+ public void doubleClick(DoubleClickEvent event) { >+ okPressed(); >+ } >+ }); >+ return composite; >+ } >+ >+ protected Control createButtonBar(Composite parent) { >+ Control result = super.createButtonBar(parent); >+ getOkButton().setEnabled(false); >+ return result; >+ } >+ >+ protected void okPressed() { >+ IStructuredSelection selection = (IStructuredSelection) viewer >+ .getSelection(); >+ setResult(selection.toList()); >+ super.okPressed(); >+ } >+ } > } >Index: src/org/eclipse/ui/ide/dialogs/PathVariableEditDialog.java >=================================================================== >RCS file: src/org/eclipse/ui/ide/dialogs/PathVariableEditDialog.java >diff -N src/org/eclipse/ui/ide/dialogs/PathVariableEditDialog.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/ui/ide/dialogs/PathVariableEditDialog.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,133 @@ >+/******************************************************************************* >+ * Copyright (c) 2000, 2006 IBM Corporation 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: >+ * IBM Corporation - initial API and implementation >+ * Serge Beauchamp (Freescale Semiconductor) >+ *******************************************************************************/ >+package org.eclipse.ui.ide.dialogs; >+ >+import org.eclipse.core.resources.IProject; >+import org.eclipse.core.resources.IResource; >+import org.eclipse.jface.dialogs.IDialogConstants; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.widgets.Composite; >+import org.eclipse.swt.widgets.Control; >+import org.eclipse.swt.widgets.Shell; >+import org.eclipse.ui.PlatformUI; >+import org.eclipse.ui.dialogs.SelectionDialog; >+import org.eclipse.ui.internal.ide.IDEWorkbenchMessages; >+import org.eclipse.ui.internal.ide.IIDEHelpContextIds; >+import org.eclipse.ui.internal.ide.dialogs.PathVariablesGroup; >+ >+public class PathVariableEditDialog extends SelectionDialog { >+ >+ private PathVariablesGroup pathVariablesGroup; >+ >+ /** >+ * Creates a path variable selection dialog. >+ * >+ * @param parentShell >+ * the parent shell >+ * @param variableType >+ * the type of variables that are displayed in this dialog. >+ * <code>IResource.FILE</code> and/or >+ * <code>IResource.FOLDER</code> logically ORed together. >+ */ >+ public PathVariableEditDialog(Shell parentShell) { >+ super(parentShell); >+ setTitle(IDEWorkbenchMessages.PathVariableSelectionDialog_title); >+ pathVariablesGroup = new PathVariablesGroup(false, IResource.FOLDER, >+ null); >+ setShellStyle(getShellStyle() | SWT.RESIZE); >+ } >+ >+ public void setProject(IProject receivingProject) { >+ pathVariablesGroup.setProject(receivingProject); >+ } >+ >+ /* >+ * (non-Javadoc) >+ * >+ * @see org.eclipse.jface.dialogs.Dialog#buttonPressed(int) >+ */ >+ protected void buttonPressed(int buttonId) { >+ super.buttonPressed(buttonId); >+ } >+ >+ /* >+ * (non-Javadoc) >+ * >+ * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell) >+ */ >+ protected void configureShell(Shell shell) { >+ super.configureShell(shell); >+ PlatformUI.getWorkbench().getHelpSystem().setHelp(shell, >+ IIDEHelpContextIds.PATH_VARIABLE_SELECTION_DIALOG); >+ } >+ >+ /* >+ * (non-Javadoc) >+ * >+ * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) >+ */ >+ protected void createButtonsForButtonBar(Composite parent) { >+ createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, >+ true); >+ createButton(parent, IDialogConstants.CANCEL_ID, >+ IDialogConstants.CANCEL_LABEL, false); >+ } >+ >+ /* >+ * (non-Javadoc) >+ * >+ * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite) >+ */ >+ protected Control createDialogArea(Composite parent) { >+ // create composite >+ Composite dialogArea = (Composite) super.createDialogArea(parent); >+ >+ pathVariablesGroup.createContents(dialogArea); >+ return dialogArea; >+ } >+ >+ /* >+ * (non-Javadoc) >+ * >+ * @see org.eclipse.jface.window.Window#close() >+ */ >+ public boolean close() { >+ pathVariablesGroup.dispose(); >+ return super.close(); >+ } >+ >+ /* >+ * (non-Javadoc) >+ * >+ * @see org.eclipse.jface.dialogs.Dialog#okPressed() >+ */ >+ protected void okPressed() { >+ // Sets the dialog result to the selected path variable name(s). >+ try { >+ if (pathVariablesGroup.performOk()) { >+ PathVariablesGroup.PathVariableElement[] selection = pathVariablesGroup >+ .getSelection(); >+ String[] variableNames = new String[selection.length]; >+ >+ for (int i = 0; i < selection.length; i++) { >+ variableNames[i] = selection[i].name; >+ } >+ setSelectionResult(variableNames); >+ } else { >+ setSelectionResult(null); >+ } >+ super.okPressed(); >+ } catch (Throwable t) { >+ t.printStackTrace(); >+ } >+ } >+} >Index: src/org/eclipse/ui/internal/ide/dialogs/ProjectLinkedResourcePage.java >=================================================================== >RCS file: src/org/eclipse/ui/internal/ide/dialogs/ProjectLinkedResourcePage.java >diff -N src/org/eclipse/ui/internal/ide/dialogs/ProjectLinkedResourcePage.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/ui/internal/ide/dialogs/ProjectLinkedResourcePage.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,144 @@ >+/******************************************************************************* >+ * Copyright (c) 2000, 2008 IBM Corporation 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: >+ * IBM Corporation - initial API and implementation >+ * Serge Beauchamp (Freescale Semiconductor) >+ *******************************************************************************/ >+package org.eclipse.ui.internal.ide.dialogs; >+ >+import org.eclipse.core.resources.IProject; >+import org.eclipse.core.resources.IResource; >+import org.eclipse.core.runtime.IAdaptable; >+import org.eclipse.jface.preference.PreferencePage; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.graphics.Font; >+import org.eclipse.swt.layout.GridData; >+import org.eclipse.swt.layout.GridLayout; >+import org.eclipse.swt.widgets.Composite; >+import org.eclipse.swt.widgets.Control; >+import org.eclipse.swt.widgets.Label; >+import org.eclipse.ui.IWorkbench; >+import org.eclipse.ui.IWorkbenchPreferencePage; >+import org.eclipse.ui.IWorkbenchPropertyPage; >+import org.eclipse.ui.dialogs.PropertyPage; >+import org.eclipse.ui.internal.ide.IDEWorkbenchMessages; >+ >+/** >+ * A property page for viewing and modifying the set >+ * of path variables in a given project. >+ * @since 3.4 >+ */ >+public class ProjectLinkedResourcePage extends PropertyPage implements >+ IWorkbenchPropertyPage { >+ >+ private Label topLabel; >+ >+ private PathVariablesGroup pathVariablesGroup; >+ >+ /** >+ * >+ */ >+ public ProjectLinkedResourcePage() { >+ pathVariablesGroup = new PathVariablesGroup(true, IResource.FILE | IResource.FOLDER); >+ this.noDefaultAndApplyButton(); >+ } >+ >+ protected Control createContents(Composite parent) { >+ >+ IAdaptable adaptable = getElement(); >+ if (adaptable.getAdapter(IProject.class) != null) { >+ pathVariablesGroup.setProject((IProject) adaptable.getAdapter(IProject.class)); >+ } >+ >+ Font font = parent.getFont(); >+ >+ // PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, IIDEHelpContextIds.LINKED_RESOURCE_PREFERENCE_PAGE); >+ // define container & its gridding >+ Composite pageComponent = new Composite(parent, SWT.NULL); >+ GridLayout layout = new GridLayout(); >+ layout.marginWidth = 0; >+ layout.marginHeight = 0; >+ pageComponent.setLayout(layout); >+ GridData data = new GridData(); >+ data.verticalAlignment = GridData.FILL; >+ data.horizontalAlignment = GridData.FILL; >+ pageComponent.setLayoutData(data); >+ pageComponent.setFont(font); >+ >+ // createSpace(pageComponent); >+ >+ topLabel = new Label(pageComponent, SWT.NONE); >+ topLabel.setText(IDEWorkbenchMessages.ProjectLinkedResourcePage_description); >+ data = new GridData(); >+ data.verticalAlignment = GridData.FILL; >+ data.horizontalAlignment = GridData.FILL; >+ topLabel.setLayoutData(data); >+ topLabel.setFont(font); >+ >+ pathVariablesGroup.createContents(pageComponent); >+ >+ updateWidgetState(true); >+ return pageComponent; >+ } >+ >+ >+ /** >+ * Creates a tab of one horizontal spans. >+ * >+ * @param parent the parent in which the tab should be created >+ */ >+ protected static void createSpace(Composite parent) { >+ Label vfiller = new Label(parent, SWT.LEFT); >+ GridData gridData = new GridData(); >+ gridData = new GridData(); >+ gridData.horizontalAlignment = GridData.BEGINNING; >+ gridData.grabExcessHorizontalSpace = false; >+ gridData.verticalAlignment = GridData.CENTER; >+ gridData.grabExcessVerticalSpace = false; >+ vfiller.setLayoutData(gridData); >+ } >+ >+ /** >+ * Disposes the path variables group. >+ * @see org.eclipse.jface.dialogs.IDialogPage#dispose() >+ */ >+ public void dispose() { >+ pathVariablesGroup.dispose(); >+ super.dispose(); >+ } >+ >+ /** >+ * Empty implementation. This page does not use the workbench. >+ * @param workbench >+ * >+ * @see IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench) >+ */ >+ public void init(IWorkbench workbench) { >+ } >+ >+ /** >+ * Commits the temporary state to the path variable manager in response to user >+ * confirmation. >+ * >+ * @see PreferencePage#performOk() >+ * @see PathVariablesGroup#performOk() >+ */ >+ public boolean performOk() { >+ return pathVariablesGroup.performOk(); >+ } >+ >+ /** >+ * Set the widget enabled state >+ * >+ * @param enableLinking the new widget enabled state >+ */ >+ protected void updateWidgetState(boolean enableLinking) { >+ topLabel.setEnabled(enableLinking); >+ pathVariablesGroup.setEnabled(enableLinking); >+ } >+} >#P org.eclipse.core.tests.resources >Index: src/org/eclipse/core/tests/resources/IPathVariableTest.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/IPathVariableTest.java,v >retrieving revision 1.23 >diff -u -r1.23 IPathVariableTest.java >--- src/org/eclipse/core/tests/resources/IPathVariableTest.java 13 Sep 2007 15:00:32 -0000 1.23 >+++ src/org/eclipse/core/tests/resources/IPathVariableTest.java 11 Sep 2008 12:30:52 -0000 >@@ -21,7 +21,22 @@ > * Tests path variables. > */ > public class IPathVariableTest extends ResourceTest { >- IPathVariableManager manager = getWorkspace().getPathVariableManager(); >+ >+ IPathVariableManager manager = null; >+ IProject project = null; >+ >+ protected void setUp() throws Exception { >+ super.setUp(); >+ project = getWorkspace().getRoot().getProject("MyProject"); >+ try { >+ project.create(getMonitor()); >+ project.open(getMonitor()); >+ } catch (CoreException e) { >+ fail("1.3", e); >+ } >+ assertTrue("1.4", project.exists()); >+ manager = project.getPathVariableManager(); >+ } > > class PathVariableChangeVerifier implements IPathVariableChangeListener { > class VerificationFailedException extends Exception { >@@ -156,9 +171,6 @@ > public void testGetPathVariableNames() { > String[] names = null; > >- // should be empty to start >- assertTrue("0.0", manager.getPathVariableNames().length == 0); >- > // add one > try { > manager.setValue("one", getRandomLocation()); >@@ -166,8 +178,8 @@ > fail("1.0", e); > } > names = manager.getPathVariableNames(); >- assertTrue("1.1", names.length == 1); >- assertTrue("1.2", names[0].equals("one")); >+ List list = Arrays.asList(names); >+ assertTrue("1.2", list.contains("one")); > > // add another > try { >@@ -176,9 +188,9 @@ > fail("2.0", e); > } > names = manager.getPathVariableNames(); >- assertTrue("2.1", names.length == 2); >- assertTrue("2.2", contains(names, "one")); >- assertTrue("2.3", contains(names, "two")); >+ list = Arrays.asList(names); >+ assertTrue("2.2", list.contains("one")); >+ assertTrue("2.3", list.contains("two")); > > // remove one > try { >@@ -187,8 +199,9 @@ > fail("3.0", e); > } > names = manager.getPathVariableNames(); >- assertTrue("3.1", names.length == 1); >- assertTrue("3.2", names[0].equals("two")); >+ list = Arrays.asList(names); >+ assertTrue("3.2", list.contains("two")); >+ assertTrue("3.3", !list.contains("one")); > > // remove the last one > try { >@@ -197,7 +210,9 @@ > fail("4.0", e); > } > names = manager.getPathVariableNames(); >- assertTrue("4.1", names.length == 0); >+ list = Arrays.asList(names); >+ assertTrue("4.2", !list.contains("two")); >+ assertTrue("4.3", !list.contains("one")); > } > > /** >@@ -263,9 +278,8 @@ > // set value with relative path > try { > manager.setValue("one", new Path("foo/bar")); >- fail("5.0 Accepted invalid variable value in setValue()"); > } catch (CoreException ce) { >- // success >+ fail("5.0 Did not Accepted invalid variable value in setValue()"); > } > > // set invalid value (with invalid segment) >@@ -274,12 +288,11 @@ > IPath invalidPath = Path.fromPortableString(invalidPathString); > assertTrue("6.0", invalidPath.isAbsolute()); > assertTrue("6.1", !Path.EMPTY.isValidPath(invalidPathString)); >- assertTrue("6.2", !manager.validateValue(invalidPath).isOK()); >+ assertTrue("6.2", manager.validateValue(invalidPath).isOK()); > try { > manager.setValue("one", invalidPath); >- fail("6.3 Accepted invalid variable value in setValue()"); > } catch (CoreException ce) { >- // success >+ fail("6.3 Fail to accept invalid variable value in setValue()"); > } > } > >@@ -307,6 +320,99 @@ > /** > * Test IPathVariableManager#resolvePath > */ >+ public void testResolvePathWithMacro() { >+ final boolean WINDOWS = java.io.File.separatorChar == '\\'; >+ IPath pathOne = WINDOWS ? new Path("c:/temp/foo") : new Path( >+ "/temp/foo"); >+ IPath pathTwo = new Path("/tmp/backup"); >+ // add device if neccessary >+ pathTwo = new Path(pathTwo.toFile().getAbsolutePath()); >+ >+ try { >+ manager.setValue("one", pathOne); >+ } catch (CoreException e) { >+ fail("0.1", e); >+ } >+ try { >+ manager.setValue("two", pathTwo); >+ } catch (CoreException e) { >+ fail("0.2", e); >+ } >+ >+ try { >+ manager.setValue("three", Path.fromOSString("${two}/extra")); >+ } catch (CoreException e) { >+ fail("0.3", e); >+ } >+ >+ IPath path = new Path("three/bar"); >+ IPath expected = new Path("/tmp/backup/extra/bar") >+ .setDevice(WINDOWS ? "C:" : null); >+ IPath actual = manager.resolvePath(path); >+ assertEquals("1.0", expected, actual); >+ } >+ >+ /** >+ */ >+ public void testProjectLoc() { >+ IPath path = new Path("${PROJECT_LOC}/bar"); >+ IPath projectLocation = project.getLocation(); >+ >+ IPath expected = projectLocation.append("bar"); >+ IPath actual = manager.resolvePath(path); >+ assertEquals("1.0", expected, actual); >+ } >+ >+ /** >+ */ >+ public void testEclipseHome() { >+ IPath path = new Path("${ECLIPSE_HOME}/bar"); >+ IPath expected = new Path(Platform.getInstallLocation().getURL() >+ .getPath()).append("bar"); >+ IPath actual = manager.resolvePath(path); >+ assertEquals("1.0", expected, actual); >+ } >+ >+ /** >+ */ >+ public void testWorkspaceLocation() { >+ IPath path = new Path("${WORKSPACE_LOC}/bar"); >+ IPath expected = project.getWorkspace().getRoot().getLocation().append( >+ "bar"); >+ IPath actual = manager.resolvePath(path); >+ assertEquals("1.0", expected, actual); >+ } >+ >+ /** >+ * Test IProject.getVariableRelativePathLocation(IPath) >+ */ >+ >+ public void testGetVariableRelativePathLocation() { >+ IPath path = project.getWorkspace().getRoot().getLocation().append( >+ "bar"); >+ IPath actual = project.getVariableRelativePathLocation(path); >+ IPath expected = new Path("WORKSPACE_LOC/bar"); >+ assertEquals("1.0", expected, actual); >+ >+ path = new Path(Platform.getInstallLocation().getURL().getPath()) >+ .append("bar"); >+ expected = new Path("ECLIPSE_HOME/bar"); >+ actual = project.getVariableRelativePathLocation(path); >+ assertEquals("2.0", expected, actual); >+ >+ path = project.getLocation().append("bar"); >+ expected = new Path("PROJECT_LOC/bar"); >+ actual = project.getVariableRelativePathLocation(path); >+ assertEquals("3.0", expected, actual); >+ >+ actual = project.getVariableRelativePathLocation(new Path( >+ "/nonExistentPath/foo")); >+ assertEquals("4.0", null, actual); >+ } >+ >+ /** >+ * Test IPathVariableManager#resolvePath >+ */ > public void testResolvePath() { > final boolean WINDOWS = java.io.File.separatorChar == '\\'; > IPath pathOne = WINDOWS ? new Path("c:/temp/foo") : new Path("/temp/foo"); >@@ -382,6 +488,132 @@ > } > > /** >+ * Test IPathVariableManager#convertToRelative() >+ */ >+ public void testConvertToRelative() { >+ final boolean WINDOWS = java.io.File.separatorChar == '\\'; >+ IPath pathOne = WINDOWS ? new Path("c:/foo/bar") : new Path("/foo/bar"); >+ IPath pathTwo = WINDOWS ? new Path("c:/foo/other") : new Path("/foo/other"); >+ IPath pathThree = WINDOWS ? new Path("c:/random/other/subpath") : new Path("/random/other/subpath"); >+ IPath file = WINDOWS ? new Path("c:/foo/other/file.txt") : new Path("/foo/other/file.txt"); >+ >+ try { >+ manager.setValue("ONE", pathOne); >+ manager.setValue("THREE", pathThree); >+ } catch (CoreException e) { >+ fail("0.1", e); >+ } >+ >+ IPath actual = null; >+ try { >+ actual = manager.convertToRelative(file, false, "ONE"); >+ } catch (CoreException e) { >+ fail("0.2", e); >+ } >+ IPath expected = file; >+ assertEquals("1.0", expected, actual); >+ >+ try { >+ manager.setValue("TWO", pathTwo); >+ } catch (CoreException e) { >+ fail("1.1", e); >+ } >+ >+ try { >+ actual = manager.convertToRelative(file, false, "ONE"); >+ } catch (CoreException e) { >+ fail("1.2", e); >+ } >+ expected = file; >+ assertEquals("2.0", expected, actual); >+ >+ try { >+ actual = manager.convertToRelative(file, false, "TWO"); >+ } catch (CoreException e) { >+ fail("2.1", e); >+ } >+ expected = new Path("TWO/file.txt"); >+ assertEquals("3.0", expected, actual); >+ >+ // force the path to be relative to "ONE" >+ try { >+ actual = manager.convertToRelative(file, true, "ONE"); >+ } catch (CoreException e) { >+ fail("3.1", e); >+ } >+ expected = new Path("FOO/other/file.txt"); >+ assertEquals("4.0", expected, actual); >+ assertTrue("4.1", manager.isDefined("FOO")); >+ assertEquals("4.2", manager.getValue("FOO").toOSString(), "${PARENT-1-ONE}"); >+ >+ // the second time should be re-using "FOO" >+ try { >+ actual = manager.convertToRelative(file, true, "ONE"); >+ } catch (CoreException e) { >+ fail("4.3", e); >+ } >+ expected = new Path("FOO/other/file.txt"); >+ assertEquals("5.0", expected, actual); >+ assertTrue("5.1", manager.isDefined("FOO")); >+ assertEquals("5.2", manager.getValue("FOO").toOSString(), "${PARENT-1-ONE}"); >+ >+ try { >+ manager.setValue("FOO", null); >+ } catch (CoreException e) { >+ fail("5.3", e); >+ } >+ >+ try { >+ actual = manager.convertToRelative(file, true, "TWO"); >+ } catch (CoreException e) { >+ fail("5.4", e); >+ } >+ expected = new Path("TWO/file.txt"); >+ assertEquals("6.0", expected, actual); >+ >+ try { >+ actual = manager.convertToRelative(file, true, "TWO"); >+ } catch (CoreException e) { >+ fail("6.1", e); >+ } >+ expected = new Path("TWO/file.txt"); >+ assertEquals("7.0", expected, actual); >+ >+ try { >+ actual = manager.convertToRelative(file, false, null); >+ } catch (CoreException e) { >+ fail("7.1", e); >+ } >+ expected = new Path("TWO/file.txt"); >+ assertEquals("8.0", expected, actual); >+ >+ try { >+ manager.setValue("TWO", null); >+ } catch (CoreException e) { >+ fail("8.1", e); >+ } >+ >+ // now without any direct reference >+ try { >+ actual = manager.convertToRelative(file, false, null); >+ } catch (CoreException e) { >+ fail("8.2", e); >+ } >+ expected = file; >+ assertEquals("9.0", expected, actual); >+ >+ try { >+ actual = manager.convertToRelative(file, true, null); >+ } catch (CoreException e) { >+ fail("9.1", e); >+ } >+ expected = new Path("FOO/other/file.txt");; >+ assertEquals("10.0", expected, actual); >+ assertTrue("10.1", manager.isDefined("FOO")); >+ assertEquals("10.2", manager.getValue("FOO").toOSString(), "${PARENT-1-ONE}"); >+ } >+ >+ /** > * Test IPathVariableManager#testValidateName > */ > public void testValidateName() { >@@ -478,4 +710,9 @@ > } > } > >+ protected void cleanup() throws CoreException { >+ project.delete(true, getMonitor()); >+ super.cleanup(); >+ } >+ > } >Index: src/org/eclipse/core/tests/resources/LinkedResourceTest.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/LinkedResourceTest.java,v >retrieving revision 1.51 >diff -u -r1.51 LinkedResourceTest.java >--- src/org/eclipse/core/tests/resources/LinkedResourceTest.java 20 Aug 2008 10:32:29 -0000 1.51 >+++ src/org/eclipse/core/tests/resources/LinkedResourceTest.java 11 Sep 2008 12:30:53 -0000 >@@ -926,8 +926,117 @@ > * Tests the {@link org.eclipse.core.resources.IResource#isLinked(int)} method. > */ > public void testIsLinked() { >+ // initially nothing is linked >+ IResource[] toTest = new IResource[] { closedProject, >+ existingFileInExistingProject, existingFolderInExistingFolder, >+ existingFolderInExistingProject, existingProject, >+ nonExistingFileInExistingFolder, >+ nonExistingFileInExistingProject, >+ nonExistingFileInOtherExistingProject, >+ nonExistingFolderInExistingFolder, >+ nonExistingFolderInExistingProject, >+ nonExistingFolderInNonExistingFolder, >+ nonExistingFolderInNonExistingProject, >+ nonExistingFolderInOtherExistingProject, nonExistingProject, >+ otherExistingProject }; >+ for (int i = 0; i < toTest.length; i++) { >+ assertTrue("1.0 " + toTest[i], !toTest[i].isLinked()); >+ assertTrue("1.1 " + toTest[i], !toTest[i].isLinked(IResource.NONE)); >+ assertTrue("1.2 " + toTest[i], !toTest[i] >+ .isLinked(IResource.CHECK_ANCESTORS)); >+ } >+ // create a link >+ IFolder link = nonExistingFolderInExistingProject; >+ try { >+ link.createLink(localFolder, IResource.NONE, getMonitor()); >+ } catch (CoreException e) { >+ fail("1.99", e); >+ } >+ IFile child = link.getFile(childName); >+ assertTrue("2.0", child.exists()); >+ assertTrue("2.1", link.isLinked()); >+ assertTrue("2.2", link.isLinked(IResource.NONE)); >+ assertTrue("2.3", link.isLinked(IResource.CHECK_ANCESTORS)); >+ assertTrue("2.1", !child.isLinked()); >+ assertTrue("2.2", !child.isLinked(IResource.NONE)); >+ assertTrue("2.3", child.isLinked(IResource.CHECK_ANCESTORS)); >+ >+ } >+ >+ /** >+ * Tests the >+ * {@link org.eclipse.core.resources.IResource#setLinkLocation(URI , int , IProgressMonitor )} >+ * method. >+ */ >+ public void testsetLinkLocation() { >+ // initially nothing is linked >+ IResource[] toTest = new IResource[] { closedProject, >+ existingFileInExistingProject, existingFolderInExistingFolder, >+ existingFolderInExistingProject, existingProject, >+ nonExistingFileInExistingFolder, >+ nonExistingFileInExistingProject, >+ nonExistingFileInOtherExistingProject, >+ nonExistingFolderInExistingFolder, >+ nonExistingFolderInExistingProject, >+ nonExistingFolderInNonExistingFolder, >+ nonExistingFolderInNonExistingProject, >+ nonExistingFolderInOtherExistingProject, nonExistingProject, >+ otherExistingProject }; >+ for (int i = 0; i < toTest.length; i++) { >+ assertTrue("1.0 " + toTest[i], !toTest[i].isLinked()); >+ assertTrue("1.1 " + toTest[i], !toTest[i].isLinked(IResource.NONE)); >+ assertTrue("1.2 " + toTest[i], !toTest[i] >+ .isLinked(IResource.CHECK_ANCESTORS)); >+ } >+ // create a link >+ IFolder link = nonExistingFolderInExistingProject; >+ try { >+ link.createLink(localFolder, IResource.NONE, getMonitor()); >+ } catch (CoreException e) { >+ fail("1.99", e); >+ } >+ IFile child = link.getFile(childName); >+ assertTrue("2.0", child.exists()); >+ assertTrue("2.1", link.isLinked()); >+ assertTrue("2.2", link.isLinked(IResource.NONE)); >+ assertTrue("2.3", link.isLinked(IResource.CHECK_ANCESTORS)); >+ assertTrue("2.1", !child.isLinked()); >+ assertTrue("2.2", !child.isLinked(IResource.NONE)); >+ assertTrue("2.3", child.isLinked(IResource.CHECK_ANCESTORS)); >+ >+ try { >+ link.setLinkLocation( >+ existingFileInExistingProject.getLocationURI(), >+ IResource.NONE, getMonitor()); >+ } catch (CoreException e) { >+ fail("2.99", e); >+ } >+ assertTrue("3.1", link.isLinked()); >+ assertTrue("3.2", link.isLinked(IResource.NONE)); >+ assertTrue("3.3", link.isLinked(IResource.CHECK_ANCESTORS)); >+ assertTrue("3.4", link.getLocation().equals( >+ existingFileInExistingProject.getLocation())); >+ } >+ >+ /** >+ * Tests the >+ * {@link org.eclipse.core.resources.IResource#setLinkLocation(IPath, int , IProgressMonitor )} >+ * method. >+ */ >+ public void testsetLinkLocationPath() { > //initially nothing is linked >- IResource[] toTest = new IResource[] {closedProject, existingFileInExistingProject, existingFolderInExistingFolder, existingFolderInExistingProject, existingProject, nonExistingFileInExistingFolder, nonExistingFileInExistingProject, nonExistingFileInOtherExistingProject, nonExistingFolderInExistingFolder, nonExistingFolderInExistingProject, nonExistingFolderInNonExistingFolder, nonExistingFolderInNonExistingProject, nonExistingFolderInOtherExistingProject, nonExistingProject, otherExistingProject}; >+ IResource[] toTest = new IResource[] { closedProject, >+ existingFileInExistingProject, existingFolderInExistingFolder, >+ existingFolderInExistingProject, existingProject, >+ nonExistingFileInExistingFolder, >+ nonExistingFileInExistingProject, >+ nonExistingFileInOtherExistingProject, >+ nonExistingFolderInExistingFolder, >+ nonExistingFolderInExistingProject, >+ nonExistingFolderInNonExistingFolder, >+ nonExistingFolderInNonExistingProject, >+ nonExistingFolderInOtherExistingProject, nonExistingProject, >+ otherExistingProject }; > for (int i = 0; i < toTest.length; i++) { > assertTrue("1.0 " + toTest[i], !toTest[i].isLinked()); > assertTrue("1.1 " + toTest[i], !toTest[i].isLinked(IResource.NONE)); >@@ -949,6 +1058,17 @@ > assertTrue("2.2", !child.isLinked(IResource.NONE)); > assertTrue("2.3", child.isLinked(IResource.CHECK_ANCESTORS)); > >+ try { >+ link.setLinkLocation(existingFileInExistingProject.getLocation(), >+ IResource.NONE, getMonitor()); >+ } catch (CoreException e) { >+ fail("2.99", e); >+ } >+ assertTrue("3.1", link.isLinked()); >+ assertTrue("3.2", link.isLinked(IResource.NONE)); >+ assertTrue("3.3", link.isLinked(IResource.CHECK_ANCESTORS)); >+ assertTrue("3.4", link.getLocation().equals( >+ existingFileInExistingProject.getLocation())); > } > > /** >Index: src/org/eclipse/core/tests/resources/LinkedResourceWithPathVariableTest.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/LinkedResourceWithPathVariableTest.java,v >retrieving revision 1.23 >diff -u -r1.23 LinkedResourceWithPathVariableTest.java >--- src/org/eclipse/core/tests/resources/LinkedResourceWithPathVariableTest.java 1 Sep 2008 15:29:57 -0000 1.23 >+++ src/org/eclipse/core/tests/resources/LinkedResourceWithPathVariableTest.java 11 Sep 2008 12:30:54 -0000 >@@ -8,6 +8,7 @@ > * Contributors: > * IBM Corporation - initial API and implementation > * Martin Oberhuber (Wind River) - testImportWrongLineEndings() for bug [210664] >+ * Serge Beauchamp (Freescale Semiconductor) > *******************************************************************************/ > > package org.eclipse.core.tests.resources; >@@ -32,6 +33,9 @@ > public class LinkedResourceWithPathVariableTest extends LinkedResourceTest { > > private final static String VARIABLE_NAME = "ROOT"; >+ private final static String PROJECT_VARIABLE_NAME = "PROOT"; >+ private final static String PROJECT_RELATIVE_VARIABLE_NAME = "RELATIVE_PROOT"; >+ private final static String PROJECT_RELATIVE_VARIABLE_VALUE = "${PROOT}"; > private final ArrayList toDelete = new ArrayList(); > private IFileStore toSetWritable = null; > >@@ -54,7 +58,14 @@ > IPath base = super.getRandomLocation(); > toDelete.add(base); > getWorkspace().getPathVariableManager().setValue(VARIABLE_NAME, base); >+ base = super.getRandomLocation(); >+ toDelete.add(base); > super.setUp(); >+ existingProject.getPathVariableManager().setValue( >+ PROJECT_VARIABLE_NAME, base); >+ existingProject.getPathVariableManager().setValue( >+ PROJECT_RELATIVE_VARIABLE_NAME, >+ Path.fromPortableString(PROJECT_RELATIVE_VARIABLE_VALUE)); > } > > protected void tearDown() throws Exception { >@@ -65,6 +76,10 @@ > toSetWritable = null; > } > getWorkspace().getPathVariableManager().setValue(VARIABLE_NAME, null); >+ existingProject.getPathVariableManager().setValue( >+ PROJECT_VARIABLE_NAME, null); >+ existingProject.getPathVariableManager().setValue( >+ PROJECT_RELATIVE_VARIABLE_NAME, null); > IPath[] paths = (IPath[]) toDelete.toArray(new IPath[0]); > toDelete.clear(); > for (int i = 0; i < paths.length; i++) >@@ -127,7 +142,47 @@ > try { > Thread.sleep(10); > } catch (InterruptedException e) { >- //ignore >+ // ignore >+ } >+ path = FileSystemHelper.computeRandomLocation(parent); >+ } >+ toDelete.add(pathVars.resolvePath(path)); >+ return path; >+ } >+ >+ /** >+ * @see org.eclipse.core.tests.harness.ResourceTest#getRandomLocation() >+ */ >+ public IPath getRandomProjectLocation() { >+ IPathVariableManager pathVars = getWorkspace().getPathVariableManager(); >+ // low order bits are current time, high order bits are static counter >+ IPath parent = new Path(PROJECT_VARIABLE_NAME); >+ IPath path = FileSystemHelper.computeRandomLocation(parent); >+ while (pathVars.resolvePath(path).toFile().exists()) { >+ try { >+ Thread.sleep(10); >+ } catch (InterruptedException e) { >+ // ignore >+ } >+ path = FileSystemHelper.computeRandomLocation(parent); >+ } >+ toDelete.add(pathVars.resolvePath(path)); >+ return path; >+ } >+ >+ /** >+ * @see org.eclipse.core.tests.harness.ResourceTest#getRandomLocation() >+ */ >+ public IPath getRandomRelativeProjectLocation() { >+ IPathVariableManager pathVars = getWorkspace().getPathVariableManager(); >+ // low order bits are current time, high order bits are static counter >+ IPath parent = new Path(PROJECT_RELATIVE_VARIABLE_NAME); >+ IPath path = FileSystemHelper.computeRandomLocation(parent); >+ while (pathVars.resolvePath(path).toFile().exists()) { >+ try { >+ Thread.sleep(10); >+ } catch (InterruptedException e) { >+ // ignore > } > path = FileSystemHelper.computeRandomLocation(parent); > } >@@ -149,6 +204,23 @@ > return getWorkspace().getPathVariableManager().resolveURI(uri); > } > >+ public void testProjectResolution() { >+ final IPathVariableManager manager = existingProject >+ .getPathVariableManager(); >+ IPath value = manager.getValue(PROJECT_VARIABLE_NAME); >+ IPath relativeValue = manager.getValue(PROJECT_RELATIVE_VARIABLE_NAME); >+ >+ assertTrue("1.0", !value.equals(relativeValue)); >+ >+ IPath resolvedValue = manager.resolvePath(value); >+ assertTrue("1.1", value.equals(resolvedValue)); >+ >+ IPath resolvedRelativeValue = manager.resolvePath(relativeValue); >+ assertTrue("1.2", !relativeValue.equals(resolvedRelativeValue)); >+ >+ assertTrue("1.3", resolvedValue.equals(resolvedRelativeValue)); >+ } >+ > /** > * Tests a scenario where a variable used in a linked file location is > * removed. >@@ -227,6 +299,286 @@ > assertExistsInFileSystem("5.2", file); > // the contents must be the original ones > try { >+ assertTrue("5.3", compareContent(file.getContents(true), >+ getContents("contents for a file"))); >+ } catch (CoreException e) { >+ fail("5.4", e); >+ } >+ } >+ >+ /** >+ * Tests a scenario where a variable used in a linked file location is >+ * removed. >+ */ >+ public void testFileProjectVariableRemoved() { >+ final IPathVariableManager manager = existingProject >+ .getPathVariableManager(); >+ >+ IFile file = nonExistingFileInExistingProject; >+ IPath existingValue = manager.getValue(PROJECT_VARIABLE_NAME); >+ >+ // creates a variable-based location >+ IPath variableBasedLocation = getRandomProjectLocation(); >+ >+ // the file should not exist yet >+ assertDoesNotExistInWorkspace("1.0", file); >+ >+ try { >+ file.createLink(variableBasedLocation, >+ IResource.ALLOW_MISSING_LOCAL, null); >+ } catch (CoreException e) { >+ fail("1.1", e); >+ } >+ try { >+ file.setContents(getContents("contents for a file"), >+ IResource.FORCE, null); >+ } catch (CoreException e) { >+ fail("1.2", e); >+ } >+ >+ // now the file exists in both workspace and file system >+ assertExistsInWorkspace("2.0", file); >+ assertExistsInFileSystem("2.1", file); >+ >+ // removes the variable - the location will be undefined (null) >+ try { >+ manager.setValue(PROJECT_VARIABLE_NAME, null); >+ } catch (CoreException e) { >+ fail("3.0", e); >+ } >+ assertExistsInWorkspace("3,1", file); >+ >+ // refresh local - should not fail or make the link disappear >+ try { >+ file.refreshLocal(IResource.DEPTH_ONE, getMonitor()); >+ file.getProject().refreshLocal(IResource.DEPTH_INFINITE, >+ getMonitor()); >+ } catch (CoreException e) { >+ fail("3.2"); >+ } >+ >+ assertExistsInWorkspace("3.3", file); >+ >+ // try to change resource's contents >+ try { >+ file.setContents(getContents("new contents"), IResource.NONE, null); >+ // Resource has no-defined location - should fail >+ fail("3.4"); >+ } catch (CoreException re) { >+ // success: resource had no defined location >+ } >+ >+ assertExistsInWorkspace("3.5", file); >+ // the location is null >+ assertNull("3.6", file.getLocation()); >+ >+ // try validating another link location while there is a link with null >+ // location >+ IFile other = existingProject.getFile("OtherVar"); >+ getWorkspace().validateLinkLocation(other, getRandomLocation()); >+ >+ // re-creates the variable with its previous value >+ try { >+ manager.setValue(PROJECT_VARIABLE_NAME, existingValue); >+ } catch (CoreException e) { >+ fail("4.0", e); >+ } >+ >+ assertExistsInWorkspace("5.0", file); >+ assertNotNull("5.1", file.getLocation()); >+ assertExistsInFileSystem("5.2", file); >+ // the contents must be the original ones >+ try { >+ assertTrue("5.3", compareContent(file.getContents(true), >+ getContents("contents for a file"))); >+ } catch (CoreException e) { >+ fail("5.4", e); >+ } >+ } >+ >+ /** >+ * Tests a scenario where a variable used in a linked file location is >+ * removed. >+ */ >+ public void testMoveFileProjectVariable() { >+ final IPathVariableManager manager = existingProject >+ .getPathVariableManager(); >+ >+ IFile file = nonExistingFileInExistingProject; >+ >+ // creates a variable-based location >+ IPath variableBasedLocation = getRandomProjectLocation(); >+ >+ IPath resolvedPath = manager.resolvePath(variableBasedLocation); >+ // the file should not exist yet >+ assertDoesNotExistInWorkspace("1.0", file); >+ >+ try { >+ file.createLink(variableBasedLocation, >+ IResource.ALLOW_MISSING_LOCAL, null); >+ } catch (CoreException e) { >+ fail("1.1", e); >+ } >+ try { >+ file.setContents(getContents("contents for a file"), >+ IResource.FORCE, null); >+ } catch (CoreException e) { >+ fail("1.2", e); >+ } >+ >+ // now the file exists in both workspace and file system >+ assertExistsInWorkspace("2.0", file); >+ assertExistsInFileSystem("2.1", file); >+ >+ IFile newFile = nonExistingFileInExistingFolder; >+ // removes the variable - the location will be undefined (null) >+ try { >+ file.move(newFile.getFullPath(), IResource.SHALLOW, null); >+ } catch (CoreException e) { >+ fail("3.0", e); >+ } >+ assertExistsInWorkspace("3,1", newFile); >+ assertTrue("3,2", !newFile.getLocation().equals( >+ newFile.getRawLocation())); >+ assertTrue("3,3", newFile.getRawLocation() >+ .equals(variableBasedLocation)); >+ assertTrue("3,4", newFile.getRawLocation() >+ .equals(variableBasedLocation)); >+ assertTrue("3,5", newFile.getLocation().equals(resolvedPath)); >+ } >+ >+ /** >+ * Tests a scenario where a variable used in a linked file location is >+ * removed. >+ */ >+ public void testMoveFileToNewProjectProjectVariable() { >+ final IPathVariableManager manager = existingProject >+ .getPathVariableManager(); >+ >+ IFile file = nonExistingFileInExistingProject; >+ >+ // creates a variable-based location >+ IPath variableBasedLocation = getRandomRelativeProjectLocation(); >+ >+ IPath resolvedPath = manager.resolvePath(variableBasedLocation); >+ // the file should not exist yet >+ assertDoesNotExistInWorkspace("1.0", file); >+ >+ try { >+ file.createLink(variableBasedLocation, >+ IResource.ALLOW_MISSING_LOCAL, null); >+ } catch (CoreException e) { >+ fail("1.1", e); >+ } >+ try { >+ file.setContents(getContents("contents for a file"), >+ IResource.FORCE, null); >+ } catch (CoreException e) { >+ fail("1.2", e); >+ } >+ >+ // now the file exists in both workspace and file system >+ assertExistsInWorkspace("2.0", file); >+ assertExistsInFileSystem("2.1", file); >+ >+ IFile newFile = nonExistingFileInOtherExistingProject; >+ // moves the variable - the location will be undefined (null) >+ try { >+ file.move(newFile.getFullPath(), IResource.SHALLOW, getMonitor()); >+ } catch (CoreException e) { >+ fail("3.0", e); >+ } >+ assertExistsInWorkspace("3,1", newFile); >+ assertTrue("3,2", !newFile.getLocation().equals( >+ newFile.getRawLocation())); >+ assertTrue("3,3", newFile.getRawLocation() >+ .equals(variableBasedLocation)); >+ assertTrue("3,4", newFile.getLocation().equals(resolvedPath)); >+ } >+ >+ /** >+ * Tests a scenario where a variable used in a linked file location is >+ * removed. >+ */ >+ public void testFileProjectRelativeVariableRemoved() { >+ final IPathVariableManager manager = existingProject >+ .getPathVariableManager(); >+ >+ IFile file = nonExistingFileInExistingProject; >+ IPath existingValue = manager.getValue(PROJECT_RELATIVE_VARIABLE_NAME); >+ >+ // creates a variable-based location >+ IPath variableBasedLocation = getRandomRelativeProjectLocation(); >+ >+ // the file should not exist yet >+ assertDoesNotExistInWorkspace("1.0", file); >+ >+ try { >+ file.createLink(variableBasedLocation, >+ IResource.ALLOW_MISSING_LOCAL, null); >+ } catch (CoreException e) { >+ fail("1.1", e); >+ } >+ try { >+ file.setContents(getContents("contents for a file"), >+ IResource.FORCE, null); >+ } catch (CoreException e) { >+ fail("1.2", e); >+ } >+ >+ // now the file exists in both workspace and file system >+ assertExistsInWorkspace("2.0", file); >+ assertExistsInFileSystem("2.1", file); >+ >+ // removes the variable - the location will be undefined (null) >+ try { >+ manager.setValue(PROJECT_RELATIVE_VARIABLE_NAME, null); >+ } catch (CoreException e) { >+ fail("3.0", e); >+ } >+ assertExistsInWorkspace("3,1", file); >+ >+ // refresh local - should not fail or make the link disappear >+ try { >+ file.refreshLocal(IResource.DEPTH_ONE, getMonitor()); >+ file.getProject().refreshLocal(IResource.DEPTH_INFINITE, >+ getMonitor()); >+ } catch (CoreException e) { >+ fail("3.2"); >+ } >+ >+ assertExistsInWorkspace("3.3", file); >+ >+ // try to change resource's contents >+ try { >+ file.setContents(getContents("new contents"), IResource.NONE, null); >+ // Resource has no-defined location - should fail >+ fail("3.4"); >+ } catch (CoreException re) { >+ // success: resource had no defined location >+ } >+ >+ assertExistsInWorkspace("3.5", file); >+ // the location is null >+ assertNull("3.6", file.getLocation()); >+ >+ // try validating another link location while there is a link with null >+ // location >+ IFile other = existingProject.getFile("OtherVar"); >+ getWorkspace().validateLinkLocation(other, getRandomLocation()); >+ >+ // re-creates the variable with its previous value >+ try { >+ manager.setValue(PROJECT_RELATIVE_VARIABLE_NAME, existingValue); >+ } catch (CoreException e) { >+ fail("4.0", e); >+ } >+ >+ assertExistsInWorkspace("5.0", file); >+ assertNotNull("5.1", file.getLocation()); >+ assertExistsInFileSystem("5.2", file); >+ // the contents must be the original ones >+ try { > assertTrue("5.3", compareContent(file.getContents(true), getContents("contents for a file"))); > } catch (CoreException e) { > fail("5.4", e); >@@ -342,7 +694,135 @@ > assertDoesNotExistInWorkspace("6.3", childFile); > assertExistsInFileSystem("6.4", childFile); > >- //refresh should recreate the child >+ // refresh should recreate the child >+ try { >+ folder.refreshLocal(IResource.DEPTH_INFINITE, getMonitor()); >+ } catch (CoreException e) { >+ fail("7.0", e); >+ } >+ assertExistsInWorkspace("7.1", folder); >+ assertExistsInWorkspace("7.2", childFile); >+ } >+ >+ /** >+ * Tests a scenario where a variable used in a linked folder location is >+ * removed. >+ */ >+ public void testFolderProjectVariableRemoved() { >+ final IPathVariableManager manager = existingProject >+ .getPathVariableManager(); >+ >+ IFolder folder = nonExistingFolderInExistingProject; >+ IFile childFile = folder.getFile(childName); >+ IPath existingValue = manager.getValue(PROJECT_VARIABLE_NAME); >+ >+ // creates a variable-based location >+ IPath variableBasedLocation = getRandomProjectLocation(); >+ >+ // the file should not exist yet >+ assertDoesNotExistInWorkspace("1.0", folder); >+ >+ try { >+ folder.createLink(variableBasedLocation, >+ IResource.ALLOW_MISSING_LOCAL, null); >+ childFile.create(getRandomContents(), IResource.NONE, getMonitor()); >+ } catch (CoreException e) { >+ fail("1.1", e); >+ } >+ try { >+ childFile.setContents(getContents("contents for a file"), >+ IResource.FORCE, null); >+ } catch (CoreException e) { >+ fail("1.2", e); >+ } >+ >+ // now the file exists in both workspace and file system >+ assertExistsInWorkspace("2.0", folder); >+ assertExistsInWorkspace("2.1", childFile); >+ assertExistsInFileSystem("2.2", folder); >+ assertExistsInFileSystem("2.3", childFile); >+ >+ // removes the variable - the location will be undefined (null) >+ try { >+ manager.setValue(PROJECT_VARIABLE_NAME, null); >+ } catch (CoreException e) { >+ fail("3.0", e); >+ } >+ assertExistsInWorkspace("3.1", folder); >+ >+ // refresh local - should not fail but should cause link's children to >+ // disappear >+ try { >+ folder.refreshLocal(IResource.DEPTH_INFINITE, getMonitor()); >+ folder.getProject().refreshLocal(IResource.DEPTH_INFINITE, >+ getMonitor()); >+ } catch (CoreException e) { >+ fail("3.2", e); >+ } >+ assertExistsInWorkspace("3.3", folder); >+ assertDoesNotExistInWorkspace("3.4", childFile); >+ >+ // try to copy a file to the folder >+ IFile destination = folder.getFile(existingFileInExistingProject >+ .getName()); >+ try { >+ existingFileInExistingProject.copy(destination.getFullPath(), >+ IResource.NONE, getMonitor()); >+ // should fail >+ fail("3.5"); >+ } catch (CoreException e) { >+ // expected >+ } >+ assertTrue("3.6", !destination.exists()); >+ >+ // try to create a sub-file >+ try { >+ destination.create(getRandomContents(), IResource.NONE, >+ getMonitor()); >+ // should fail >+ fail("3.7"); >+ } catch (CoreException e) { >+ // expected >+ } >+ >+ // try to create a sub-folder >+ IFolder subFolder = folder.getFolder("SubFolder"); >+ try { >+ subFolder.create(IResource.NONE, true, getMonitor()); >+ // should fail >+ fail("3.8"); >+ } catch (CoreException e) { >+ // expected >+ } >+ >+ // try to change resource's contents >+ try { >+ childFile.setContents(getContents("new contents"), IResource.NONE, >+ null); >+ // Resource has no-defined location - should fail >+ fail("4.0"); >+ } catch (CoreException re) { >+ // success: resource had no defined location >+ } >+ >+ assertExistsInWorkspace("4.1", folder); >+ // the location is null >+ assertNull("4.2", folder.getLocation()); >+ >+ // re-creates the variable with its previous value >+ try { >+ manager.setValue(PROJECT_VARIABLE_NAME, existingValue); >+ } catch (CoreException e) { >+ fail("5.0", e); >+ } >+ >+ assertExistsInWorkspace("6.0", folder); >+ assertNotNull("6.1", folder.getLocation()); >+ assertExistsInFileSystem("6.2", folder); >+ assertDoesNotExistInWorkspace("6.3", childFile); >+ assertExistsInFileSystem("6.4", childFile); >+ >+ // refresh should recreate the child > try { > folder.refreshLocal(IResource.DEPTH_INFINITE, getMonitor()); > } catch (CoreException e) { >@@ -599,6 +1079,110 @@ > assertExistsInFileSystem("5.2", file); > // the contents must be the original ones > try { >+ assertTrue("5.3", compareContent(file.getContents(true), >+ getContents("contents for a file"))); >+ } catch (CoreException e) { >+ fail("5.4", e); >+ } >+ } >+ >+ /** >+ * Tests a scenario where a variable used in a linked file location is >+ * changed. >+ */ >+ public void testProjectVariableChanged() { >+ final IPathVariableManager manager = existingProject >+ .getPathVariableManager(); >+ >+ IPath existingValue = manager.getValue(PROJECT_VARIABLE_NAME); >+ >+ IFile file = nonExistingFileInExistingProject; >+ >+ // creates a variable-based location >+ IPath variableBasedLocation = getRandomProjectLocation(); >+ >+ // the file should not exist yet >+ assertDoesNotExistInWorkspace("1.0", file); >+ >+ try { >+ file.createLink(variableBasedLocation, >+ IResource.ALLOW_MISSING_LOCAL, getMonitor()); >+ } catch (CoreException e) { >+ fail("1.1", e); >+ } >+ try { >+ file.setContents(getContents("contents for a file"), >+ IResource.FORCE, getMonitor()); >+ } catch (CoreException e) { >+ fail("1.2", e); >+ } >+ >+ // now the file exists in both workspace and file system >+ assertExistsInWorkspace("2.0", file); >+ assertExistsInFileSystem("2.1", file); >+ >+ // changes the variable value - the file location will change >+ try { >+ IPath newLocation = super.getRandomLocation(); >+ toDelete.add(newLocation); >+ manager.setValue(PROJECT_VARIABLE_NAME, newLocation); >+ } catch (CoreException e) { >+ fail("2.2", e); >+ } >+ >+ // try to change resource's contents >+ try { >+ file.setContents(getContents("new contents"), IResource.NONE, >+ getMonitor()); >+ // Resource was out of sync - should not be able to change >+ fail("3.0"); >+ } catch (CoreException e) { >+ assertEquals("3.1", IResourceStatus.OUT_OF_SYNC_LOCAL, e >+ .getStatus().getCode()); >+ } >+ >+ assertExistsInWorkspace("3.2", file); >+ // the location is different - does not exist anymore >+ assertDoesNotExistInFileSystem("3.3", file); >+ >+ // successfully changes resource's contents (using IResource.FORCE) >+ try { >+ file.setContents(getContents("contents in different location"), >+ IResource.FORCE, getMonitor()); >+ } catch (CoreException e) { >+ fail("4.0", e); >+ } >+ >+ // now the file exists in a different location >+ assertExistsInFileSystem("4.1", file); >+ >+ // its location must have changed reflecting the variable change >+ IPath expectedNewLocation = manager.resolvePath(variableBasedLocation); >+ IPath actualNewLocation = file.getLocation(); >+ assertEquals("4.2", expectedNewLocation, actualNewLocation); >+ >+ // its contents are as just set >+ try { >+ assertTrue("4.3", compareContent(file.getContents(), >+ getContents("contents in different location"))); >+ } catch (CoreException e) { >+ fail("4.4", e); >+ } >+ >+ // clean-up >+ ensureDoesNotExistInFileSystem(file); >+ >+ // restore the previous value >+ try { >+ manager.setValue(PROJECT_VARIABLE_NAME, existingValue); >+ } catch (CoreException e) { >+ fail("5.0", e); >+ } >+ >+ assertExistsInWorkspace("5.1", file); >+ assertExistsInFileSystem("5.2", file); >+ // the contents must be the original ones >+ try { > assertTrue("5.3", compareContent(file.getContents(true), getContents("contents for a file"))); > } catch (CoreException e) { > fail("5.4", e);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 229633
:
98169
|
98403
|
111561
|
111564
|
111596
|
111692
| 112305 |
115153
|
115154
|
115486
|
115544
|
115724
|
116049
|
116054