package org.rubypeople.rdt.internal.core; import java.io.File; import java.util.ArrayList; import java.util.Map; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.rubypeople.rdt.core.IRubyElement; import org.rubypeople.rdt.core.IRubyModelStatusConstants; import org.rubypeople.rdt.core.ISourceFolder; import org.rubypeople.rdt.core.ISourceFolderRoot; import org.rubypeople.rdt.core.RubyModelException; import org.rubypeople.rdt.internal.core.util.CharOperation; import org.rubypeople.rdt.internal.core.util.Util; public class ExternalSourceFolderRoot extends SourceFolderRoot implements ISourceFolderRoot { protected final IPath folderPath; protected ExternalSourceFolderRoot(IPath resource, RubyProject project) { super(null, project); this.folderPath = resource; } public String getElementName() { return this.folderPath.toPortableString(); } /** * Returns an array of non-ruby resources contained in the receiver. */ public Object[] getNonRubyResources() throws RubyModelException { // We want to show non ruby resources of the default src folder at the root (see PR #1G58NB8) return ((ExternalSourceFolder) getSourceFolder(CharOperation.NO_STRINGS)).storedNonRubyResources(); } @Override protected boolean computeChildren(OpenableElementInfo info, Map newElements) throws RubyModelException { try { // the underlying resource may be a folder or a project (in the case // that the project folder // is actually the source folder root) Object target = RubyModel.getTarget(this.folderPath, false); if (target instanceof File) { ArrayList<ISourceFolder> vChildren = new ArrayList<ISourceFolder>(5); computeFolderChildren((File) target, CharOperation.NO_STRINGS, vChildren); IRubyElement[] children = new IRubyElement[vChildren.size()]; vChildren.toArray(children); info.setChildren(children); // Now go through every SourceFolder and set it's children! for (int i = 0; i < children.length; i++) { ExternalSourceFolder packFrag = (ExternalSourceFolder) children[i]; ExternalSourceFolderInfo fragInfo = new ExternalSourceFolderInfo(); packFrag.computeChildren(fragInfo); newElements.put(packFrag, fragInfo); } } } catch (RubyModelException e) { // problem resolving children; structure remains unknown info.setChildren(new IRubyElement[] {}); throw e; } return true; } protected void computeFolderChildren(File folder, String[] pkgName, ArrayList<ISourceFolder> vChildren) throws RubyModelException { ISourceFolder pkg = getSourceFolder(pkgName); vChildren.add(pkg); try { RubyModelManager manager = RubyModelManager.getRubyModelManager(); File[] members = folder.listFiles(); if (members == null) return; for (int i = 0, max = members.length; i < max; i++) { File member = members[i]; String memberName = member.getName(); if (member.isDirectory()) { String[] newNames = Util.arrayConcat(pkgName, manager.intern(memberName)); computeFolderChildren(member, newNames, vChildren); } else if (member.isFile()) { // do nothing } } } catch (IllegalArgumentException e) { throw new RubyModelException(e, IRubyModelStatusConstants.ELEMENT_DOES_NOT_EXIST); // could // be // thrown // by // ElementTree // when // path // is // not // found } catch (CoreException e) { throw new RubyModelException(e); } } public SourceFolder getSourceFolder(String[] pkgName) { return new ExternalSourceFolder(this, pkgName); } @Override public IPath getPath() { return folderPath; } @Override public boolean isExternal() { return true; } public int hashCode() { return this.folderPath.hashCode(); } @Override public boolean isReadOnly() { return true; } /** * Returns true if this handle represents the same folder as the given * handle. * * @see Object#equals */ public boolean equals(Object o) { if (this == o) return true; if (o instanceof ExternalSourceFolderRoot) { ExternalSourceFolderRoot other = (ExternalSourceFolderRoot) o; return this.folderPath.equals(other.folderPath); } return false; } /** * @see IRubyElement */ public IResource getUnderlyingResource() throws RubyModelException { if (isExternal()) { if (!exists()) throw newNotPresentException(); return null; } return super.getUnderlyingResource(); } /** * Returns a new element info for this element. */ protected Object createElementInfo() { return new ExternalSourceFolderRootInfo(); } public IResource getResource() { if (this.resource == null) { this.resource = RubyModel.getTarget(this.folderPath, false); } // FIXME We need to turn this File into an IResource somehow! if (this.resource instanceof IResource) { return super.getResource(); } return null; } @Override protected IStatus validateOnLoadpath() { // FIXME This is a HACK. Override so all external roots are said to be on loadpath. This is done so opening external file through File > Open File.. shows content in outline page. return Status.OK_STATUS; } protected boolean resourceExists() { if (this.isExternal()) { return RubyModel.getTarget(this.getPath(), // don't // make // the // path // relative // as // this // is // an // external // archive true) != null; } return super.resourceExists(); } }