/** * Copyright (c) 2005-2013 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.io.File; import java.io.IOException; import java.net.URI; import java.util.List; import java.util.zip.ZipFile; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.swt.graphics.Image; import org.python.pydev.core.log.Log; 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.shared_core.structure.TreeNode; import org.python.pydev.shared_ui.ImageCache; import org.python.pydev.shared_ui.UIConstants; import org.python.pydev.ui.filetypes.FileTypesPreferencesPage; /** * This class represents nodes in the tree that are below the interpreter pythonpath information * (i.e.: modules in the pythonpath for the system interpreter) * * It sets packages with a package icon and python files with a python icon (other files/folders * have default icons) */ public class PythonpathTreeNode extends TreeNode<LabelAndImage> implements ISortedElement, IAdaptable { private static final File[] EMPTY_FILES = new File[0]; /** * The file/folder we're wrapping here. */ public final File file; /** * Identifies whether we already calculated the children */ private boolean calculated = false; /** * Is this a file for a directory? */ private boolean isDir; /** * Is it added as a package if a directory? (all parents must also be packages and it needs * the __init__ file) */ private boolean isPackage; /** * The files beneath this directory (if not a directory, it remains null) */ private File[] dirFiles; public PythonpathTreeNode(TreeNode<LabelAndImage> parent, File file) { this(parent, file, null, false); } @SuppressWarnings("unchecked") @Override public <T> T getAdapter(Class<T> adapter) { if (adapter == URI.class) { return (T) file.toURI(); } return null; } public PythonpathTreeNode(TreeNode<LabelAndImage> parent, File file, Image icon, boolean isPythonpathRoot) { super(parent, null); //data will be set later try { this.file = file; this.isDir = file.isDirectory(); if (isDir) { dirFiles = file.listFiles(); if (dirFiles == null) { dirFiles = EMPTY_FILES; } //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 PythonpathTreeNode && ((PythonpathTreeNode) parent).isPackage) { for (File file2 : dirFiles) { if (PythonPathHelper.isValidInitFile(file2.getName())) { 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(file.getName())) { icon = imageCache.get(UIConstants.PY_FILE_ICON); } else { icon = imageCache.get(UIConstants.FILE_ICON); } } } } finally { setData(new LabelAndImage(getLabel(file, isPythonpathRoot), icon)); } } private static String getLabel(File file, boolean isPythonpathRoot) { if (isPythonpathRoot) { File parent2 = file.getParentFile(); if (parent2 != null) { return parent2.getName() + "/" + file.getName(); } return file.getName(); } else { return file.getName(); } } private boolean isZipFile() { return file.isFile() && FileTypesPreferencesPage.isValidZipFile(file.getName()); } @Override public boolean hasChildren() { return (isDir && dirFiles != null && dirFiles.length > 0) || (!isDir && isZipFile()); } @Override public int getRank() { return isDir ? ISortedElement.RANK_PYTHON_FOLDER : ISortedElement.RANK_PYTHON_FILE; } @SuppressWarnings("rawtypes") @Override public synchronized List<TreeNode> getChildren() { if (!calculated) { this.calculated = true; if (isDir && dirFiles != null) { for (File file : dirFiles) { //just creating it will already add it to the children new PythonpathTreeNode(this, file); } } else if (!isDir && isZipFile()) { ZipFile zipFile = null; try { zipFile = new ZipFile(file); } catch (IOException e) { Log.log(e); } if (zipFile != null) { try { ZipStructure zipStructure = new ZipStructure(file, zipFile); for (String content : zipStructure.contents("")) { //just creating it will already add it to the children new PythonpathZipChildTreeNode(this, zipStructure, content, null, true); } } finally { try { zipFile.close(); } catch (IOException e) { Log.log(e); } } } } } return super.getChildren(); } }