Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 264878
Collapse All | Expand All

(-)src/org/eclipse/core/internal/localstore/DeleteVisitor.java (-1 / +1 lines)
Lines 105-111 Link Here
105
	private void recursiveKeepHistory(IHistoryStore store, UnifiedTreeNode node) {
105
	private void recursiveKeepHistory(IHistoryStore store, UnifiedTreeNode node) {
106
		final IResource target = node.getResource();
106
		final IResource target = node.getResource();
107
		//we don't delete linked content, so no need to keep history
107
		//we don't delete linked content, so no need to keep history
108
		if (target.isLinked() || node.isSymbolicLink())
108
		if (target.isLinked() || target.isGroup() || node.isSymbolicLink())
109
			return;
109
			return;
110
		if (node.isFolder()) {
110
		if (node.isFolder()) {
111
			monitor.subTask(NLS.bind(Messages.localstore_deleting, target.getFullPath()));
111
			monitor.subTask(NLS.bind(Messages.localstore_deleting, target.getFullPath()));
(-)src/org/eclipse/core/internal/localstore/FileSystemResourceManager.java (-32 / +5 lines)
Lines 12-25 Link Here
12
 *******************************************************************************/
12
 *******************************************************************************/
13
package org.eclipse.core.internal.localstore;
13
package org.eclipse.core.internal.localstore;
14
14
15
import java.net.URISyntaxException;
16
17
import org.eclipse.core.filesystem.URIUtil;
18
19
import java.io.*;
15
import java.io.*;
20
import java.net.URI;
16
import java.net.URI;
21
import java.util.*;
17
import java.util.*;
22
import org.eclipse.core.filesystem.*;
18
import org.eclipse.core.filesystem.*;
19
import org.eclipse.core.filesystem.URIUtil;
23
import org.eclipse.core.internal.resources.*;
20
import org.eclipse.core.internal.resources.*;
24
import org.eclipse.core.internal.resources.File;
21
import org.eclipse.core.internal.resources.File;
25
import org.eclipse.core.internal.utils.*;
22
import org.eclipse.core.internal.utils.*;
Lines 159-166 Link Here
159
			//replace the path in the list with the appropriate resource type
156
			//replace the path in the list with the appropriate resource type
160
			IResource resource = resourceFor((IPath) result.get(i), files);
157
			IResource resource = resourceFor((IPath) result.get(i), files);
161
158
162
			if (resource == null || (((memberFlags & IContainer.INCLUDE_HIDDEN) == 0) && resource.isHidden(IResource.CHECK_ANCESTORS)) 
159
			if (resource == null || (((memberFlags & IContainer.INCLUDE_HIDDEN) == 0) && resource.isHidden(IResource.CHECK_ANCESTORS)) || (((memberFlags & IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS) == 0) && resource.isTeamPrivateMember(IResource.CHECK_ANCESTORS)))
163
					|| (((memberFlags & IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS) == 0) && resource.isTeamPrivateMember(IResource.CHECK_ANCESTORS)))
164
				resource = null;
160
				resource = null;
165
161
166
			result.set(i, resource);
162
			result.set(i, resource);
Lines 426-437 Link Here
426
			if (root != null && root.isValid())
422
			if (root != null && root.isValid())
427
				return root;
423
				return root;
428
			if (info.isSet(ICoreConstants.M_GROUP)) {
424
			if (info.isSet(ICoreConstants.M_GROUP)) {
429
				ProjectDescription description = ((Project) target.getProject())
425
				ProjectDescription description = ((Project) target.getProject()).internalGetDescription();
430
						.internalGetDescription();
431
				if (description != null) {
426
				if (description != null) {
432
					setLocation(target, info, description
427
					setLocation(target, info, description.getGroupLocationURI(target.getProjectRelativePath()));
433
							.getGroupLocationURI(target
434
									.getProjectRelativePath()));
435
					return info.getFileStoreRoot();
428
					return info.getFileStoreRoot();
436
				}
429
				}
437
				return info.getFileStoreRoot();
430
				return info.getFileStoreRoot();
Lines 622-644 Link Here
622
		updateLocalSync(info, lastModified);
615
		updateLocalSync(info, lastModified);
623
	}
616
	}
624
617
625
	public void group(Resource target) {
626
		URI virtualLocation;
627
		try {
628
			virtualLocation = FileUtil.canonicalURI(new URI("group")); //$NON-NLS-1$
629
			IFileStore store = initializeStore(target, virtualLocation);
630
			ResourceInfo info = target.getResourceInfo(false, true);
631
			long lastModified = store.fetchInfo().getLastModified();
632
			if (lastModified == 0)
633
				info.clearModificationStamp();
634
			updateLocalSync(info, lastModified);
635
		} catch (URISyntaxException e) {
636
			// can't happen
637
		} catch (CoreException e) {
638
			// can't happen
639
		}
640
	}
641
642
	/**
618
	/**
643
	 * Returns the resolved, absolute file system location of the given resource.
619
	 * Returns the resolved, absolute file system location of the given resource.
644
	 * Returns null if the location could not be resolved.
620
	 * Returns null if the location could not be resolved.
Lines 933-942 Link Here
933
		if (localSyncInfo == I_NULL_SYNC_INFO)
909
		if (localSyncInfo == I_NULL_SYNC_INFO)
934
			info.clear(M_LOCAL_EXISTS);
910
			info.clear(M_LOCAL_EXISTS);
935
		else {
911
		else {
936
			if (!info.isSet(M_GROUP))
912
			info.set(M_LOCAL_EXISTS);
937
				info.set(M_LOCAL_EXISTS);
938
			else
939
				info.clear(M_LOCAL_EXISTS);
940
		}
913
		}
941
	}
914
	}
942
915
(-)src/org/eclipse/core/internal/localstore/CopyVisitor.java (-9 / +8 lines)
Lines 59-65 Link Here
59
	private FileSystemResourceManager localManager;
59
	private FileSystemResourceManager localManager;
60
60
61
	public CopyVisitor(IResource rootSource, IResource destination, int updateFlags, IProgressMonitor monitor) {
61
	public CopyVisitor(IResource rootSource, IResource destination, int updateFlags, IProgressMonitor monitor) {
62
		this.localManager = ((Resource)rootSource).getLocalManager();
62
		this.localManager = ((Resource) rootSource).getLocalManager();
63
		this.rootDestination = destination;
63
		this.rootDestination = destination;
64
		this.updateFlags = updateFlags;
64
		this.updateFlags = updateFlags;
65
		this.isDeep = (updateFlags & IResource.SHALLOW) == 0;
65
		this.isDeep = (updateFlags & IResource.SHALLOW) == 0;
Lines 80-100 Link Here
80
80
81
	protected boolean copyContents(UnifiedTreeNode node, Resource source, Resource destination) {
81
	protected boolean copyContents(UnifiedTreeNode node, Resource source, Resource destination) {
82
		try {
82
		try {
83
			if (source.isGroup()) {
84
				((Folder) destination).createGroup(updateFlags & IResource.ALLOW_MISSING_LOCAL, null);
85
				return true;
86
			}
83
			if ((!isDeep || source.isUnderGroup()) && source.isLinked()) {
87
			if ((!isDeep || source.isUnderGroup()) && source.isLinked()) {
84
				URI sourceLocationURI = getWorkspace().transferVariableDefinition(source, destination, source.getRawLocationURI());
88
				URI sourceLocationURI = getWorkspace().transferVariableDefinition(source, destination, source.getRawLocationURI());
85
				destination.createLink(sourceLocationURI, updateFlags & IResource.ALLOW_MISSING_LOCAL, null);
89
				destination.createLink(sourceLocationURI, updateFlags & IResource.ALLOW_MISSING_LOCAL, null);
86
				return false;
90
				return false;
87
			}
91
			}
88
			if (source.isGroup()) {
89
				((Folder) destination).createGroup(updateFlags
90
						& IResource.ALLOW_MISSING_LOCAL, null);
91
				return true;
92
			}
93
			// update filters in project descriptions
92
			// update filters in project descriptions
94
			if (source.hasFilters()) {
93
			if (source.hasFilters()) {
95
				Project sourceProject = (Project) source.getProject();
94
				Project sourceProject = (Project) source.getProject();
96
				LinkedList/*<FilterDescription>*/ originalDescriptions = sourceProject.internalGetDescription().getFilter(source.getProjectRelativePath());
95
				LinkedList/*<FilterDescription>*/originalDescriptions = sourceProject.internalGetDescription().getFilter(source.getProjectRelativePath());
97
				LinkedList/*<FilterDescription>*/ filterDescriptions = FilterDescription.copy(originalDescriptions, destination.getProjectRelativePath());
96
				LinkedList/*<FilterDescription>*/filterDescriptions = FilterDescription.copy(originalDescriptions, destination.getProjectRelativePath());
98
				Project project = (Project) destination.getProject();
97
				Project project = (Project) destination.getProject();
99
				project.internalGetDescription().setFilters(destination.getProjectRelativePath(), filterDescriptions);
98
				project.internalGetDescription().setFilters(destination.getProjectRelativePath(), filterDescriptions);
100
				project.writeDescription(updateFlags);
99
				project.writeDescription(updateFlags);
Lines 129-135 Link Here
129
128
130
	protected Resource getDestinationResource(Resource source, IPath suffix) {
129
	protected Resource getDestinationResource(Resource source, IPath suffix) {
131
		if (suffix.segmentCount() == 0)
130
		if (suffix.segmentCount() == 0)
132
			return (Resource)rootDestination;
131
			return (Resource) rootDestination;
133
		IPath destinationPath = rootDestination.getFullPath().append(suffix);
132
		IPath destinationPath = rootDestination.getFullPath().append(suffix);
134
		return getWorkspace().newResource(destinationPath, source.getType());
133
		return getWorkspace().newResource(destinationPath, source.getType());
135
	}
134
	}
(-)src/org/eclipse/core/internal/resources/Project.java (-77 / +25 lines)
Lines 31-37 Link Here
31
		super(path, container);
31
		super(path, container);
32
		pathVariableManager = new ProjectPathVariableManager(this);
32
		pathVariableManager = new ProjectPathVariableManager(this);
33
	}
33
	}
34
	
34
35
	protected void assertCreateRequirements(IProjectDescription description) throws CoreException {
35
	protected void assertCreateRequirements(IProjectDescription description) throws CoreException {
36
		checkDoesNotExist();
36
		checkDoesNotExist();
37
		checkDescription(this, description, false);
37
		checkDescription(this, description, false);
Lines 230-258 Link Here
230
	public void create(IProgressMonitor monitor) throws CoreException {
230
	public void create(IProgressMonitor monitor) throws CoreException {
231
		create(null, monitor);
231
		create(null, monitor);
232
	}
232
	}
233
	
233
234
	/* (non-Javadoc)
234
	/* (non-Javadoc)
235
	 * @see IProject#create(IProjectDescription, IProgressMonitor)
235
	 * @see IProject#create(IProjectDescription, IProgressMonitor)
236
	 */
236
	 */
237
	public void create(IProjectDescription description, IProgressMonitor monitor) throws CoreException {
237
	public void create(IProjectDescription description, IProgressMonitor monitor) throws CoreException {
238
		create(description, IResource.NONE, monitor);
238
		create(description, IResource.NONE, monitor);
239
	}
239
	}
240
	
240
241
	/* (non-Javadoc)
241
	/* (non-Javadoc)
242
	 * @see IProject#create(IProjectDescription, IProgressMonitor)
242
	 * @see IProject#create(IProjectDescription, IProgressMonitor)
243
	 */
243
	 */
244
	public  void create(IProjectDescription description, int updateFlags, IProgressMonitor monitor) throws CoreException {
244
	public void create(IProjectDescription description, int updateFlags, IProgressMonitor monitor) throws CoreException {
245
		monitor = Policy.monitorFor(monitor);
245
		monitor = Policy.monitorFor(monitor);
246
		try {
246
		try {
247
			monitor.beginTask(Messages.resources_create, Policy.totalWork);
247
			monitor.beginTask(Messages.resources_create, Policy.totalWork);
248
			checkValidPath(path, PROJECT, false);
248
			checkValidPath(path, PROJECT, false);
249
			final ISchedulingRule rule = workspace.getRuleFactory().createRule(this);
249
			final ISchedulingRule rule = workspace.getRuleFactory().createRule(this);
250
			try {
250
			try {
251
				workspace.prepareOperation(rule, monitor);				
251
				workspace.prepareOperation(rule, monitor);
252
				if (description == null) {
252
				if (description == null) {
253
					description = new ProjectDescription();
253
					description = new ProjectDescription();
254
					description.setName(getName());
254
					description.setName(getName());
255
				}		
255
				}
256
				assertCreateRequirements(description);
256
				assertCreateRequirements(description);
257
				workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_PROJECT_CREATE, this));
257
				workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_PROJECT_CREATE, this));
258
				workspace.beginOperation(true);
258
				workspace.beginOperation(true);
Lines 329-335 Link Here
329
		clearHistory(null);
329
		clearHistory(null);
330
	}
330
	}
331
331
332
	protected void fixupAfterMoveSource()  throws CoreException {
332
	protected void fixupAfterMoveSource() throws CoreException {
333
		workspace.deleteResource(this);
333
		workspace.deleteResource(this);
334
		// check if we deleted a preferences file 
334
		// check if we deleted a preferences file 
335
		ProjectPreferences.deleted(this);
335
		ProjectPreferences.deleted(this);
Lines 739-745 Link Here
739
	public boolean isLinked(int options) {
739
	public boolean isLinked(int options) {
740
		return false;//projects are never linked
740
		return false;//projects are never linked
741
	}
741
	}
742
	
742
743
	public boolean isGroup() {
743
	public boolean isGroup() {
744
		return false;// projects are never groups
744
		return false;// projects are never groups
745
	}
745
	}
Lines 898-904 Link Here
898
				// the M_USED flag is used to indicate the difference between opening a project
898
				// the M_USED flag is used to indicate the difference between opening a project
899
				// for the first time and opening it from a previous close (restoring it from disk)
899
				// for the first time and opening it from a previous close (restoring it from disk)
900
				boolean used = info.isSet(M_USED);
900
				boolean used = info.isSet(M_USED);
901
				boolean minorIssuesDuringRestore = false;	
901
				boolean minorIssuesDuringRestore = false;
902
				if (used) {
902
				if (used) {
903
					minorIssuesDuringRestore = workspace.getSaveManager().restore(this, Policy.subMonitorFor(monitor, Policy.opWork * 20 / 100));
903
					minorIssuesDuringRestore = workspace.getSaveManager().restore(this, Policy.subMonitorFor(monitor, Policy.opWork * 20 / 100));
904
				} else {
904
				} else {
Lines 953-959 Link Here
953
	 */
953
	 */
954
	public IStatus reconcileLinksAndGroups(ProjectDescription newDescription) {
954
	public IStatus reconcileLinksAndGroups(ProjectDescription newDescription) {
955
		String msg = Messages.links_errorLinkReconcile;
955
		String msg = Messages.links_errorLinkReconcile;
956
		HashMap newGroups = newDescription.getGroups();
957
		HashMap newLinks = newDescription.getLinks();
956
		HashMap newLinks = newDescription.getLinks();
958
		MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.OPERATION_FAILED, msg, null);
957
		MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.OPERATION_FAILED, msg, null);
959
		//walk over old linked resources and remove those that are no longer defined
958
		//walk over old linked resources and remove those that are no longer defined
Lines 981-1033 Link Here
981
					}
980
					}
982
				}
981
				}
983
			}
982
			}
984
			HashMap oldGroups = oldDescription.getGroups();
985
			if (oldGroups != null) {
986
				for (Iterator it = oldGroups.values().iterator(); it.hasNext();) {
987
					GroupDescription oldGroup = (GroupDescription) it.next();
988
					Resource oldGroupResource = (Resource) findMember(oldGroup
989
							.getProjectRelativePath());
990
					if (oldGroupResource == null || !oldGroupResource.isGroup())
991
						continue;
992
					GroupDescription newGroup = null;
993
					if (newGroups != null)
994
						newGroup = (GroupDescription) newGroups.get(oldGroup
995
								.getProjectRelativePath());
996
					// if the new group is missing then remove old group
997
					if (newGroup == null) {
998
						try {
999
							oldGroupResource.delete(IResource.NONE, null);
1000
							// refresh the resource, because removing a group
1001
							// can reveal a previously hidden resource in parent
1002
							oldGroupResource.refreshLocal(
1003
									IResource.DEPTH_INFINITE, null);
1004
						} catch (CoreException e) {
1005
							status.merge(e.getStatus());
1006
						}
1007
					}
1008
				}
1009
			}
1010
		}
983
		}
