From 4ef61d331b43aae1ad24d1251ee365995bbeb674 Mon Sep 17 00:00:00 2001 From: Alefas Date: Wed, 15 Feb 2012 18:22:11 +0400 Subject: [PATCH] Project View for Kotlin. --- idea/src/META-INF/plugin.xml | 1 + .../jetbrains/jet/plugin/JetIconProvider.java | 3 + .../projectView/JetClassOrObjectTreeNode.java | 94 +++++++++++++ .../projectView/JetDeclarationTreeNode.java | 79 +++++++++++ .../plugin/projectView/JetFileTreeNode.java | 60 ++++++++ .../projectView/JetProjectViewProvider.java | 133 ++++++++++++++++++ 6 files changed, 370 insertions(+) create mode 100644 idea/src/org/jetbrains/jet/plugin/projectView/JetClassOrObjectTreeNode.java create mode 100644 idea/src/org/jetbrains/jet/plugin/projectView/JetDeclarationTreeNode.java create mode 100644 idea/src/org/jetbrains/jet/plugin/projectView/JetFileTreeNode.java create mode 100644 idea/src/org/jetbrains/jet/plugin/projectView/JetProjectViewProvider.java diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index f8b8aeaaf52..acbebe0abdd 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -58,6 +58,7 @@ + diff --git a/idea/src/org/jetbrains/jet/plugin/JetIconProvider.java b/idea/src/org/jetbrains/jet/plugin/JetIconProvider.java index 4b306fd6f06..d6a535fa329 100644 --- a/idea/src/org/jetbrains/jet/plugin/JetIconProvider.java +++ b/idea/src/org/jetbrains/jet/plugin/JetIconProvider.java @@ -59,6 +59,9 @@ public class JetIconProvider extends IconProvider { } return icon; } + if (psiElement instanceof JetObjectDeclaration) { + return ICON_FOR_OBJECT; + } if (psiElement instanceof JetParameter) { if (((JetParameter) psiElement).getValOrVarNode() != null) { JetParameterList parameterList = PsiTreeUtil.getParentOfType(psiElement, JetParameterList.class); diff --git a/idea/src/org/jetbrains/jet/plugin/projectView/JetClassOrObjectTreeNode.java b/idea/src/org/jetbrains/jet/plugin/projectView/JetClassOrObjectTreeNode.java new file mode 100644 index 00000000000..f6f79699925 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/projectView/JetClassOrObjectTreeNode.java @@ -0,0 +1,94 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.projectView; + +import com.intellij.ide.projectView.PresentationData; +import com.intellij.ide.projectView.ViewSettings; +import com.intellij.ide.projectView.impl.nodes.AbstractPsiBasedNode; +import com.intellij.ide.util.treeView.AbstractTreeNode; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import org.jetbrains.jet.lang.psi.JetClassOrObject; +import org.jetbrains.jet.lang.psi.JetDeclaration; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * User: Alefas + * Date: 15.02.12 + */ +public class JetClassOrObjectTreeNode extends AbstractPsiBasedNode { + protected JetClassOrObjectTreeNode(Project project, JetClassOrObject jetClassOrObject, ViewSettings viewSettings) { + super(project, jetClassOrObject, viewSettings); + } + + @Override + protected PsiElement extractPsiFromValue() { + return getValue(); + } + + @Override + protected Collection getChildrenImpl() { + if (getSettings().isShowMembers()) { + ArrayList result = new ArrayList(); + List declarations = getValue().getDeclarations(); + for (JetDeclaration declaration : declarations) { + if (declaration instanceof JetClassOrObject) { + result.add(new JetClassOrObjectTreeNode(getProject(), (JetClassOrObject) declaration, getSettings())); + } else { + result.add(new JetDeclarationTreeNode(getProject(), declaration, getSettings())); + } + } + return result; + } else return Collections.emptyList(); + } + + @Override + protected void updateImpl(PresentationData data) { + JetClassOrObject value = getValue(); + if (value != null) { + data.setPresentableText(value.getName()); + } + } + + @Override + public boolean canRepresent(Object element) { + if (!isValid()) return false; + return super.canRepresent(element) || canRepresent(getValue(), element); + } + + private boolean canRepresent(JetClassOrObject value, Object element) { + if (value == null || !value.isValid()) return false; + PsiFile file = value.getContainingFile(); + if (file != null && (file == element || file.getVirtualFile() == element)) return true; + + if (value == element) return true; + if (!getSettings().isShowMembers()) { + if (element instanceof PsiElement && ((PsiElement) element).getContainingFile() != null) { + PsiFile elementFile = ((PsiElement) element).getContainingFile(); + if (elementFile != null && file != null) { + return elementFile.equals(file); + } + } + } + return false; + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/projectView/JetDeclarationTreeNode.java b/idea/src/org/jetbrains/jet/plugin/projectView/JetDeclarationTreeNode.java new file mode 100644 index 00000000000..f3eca556ea7 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/projectView/JetDeclarationTreeNode.java @@ -0,0 +1,79 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.projectView; + +import com.intellij.ide.projectView.PresentationData; +import com.intellij.ide.projectView.ViewSettings; +import com.intellij.ide.projectView.impl.nodes.AbstractPsiBasedNode; +import com.intellij.ide.util.treeView.AbstractTreeNode; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.psi.JetClassInitializer; +import org.jetbrains.jet.lang.psi.JetDeclaration; +import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; +import org.jetbrains.jet.plugin.structureView.JetStructureViewElement; + +import java.util.Collection; +import java.util.Collections; + +/** + * User: Alefas + * Date: 15.02.12 + */ +public class JetDeclarationTreeNode extends AbstractPsiBasedNode { + protected JetDeclarationTreeNode(Project project, JetDeclaration jetDeclaration, ViewSettings viewSettings) { + super(project, jetDeclaration, viewSettings); + } + + @Override + protected PsiElement extractPsiFromValue() { + return getValue(); + } + + @Override + protected Collection getChildrenImpl() { + return Collections.emptyList(); + } + + @Override + protected void updateImpl(PresentationData data) { + JetDeclaration declaration = getValue(); + if (declaration != null) { + BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile( + (JetFile) declaration.getContainingFile()); + + final DeclarationDescriptor descriptor = + context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration); + if (descriptor != null) { + String text = JetStructureViewElement.getDescriptorTreeText(descriptor); + if (declaration instanceof JetClassInitializer) { + text = ""; + } + data.setPresentableText(text); + } else { + String text = declaration.getName(); + if (declaration instanceof JetClassInitializer) { + text = ""; + } + data.setPresentableText(text); + } + } + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/projectView/JetFileTreeNode.java b/idea/src/org/jetbrains/jet/plugin/projectView/JetFileTreeNode.java new file mode 100644 index 00000000000..fd7b4532006 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/projectView/JetFileTreeNode.java @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.projectView; + +import com.intellij.ide.projectView.ViewSettings; +import com.intellij.ide.projectView.impl.nodes.PsiFileNode; +import com.intellij.ide.util.treeView.AbstractTreeNode; +import com.intellij.openapi.project.Project; +import org.jetbrains.jet.lang.psi.JetClassOrObject; +import org.jetbrains.jet.lang.psi.JetDeclaration; +import org.jetbrains.jet.lang.psi.JetFile; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * User: Alefas + * Date: 15.02.12 + */ +public class JetFileTreeNode extends PsiFileNode { + public JetFileTreeNode(Project project, JetFile value, ViewSettings viewSettings) { + super(project, value, viewSettings); + } + + @Override + public Collection getChildrenImpl() { + JetFile file = (JetFile) getValue(); + + if (file == null) return Collections.emptyList(); + ArrayList result = new ArrayList(); + + List declarations = file.getDeclarations(); + + for (JetDeclaration declaration : declarations) { + if (declaration instanceof JetClassOrObject) { + result.add(new JetClassOrObjectTreeNode(file.getProject(), (JetClassOrObject) declaration, getSettings())); + } else if (getSettings().isShowMembers()) { + result.add(new JetDeclarationTreeNode(getProject(), declaration, getSettings())); + } + } + + return result; + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/projectView/JetProjectViewProvider.java b/idea/src/org/jetbrains/jet/plugin/projectView/JetProjectViewProvider.java new file mode 100644 index 00000000000..347f66ef6d5 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/projectView/JetProjectViewProvider.java @@ -0,0 +1,133 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.projectView; + +import com.intellij.ide.projectView.SelectableTreeStructureProvider; +import com.intellij.ide.projectView.ViewSettings; +import com.intellij.ide.util.treeView.AbstractTreeNode; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectFileIndex; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import org.jetbrains.jet.lang.psi.JetClassBody; +import org.jetbrains.jet.lang.psi.JetClassOrObject; +import org.jetbrains.jet.lang.psi.JetDeclaration; +import org.jetbrains.jet.lang.psi.JetFile; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * User: Alefas + * Date: 15.02.12 + */ +public class JetProjectViewProvider implements SelectableTreeStructureProvider, DumbAware { + private Project myProject; + + public JetProjectViewProvider(Project project) { + myProject = project; + } + + @Override + public Collection modify(AbstractTreeNode parent, Collection children, ViewSettings settings) { + List result = new ArrayList(); + + for (AbstractTreeNode child : children) { + Object childValue = child.getValue(); + + if (childValue instanceof JetFile) { + JetFile file = (JetFile) childValue; + List declarations = file.getDeclarations(); + + ArrayList classDeclarations = new ArrayList(); + for (JetDeclaration declaration : declarations) { + if (declaration instanceof JetClassOrObject) { + classDeclarations.add((JetClassOrObject) declaration); + } + } + VirtualFile virtualFile = file.getVirtualFile(); + String nameWithoutExtension = virtualFile != null ? virtualFile.getNameWithoutExtension() : file.getName(); + if (classDeclarations.size() == 1 && (!settings.isShowMembers() || declarations.size() == 1) && + nameWithoutExtension.equals(classDeclarations.get(0).getName())) { + result.add(new JetClassOrObjectTreeNode(file.getProject(), classDeclarations.get(0), settings)); + } else { + result.add(new JetFileTreeNode(file.getProject(), file, settings)); + } + } else { + result.add(child); + } + + } + + return result; + } + + @Override + public Object getData(Collection selected, String dataName) { + return null; + } + + @Override + public PsiElement getTopLevelElement(PsiElement element) { + PsiFile file = element.getContainingFile(); + if (file == null || !(file instanceof JetFile)) return null; + + VirtualFile virtualFile = file.getVirtualFile(); + if (!fileInRoots(virtualFile)) return file; + + PsiElement current = element; + while (current != null) { + if (isSelectable(current)) break; + current = current.getParent(); + } + + if (current instanceof JetFile) { + List declarations = ((JetFile) current).getDeclarations(); + String nameWithoutExtension = virtualFile != null ? virtualFile.getNameWithoutExtension() : file.getName(); + if (declarations.size() == 1 && declarations.get(0) instanceof JetClassOrObject && + nameWithoutExtension.equals(declarations.get(0).getName())) { + current = declarations.get(0); + } + } + + return current != null ? current : file; + } + + private boolean isSelectable(PsiElement element) { + if (element instanceof JetFile) return true; + if (element instanceof JetDeclaration) { + PsiElement parent = element.getParent(); + if (parent instanceof JetFile) { + return true; + } else if (parent instanceof JetClassBody) { + parent = parent.getParent(); + if (parent instanceof JetClassOrObject) { + return isSelectable(parent); + } else return false; + } else return false; + } else return false; + } + + private boolean fileInRoots(VirtualFile file) { + final ProjectFileIndex index = ProjectRootManager.getInstance(myProject).getFileIndex(); + return file != null && (index.isInSourceContent(file) || index.isInLibraryClasses(file) || index.isInLibrarySource(file)); + } +}