/**
* Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Eclipse Public License (EPL).
* Please see the license.txt included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
package org.python.pydev.navigator;
import java.util.List;
import org.eclipse.swt.graphics.Image;
import org.python.pydev.core.bundle.ImageCache;
import org.python.pydev.core.docutils.StringUtils;
import org.python.pydev.core.structure.TreeNode;
import org.python.pydev.editor.codecompletion.revisited.PythonPathHelper;
import org.python.pydev.navigator.elements.ISortedElement;
import org.python.pydev.plugin.PydevPlugin;
import org.python.pydev.ui.UIConstants;
/**
* This class represents a file or folder that's inside a zip file.
*/
public class PythonpathZipChildTreeNode extends TreeNode<LabelAndImage> implements ISortedElement {
/**
* Identifies whether we already calculated the children
*/
private boolean calculated = false;
/**
* Is this a file for a directory?
*/
public final boolean isDir;
/**
* Helper structure to get data from the zip
*/
public final ZipStructure zipStructure;
/**
* The path inside the zip for this node
*/
public final String zipPath;
/**
* Marks whether this is a python package (has __init__) or not.
*/
private boolean isPackage;
/**
* If this is a dir, these are the contents from this dir.
*/
private List<String> dirContents;
/**
* @param zipStructure helper to deal with zip
* @param zipPath the path in the zip for this node
* @param icon if not provided, it'll be calculated
* @param isPythonpathRoot identifies whether we're directly in the root of the zip file
*/
public PythonpathZipChildTreeNode(TreeNode<LabelAndImage> parent, ZipStructure zipStructure, String zipPath,
Image icon, boolean isPythonpathRoot) {
super(parent, null); //data will be set later
try {
this.zipStructure = zipStructure;
this.zipPath = zipPath;
this.isDir = StringUtils.endsWith(zipPath, '/');
if (isDir) {
dirContents = zipStructure.contents(zipPath);
//This one can only be a package if its parent is a root or if it's also a package.
if (isPythonpathRoot) {
isPackage = true;
} else if (parent instanceof PythonpathZipChildTreeNode
&& ((PythonpathZipChildTreeNode) parent).isPackage) {
for (String s : dirContents) {
if (PythonPathHelper.isValidInitFile(s)) {
isPackage = true;
break;
}
}
}
}
//Update the icon if it wasn't received.
if (icon == null) {
ImageCache imageCache = PydevPlugin.getImageCache();
if (isDir) {
if (isPackage) {
icon = imageCache.get(UIConstants.FOLDER_PACKAGE_ICON);
} else {
icon = imageCache.get(UIConstants.FOLDER_ICON);
}
} else {
if (PythonPathHelper.isValidSourceFile(zipPath)) {
icon = imageCache.get(UIConstants.PY_FILE_ICON);
} else {
icon = imageCache.get(UIConstants.FILE_ICON);
}
}
}
} finally {
setData(new LabelAndImage(getLabel(zipPath), icon));
}
}
/**
* @return the label for the passed zip path.
*
* E.g.:
* For /dir/foo/file.py, this will return 'file.py'
* For /dir/foo/dir2/, this will return 'dir2'
*/
private static String getLabel(String zipPath) {
if (StringUtils.endsWith(zipPath, '/')) {
zipPath = zipPath.substring(0, zipPath.length() - 1); //remove last char
}
int lastIndexOf = zipPath.lastIndexOf('/');
if (lastIndexOf == -1) {
return zipPath;
} else {
return zipPath.substring(lastIndexOf + 1);
}
}
public boolean hasChildren() {
return isDir && dirContents != null && dirContents.size() > 0;
}
public int getRank() {
return isDir ? ISortedElement.RANK_PYTHON_FOLDER : ISortedElement.RANK_PYTHON_FILE;
}
public synchronized List<TreeNode<LabelAndImage>> getChildren() {
if (!calculated) {
this.calculated = true;
if (isDir && dirContents != null) {
for (String childPath : dirContents) {
new PythonpathZipChildTreeNode(this, zipStructure, childPath, null, false);
}
}
}
return super.getChildren();
}
}