| /******************************************************************************* |
| * Copyright (c) 2005, 2007 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 |
| * |
| |
| *******************************************************************************/ |
| package org.eclipse.dltk.internal.core; |
| |
| import java.util.ArrayList; |
| import java.util.Map; |
| |
| import org.eclipse.core.resources.IContainer; |
| import org.eclipse.core.resources.IFolder; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.dltk.core.IBuildpathEntry; |
| import org.eclipse.dltk.core.IModelElement; |
| import org.eclipse.dltk.core.IModelStatusConstants; |
| import org.eclipse.dltk.core.IProjectFragment; |
| import org.eclipse.dltk.core.IScriptFolder; |
| import org.eclipse.dltk.core.ModelException; |
| import org.eclipse.dltk.core.WorkingCopyOwner; |
| import org.eclipse.dltk.internal.core.util.MementoTokenizer; |
| import org.eclipse.dltk.internal.core.util.Util; |
| import org.eclipse.dltk.utils.CorePrinter; |
| |
| |
| public class ProjectFragment extends Openable implements IProjectFragment { |
| /** |
| * The resource associated with this root. (an IResource or a java.io.File |
| * (for externals)) |
| */ |
| protected Object resource; |
| |
| /** |
| * Constructs a project fragment which is the root of the directory |
| * hierarchy. |
| */ |
| protected ProjectFragment(IResource resource, ScriptProject project) { |
| super(project); |
| this.resource = resource; |
| } |
| |
| /** |
| * @see IProjectFragment |
| */ |
| public boolean isArchive() { |
| return false; |
| } |
| |
| protected Object createElementInfo() { |
| return new ProjectFragmentInfo(); |
| } |
| |
| public int getElementType() { |
| return PROJECT_FRAGMENT; |
| } |
| |
| public IResource getResource() { |
| return (IResource) this.resource; |
| } |
| |
| public IPath getPath() { |
| return this.getResource().getFullPath(); |
| } |
| |
| public int getKind() throws ModelException { |
| Object elementInfo = this.getElementInfo(); |
| return ((ProjectFragmentInfo) elementInfo).getRootKind(); |
| } |
| |
| /** |
| * Compares two objects for equality; for <code>ProjectFragments</code>s, |
| * equality is having the same parent, same resources, and occurrence count. |
| * |
| */ |
| public boolean equals(Object o) { |
| if (this == o) { |
| return true; |
| } |
| if (!(o instanceof ProjectFragment)) { |
| return false; |
| } |
| ProjectFragment other = (ProjectFragment) o; |
| if (this.resource == null && other.resource != null) { |
| return false; |
| } |
| if (this.resource != null && other.resource == null) { |
| return false; |
| } |
| if( this.resource != null && other.resource != null && !this.resource.equals(other.resource) ) { |
| return false; |
| } |
| |
| return this.parent.equals(other.parent); |
| } |
| |
| public int hashCode() { |
| return this.resource.hashCode(); |
| } |
| |
| protected boolean buildStructure(OpenableElementInfo info, IProgressMonitor pm, Map newElements, IResource underlyingResource) |
| throws ModelException { |
| // check whether this project fragment can be opened |
| IStatus status = this.validateOnBuildpath(); |
| if (!status.isOK()) { |
| throw this.newModelException(status); |
| } |
| if (!this.resourceExists()) { |
| throw this.newNotPresentException(); |
| } |
| // TODO determine fragment kind |
| return this.computeChildren(info, newElements); |
| } |
| |
| /* |
| * Validate whether this project fragment is on the buildpath of its |
| * project. |
| */ |
| protected IStatus validateOnBuildpath() { |
| IPath path = this.getPath(); |
| try { |
| // check project fragment on buildpath of its project |
| ScriptProject project = (ScriptProject) this.getScriptProject(); |
| IBuildpathEntry[] buildpath = project.getResolvedBuildpath(); |
| for (int i = 0, length = buildpath.length; i < length; i++) { |
| IBuildpathEntry entry = buildpath[i]; |
| if (entry.getPath().equals(path)) { |
| return Status.OK_STATUS; |
| } |
| } |
| } catch (ModelException e) { |
| // could not read buildpath, then assume it is outside |
| return e.getModelStatus(); |
| } |
| return new ModelStatus(IModelStatusConstants.ELEMENT_NOT_ON_BUILDPATH, this); |
| } |
| |
| /** |
| * Compute the project fragment children of this project fragment. |
| * |
| * @exception ModelException |
| * The resource associated with this project fragment does |
| * not exist |
| */ |
| protected boolean computeChildren(OpenableElementInfo info, Map newElements) throws ModelException { |
| // Note the children are not opened (so not added to newElements) for a |
| // regular package fragment root |
| // However they are opened for a ZIP project fragment. |
| try { |
| // the underlying resource may be a folder or a project (in the case |
| // that the project folder |
| // is actually the package fragment root) |
| IResource underlyingResource = this.getResource(); |
| if (underlyingResource.getType() == IResource.FOLDER || underlyingResource.getType() == IResource.PROJECT) { |
| ArrayList vChildren = new ArrayList(5); |
| IContainer rootFolder = (IContainer) underlyingResource; |
| char[][] inclusionPatterns = this.fullInclusionPatternChars(); |
| char[][] exclusionPatterns = this.fullExclusionPatternChars(); |
| this.computeFolderChildren(rootFolder, !Util.isExcluded(rootFolder, inclusionPatterns, exclusionPatterns), Path.EMPTY, |
| vChildren, inclusionPatterns, exclusionPatterns); |
| IModelElement[] children = new IModelElement[vChildren.size()]; |
| vChildren.toArray(children); |
| info.setChildren(children); |
| } |
| } catch (ModelException e) { |
| // problem resolving children; structure remains unknown |
| info.setChildren(new IModelElement[] {}); |
| throw e; |
| } |
| return true; |
| } |
| |
| /** |
| * Starting at this folder, create folders and add them to the collection of |
| * children. |
| * |
| * @exception ModelException |
| * The resource associated with this project fragment does |
| * not exist |
| */ |
| protected void computeFolderChildren(IContainer folder, boolean isIncluded, IPath path, ArrayList vChildren, |
| char[][] inclusionPatterns, char[][] exclusionPatterns) throws ModelException { |
| if (isIncluded) { |
| IScriptFolder pkg = this.getScriptFolder(path); |
| vChildren.add(pkg); |
| } |
| try { |
| ScriptProject scriptProject = (ScriptProject) this.getScriptProject(); |
| ModelManager manager = ModelManager.getModelManager(); |
| IResource[] members = folder.members(); |
| boolean hasIncluded = isIncluded; |
| for (int i = 0, max = members.length; i < max; i++) { |
| IResource member = members[i]; |
| String memberName = member.getName(); |
| switch (member.getType()) { |
| case IResource.FOLDER: |
| // TODO check is folder is valid for a package |
| if (Util.isValidFolderNameForPackage(memberName)) { |
| if (scriptProject.contains(member)) { |
| IPath newPath = path.append(manager.intern(memberName)); |
| boolean isMemberIncluded = !Util.isExcluded(member, inclusionPatterns, exclusionPatterns); |
| this.computeFolderChildren((IFolder) member, isMemberIncluded, newPath, vChildren, inclusionPatterns, |
| exclusionPatterns); |
| } |
| } |
| break; |
| case IResource.FILE: |
| // inclusion filter may only include files, in which |
| // case we still want to include the immediate parent |
| // package (lazily) |
| if (!hasIncluded && Util.isValidSourceModule(this, member) |
| && !Util.isExcluded(member, inclusionPatterns, exclusionPatterns)) { |
| hasIncluded = true; |
| IScriptFolder pkg = this.getScriptFolder(path); |
| vChildren.add(pkg); |
| } |
| break; |
| } |
| } |
| } catch (IllegalArgumentException e) { |
| /* could be thrown by ElementTree when path is not found */ |
| throw new ModelException(e, IModelStatusConstants.ELEMENT_DOES_NOT_EXIST); |
| } catch (CoreException e) { |
| throw new ModelException(e); |
| } |
| } |
| |
| public IScriptFolder getScriptFolder(IPath path) { |
| return new ScriptFolder(this, path); |
| } |
| |
| public String getElementName() { |
| if (this.resource instanceof IFolder) { |
| return ((IFolder) this.resource).getName(); |
| } |
| return super.getElementName(); |
| } |
| |
| public boolean exists() { |
| return super.exists() && this.validateOnBuildpath().isOK(); |
| } |
| |
| public boolean isExternal() { |
| return false; |
| } |
| |
| public IResource getUnderlyingResource() throws ModelException { |
| if (!this.exists()) { |
| throw this.newNotPresentException(); |
| } |
| return this.getResource(); |
| } |
| |
| /** |
| * @private Debugging purposes |
| */ |
| protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) { |
| buffer.append(this.tabString(tab)); |
| IPath path = this.getPath(); |
| if (this.getScriptProject().getElementName().equals(path.segment(0))) { |
| if (path.segmentCount() == 1) { |
| buffer.append("<project root>"); //$NON-NLS-1$ |
| } else { |
| buffer.append(path.removeFirstSegments(1).makeRelative()); |
| } |
| } else { |
| if (this.isExternal()) { |
| buffer.append(path.toOSString()); |
| } else { |
| buffer.append(path); |
| } |
| } |
| if (info == null) { |
| buffer.append(" (not open)"); //$NON-NLS-1$ |
| } |
| } |
| |
| public void printNode(CorePrinter output) { |
| output.formatPrint("ScriptProject fragment:" + this.getPath().toOSString()); //$NON-NLS-1$ |
| output.indent(); |
| try { |
| IModelElement modelElements[] = this.getChildren(); |
| for (int i = 0; i < modelElements.length; ++i) { |
| IModelElement element = modelElements[i]; |
| if (element instanceof ModelElement) { |
| ((ModelElement) element).printNode(output); |
| } else { |
| output.print("Unknown element:" + element); //$NON-NLS-1$ |
| } |
| } |
| } catch (ModelException ex) { |
| output.formatPrint(ex.getLocalizedMessage()); |
| } |
| output.dedent(); |
| } |
| |
| public IScriptFolder getScriptFolder(String path) { |
| // tolerate package names with spaces (e.g. 'x . y') |
| // (http://bugs.eclipse.org/bugs/show_bug.cgi?id=21957) |
| return this.getScriptFolder(new Path(path)); |
| } |
| |
| public Object[] getForeignResources() throws ModelException { |
| return ((ProjectFragmentInfo) this.getElementInfo()).getForeignResources(this.getScriptProject(), this.getResource(), this); |
| } |
| |
| /* |
| * Returns the exclusion patterns from the buildpath entry associated with |
| * this root. |
| */ |
| public char[][] fullExclusionPatternChars() { |
| try { |
| if (this.isOpen() && this.getKind() != IProjectFragment.K_SOURCE) { |
| return null; |
| } |
| BuildpathEntry entry = (BuildpathEntry) this.getBuildpathEntry(); |
| if (entry == null) { |
| return null; |
| } else { |
| return entry.fullExclusionPatternChars(); |
| } |
| } catch (ModelException e) { |
| return null; |
| } |
| } |
| |
| /* |
| * Returns the inclusion patterns from the buildpath entry associated with |
| * this root. |
| */ |
| |
| public char[][] fullInclusionPatternChars() { |
| try { |
| if (this.isOpen() && this.getKind() != IProjectFragment.K_SOURCE) { |
| return null; |
| } |
| BuildpathEntry entry = (BuildpathEntry) this.getBuildpathEntry(); |
| if (entry == null) { |
| return null; |
| } else { |
| return entry.fullInclusionPatternChars(); |
| } |
| } catch (ModelException e) { |
| return null; |
| } |
| } |
| |
| /* |
| * @see IProjectFragment |
| */ |
| public IBuildpathEntry getRawBuildpathEntry() throws ModelException { |
| IBuildpathEntry rawEntry = null; |
| ScriptProject project = (ScriptProject)this.getScriptProject(); |
| project.getResolvedBuildpath(); // force the reverse rawEntry cache to be populated |
| Map rootPathToRawEntries = project.getPerProjectInfo().resolvedPathToRawEntries; |
| if (rootPathToRawEntries != null) { |
| rawEntry = (IBuildpathEntry) rootPathToRawEntries.get(this.getPath()); |
| } |
| if (rawEntry == null) { |
| throw new ModelException(new ModelStatus(IModelStatusConstants.ELEMENT_NOT_ON_BUILDPATH, this)); |
| } |
| return rawEntry; |
| } |
| public IBuildpathEntry getBuildpathEntry() throws ModelException { |
| return this.getRawBuildpathEntry(); |
| } |
| |
| protected void getHandleMemento(StringBuffer buff) { |
| ((ModelElement) getParent()).getHandleMemento(buff); |
| buff.append(getHandleMementoDelimiter()); |
| final IPath path = ((IResource) resource).getProjectRelativePath(); |
| escapeMementoName(buff, path.toString()); |
| } |
| |
| public IModelElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner owner) { |
| switch (token.charAt(0)) { |
| case JEM_SCRIPTFOLDER: |
| String pkgName; |
| if (memento.hasMoreTokens()) { |
| pkgName = memento.nextToken(); |
| char firstChar = pkgName.charAt(0); |
| if (firstChar == JEM_SOURCEMODULE || firstChar == JEM_COUNT) { |
| token = pkgName; |
| pkgName = IProjectFragment.DEFAULT_SCRIPT_FOLDER_NAME; |
| } else { |
| token = null; |
| } |
| } else { |
| pkgName = IScriptFolder.DEFAULT_FOLDER_NAME; |
| token = null; |
| } |
| ModelElement pkg = (ModelElement) this.getScriptFolder(pkgName); |
| if (token == null) { |
| return pkg.getHandleFromMemento(memento, owner); |
| } else { |
| return pkg.getHandleFromMemento(token, memento, owner); |
| } |
| } |
| return null; |
| } |
| |
| protected char getHandleMementoDelimiter() { |
| return JEM_PROJECTFRAGMENT; |
| } |
| |
| /** |
| * @see IProjectFragment |
| */ |
| public IScriptFolder createScriptFolder(String pkgName, boolean force, IProgressMonitor monitor) throws ModelException { |
| CreateScriptFolderOperation op = new CreateScriptFolderOperation(this, pkgName, force); |
| op.runOperation(monitor); |
| return this.getScriptFolder(op.pkgName); |
| } |
| |
| public void delete(int updateResourceFlags, int updateModelFlags, IProgressMonitor monitor) throws ModelException { |
| DeleteProjectFragmentOperation op = new DeleteProjectFragmentOperation(this, updateResourceFlags, updateModelFlags); |
| op.runOperation(monitor); |
| } |
| |
| public void copy(IPath destination, int updateResourceFlags, int updateModelFlags, IBuildpathEntry sibling, IProgressMonitor monitor) throws ModelException { |
| CopyProjectFragmentOperation op = new CopyProjectFragmentOperation(this, destination, updateResourceFlags, |
| updateModelFlags, sibling); |
| op.runOperation(monitor); |
| } |
| |
| public void move(IPath destination, int updateResourceFlags, int updateModelFlags, IBuildpathEntry sibling, IProgressMonitor monitor) throws ModelException { |
| MoveProjectFragmentOperation op = new MoveProjectFragmentOperation(this, destination, updateResourceFlags, |
| updateModelFlags, sibling); |
| op.runOperation(monitor); |
| } |
| |
| public IScriptFolder getScriptFolder(String[] pkgName) { |
| if( pkgName.length == 0 ) { |
| return this.getScriptFolder(Path.EMPTY); |
| } |
| IPath path = new Path(pkgName[0]); |
| for( int i = 1; i < pkgName.length; ++i ) { |
| path = path.append(pkgName[i]); |
| } |
| return this.getScriptFolder(path); |
| } |
| } |