001: /*******************************************************************************
002: * Copyright (c) 2006, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal.ide.undo;
011:
012: import java.net.URI;
013:
014: import org.eclipse.core.resources.IContainer;
015: import org.eclipse.core.resources.IFile;
016: import org.eclipse.core.resources.IFolder;
017: import org.eclipse.core.resources.IResource;
018: import org.eclipse.core.resources.IWorkspaceRoot;
019: import org.eclipse.core.resources.ResourcesPlugin;
020: import org.eclipse.core.runtime.Assert;
021: import org.eclipse.core.runtime.CoreException;
022: import org.eclipse.core.runtime.IPath;
023: import org.eclipse.core.runtime.IProgressMonitor;
024: import org.eclipse.core.runtime.Path;
025: import org.eclipse.core.runtime.SubProgressMonitor;
026: import org.eclipse.ui.ide.undo.ResourceDescription;
027:
028: /**
029: * ContainerDescription is a lightweight description that describes a container
030: * to be created.
031: *
032: * This class is not intended to be instantiated or used by clients.
033: *
034: * @since 3.3
035: *
036: */
037: public abstract class ContainerDescription extends
038: AbstractResourceDescription {
039:
040: String name;
041:
042: URI location;
043:
044: String defaultCharSet;
045:
046: AbstractResourceDescription[] members;
047:
048: /**
049: * Create a container description from the specified container handle that
050: * can be used to create the container. The returned ContainerDescription
051: * should represent any non-existing parents in addition to the specified
052: * container.
053: *
054: * @param container
055: * the handle of the container to be described
056: * @return a container description describing the container and any
057: * non-existing parents.
058: */
059:
060: public static ContainerDescription fromContainer(
061: IContainer container) {
062: IPath fullPath = container.getFullPath();
063: ContainerDescription firstCreatedParent = null;
064: ContainerDescription currentContainerDescription = null;
065:
066: // Does the container exist already? If so, then the parent exists and
067: // we use the normal creation constructor.
068: IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
069: IContainer currentContainer = (IContainer) root
070: .findMember(fullPath);
071: if (currentContainer != null) {
072: return (ContainerDescription) ResourceDescription
073: .fromResource(container);
074: }
075:
076: // Create container descriptions for any uncreated parents in the given
077: // path.
078: currentContainer = root;
079: for (int i = 0; i < fullPath.segmentCount(); i++) {
080: String currentSegment = fullPath.segment(i);
081: IResource resource = currentContainer
082: .findMember(currentSegment);
083: if (resource != null) {
084: // parent already exists, no need to create a description for it
085: currentContainer = (IContainer) resource;
086: } else {
087: if (i == 0) {
088: // parent does not exist and it is a project
089: firstCreatedParent = new ProjectDescription(root
090: .getProject(currentSegment));
091: currentContainerDescription = firstCreatedParent;
092: } else {
093: IFolder folderHandle = currentContainer
094: .getFolder(new Path(currentSegment));
095: ContainerDescription currentFolder = new FolderDescription(
096: folderHandle);
097: currentContainer = folderHandle;
098: if (currentContainerDescription != null) {
099: currentContainerDescription
100: .addMember(currentFolder);
101: }
102: currentContainerDescription = currentFolder;
103: if (firstCreatedParent == null) {
104: firstCreatedParent = currentFolder;
105: }
106: }
107: }
108: }
109: return firstCreatedParent;
110: }
111:
112: /**
113: * Create a ContainerDescription with no state.
114: */
115: public ContainerDescription() {
116:
117: }
118:
119: /**
120: * Create a ContainerDescription from the specified container handle.
121: * Typically used when the container handle represents a resource that
122: * actually exists, although it will not fail if the resource is
123: * non-existent.
124: *
125: * @param container
126: * the container to be described
127: */
128: public ContainerDescription(IContainer container) {
129: super (container);
130: this .name = container.getName();
131: if (container.isLinked()) {
132: this .location = container.getLocationURI();
133: }
134: try {
135: if (container.isAccessible()) {
136: defaultCharSet = container.getDefaultCharset(false);
137: IResource[] resourceMembers = container.members();
138: members = new AbstractResourceDescription[resourceMembers.length];
139: for (int i = 0; i < resourceMembers.length; i++) {
140: members[i] = (AbstractResourceDescription) ResourceDescription
141: .fromResource(resourceMembers[i]);
142: }
143: }
144: } catch (CoreException e) {
145: // Eat this exception because it only occurs when the resource
146: // does not exist and we have already checked this.
147: // We do not want to throw exceptions on the simple constructor, as
148: // no one has actually tried to do anything yet.
149: }
150: }
151:
152: /**
153: * Create any child resources known by this container description.
154: *
155: * @param parentHandle
156: * the handle of the created parent
157: * @param monitor
158: * the progress monitor to be used
159: * @param ticks
160: * the number of ticks allocated for creating children
161: * @throws CoreException
162: */
163: protected void createChildResources(IContainer parentHandle,
164: IProgressMonitor monitor, int ticks) throws CoreException {
165:
166: // restore any children
167: if (members != null && members.length > 0) {
168: for (int i = 0; i < members.length; i++) {
169: members[i].parent = parentHandle;
170: members[i].createResource(new SubProgressMonitor(
171: monitor, ticks / members.length));
172: }
173: }
174: }
175:
176: /*
177: * (non-Javadoc)
178: *
179: * @see org.eclipse.ui.internal.ide.undo.ResourceDescription#recordStateFromHistory(org.eclipse.core.resources.IResource,
180: * org.eclipse.core.runtime.IProgressMonitor)
181: */
182: public void recordStateFromHistory(IResource resource,
183: IProgressMonitor monitor) throws CoreException {
184: monitor.beginTask(
185: UndoMessages.FolderDescription_SavingUndoInfoProgress,
186: 100);
187: if (members != null) {
188: for (int i = 0; i < members.length; i++) {
189: if (members[i] instanceof FileDescription) {
190: IPath path = resource.getFullPath().append(
191: ((FileDescription) members[i]).name);
192: IFile fileHandle = resource.getWorkspace()
193: .getRoot().getFile(path);
194: members[i].recordStateFromHistory(fileHandle,
195: new SubProgressMonitor(monitor,
196: 100 / members.length));
197: } else if (members[i] instanceof FolderDescription) {
198: IPath path = resource.getFullPath().append(
199: ((FolderDescription) members[i]).name);
200: IFolder folderHandle = resource.getWorkspace()
201: .getRoot().getFolder(path);
202: members[i].recordStateFromHistory(folderHandle,
203: new SubProgressMonitor(monitor,
204: 100 / members.length));
205: }
206: }
207: }
208: monitor.done();
209: }
210:
211: /**
212: * Return the name of the container described by this ContainerDescription.
213: *
214: * @return the name of the container.
215: */
216: public String getName() {
217: return name;
218: }
219:
220: /**
221: * Return the first folder found that has no child folders.
222: *
223: * @return the container description for the first child in the receiver
224: * that is a leaf, or this container if there are no children.
225: */
226: public ContainerDescription getFirstLeafFolder() {
227: // If there are no members, this is a leaf
228: if (members == null || members.length == 0) {
229: return this ;
230: }
231: // Traverse the members and find the first potential leaf
232: for (int i = 0; i < members.length; i++) {
233: if (members[i] instanceof ContainerDescription) {
234: return ((ContainerDescription) members[i])
235: .getFirstLeafFolder();
236: }
237: }
238: // No child folders were found, this is a leaf
239: return this ;
240: }
241:
242: /**
243: * Add the specified resource description as a member of this resource
244: * description
245: *
246: * @param member
247: * the resource description considered a member of this
248: * container.
249: */
250: public void addMember(AbstractResourceDescription member) {
251: if (members == null) {
252: members = new AbstractResourceDescription[] { member };
253: } else {
254: AbstractResourceDescription[] expandedMembers = new AbstractResourceDescription[members.length + 1];
255: System.arraycopy(members, 0, expandedMembers, 0,
256: members.length);
257: expandedMembers[members.length] = member;
258: members = expandedMembers;
259: }
260: }
261:
262: /*
263: * (non-Javadoc)
264: *
265: * @see org.eclipse.ui.internal.ide.undo.ResourceDescription#restoreResourceAttributes(org.eclipse.core.resources.IResource)
266: */
267: protected void restoreResourceAttributes(IResource resource)
268: throws CoreException {
269: super .restoreResourceAttributes(resource);
270: Assert.isLegal(resource instanceof IContainer);
271: IContainer container = (IContainer) resource;
272: if (defaultCharSet != null) {
273: container.setDefaultCharset(defaultCharSet, null);
274: }
275: }
276:
277: /**
278: * Set the location to which this container is linked.
279: *
280: * @param location
281: * the location URI, or <code>null</code> if there is no link
282: */
283: public void setLocation(URI location) {
284: this .location = location;
285: }
286:
287: /*
288: * (non-Javadoc)
289: *
290: * @see org.eclipse.ui.internal.ide.undo.ResourceDescription#verifyExistence(boolean)
291: */
292: public boolean verifyExistence(boolean checkMembers) {
293: boolean existence = super .verifyExistence(checkMembers);
294: if (existence) {
295: if (checkMembers) {
296: // restore any children
297: if (members != null && members.length > 0) {
298: for (int i = 0; i < members.length; i++) {
299: if (!members[i].verifyExistence(checkMembers)) {
300: return false;
301: }
302: }
303: }
304: }
305: return true;
306: }
307: return false;
308: }
309: }
|