1011
		// walk over new links and groups and create if necessary
984
		// walk over new links and groups and create if necessary
1012
		// Recreate them in order of the higher up in the tree hierarchy first,
985
		// Recreate them in order of the higher up in the tree hierarchy first,
1013
		// so we don't have to create intermediate directories that would turn
986
		// so we don't have to create intermediate directories that would turn
1014
		// out
987
		// out
1015
		// to be groups or link folders.
988
		// to be groups or link folders.
1016
		if (newLinks == null && newGroups == null)
989
		if (newLinks == null)
1017
			return status;
990
			return status;
1018
		//sort links to avoid creating nested links before their parents
991
		//sort links to avoid creating nested links before their parents
1019
		TreeSet newLinksAndGroups = new TreeSet(new Comparator() {
992
		TreeSet newLinksAndGroups = new TreeSet(new Comparator() {
1020
			public int compare(Object arg0, Object arg1) {
993
			public int compare(Object arg0, Object arg1) {
1021
				int numberOfSegments0;
994
				int numberOfSegments0 = ((LinkDescription) arg0).getProjectRelativePath().segmentCount();
1022
				if (arg0 instanceof LinkDescription)
995
				int numberOfSegments1 = ((LinkDescription) arg1).getProjectRelativePath().segmentCount();
1023
					numberOfSegments0 = ((LinkDescription) arg0).getProjectRelativePath().segmentCount();
1024
				else
1025
					numberOfSegments0 = ((GroupDescription) arg0).getProjectRelativePath().segmentCount();
1026
				int numberOfSegments1;
1027
				if (arg1 instanceof LinkDescription)
1028
					numberOfSegments1 = ((LinkDescription) arg1).getProjectRelativePath().segmentCount();
1029
				else
1030
					numberOfSegments1 = ((GroupDescription) arg1).getProjectRelativePath().segmentCount();
1031
				if (numberOfSegments0 != numberOfSegments1)
996
				if (numberOfSegments0 != numberOfSegments1)
1032
					return numberOfSegments0 - numberOfSegments1;
997
					return numberOfSegments0 - numberOfSegments1;
1033
				else if (arg0.equals(arg1))
998
				else if (arg0.equals(arg1))
Lines 1039-1076 Link Here
1039
		});
1004
		});
1040
		if (newLinks != null)
1005
		if (newLinks != null)
1041
			newLinksAndGroups.addAll(newLinks.values());
1006
			newLinksAndGroups.addAll(newLinks.values());
1042
		if (newGroups != null)
1043
			newLinksAndGroups.addAll(newGroups.values());
1044
1007
1045
		for (Iterator it = newLinksAndGroups.iterator(); it.hasNext();) {
1008
		for (Iterator it = newLinksAndGroups.iterator(); it.hasNext();) {
1046
			Object description = it.next();
1009
			Object description = it.next();
1047
			if (description instanceof LinkDescription) {
1010
			LinkDescription newLink = (LinkDescription) description;
1048
				LinkDescription newLink = (LinkDescription) description;
1011
			try {
1049
				try {
1012
				Resource toLink = workspace.newResource(getFullPath().append(newLink.getProjectRelativePath()), newLink.getType());
1050
					Resource toLink = workspace.newResource(getFullPath().append(newLink.getProjectRelativePath()), newLink.getType());
1013
				IContainer parent = toLink.getParent();
1051
					IContainer parent = toLink.getParent();
1014
				if (parent != null && !parent.exists() && parent.getType() == FOLDER)
1052
					if (parent != null && !parent.exists() && parent.getType() == FOLDER)
1015
					((Folder) parent).ensureExists(Policy.monitorFor(null));
1053
						((Folder) parent).ensureExists(Policy.monitorFor(null));
1016
				if (newLink.isGroup())
1054
					toLink.createLink(newLink.getLocationURI(), IResource.REPLACE | IResource.ALLOW_MISSING_LOCAL,
1017
					((Folder) toLink).createGroup(IResource.REPLACE | IResource.ALLOW_MISSING_LOCAL, null);
1055
							null);
1018
				else
1056
				} catch (CoreException e) {
1019
					toLink.createLink(newLink.getLocationURI(), IResource.REPLACE | IResource.ALLOW_MISSING_LOCAL, null);
1057
					status.merge(e.getStatus());
1020
			} catch (CoreException e) {
1058
				}
1021
				status.merge(e.getStatus());
1059
			} else {
1060
				GroupDescription newGroup = (GroupDescription) description;
1061
				try {
1062
					Resource toGroup = workspace.newResource(getFullPath()
1063
							.append(newGroup.getProjectRelativePath()),
1064
							IResource.FOLDER);
1065
					IContainer parent = toGroup.getParent();
1066
					if (parent != null && !parent.exists()
1067
							&& parent.getType() == FOLDER)
1068
						((Folder) parent).ensureExists(Policy.monitorFor(null));
1069
					((Folder) toGroup).createGroup(IResource.REPLACE
1070
							| IResource.ALLOW_MISSING_LOCAL, null);
1071
				} catch (CoreException e) {
1072
					status.merge(e.getStatus());
1073
				}
1074
			}
1022
			}
1075
		}
1023
		}
1076
		return status;
1024
		return status;
Lines 1090-1096 Link Here
1090
			if ((updateFlags & IResource.AVOID_NATURE_CONFIG) != 0)
1038
			if ((updateFlags & IResource.AVOID_NATURE_CONFIG) != 0)
1091
				rule = workspace.getRuleFactory().modifyRule(this);
1039
				rule = workspace.getRuleFactory().modifyRule(this);
1092
			else
1040
			else
1093
				rule = workspace.getRoot();		
1041
				rule = workspace.getRoot();
1094
			try {
1042
			try {
1095
				//need to use root rule because nature configuration calls third party code
1043
				//need to use root rule because nature configuration calls third party code
1096
				workspace.prepareOperation(rule, monitor);
1044
				workspace.prepareOperation(rule, monitor);
(-)src/org/eclipse/core/internal/resources/Workspace.java (-18 lines)
Lines 768-791 Link Here
768
			newInfo.setFileStoreRoot(null);
768
			newInfo.setFileStoreRoot(null);
769
		}
769
		}
770
770
771
		// update group locations in project descriptions
772
		if (source.isGroup()) {
773
			GroupDescription groupDescription;
774
			newInfo.set(ICoreConstants.M_GROUP);
775
			groupDescription = new GroupDescription(destinationResource);
776
			if (moveResources && !movingProject) {
777
				if (((Project) source.getProject())
778
						.internalGetDescription()
779
						.setGroupLocation(source.getProjectRelativePath(), null))
780
					((Project) source.getProject()).writeDescription(updateFlags);
781
			}
782
			Project project = (Project) destinationResource.getProject();
783
			project.internalGetDescription().setGroupLocation(
784
					destinationResource.getProjectRelativePath(),
785
					groupDescription);
786
			project.writeDescription(updateFlags);
787
		}
788
789
		// update filters in project descriptions
771
		// update filters in project descriptions
790
		if (source.hasFilters() && source.getProject().exists()) {
772
		if (source.hasFilters() && source.getProject().exists()) {
791
			Project sourceProject = (Project) source.getProject();
773
			Project sourceProject = (Project) source.getProject();
(-)src/org/eclipse/core/internal/resources/GroupDescription.java (-81 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2007 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.core.internal.resources;
12
13
import org.eclipse.core.runtime.IPath;
14
15
import org.eclipse.core.resources.IResource;
16
import org.eclipse.core.runtime.*;
17
18
/**
19
 * Object for describing the characteristics of linked resources that are stored
20
 * in the project description.
21
 */
22
public class GroupDescription implements Comparable {
23
24
	/**
25
	 * The project relative path.
26
	 */
27
	private IPath path;
28
29
	public GroupDescription() {
30
		this.path = Path.EMPTY;
31
	}
32
33
	public GroupDescription(IResource linkedResource) {
34
		super();
35
		Assert.isNotNull(linkedResource);
36
		this.path = linkedResource.getProjectRelativePath();
37
	}
38
39
	public boolean equals(Object o) {
40
		if (!(o.getClass() == GroupDescription.class))
41
			return false;
42
		GroupDescription other = (GroupDescription) o;
43
		return path.equals(other.path);
44
	}
45
46
	/**
47
	 * Returns the project relative path of the group.
48
	 * 
49
	 * @return the project relative path of the group.
50
	 */
51
	public IPath getProjectRelativePath() {
52
		return path;
53
	}
54
55
	public int hashCode() {
56
		return path.hashCode();
57
	}
58
59
	public void setPath(IPath path) {
60
		this.path = path;
61
	}
62
63
	/**
64
	 * Compare group descriptions in a way that sorts them topologically by path.
65
	 */
66
	public int compareTo(Object o) {
67
		GroupDescription that = (GroupDescription) o;
68
		IPath path1 = this.getProjectRelativePath();
69
		IPath path2 = that.getProjectRelativePath();
70
		int count1 = path1.segmentCount();
71
		int compare = count1 - path2.segmentCount();
72
		if (compare != 0)
73
			return compare;
74
		for (int i = 0; i < count1; i++) {
75
			compare = path1.segment(i).compareTo(path2.segment(i));
76
			if (compare != 0)
77
				return compare;
78
		}
79
		return 0;
80
	}
81
}
(-)src/org/eclipse/core/internal/resources/Container.java (-16 lines)
Lines 157-178 Link Here
157
		return true;
157
		return true;
158
	}
158
	}
159
159
160
	public boolean isLocalOrGroup(int flags, int depth) {
161
		if (!super.isLocalOrGroup(flags, depth))
162
			return false;
163
		if (depth == DEPTH_ZERO)
164
			return true;
165
		if (depth == DEPTH_ONE)
166
			depth = DEPTH_ZERO;
167
		// get the children via the workspace since we know that this
168
		// resource exists (it is local).
169
		IResource[] children = getChildren(IResource.NONE);
170
		for (int i = 0; i < children.length; i++)
171
			if (!((Resource) children[i]).isLocalOrGroup(depth))
172
				return false;
173
		return true;
174
	}
175
176
	/* (non-Javadoc)
160
	/* (non-Javadoc)
177
	 * @see IContainer#members()
161
	 * @see IContainer#members()
178
	 */
162
	 */
(-)src/org/eclipse/core/internal/resources/Folder.java (-52 / +2 lines)
Lines 11-18 Link Here
11
 *******************************************************************************/
11
 *******************************************************************************/
12
package org.eclipse.core.internal.resources;
12
package org.eclipse.core.internal.resources;
13
13
14
import org.eclipse.core.internal.events.LifecycleEvent;
15
16
import java.net.URI;
14
import java.net.URI;
17
import org.eclipse.core.filesystem.IFileInfo;
15
import org.eclipse.core.filesystem.IFileInfo;
18
import org.eclipse.core.filesystem.IFileStore;
16
import org.eclipse.core.filesystem.IFileStore;
Lines 128-183 Link Here
128
	 * @see org.eclipse.core.resources.IFolder#createGroup(int,
126
	 * @see org.eclipse.core.resources.IFolder#createGroup(int,
129
	 *      IProgressMonitor)
127
	 *      IProgressMonitor)
130
	 */
128
	 */
131
	public void createGroup(int updateFlags, IProgressMonitor monitor)
129
	public void createGroup(int updateFlags, IProgressMonitor monitor) throws CoreException {
132
			throws CoreException {
130
		createLink(LinkDescription.GROUP_LOCATION, updateFlags, monitor);
133
		monitor = Policy.monitorFor(monitor);
134
		try {
135
			String message = NLS.bind(Messages.group_creating, getFullPath());
136
			monitor.beginTask(message, Policy.totalWork);
137
			Policy.checkCanceled(monitor);
138
			checkValidPath(path, FOLDER, true);
139
			final ISchedulingRule rule = workspace.getRuleFactory().createRule(
140
					this);
141
			try {
142
				workspace.prepareOperation(rule, monitor);
143
				workspace.broadcastEvent(LifecycleEvent.newEvent(
144
						LifecycleEvent.PRE_GROUP_CREATE, this));
145
				workspace.beginOperation(true);
146
				// replace existing resource, if applicable
147
				if ((updateFlags & REPLACE) != 0) {
148
					IResource existing = workspace.getRoot().findMember(
149
							getFullPath());
150
					if (existing != null)
151
						workspace.deleteResource(existing);
152
				}
153
				ResourceInfo info = workspace.createResource(this, false);
154
				info.set(M_GROUP);
155
				getLocalManager().group(this);
156
				monitor.worked(Policy.opWork * 5 / 100);
157
				// save the location in the project description
158
				Project project = (Project) getProject();
159
				if (project.internalGetDescription().setGroupLocation(
160
						getProjectRelativePath(), new GroupDescription(this)))
161
					project.writeDescription(IResource.NONE);
162
				monitor.worked(Policy.opWork * 5 / 100);
163
164
				// refresh to discover any new resources below this group
165
				// location
166
				if (getType() != IResource.FILE)
167
					refreshLocal(DEPTH_INFINITE, Policy.subMonitorFor(monitor,
168
							Policy.opWork * 90 / 100));
169
				else
170
					monitor.worked(Policy.opWork * 90 / 100);
171
			} catch (OperationCanceledException e) {
172
				workspace.getWorkManager().operationCanceled();
173
				throw e;
174
			} finally {
175
				workspace.endOperation(rule, true, Policy.subMonitorFor(
176
						monitor, Policy.endOpWork));
177
			}
178
		} finally {
179
			monitor.done();
180
		}
181
	}
131
	}
182
132
183
	/**
133
	/**
(-)src/org/eclipse/core/internal/resources/Resource.java (-81 / +7 lines)
Lines 244-250 Link Here
244
		checkValidPath(destination, destinationType, false);
244
		checkValidPath(destination, destinationType, false);
245
245
246
		ResourceInfo info;
246
		ResourceInfo info;
247
		checkAccessibleAndLocalOrGroup(DEPTH_INFINITE);
247
		checkAccessibleAndLocal(DEPTH_INFINITE);
248
248
249
		IPath destinationParent = destination.removeLastSegments(1);
249
		IPath destinationParent = destination.removeLastSegments(1);
250
		checkValidGroupContainer(destinationParent, isLinked(), isGroup());
250
		checkValidGroupContainer(destinationParent, isLinked(), isGroup());
Lines 349-370 Link Here
349
	}
349
	}
350
350
351
	/**
351
	/**
352
	 * Checks that this resource is Accessible && (local to the given depth || is a group).
353
	 * 
354
	 * @exception CoreException
355
	 *                if this resource is not local
356
	 */
357
	protected void checkAccessibleAndLocalOrGroup(int depth) throws CoreException {
358
		ResourceInfo info = getResourceInfo(false, false);
359
		int flags = getFlags(info);
360
		checkAccessible(flags);
361
		if (!isLocalOrGroup(flags, depth)) {
362
			String message = NLS.bind(Messages.resources_mustBeLocal, getFullPath());
363
			throw new ResourceException(IResourceStatus.RESOURCE_NOT_LOCAL, getFullPath(), message, null);
364
		}
365
	}
366
367
	/**
368
	 * This method reports errors in two different ways. It can throw a
352
	 * This method reports errors in two different ways. It can throw a
369
	 * CoreException or log a status. CoreExceptions are used according
353
	 * CoreException or log a status. CoreExceptions are used according
370
	 * to the specification of the move method. Programming errors, that
354
	 * to the specification of the move method. Programming errors, that
Lines 393-399 Link Here
393
		checkValidPath(destination, destinationType, false);
377
		checkValidPath(destination, destinationType, false);
394
378
395
		ResourceInfo info;
379
		ResourceInfo info;
396
		checkAccessibleAndLocalOrGroup(DEPTH_INFINITE);
380
		checkAccessibleAndLocal(DEPTH_INFINITE);
397
381
398
		IPath destinationParent = destination.removeLastSegments(1);
382
		IPath destinationParent = destination.removeLastSegments(1);
399
		checkValidGroupContainer(destinationParent, isLinked(), isGroup());
383
		checkValidGroupContainer(destinationParent, isLinked(), isGroup());
Lines 683-693 Link Here
683
					info.set(M_HIDDEN);
667
					info.set(M_HIDDEN);
684
				info.set(M_LINK);
668
				info.set(M_LINK);
685
				localLocation = FileUtil.canonicalURI(localLocation);
669
				localLocation = FileUtil.canonicalURI(localLocation);
670
				LinkDescription linkDescription = new LinkDescription(this, localLocation);
671
				if (linkDescription.isGroup())
672
					info.set(M_GROUP);
686
				getLocalManager().link(this, localLocation, fileInfo);
673
				getLocalManager().link(this, localLocation, fileInfo);
687
				monitor.worked(Policy.opWork * 5 / 100);
674
				monitor.worked(Policy.opWork * 5 / 100);
688
				//save the location in the project description
675
				//save the location in the project description
689
				Project project = (Project) getProject();
676
				Project project = (Project) getProject();
690
				boolean changed = project.internalGetDescription().setLinkLocation(getProjectRelativePath(), new LinkDescription(this, localLocation));
677
				boolean changed = project.internalGetDescription().setLinkLocation(getProjectRelativePath(), linkDescription);
691
				if (changed)
678
				if (changed)
692
					project.writeDescription(IResource.NONE);
679
					project.writeDescription(IResource.NONE);
693
				monitor.worked(Policy.opWork * 5 / 100);
680
				monitor.worked(Policy.opWork * 5 / 100);
Lines 956-971 Link Here
956
			getMarkerManager().removeMarkers(this, IResource.DEPTH_INFINITE);
943
			getMarkerManager().removeMarkers(this, IResource.DEPTH_INFINITE);
957
		// if this is a linked resource or contains linked resources , remove their entries from the project description
944
		// if this is a linked resource or contains linked resources , remove their entries from the project description
958
		List links = findLinks();
945
		List links = findLinks();
959
		List groups = findGroups();
960
		//pre-delete notification to internal infrastructure
946
		//pre-delete notification to internal infrastructure
961
		if (links != null)
947
		if (links != null)
962
			for (Iterator it = links.iterator(); it.hasNext();)
948
			for (Iterator it = links.iterator(); it.hasNext();)
963
				workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_LINK_DELETE, (IResource) it.next()));
949
				workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_LINK_DELETE, (IResource) it.next()));
964
950
965
		if (groups != null)
966
			for (Iterator it = groups.iterator(); it.hasNext();)
967
				workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_GROUP_DELETE, (IResource) it.next()));
968
969
		// check if we deleted a preferences file 
951
		// check if we deleted a preferences file 
970
		ProjectPreferences.deleted(this);
952
		ProjectPreferences.deleted(this);
971
953
Lines 1004-1024 Link Here
1004
			}
986
			}
1005
		}
987
		}
1006
		
988
		
1007
		if ((groups != null) && (groups.size() > 0)) {
1008
			Project project = (Project) getProject();
1009
			ProjectDescription description = project.internalGetDescription();
1010
			if (description != null) {
1011
				description.setGroupLocation(getProjectRelativePath(), null);
1012
				boolean wasChanged = false;
1013
				for (Iterator it = groups.iterator(); it.hasNext();)
1014
					wasChanged |= description.setGroupLocation(((IResource) it.next()).getProjectRelativePath(), null);
1015
				if (wasChanged) {
1016
					project.internalSetDescription(description, true);
1017
					project.writeDescription(IResource.FORCE);
1018
				}
1019
			}
1020
		}
1021
1022
		// Delete properties after the resource is deleted from the tree. See bug 84584.
989
		// Delete properties after the resource is deleted from the tree. See bug 84584.
1023
		CoreException err = null;
990
		CoreException err = null;
1024
		try {
991
		try {
Lines 1058-1087 Link Here
1058
	}
1025
	}
1059
1026
1060
	/*
1027
	/*
1061
	 * Returns a list of all linked resources at or below this resource, or null if there
1062
	 * are no links.
1063
	 */
1064
	private List findGroups() {
1065
		Project project = (Project) getProject();
1066
		ProjectDescription description = project.internalGetDescription();
1067
		HashMap groupMap = description.getGroups();
1068
		if (groupMap == null)
1069
			return null;
1070
		List groups = null;
1071
		IPath myPath = getProjectRelativePath();
1072
		for (Iterator it = groupMap.values().iterator(); it.hasNext();) {
1073
			GroupDescription group = (GroupDescription) it.next();
1074
			IPath groupPath = group.getProjectRelativePath();
1075
			if (myPath.isPrefixOf(groupPath)) {
1076
				if (groups == null)
1077
					groups = new ArrayList();
1078
				groups.add(workspace.newResource(project.getFullPath().append(groupPath), IResource.FOLDER));
1079
			}
1080
		}
1081
		return groups;
1082
	}
1083
1084
	/*
1085
	 * Returns a list of all filtered resources at or below this resource, or null if there
1028
	 * Returns a list of all filtered resources at or below this resource, or null if there
1086
	 * are no links.
1029
	 * are no links.
1087
	 */
1030
	 */
Lines 1202-1221 Link Here
1202
	protected void fixupAfterMoveSource() throws CoreException {
1145
	protected void fixupAfterMoveSource() throws CoreException {
1203
		ResourceInfo info = getResourceInfo(true, true);
1146
		ResourceInfo info = getResourceInfo(true, true);
1204
		//if a linked resource is moved, we need to remove the location info from the .project 
1147
		//if a linked resource is moved, we need to remove the location info from the .project 
1205
		if (isLinked()) {
1148
		if (isLinked() || isGroup()) {
1206
			Project project = (Project) getProject();
1149
			Project project = (Project) getProject();
1207
			if (project.internalGetDescription().setLinkLocation(getProjectRelativePath(), null))
1150
			if (project.internalGetDescription().setLinkLocation(getProjectRelativePath(), null))
1208
				project.writeDescription(IResource.NONE);
1151
				project.writeDescription(IResource.NONE);
1209
		}
1152
		}
1210
1153
1211
		// if a group resource is moved, we need to remove the location info
1212
		// from the .project
1213
		if (isGroup()) {
1214
			Project project = (Project) getProject();
1215
			if (project.internalGetDescription().setGroupLocation(getProjectRelativePath(), null))
1216
				project.writeDescription(IResource.NONE);
1217
		}
1218
		
1219
		List filters = findFilters();
1154
		List filters = findFilters();
1220
		if ((filters != null) && (filters.size() > 0)) {
1155
		if ((filters != null) && (filters.size() > 0)) {
1221
			// delete resource filters
1156
			// delete resource filters
Lines 1614-1623 Link Here
1614
		return isLocal(getFlags(info), depth);
1549
		return isLocal(getFlags(info), depth);
1615
	}
1550
	}
1616
1551
1617
	protected boolean isLocalOrGroup(int depth) {
1618
		ResourceInfo info = getResourceInfo(false, false);
1619
		return isLocalOrGroup(getFlags(info), depth);
1620
	}
1621
	/**
1552
	/**
1622
	 * Note the depth parameter is intentionally ignored because 
1553
	 * Note the depth parameter is intentionally ignored because 
1623
	 * this method is over-ridden by Container.isLocal().
1554
	 * this method is over-ridden by Container.isLocal().
Lines 1627-1637 Link Here
1627
		return flags != NULL_FLAG && ResourceInfo.isSet(flags, M_LOCAL_EXISTS);
1558
		return flags != NULL_FLAG && ResourceInfo.isSet(flags, M_LOCAL_EXISTS);
1628
	}
1559
	}
1629
1560
1630
	protected boolean isLocalOrGroup(int flags, int depth) {
1631
		return flags != NULL_FLAG && ResourceInfo.isSet(flags, M_LOCAL_EXISTS)
1632
					|| isGroup();
1633
	}
1634
	
1635
	/**
1561
	/**
1636
	 * Returns whether a resource should be included in a traversal
1562
	 * Returns whether a resource should be included in a traversal
1637
	 * based on the provided member flags.
1563
	 * based on the provided member flags.
(-)src/org/eclipse/core/internal/resources/LinkDescription.java (-3 / +17 lines)
Lines 12-17 Link Here
12
package org.eclipse.core.internal.resources;
12
package org.eclipse.core.internal.resources;
13
13
14
import java.net.URI;
14
import java.net.URI;
15
import java.net.URISyntaxException;
15
import org.eclipse.core.resources.IResource;
16
import org.eclipse.core.resources.IResource;
16
import org.eclipse.core.runtime.*;
17
import org.eclipse.core.runtime.*;
17
18
Lines 20-25 Link Here
20
 * in the project description.
21
 * in the project description.
21
 */
22
 */
22
public class LinkDescription implements Comparable {
23
public class LinkDescription implements Comparable {
24
	public static final URI GROUP_LOCATION = getGroupLocation();
25
	private static URI getGroupLocation() {
26
		try {
27
			return  new URI("group:/group"); //$NON-NLS-1$
28
		} catch (URISyntaxException e) {
29
			//cannot happen
30
			return null;
31
		}
32
	}
23
33
24
	private URI localLocation;
34
	private URI localLocation;
25
35
Lines 28-34 Link Here
28
	 */
38
	 */
29
	private IPath path;
39
	private IPath path;
30
	/**
40
	/**
31
	 * The resource type (IResource.FILE or IResoruce.FOLDER)
41
	 * The resource type (IResource.FILE or IResource.FOLDER)
32
	 */
42
	 */
33
	private int type;
43
	private int type;
34
44
Lines 50-56 Link Here
50
		if (!(o.getClass() == LinkDescription.class))
60
		if (!(o.getClass() == LinkDescription.class))
51
			return false;
61
			return false;
52
		LinkDescription other = (LinkDescription) o;
62
		LinkDescription other = (LinkDescription) o;
53
		return localLocation.equals(other.localLocation) && type == other.type;
63
		return localLocation.equals(other.localLocation) && path.equals(other.path) && type == other.type;
54
	}
64
	}
55
65
56
	public URI getLocationURI() {
66
	public URI getLocationURI() {
Lines 68-76 Link Here
68
	public int getType() {
78
	public int getType() {
69
		return type;
79
		return type;
70
	}
80
	}
81
	
82
	public boolean isGroup() {
83
		return localLocation.equals(GROUP_LOCATION);
84
	}
71
85
72
	public int hashCode() {
86
	public int hashCode() {
73
		return type + localLocation.hashCode();
87
		return type + path.hashCode() + localLocation.hashCode();
74
	}
88
	}
75
89
76
	public void setLocationURI(URI location) {
90
	public void setLocationURI(URI location) {
(-)src/org/eclipse/core/internal/resources/ProjectDescriptionReader.java (-84 lines)
Lines 58-66 Link Here
58
	protected static final int S_FILTER_PATH = 25;
58
	protected static final int S_FILTER_PATH = 25;
59
	protected static final int S_FILTER_TYPE = 26;
59
	protected static final int S_FILTER_TYPE = 26;
60
	protected static final int S_FILTERED_RESOURCES = 27;
60
	protected static final int S_FILTERED_RESOURCES = 27;
61
	protected static final int S_GROUP_RESOURCES = 28;
62
	protected static final int S_GROUP = 29;
63
	protected static final int S_GROUP_PATH = 30;
64
	protected static final int S_VARIABLE_LIST = 31;
61
	protected static final int S_VARIABLE_LIST = 31;
65
	protected static final int S_VARIABLE = 32;
62
	protected static final int S_VARIABLE = 32;
66
	protected static final int S_VARIABLE_NAME = 33;
63
	protected static final int S_VARIABLE_NAME = 33;
Lines 316-324 Link Here
316
			case S_LINKED_RESOURCES :
313
			case S_LINKED_RESOURCES :
317
				endLinkedResourcesElement(elementName);
314
				endLinkedResourcesElement(elementName);
318
				break;
315
				break;
319
			case S_GROUP :
320
				endGroupElement(elementName);
321
				break;
322
			case S_VARIABLE :
316
			case S_VARIABLE :
323
				endVariableElement(elementName);
317
				endVariableElement(elementName);
324
				break;
318
				break;
Lines 328-336 Link Here
328
			case S_FILTERED_RESOURCES :
322
			case S_FILTERED_RESOURCES :
329
				endFilteredResourcesElement(elementName);
323
				endFilteredResourcesElement(elementName);
330
				break;
324
				break;
331
			case S_GROUP_RESOURCES :
332
				endGroupResourcesElement(elementName);
333
				break;
334
			case S_VARIABLE_LIST :
325
			case S_VARIABLE_LIST :
335
				endVariableListElement(elementName);
326
				endVariableListElement(elementName);
336
				break;
327
				break;
Lines 398-406 Link Here
398
			case S_FILTER_ARGUMENTS:
389
			case S_FILTER_ARGUMENTS:
399
				endFilterArguments(elementName);
390
				endFilterArguments(elementName);
400
				break;
391
				break;
401
			case S_GROUP_PATH :
402
				endGroupPath(elementName);
403
				break;
404
			case S_VARIABLE_NAME :
392
			case S_VARIABLE_NAME :
405
				endVariableName(elementName);
393
				endVariableName(elementName);
406
				break;
394
				break;
Lines 441-460 Link Here
441
	 * End this group of group resources and add them to the project
429
	 * End this group of group resources and add them to the project
442
	 * description.
430
	 * description.
443
	 */
431
	 */
444
	private void endGroupResourcesElement(String elementName) {
445
		if (elementName.equals(GROUP_RESOURCES)) {
446
			HashMap groupResources = (HashMap) objectStack.pop();
447
			state = S_PROJECT_DESC;
448
			if (groupResources.isEmpty())
449
				return;
450
			projectDescription.setGroupDescriptions(groupResources);
451
		}
452
	}
453
454
	/**
455
	 * End this group of group resources and add them to the project
456
	 * description.
457
	 */
458
	private void endVariableListElement(String elementName) {
432
	private void endVariableListElement(String elementName) {
459
		if (elementName.equals(VARIABLE_LIST)) {
433
		if (elementName.equals(VARIABLE_LIST)) {
460
			HashMap variableList = (HashMap) objectStack.pop();
434
			HashMap variableList = (HashMap) objectStack.pop();
Lines 553-580 Link Here
553
	}
527
	}
554
528
555
	/**
529
	/**
556
	 * End a single group resource and add it to the HashMap.
557
	 */
558
	private void endGroupElement(String elementName) {
559
		if (elementName.equals(GROUP)) {
560
			state = S_GROUP_RESOURCES;
561
			// Pop off the link description
562
			GroupDescription group = (GroupDescription) objectStack.pop();
563
			// Make sure that you have something reasonable
564
			IPath path = group.getProjectRelativePath();
565
			if ((path == null) || path.segmentCount() == 0) {
566
				parseProblem(NLS.bind(Messages.projRead_emptyGroupName,
567
						elementName));
568
				return;
569
			}
570
571
			// The HashMap of group resources is the next thing on the stack
572
			((HashMap) objectStack.peek()).put(group.getProjectRelativePath(),
573
					group);
574
		}
575
	}
576
577
	/**
578
	 * For backwards compatibility, link locations in the local file system are represented 
530
	 * For backwards compatibility, link locations in the local file system are represented 
579
	 * in the project description under the "location" tag.
531
	 * in the project description under the "location" tag.
580
	 * @param elementName
532
	 * @param elementName
Lines 699-721 Link Here
699
			state = S_FILTER;
651
			state = S_FILTER;
700
		}
652
		}
701
	}
653
	}
702
	
703
	private void endGroupPath(String elementName) {
704
		if (elementName.equals(NAME)) {
705
			IPath newPath = new Path(charBuffer.toString());
706
			// objectStack has a GroupDescription on it. Set the name
707
			// on this GroupDescription.
708
			IPath oldPath = ((GroupDescription) objectStack.peek())
709
					.getProjectRelativePath();
710
			if (oldPath.segmentCount() != 0) {
711
				parseProblem(NLS.bind(Messages.projRead_badGroupName, oldPath,
712
						newPath));
713
			} else {
714
				((GroupDescription) objectStack.peek()).setPath(newPath);
715
			}
716
			state = S_GROUP;
717
		}
718
	}
719
654
720
	private void endVariableName(String elementName) {
655
	private void endVariableName(String elementName) {
721
		if (elementName.equals(NAME)) {
656
		if (elementName.equals(NAME)) {
Lines 871-882 Link Here
871
			state = S_FILTERED_RESOURCES;
806
			state = S_FILTERED_RESOURCES;
872
			return;
807
			return;
873
		}
808
		}
874
		if (elementName.equals(GROUP_RESOURCES)) {
875
			// Push a HashMap to collect all the groups.
876
			objectStack.push(new HashMap());
877
			state = S_GROUP_RESOURCES;
878
			return;
879
		}
880
		if (elementName.equals(VARIABLE_LIST)) {
809
		if (elementName.equals(VARIABLE_LIST)) {
881
			// Push a HashMap to collect all the variables.
810
			// Push a HashMap to collect all the variables.
882
			objectStack.push(new HashMap());
811
			objectStack.push(new HashMap());
Lines 1007-1020 Link Here
1007
					objectStack.push(new LinkDescription());
936
					objectStack.push(new LinkDescription());
1008
				}
937
				}
1009
				break;
938
				break;
1010
			case S_GROUP_RESOURCES:
1011
				if (elementName.equals(GROUP)) {
1012
					state = S_GROUP;
1013
					// Push place holders for the name, type and location of
1014
					// this link.
1015
					objectStack.push(new GroupDescription());
1016
				}
1017
				break;
1018
			case S_VARIABLE_LIST:
939
			case S_VARIABLE_LIST:
1019
				if (elementName.equals(VARIABLE)) {
940
				if (elementName.equals(VARIABLE)) {
1020
					state = S_VARIABLE;
941
					state = S_VARIABLE;
Lines 1053-1063 Link Here
1053
					state = S_FILTER_ARGUMENTS;
974
					state = S_FILTER_ARGUMENTS;
1054
				}
975
				}
1055
				break;
976
				break;
1056
			case S_GROUP:
1057
				if (elementName.equals(NAME)) {
1058
					state = S_GROUP_PATH;
1059
				}
1060
				break;
1061
			case S_VARIABLE:
977
			case S_VARIABLE:
1062
				if (elementName.equals(NAME)) {
978
				if (elementName.equals(NAME)) {
1063
					state = S_VARIABLE_NAME;
979
					state = S_VARIABLE_NAME;
(-)src/org/eclipse/core/internal/resources/ProjectDescription.java (-82 / +2 lines)
Lines 12-24 Link Here
12
 *******************************************************************************/
12
 *******************************************************************************/
13
package org.eclipse.core.internal.resources;
13
package org.eclipse.core.internal.resources;
14
14
15
import java.net.URISyntaxException;
16
17
import java.util.LinkedList;
18
19
import java.net.URI;
15
import java.net.URI;
20
import java.util.Arrays;
16
import java.util.*;
21
import java.util.HashMap;
22
import org.eclipse.core.filesystem.URIUtil;
17
import org.eclipse.core.filesystem.URIUtil;
23
import org.eclipse.core.internal.events.BuildCommand;
18
import org.eclipse.core.internal.events.BuildCommand;
24
import org.eclipse.core.internal.utils.FileUtil;
19
import org.eclipse.core.internal.utils.FileUtil;
Lines 59-70 Link Here
59
	protected HashMap filterDescriptions = null;
54
	protected HashMap filterDescriptions = null;
60
55
61
	/**
56
	/**
62
	 * Map of (IPath -> GroupDescription) pairs for each group resource in this
63
	 * project, where IPath is the project relative path of the resource.
64
	 */
65
	protected HashMap groupDescriptions = null;
66
67
	/**
68
	 * Map of (String -> VariableDescription) pairs for each variable in this
57
	 * Map of (String -> VariableDescription) pairs for each variable in this
69
	 * project, where String is the name of the variable.
58
	 * project, where String is the name of the variable.
70
	 */
59
	 */
Lines 84-90 Link Here
84
		//don't want the clone to have access to our internal link locations table or builders
73
		//don't want the clone to have access to our internal link locations table or builders
85
		clone.linkDescriptions = null;
74
		clone.linkDescriptions = null;
86
		clone.filterDescriptions = null;
75
		clone.filterDescriptions = null;
87
		clone.groupDescriptions = null;
88
		if (variableDescriptions != null)
76
		if (variableDescriptions != null)
89
			clone.variableDescriptions = (HashMap) variableDescriptions.clone();
77
			clone.variableDescriptions = (HashMap) variableDescriptions.clone();
90
		clone.buildSpec = getBuildSpec(true);
78
		clone.buildSpec = getBuildSpec(true);
Lines 219-234 Link Here
219
	}
207
	}
220
208
221
	/**
209
	/**
222
	 * Returns the map of group descriptions (IPath (project relative path) ->
223
	 * GroupDescription). Since this method is only used internally, it never
224
	 * creates a copy. Returns null if the project does not have any group
225
	 * resources.
226
	 */
227
	public HashMap getGroups() {
228
		return groupDescriptions;
229
	}
230
231
	/**
232
	 * Returns the map of variable descriptions (String (variable name) ->
210
	 * Returns the map of variable descriptions (String (variable name) ->
233
	 * VariableDescription). Since this method is only used internally, it never
211
	 * VariableDescription). Since this method is only used internally, it never
234
	 * creates a copy. Returns null if the project does not have any variables.
212
	 * creates a copy. Returns null if the project does not have any variables.
Lines 329-340 Link Here
329
		if ((filterDescriptions != null) && !filterDescriptions.equals(otherFilters))
307
		if ((filterDescriptions != null) && !filterDescriptions.equals(otherFilters))
330
			return true;
308
			return true;
331
309
332
		HashMap otherGroups = description.getGroups();
333
		if ((groupDescriptions == null) && (otherGroups != null))
334
			return true;
335
		if ((groupDescriptions != null) && !groupDescriptions.equals(otherGroups))
336
			return true;
337
		
338
		HashMap otherVariables = description.getVariables();
310
		HashMap otherVariables = description.getVariables();
339
		if ((variableDescriptions == null) && (otherVariables != null))
311
		if ((variableDescriptions == null) && (otherVariables != null))
340
			return true;
312
			return true;
Lines 410-424 Link Here
410
	}
382
	}
411
383
412
	/**
384
	/**
413
	 * Sets the map of group descriptions (String name -> GroupDescription).
414
	 * Since this method is only used internally, it never creates a copy. May
415
	 * pass null if this project does not have any linked resources
416
	 */
417
	public void setGroupDescriptions(HashMap groupDescriptions) {
418
		this.groupDescriptions = groupDescriptions;
419
	}
420
421
	/**
422
	 * Sets the map of variable descriptions (String name ->
385
	 * Sets the map of variable descriptions (String name ->
423
	 * VariableDescription). Since this method is only used internally, it never
386
	 * VariableDescription). Since this method is only used internally, it never
424
	 * creates a copy. May pass null if this project does not have any variables
387
	 * creates a copy. May pass null if this project does not have any variables
Lines 500-543 Link Here
500
	}
463
	}
501
464
502
	/**
465
	/**
503
	 * Sets the description of a group. Setting to a description of null will
504
	 * remove the group from the project description.
505
	 * @return <code>true</code> if the description was actually changed,
506
	 *     <code>false</code> otherwise.
507
	 * @since 3.5
508
	 */
509
	public boolean setGroupLocation(IPath path, GroupDescription description) {
510
		HashMap tempMap = groupDescriptions;
511
		if (description != null) {
512
			// addition or modification
513
			if (tempMap == null)
514
				tempMap = new HashMap(10);
515
			else
516
				// copy on write to protect against concurrent read
517
				tempMap = (HashMap) tempMap.clone();
518
			Object oldValue = tempMap.put(path, description);
519
			if (oldValue!=null && description.equals(oldValue)) {
520
				//not actually changed anything
521
				return false;
522
			}
523
			groupDescriptions = tempMap;
524
		} else {
525
			// removal
526
			if (tempMap == null)
527
				return false;
528
			// copy on write to protect against concurrent access
529
			HashMap newMap = (HashMap) tempMap.clone();
530
			Object oldValue = newMap.remove(path);
531
			if (oldValue == null) {
532
				//not actually changed anything
533
				return false;
534
			}
535
			groupDescriptions = newMap.size() == 0 ? null : newMap;
536
		}
537
		return true;
538
	}
539
540
	/**
541
	 * Sets the description of a variable. Setting to a description of null will
466
	 * Sets the description of a variable. Setting to a description of null will
542
	 * remove the variable from the project description.
467
	 * remove the variable from the project description.
543
	 * @return <code>true</code> if the description was actually changed,
468
	 * @return <code>true</code> if the description was actually changed,
Lines 644-654 Link Here
644
	}
569
	}
645
570
646
	public URI getGroupLocationURI(IPath projectRelativePath) {
571
	public URI getGroupLocationURI(IPath projectRelativePath) {
647
		try {
572
		return LinkDescription.GROUP_LOCATION;
648
			return new URI("group"); //$NON-NLS-1$
649
		} catch (URISyntaxException e) {
650
			// can not happend
651
		}
652
		return null;
653
	}
573
	}
654
}
574
}
(-)src/org/eclipse/core/internal/resources/ModelObjectWriter.java (-18 lines)
Lines 105-118 Link Here
105
		writer.endTag(FILTER);
105
		writer.endTag(FILTER);
106
	}
106
	}
107
107
108
	protected void write(GroupDescription description, XMLWriter writer) {
109
		writer.startTag(GROUP, null);
110
		if (description != null) {
111
			writer.printSimpleTag(NAME, description.getProjectRelativePath());
112
		}
113
		writer.endTag(GROUP);
114
	}
115
	
116
	protected void write(VariableDescription description, XMLWriter writer) {
108
	protected void write(VariableDescription description, XMLWriter writer) {
117
		writer.startTag(VARIABLE, null);
109
		writer.startTag(VARIABLE, null);
118
		if (description != null) {
110
		if (description != null) {
Lines 188-197 Link Here
188
			write((FilterDescription) obj, writer);
180
			write((FilterDescription) obj, writer);
189
			return;
181
			return;
190
		}
182
		}
191
		if (obj instanceof GroupDescription) {
192
			write((GroupDescription) obj, writer);
193
			return;
194
		}
195
		if (obj instanceof VariableDescription) {
183
		if (obj instanceof VariableDescription) {
196
			write((VariableDescription) obj, writer);
184
			write((VariableDescription) obj, writer);
197
			return;
185
			return;
Lines 226-237 Link Here
226
				Collections.sort(sorted);
214
				Collections.sort(sorted);
227
				write(FILTERED_RESOURCES, sorted, writer);
215
				write(FILTERED_RESOURCES, sorted, writer);
228
			}
216
			}
229
			HashMap groups = description.getGroups();
230
			if (groups != null) {
231
				List sorted = new ArrayList(groups.values());
232
				Collections.sort(sorted);
233
				write(GROUP_RESOURCES, sorted, writer);
234
			}
235
			HashMap variables = description.getVariables();
217
			HashMap variables = description.getVariables();
236
			if (variables != null) {
218
			if (variables != null) {
237
				List sorted = new ArrayList(variables.values());
219
				List sorted = new ArrayList(variables.values());
(-)src/org/eclipse/core/internal/resources/ResourceTree.java (-2 lines)
Lines 697-704 Link Here
697
				((ProjectDescription) destDescription).setLinkDescriptions(destination.internalGetDescription().getLinks());
697
				((ProjectDescription) destDescription).setLinkDescriptions(destination.internalGetDescription().getLinks());
698
				// moving filters may have modified the description in memory
698
				// moving filters may have modified the description in memory
699
				((ProjectDescription) destDescription).setFilterDescriptions(destination.internalGetDescription().getFilters());
699
				((ProjectDescription) destDescription).setFilterDescriptions(destination.internalGetDescription().getFilters());
700
				// moving group resources may have modified the description in memory
701
				((ProjectDescription) destDescription).setGroupDescriptions(destination.internalGetDescription().getGroups());
702
				// moving variables may have modified the description in memory
700
				// moving variables may have modified the description in memory
703
				((ProjectDescription) destDescription).setVariableDescriptions(destination.internalGetDescription().getVariables());
701
				((ProjectDescription) destDescription).setVariableDescriptions(destination.internalGetDescription().getVariables());
704
				destination.internalSetDescription(destDescription, true);
702
				destination.internalSetDescription(destDescription, true);
(-)src/org/eclipse/core/internal/resources/IModelObjectConstants.java (-2 lines)
Lines 49-56 Link Here
49
	public static final String LINK = "link"; //$NON-NLS-1$
49
	public static final String LINK = "link"; //$NON-NLS-1$
50
	public static final String FILTERED_RESOURCES = "filteredResources"; //$NON-NLS-1$
50
	public static final String FILTERED_RESOURCES = "filteredResources"; //$NON-NLS-1$
51
	public static final String FILTER = "filter"; //$NON-NLS-1$
51
	public static final String FILTER = "filter"; //$NON-NLS-1$
52
	public static final String GROUP_RESOURCES = "groupResources"; //$NON-NLS-1$
53
	public static final String GROUP = "group"; //$NON-NLS-1$
54
	public static final String VARIABLE = "variable"; //$NON-NLS-1$
52
	public static final String VARIABLE = "variable"; //$NON-NLS-1$
55
	public static final String VARIABLE_LIST = "variableList"; //$NON-NLS-1$
53
	public static final String VARIABLE_LIST = "variableList"; //$NON-NLS-1$
56
}
54
}
(-)plugin.xml (+9 lines)
Lines 221-224 Link Here
221
            name="PARENT">
221
            name="PARENT">
222
      </variableProvider>
222
      </variableProvider>
223
   </extension>
223
   </extension>
224
   <extension
225
         point="org.eclipse.core.filesystem.filesystems">
226
      <filesystem
227
            scheme="group">
228
         <run
229
               class="org.eclipse.core.internal.resources.GroupFileSystem">
230
         </run>
231
      </filesystem>
232
   </extension>
224
</plugin>
233
</plugin>
(-)src/org/eclipse/core/internal/resources/GroupFileSystem.java (+31 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.core.internal.resources;
12
13
import java.net.URI;
14
import org.eclipse.core.filesystem.IFileStore;
15
16
import org.eclipse.core.filesystem.provider.FileSystem;
17
18
/**
19
 * A file system for resource groups
20
 */
21
public class GroupFileSystem extends FileSystem {
22
23
	public GroupFileSystem() {
24
		super();
25
	}
26
27
	public IFileStore getStore(URI uri) {
28
		return new GroupFileStore(uri);
29
	}
30
31
}
(-)src/org/eclipse/core/internal/resources/GroupFileStore.java (+73 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.core.internal.resources;
12
13
import org.eclipse.core.runtime.CoreException;
14
15
import java.io.InputStream;
16
import java.net.URI;
17
import org.eclipse.core.filesystem.*;
18
import org.eclipse.core.filesystem.provider.FileInfo;
19
import org.eclipse.core.filesystem.provider.FileStore;
20
import org.eclipse.core.runtime.IProgressMonitor;
21
import org.eclipse.core.runtime.Path;
22
23
/**
24
 * A file store representing a group. A group always exists and has no children.
25
 */
26
public class GroupFileStore extends FileStore {
27
	private final URI location;
28
29
	public GroupFileStore(URI location) {
30
		this.location = location;
31
	}
32
33
	public String[] childNames(int options, IProgressMonitor monitor) {
34
		return FileStore.EMPTY_STRING_ARRAY;
35
	}
36
37
	public IFileInfo fetchInfo(int options, IProgressMonitor monitor) {
38
		FileInfo result = new FileInfo();
39
		result.setDirectory(true);
40
		result.setExists(true);
41
		result.setLastModified(1);//last modified of zero indicates non-existence
42
		return result;
43
	}
44
	
45
	public void delete(int options, IProgressMonitor monitor) {
46
		//nothing to do - groups don't exist in any physical file system
47
	}
48
49
	public IFileStore getChild(String name) {
50
		return EFS.getNullFileSystem().getStore(new Path(name));
51
	}
52
53
	public String getName() {
54
		return "group"; //$NON-NLS-1$
55
	}
56
57
	public IFileStore getParent() {
58
		return null;
59
	}
60
	
61
	public void move(IFileStore destination, int options, IProgressMonitor monitor) throws CoreException {
62
		destination.mkdir(EFS.NONE, monitor);
63
	}
64
65
	public InputStream openInputStream(int options, IProgressMonitor monitor) {
66
		return null;
67
	}
68
69
	public URI toURI() {
70
		return location;
71
	}
72
73
}
(-)src/org/eclipse/core/tests/resources/AllTests.java (-1 / +1 lines)
Lines 27-32 Link Here
27
		suite.addTest(CharsetTest.suite());
27
		suite.addTest(CharsetTest.suite());
28
		suite.addTest(ContentDescriptionManagerTest.suite());
28
		suite.addTest(ContentDescriptionManagerTest.suite());
29
		suite.addTest(FilteredResourceTest.suite());
29
		suite.addTest(FilteredResourceTest.suite());
30
		suite.addTest(GroupResourceTest.suite());
30
		suite.addTest(HiddenResourceTest.suite());
31
		suite.addTest(HiddenResourceTest.suite());
31
		suite.addTest(IFileTest.suite());
32
		suite.addTest(IFileTest.suite());
32
		suite.addTest(IFolderTest.suite());
33
		suite.addTest(IFolderTest.suite());
Lines 42-48 Link Here
42
		suite.addTest(IWorkspaceTest.suite());
43
		suite.addTest(IWorkspaceTest.suite());
43
		suite.addTest(LinkedResourceTest.suite());
44
		suite.addTest(LinkedResourceTest.suite());
44
		suite.addTest(LinkedResourceWithPathVariableTest.suite());
45
		suite.addTest(LinkedResourceWithPathVariableTest.suite());
45
		suite.addTest(GroupResourceTest.suite());
46
		suite.addTest(MarkerSetTest.suite());
46
		suite.addTest(MarkerSetTest.suite());
47
		suite.addTest(MarkerTest.suite());
47
		suite.addTest(MarkerTest.suite());
48
		suite.addTest(NatureTest.suite());
48
		suite.addTest(NatureTest.suite());
(-)src/org/eclipse/core/tests/resources/GroupResourceTest.java (-1 / +26 lines)
Lines 433-439 Link Here
433
			assertDoesNotExistInWorkspace("2.0", destination);
433
			assertDoesNotExistInWorkspace("2.0", destination);
434
434
435
			try {
435
			try {
436
				existingProject.move(destination.getFullPath(), IResource.NONE,
436
				existingProject.move(destination.getFullPath(), IResource.SHALLOW,
437
						getMonitor());
437
						getMonitor());
438
			} catch (CoreException e) {
438
			} catch (CoreException e) {
439
				fail("2.1", e);
439
				fail("2.1", e);
Lines 552-557 Link Here
552
		assertTrue("2.1", group.isGroup());
552
		assertTrue("2.1", group.isGroup());
553
		assertTrue("2.1", !child.isGroup());
553
		assertTrue("2.1", !child.isGroup());
554
	}
554
	}
555
	
556
	public void testIsLocal() {
557
		// create a group
558
		IFolder group = nonExisting_GROUP_InExistingProject;
559
		try {
560
			create(group, true);
561
		} catch (CoreException e) {
562
			fail("1.99", e);
563
		}
564
		assertTrue("1.0", group.isLocal(IResource.DEPTH_INFINITE));
565
		assertTrue("1.1", group.getParent().isLocal(IResource.DEPTH_INFINITE));
566
	}
567
568
	
569
	public void testIsSynchronized() {
570
		// create a group
571
		IFolder group = nonExisting_GROUP_InExistingProject;
572
		try {
573
			create(group, true);
574
		} catch (CoreException e) {
575
			fail("1.99", e);
576
		}
577
		assertTrue("1.0", group.isSynchronized(IResource.DEPTH_INFINITE));
578
		assertTrue("1.1", group.getParent().isSynchronized(IResource.DEPTH_INFINITE));
579
	}
555
580
556
	/**
581
	/**
557
	 * Specific testing of group within links.
582
	 * Specific testing of group within links.

Return to bug 264878