Files
openide/source/com/intellij/ide/util/TreeClassChooserDialog.java
2005-02-07 22:28:07 +03:00

403 lines
13 KiB
Java

package com.intellij.ide.util;
import com.intellij.ide.projectView.BaseProjectTreeBuilder;
import com.intellij.ide.projectView.PsiClassChildrenSource;
import com.intellij.ide.projectView.impl.AbstractProjectTreeStructure;
import com.intellij.ide.projectView.impl.ProjectAbstractTreeStructureBase;
import com.intellij.ide.projectView.impl.ProjectTreeBuilder;
import com.intellij.ide.projectView.impl.nodes.ClassTreeNode;
import com.intellij.ide.util.gotoByName.*;
import com.intellij.ide.util.treeView.AlphaComparator;
import com.intellij.ide.util.treeView.NodeRenderer;
import com.intellij.ide.actions.GotoClassAction;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.wm.ex.IdeFocusTraversalPolicy;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.ui.TabbedPaneWrapper;
import com.intellij.ui.TreeSpeedSearch;
import com.intellij.util.containers.FilteringIterator;
import com.intellij.util.ui.Tree;
import com.intellij.util.ui.tree.TreeUtil;
import com.intellij.navigation.NavigationItem;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Iterator;
public class TreeClassChooserDialog extends DialogWrapper implements TreeClassChooser{
private Tree myTree;
private DefaultTreeModel myModel;
private PsiClass mySelectedClass = null;
private Project myProject;
private BaseProjectTreeBuilder myBuilder;
private TabbedPaneWrapper myTabbedPane;
private ChooseByNamePanel myGotoByNamePanel;
private GlobalSearchScope myScope;
private TreeClassChooser.ClassFilter myClassFilter;
private final PsiClass myInitialClass;
private final PsiClassChildrenSource myClassChildrens;
public TreeClassChooserDialog(String title, Project project) {
this(
title,
project,
null
);
}
public TreeClassChooserDialog(String title, Project project, PsiClass initialClass) {
this(
title,
project,
GlobalSearchScope.projectScope(project),
null,
initialClass
);
}
public TreeClassChooserDialog(
String title,
Project project,
GlobalSearchScope scope,
TreeClassChooser.ClassFilter classFilter,
PsiClass initialClass
){
this(title, project, scope, classFilter, initialClass, PsiClassChildrenSource.NONE);
}
private TreeClassChooserDialog (String title,
Project project,
GlobalSearchScope scope,
TreeClassChooser.ClassFilter classFilter, PsiClass initialClass, PsiClassChildrenSource classChildrens) {
super(project, true);
myScope = scope;
myClassFilter = classFilter;
myInitialClass = initialClass;
myClassChildrens = classChildrens;
setTitle(title);
myProject = project;
init();
if (initialClass != null) {
selectClass(initialClass);
}
handleSelectionChanged();
}
public static TreeClassChooserDialog withInnerClasses(String title, Project project, GlobalSearchScope scope,
final TreeClassChooser.ClassFilter classFilter, PsiClass initialClass) {
return new TreeClassChooserDialog(title, project, scope, classFilter, initialClass, new PsiClassChildrenSource() {
public void addChildren(PsiClass psiClass, java.util.List<PsiElement> children) {
ArrayList<PsiElement> innerClasses = new ArrayList<PsiElement>();
PsiClassChildrenSource.CLASSES.addChildren(psiClass, innerClasses);
for (Iterator<PsiElement> iterator = innerClasses.iterator(); iterator.hasNext();) {
PsiElement innerClass = iterator.next();
if (classFilter.isAccepted((PsiClass)innerClass)) children.add(innerClass);
}
}
});
}
protected JComponent createCenterPanel() {
myModel = new DefaultTreeModel(new DefaultMutableTreeNode());
myTree = new Tree(myModel);
ProjectAbstractTreeStructureBase treeStructure = new AbstractProjectTreeStructure(
myProject) {
public boolean isFlattenPackages() {
return false;
}
public boolean isShowMembers() {
return myClassChildrens != PsiClassChildrenSource.NONE;
}
public boolean isHideEmptyMiddlePackages() {
return true;
}
protected boolean isAcceptedNotClass(PsiElement child) {
return !(child instanceof PsiFile);
}
public boolean isAbbreviatePackageNames() {
return false;
}
public boolean isShowLibraryContents() {
return false;
}
public boolean isShowModules() {
return false;
}
};
myBuilder = new ProjectTreeBuilder(myProject, myTree, myModel, AlphaComparator.INSTANCE, treeStructure);
myTree.setRootVisible(false);
myTree.setShowsRootHandles(true);
myTree.expandRow(0);
myTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
myTree.setCellRenderer(new NodeRenderer());
myTree.putClientProperty("JTree.lineStyle", "Angled");
JScrollPane scrollPane = new JScrollPane(myTree);
scrollPane.setPreferredSize(new Dimension(500, 300));
myTree.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
if (KeyEvent.VK_ENTER == e.getKeyCode()) {
doOKAction();
}
}
});
myTree.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
TreePath path = myTree.getPathForLocation(e.getX(), e.getY());
if (path != null && myTree.isPathSelected(path)) {
doOKAction();
}
}
}
});
myTree.addTreeSelectionListener(
new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) {
handleSelectionChanged();
}
}
);
new TreeSpeedSearch(myTree);
myTabbedPane = new TabbedPaneWrapper();
final JPanel dummyPanel = new JPanel(new BorderLayout());
String name = null;
if (myInitialClass != null) {
name = myInitialClass.getName();
}
myGotoByNamePanel = new ChooseByNamePanel(myProject, new MyGotoClassModel(), name) {
protected void close(boolean isOk) {
super.close(isOk);
if (isOk) {
doOKAction();
}
else {
doCancelAction();
}
}
protected void initUI(ChooseByNamePopupComponent.Callback callback, ModalityState modalityState, boolean allowMultipleSelection) {
super.initUI(callback, modalityState, allowMultipleSelection);
dummyPanel.add(myGotoByNamePanel.getPanel(), BorderLayout.CENTER);
IdeFocusTraversalPolicy.getPreferredFocusedComponent(myGotoByNamePanel.getPanel()).requestFocus();
}
protected void choosenElementMightChange() {
handleSelectionChanged();
}
};
myTabbedPane.addTab("Search by Name", dummyPanel);
myTabbedPane.addTab("Project", scrollPane);
myGotoByNamePanel.invoke(new MyCallback(), getModalityState(), false);
myTabbedPane.installKeyboardNavigation();
myTabbedPane.addChangeListener(
new ChangeListener() {
public void stateChanged(ChangeEvent e) {
handleSelectionChanged();
}
}
);
return myTabbedPane.getComponent();
}
private void handleSelectionChanged(){
PsiClass selection = calcSelectedClass();
setOKActionEnabled(selection != null);
}
protected void doOKAction() {
mySelectedClass = calcSelectedClass();
if (mySelectedClass == null) return;
super.doOKAction();
}
public PsiClass getSelectedClass() {
return mySelectedClass;
}
public void selectClass(final PsiClass aClass) {
selectElementInTree(aClass);
}
public void selectDirectory(final PsiDirectory directory) {
selectElementInTree(directory);
}
public void showDialog() {
show();
}
public void showPopup() {
ChooseByNamePopup popup = ChooseByNamePopup.createPopup(myProject, new MyGotoClassModel());
popup.invoke(new ChooseByNamePopupComponent.Callback() {
public void onClose () {
}
public void elementChosen(Object element) {
mySelectedClass = (PsiClass)element;
((NavigationItem)element).navigate(true);
}
}, getModalityState(), true);
}
private void selectElementInTree(final PsiElement element) {
if (element == null)
throw new IllegalArgumentException("aClass cannot be null");
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
if (myBuilder == null) return;
myBuilder.buildNodeForElement(element);
DefaultMutableTreeNode node = myBuilder.getNodeForElement(element);
if (node != null) {
final TreePath treePath = new TreePath(node.getPath());
myTree.expandPath(treePath);
TreeUtil.selectPath(myTree, treePath);
}
}
}, getModalityState());
}
private ModalityState getModalityState() {
return ModalityState.stateForComponent(getRootPane());
}
private PsiClass calcSelectedClass() {
if (myTabbedPane.getSelectedIndex() == 0) {
return (PsiClass)myGotoByNamePanel.getChosenElement();
}
else {
TreePath path = myTree.getSelectionPath();
if (path == null) return null;
DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
Object userObject = node.getUserObject();
if (!(userObject instanceof ClassTreeNode)) return null;
ClassTreeNode descriptor = (ClassTreeNode)userObject;
return descriptor.getPsiClass();
}
}
protected void dispose() {
if (myBuilder != null) {
myBuilder.dispose();
myBuilder = null;
}
if (myTabbedPane != null) {
myTabbedPane.uninstallKeyboardNavigation();
}
super.dispose();
}
protected String getDimensionServiceKey() {
return "#com.intellij.ide.util.TreeClassChooserDialog";
}
public JComponent getPreferredFocusedComponent() {
return myGotoByNamePanel.getPreferredFocusedComponent();
}
private class MyGotoClassModel extends GotoClassModel {
public MyGotoClassModel() {
super(myProject);
}
public Object[] getElementsByName(final String name, final boolean checkBoxState) {
final PsiManager manager = PsiManager.getInstance(myProject);
PsiClass[] classes = manager.getShortNamesCache().getClassesByName(name, myScope);
ArrayList<PsiClass> list = new ArrayList<PsiClass>();
for (int i = 0; i < classes.length; i++) {
PsiClass aClass = classes[i];
if (myClassFilter != null && !myClassFilter.isAccepted(aClass)) continue;
list.add(aClass);
}
return list.toArray(new PsiClass[list.size()]);
}
public String getPromptText() {
return null;
}
}
private class MyCallback extends ChooseByNamePopupComponent.Callback {
public void elementChosen(Object element) {
mySelectedClass = (PsiClass)element;
close(OK_EXIT_CODE);
}
}
public static class InheritanceClassFilterImpl implements TreeClassChooser.InheritanceClassFilter{
private final PsiClass myBase;
private final boolean myAcceptsSelf;
private final boolean myAcceptsInner;
private final Condition<PsiClass> myAddtionalCondition;
public InheritanceClassFilterImpl(PsiClass base, boolean acceptsSelf, boolean acceptInner) {
this(base, acceptsSelf, acceptInner, FilteringIterator.alwaysTrueCondition(PsiClass.class));
}
public InheritanceClassFilterImpl(PsiClass base, boolean acceptsSelf, boolean acceptInner,
Condition<PsiClass> addtionalCondition
) {
myAcceptsSelf = acceptsSelf;
myAcceptsInner = acceptInner;
myAddtionalCondition = addtionalCondition;
myBase = base;
}
public boolean isAccepted(PsiClass aClass) {
if (!myAcceptsInner && !(aClass.getParent() instanceof PsiJavaFile)) return false;
if (!myAddtionalCondition.value(aClass)) return false;
if (myBase == null) return true;
return myAcceptsSelf ?
InheritanceUtil.isInheritorOrSelf(aClass, myBase, true) :
aClass.isInheritor(myBase, true);
}
}
}