/** * 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.editor.codecompletion.revisited.javaintegration; import java.io.File; import java.util.ArrayList; import java.util.List; import org.eclipse.jdt.core.CompletionProposal; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.ui.text.java.CompletionProposalCollector; import org.python.pydev.core.IPythonNature; import org.python.pydev.core.IToken; import org.python.pydev.plugin.PydevPlugin; import org.python.pydev.shared_core.string.StringUtils; import org.python.pydev.shared_core.structure.Tuple; /** * This class defines a module that represents a given java class or package within a java project * (that's referenced from a jython project). * * @author Fabio */ public class JavaModuleInProject extends AbstractJavaClassModule { private static final boolean DEBUG_CLASS_MODULE_IN_PROJECT = false; private static final int UNKNOWN = -1; private static final int IS_PACKAGE = 0; private static final int IS_CLASS = 1; private IJavaProject javaProject; private int moduleType = UNKNOWN; @Override public IPythonNature getNature() { return null; } /** * @param name that's the name of the module for jython * @param javaProject that's the project where it exists. */ protected JavaModuleInProject(String name, IJavaProject javaProject) { super(name); this.javaProject = javaProject; if (DEBUG_CLASS_MODULE_IN_PROJECT) { System.out.println("Created JavaClassModuleInProject: " + name); } this.tokens = createTokens(name); if (DEBUG_CLASS_MODULE_IN_PROJECT) { System.out.println("JavaClassModuleInProject tokens:"); if (this.tokens == null) { System.out.println("null tokens"); } else { for (IToken t : this.tokens) { System.out.println(t.getRepresentation()); } } } } /** * @return whether it's a package or a class. */ @Override public boolean isPackage() { if (this.moduleType == UNKNOWN) { throw new RuntimeException("Still can't determine whether it's a package or not."); } return this.moduleType == IS_PACKAGE; } private File file; @Override public File getFile() { return file; } /** * @see AbstractJavaClassModule#getJavaCompletionProposals(String, String) */ @Override protected List<Tuple<IJavaElement, CompletionProposal>> getJavaCompletionProposals(String completeClassDesc, String filterCompletionName) throws Exception { String contents; if (filterCompletionName != null) { //pre-filter it a bit if we already know the completion name contents = "new %s().%s"; contents = StringUtils.format(contents, completeClassDesc, completeClassDesc, filterCompletionName); } else { contents = "new %s()."; contents = StringUtils.format(contents, completeClassDesc, completeClassDesc); } List<Tuple<IJavaElement, CompletionProposal>> javaCompletionProposals = getJavaCompletionProposals(contents, contents.length(), filterCompletionName); if (javaCompletionProposals.size() == 0) { //Handle static access (notice that we don't create an instance.) if (filterCompletionName != null) { //pre-filter it a bit if we already know the completion name contents = "%s.%s"; contents = StringUtils.format(contents, completeClassDesc, completeClassDesc, filterCompletionName); } else { contents = "%s."; contents = StringUtils.format(contents, completeClassDesc, completeClassDesc); } javaCompletionProposals = getJavaCompletionProposals(contents, contents.length() - 2, filterCompletionName); } return javaCompletionProposals; } /** * @see AbstractJavaClassModule#getJavaCompletionProposals(String, int, String) * * @note: the completionOffset is ignored (we find the type and go for the completions on that type). */ @Override protected List<Tuple<IJavaElement, CompletionProposal>> getJavaCompletionProposals(String contents, int completionOffset, String filterCompletionName) throws Exception { try { IType type = this.javaProject.findType(name); final List<Tuple<IJavaElement, CompletionProposal>> ret = new ArrayList<Tuple<IJavaElement, CompletionProposal>>(); //we only get actual completions on a class (otherwise, what we have is a package -- which is treated //as if it was an empty __init__.py file -- without any tokens). if (type != null) { getCompletionsForType(contents, filterCompletionName, type, ret); } if (this.moduleType == UNKNOWN) { //if we found the type, it's a class (otherwise it's a package). if (type == null) { this.moduleType = IS_PACKAGE; } else { this.moduleType = IS_CLASS; this.file = new File(PydevPlugin.getIResourceOSString(type.getResource())); } } return ret; } catch (Throwable e) { throw new RuntimeException(e); } } @Override protected IJavaElement findJavaElement(String javaClassModuleName) throws Exception { return this.javaProject.findType(javaClassModuleName); } /** * Tries to get completions for a given element. */ private void getCompletionsForType(String contents, String filterCompletionName, IType type, final List<Tuple<IJavaElement, CompletionProposal>> ret) throws JavaModelException { ICompilationUnit unit = type.getCompilationUnit(); if (unit == null) { return; } CompletionProposalCollector collector = createCollector(filterCompletionName, ret, unit); type.codeComplete(StringUtils.format(contents, name).toCharArray(), -1, 0, new char[0][0], new char[0][0], new int[0], false, collector); } @Override public boolean equals(Object obj) { if (!(obj instanceof JavaModuleInProject)) { return false; } JavaModuleInProject m = (JavaModuleInProject) obj; if (name == null || m.name == null) { if (name != m.name) { return false; } //both null at this point } else if (!name.equals(m.name)) { return false; } if (file == null || m.file == null) { if (file != m.file) { return false; } //both null at this point } else if (!file.equals(m.file)) { return false; } return true; } @Override public int hashCode() { int hash = 31; if (file != null) { hash += file.hashCode(); } if (name != null) { hash += name.hashCode(); } return hash; } }