/**
* 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.
*/
/*
* Created on Jun 10, 2006
* @author Fabio
*/
package org.python.pydev.outline;
import java.util.ArrayList;
import org.eclipse.swt.graphics.Image;
import org.python.pydev.parser.jython.SimpleNode;
import org.python.pydev.parser.jython.ast.Attribute;
import org.python.pydev.parser.jython.ast.ClassDef;
import org.python.pydev.parser.jython.ast.FunctionDef;
import org.python.pydev.parser.jython.ast.If;
import org.python.pydev.parser.jython.ast.Import;
import org.python.pydev.parser.jython.ast.ImportFrom;
import org.python.pydev.parser.jython.ast.Name;
import org.python.pydev.parser.jython.ast.NameTok;
import org.python.pydev.parser.jython.ast.aliasType;
import org.python.pydev.parser.jython.ast.commentType;
import org.python.pydev.parser.jython.ast.decoratorsType;
import org.python.pydev.parser.visitors.NodeUtils;
import org.python.pydev.parser.visitors.scope.ASTEntry;
import org.python.pydev.parser.visitors.scope.ASTEntryWithChildren;
import org.python.pydev.plugin.PydevPlugin;
import org.python.pydev.shared_core.model.ErrorDescription;
import org.python.pydev.shared_core.string.FastStringBuffer;
import org.python.pydev.shared_core.string.StringUtils;
import org.python.pydev.shared_ui.ImageCache;
import org.python.pydev.shared_ui.UIConstants;
import org.python.pydev.shared_ui.outline.BaseParsedItem;
import org.python.pydev.shared_ui.outline.IParsedItem;
public class ParsedItem extends BaseParsedItem {
protected ASTEntryWithChildren astThis; //may be null if root
protected ASTEntryWithChildren[] astChildrenEntries;
/**
* Constructor for a child with valid ast.
*/
public ParsedItem(ParsedItem parent, ASTEntryWithChildren root, ASTEntryWithChildren[] astChildren) {
this(astChildren, null);
this.parent = parent;
this.astThis = root;
}
@Override
public int getBeginCol() {
ASTEntryWithChildren astThis = getAstThis();
if (astThis != null && astThis.node != null) {
return astThis.node.beginColumn;
}
return -1;
}
/**
* Constructor for a child with error.
*/
public ParsedItem(ParsedItem parent, ErrorDescription errorDesc) {
this.parent = parent;
this.setErrorDesc(errorDesc);
}
/**
* Constructor for the root.
*/
public ParsedItem(ASTEntryWithChildren[] astChildren, ErrorDescription errorDesc) {
this.astChildrenEntries = astChildren;
this.setErrorDesc(errorDesc);
}
@Override
public void updateTo(IParsedItem item) {
ParsedItem updateToItem = (ParsedItem) item;
this.astThis = updateToItem.astThis;
this.astChildrenEntries = updateToItem.astChildrenEntries;
super.updateTo(item);
}
@Override
public int getBeginLine() {
ASTEntryWithChildren astThis = getAstThis();
if (astThis != null && astThis.node != null) {
return astThis.node.beginLine;
}
return -1;
}
public ASTEntryWithChildren getAstThis() {
return astThis;
}
public void setAstThis(ASTEntryWithChildren astThis) {
this.setAstThis(astThis, null);
}
public void setAstThis(ASTEntryWithChildren astThis, ASTEntryWithChildren[] astChildrenEntries) {
this.toStringCache = null;
this.astThis = astThis;
if (astChildrenEntries != null) {
this.astChildrenEntries = astChildrenEntries;
this.children = null; //the children must be recalculated...
}
}
public ASTEntryWithChildren[] getAstChildrenEntries() {
return astChildrenEntries;
}
private static final int QUALIFIER_PUBLIC = 0;
private static final int QUALIFIER_PROTECTED = 1;
private static final int QUALIFIER_PRIVATE = 2;
private static int qualifierFromName(String name) {
if (name.startsWith("__")) {
if (!name.endsWith("__")) {
return QUALIFIER_PRIVATE;
} else {
return QUALIFIER_PUBLIC;
}
} else if (name.startsWith("_")) {
return QUALIFIER_PROTECTED;
} else {
return QUALIFIER_PUBLIC;
}
}
// returns images based upon element type
@Override
public Image getImage() {
ImageCache imageCache = PydevPlugin.getImageCache();
if (astThis == null) {
return imageCache.get(UIConstants.ERROR);
}
SimpleNode token = astThis.node;
return getImageForNode(imageCache, token, astThis.parent);
}
public static Image getImageForNode(ImageCache imageCache, SimpleNode token, ASTEntry parent) {
if (token instanceof ClassDef) {
String className = NodeUtils.getNameFromNameTok((NameTok) ((ClassDef) token).name);
switch (qualifierFromName(className)) {
case QUALIFIER_PROTECTED:
return imageCache.getImageDecorated(UIConstants.CLASS_ICON, UIConstants.PROTECTED_ICON,
ImageCache.DECORATION_LOCATION_BOTTOM_RIGHT);
case QUALIFIER_PRIVATE:
return imageCache.getImageDecorated(UIConstants.CLASS_ICON, UIConstants.PRIVATE_ICON,
ImageCache.DECORATION_LOCATION_BOTTOM_RIGHT);
default:
return imageCache.get(UIConstants.CLASS_ICON);
}
} else if (token instanceof FunctionDef) {
FunctionDef functionDefToken = (FunctionDef) token;
String methodName = NodeUtils.getNameFromNameTok((NameTok) ((FunctionDef) token).name);
String qualifierIcon = null;
switch (qualifierFromName(methodName)) {
case QUALIFIER_PRIVATE:
qualifierIcon = UIConstants.PRIVATE_ICON;
break;
case QUALIFIER_PROTECTED:
qualifierIcon = UIConstants.PROTECTED_ICON;
break;
}
String decorationIcon = null;
if (functionDefToken.decs != null) {
for (decoratorsType decorator : functionDefToken.decs) {
if (decorator.func instanceof Name) {
Name decoratorFuncName = (Name) decorator.func;
if (decoratorFuncName.id.equals("staticmethod")) {
decorationIcon = UIConstants.DECORATION_STATIC;
} else if (decoratorFuncName.id.equals("classmethod")) {
decorationIcon = UIConstants.DECORATION_CLASS;
}
}
}
}
if (qualifierIcon != null) {
//it's OK if the decorationIcon is null as that's properly handled in getImageDecorated.
return imageCache.getImageDecorated(UIConstants.METHOD_ICON, qualifierIcon,
ImageCache.DECORATION_LOCATION_BOTTOM_RIGHT, decorationIcon,
ImageCache.DECORATION_LOCATION_TOP_RIGHT);
} else if (decorationIcon != null) {
return imageCache.getImageDecorated(UIConstants.METHOD_ICON, decorationIcon,
ImageCache.DECORATION_LOCATION_TOP_RIGHT);
}
return imageCache.get(UIConstants.METHOD_ICON);
} else if (token instanceof Import) {
return imageCache.get(UIConstants.IMPORT_ICON);
} else if (token instanceof If && NodeUtils.isIfMAinNode((If) token)) {
return imageCache.get(UIConstants.MAIN_FUNCTION_ICON);
} else if (token instanceof ImportFrom) {
return imageCache.get(UIConstants.IMPORT_ICON);
} else if (token instanceof commentType) {
return imageCache.get(UIConstants.COMMENT);
} else if (token instanceof Attribute || token instanceof Name || token instanceof NameTok) {
String name = null;
if (token instanceof Attribute) {
Attribute attributeToken = (Attribute) token;
name = NodeUtils.getNameFromNameTok((NameTok) (attributeToken).attr);
} else if (token instanceof Name) {
Name nameToken = (Name) token;
name = nameToken.id;
} else {
NameTok nameTokToken = (NameTok) token;
name = NodeUtils.getNameFromNameTok(nameTokToken);
}
String image;
if (name.startsWith("__")) {
if (name.endsWith("__")) {
image = UIConstants.PUBLIC_ATTR_ICON;
} else {
image = UIConstants.PRIVATE_FIELD_ICON;
}
} else if (name.startsWith("_")) {
image = UIConstants.PROTECTED_FIELD_ICON;
} else {
image = UIConstants.PUBLIC_ATTR_ICON;
}
if (parent != null && parent.node != null && parent.node instanceof ClassDef) {
return imageCache.getImageDecorated(image, UIConstants.DECORATION_CLASS);
}
return imageCache.get(image);
} else {
return imageCache.get(UIConstants.ERROR);
}
}
@Override
public IParsedItem[] getChildren() {
if (children != null) {
return children;
}
if (astChildrenEntries == null) {
astChildrenEntries = new ASTEntryWithChildren[0];
}
ArrayList<ParsedItem> items = new ArrayList<ParsedItem>();
//only the root can have an error as a child (from there on, the errors don't contain inner errors)
if (this.parent == null && errorDesc != null && errorDesc.message != null) {
items.add(new ParsedItem(this, errorDesc));
}
for (ASTEntryWithChildren c : astChildrenEntries) {
items.add(new ParsedItem(this, c, c.getChildren()));
}
children = items.toArray(new ParsedItem[items.size()]);
return children;
}
@Override
protected String calcToString() {
if (errorDesc != null && errorDesc.message != null) {
return errorDesc.message;
}
if (astThis == null) {
return "null";
} else if (astThis.node instanceof If && NodeUtils.isIfMAinNode((If) astThis.node)) {
return "__main__";
} else if (astThis.node instanceof Import) {
aliasType[] imports = ((Import) astThis.node).names;
FastStringBuffer retVal = new FastStringBuffer();
for (int i = 0; i < imports.length; i++) {
aliasType aliasType = imports[i];
//as ...
if (aliasType.asname != null) {
retVal.append(((NameTok) aliasType.asname).id);
retVal.append(" = ");
}
retVal.append(((NameTok) aliasType.name).id);
retVal.append(", ");
}
//delete the last 2 chars
retVal.deleteLast();
retVal.deleteLast();
return retVal.toString();
} else if (astThis.node instanceof ImportFrom) {
// from wxPython.wx import *
ImportFrom importToken = (ImportFrom) astThis.node;
StringBuffer modules = new StringBuffer();
for (int i = 0; i < importToken.names.length; i++) {
aliasType aliasType = importToken.names[i];
//as ...
if (aliasType.asname != null) {
modules.append(((NameTok) aliasType.asname).id);
modules.append(" = ");
}
modules.append(((NameTok) aliasType.name).id);
modules.append(",");
}
if (modules.length() == 0) {
modules.append("*,"); //the comma will be deleted
}
modules.deleteCharAt(modules.length() - 1);
return modules.toString() + " (" + ((NameTok) importToken.module).id + ")";
} else if (astThis.node instanceof commentType) {
commentType type = (commentType) astThis.node;
String rep = type.id.trim();
rep = StringUtils.split(rep, '\n').get(0);
rep = StringUtils.split(rep, '\r').get(0);
rep = rep.substring(1);
rep = StringUtils.rightTrim(rep, '-');
return StringUtils.leftTrim(rep, '-');
} else {
return NodeUtils.getFullRepresentationString(astThis.node);
}
}
/**
* @return rank for sorting ParserItems. When comparing
* two items, first we compare class ranking, then titles
*/
public int getClassRanking() {
int rank;
if (astThis == null || (errorDesc != null && errorDesc.message != null)) {
rank = -2;
} else if (astThis.node instanceof ImportFrom) {
rank = 0;
} else if (astThis.node instanceof Import) {
rank = 1;
} else if (astThis.node instanceof commentType) {
rank = -1;
} else {
rank = 10;
}
return rank;
}
@Override
public int compareTo(Object o) {
if (!(o instanceof ParsedItem)) {
return 0;
}
ParsedItem item = (ParsedItem) o;
int myRank = getClassRanking();
int rank = item.getClassRanking();
if (myRank == rank) {
if (rank == -1) {
return astThis.node.beginLine < item.astThis.node.beginLine ? -1 : 1;
} else {
return toString().compareTo(item.toString());
}
} else {
return (myRank < rank ? -1 : 1);
}
}
@Override
public boolean sameNodeType(IParsedItem newItem) {
ASTEntryWithChildren astThisOld = this.getAstThis();
ASTEntryWithChildren astThisNew = ((ParsedItem) newItem).getAstThis();
if (astThisOld != null && astThisNew != null && astThisOld.node != null && astThisNew.node != null
&& astThisOld.node.getClass() != astThisNew.node.getClass()) {
return false;
}
return true; //still the same
}
@Override
public void updateShallow(IParsedItem newItem) {
setAstThis(((ParsedItem) newItem).getAstThis());
setErrorDesc(newItem.getErrorDesc());
}
}