Java tutorial
/* * Copyright 2000-2009 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.plugins.groovy.annotator.intentions.dynamic; import com.intellij.ide.DeleteProvider; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.SimpleToolWindowPanel; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowAnchor; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.refactoring.listeners.RefactoringElementListener; import com.intellij.refactoring.listeners.RefactoringElementListenerProvider; import com.intellij.refactoring.listeners.RefactoringListenerManager; import com.intellij.ui.*; import com.intellij.ui.content.Content; import com.intellij.ui.content.ContentManager; import com.intellij.ui.treeStructure.treetable.ListTreeTableModelOnColumns; import com.intellij.ui.treeStructure.treetable.TreeTable; import com.intellij.ui.treeStructure.treetable.TreeTableModel; import com.intellij.ui.treeStructure.treetable.TreeTableTree; import com.intellij.util.IncorrectOperationException; import com.intellij.util.NullableFunction; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.Convertor; import com.intellij.util.ui.AbstractTableCellEditor; import com.intellij.util.ui.ColumnInfo; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.tree.TreeUtil; import icons.JetgroovyIcons; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyBundle; import org.jetbrains.plugins.groovy.GroovyFileType; import org.jetbrains.plugins.groovy.annotator.intentions.QuickfixUtil; import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.elements.*; import org.jetbrains.plugins.groovy.debugger.fragments.GroovyCodeFragment; import javax.swing.*; import javax.swing.event.CellEditorListener; import javax.swing.event.ChangeEvent; import javax.swing.table.TableCellRenderer; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.MutableTreeNode; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.util.Collection; import java.util.List; import java.util.Set; /** * User: Dmitry.Krasilschikov * Date: 09.01.2008 */ public class DynamicToolWindowWrapper { private static final Logger LOG = Logger.getInstance(DynamicToolWindowWrapper.class); private static final int CLASS_OR_ELEMENT_NAME_COLUMN = 0; private static final int TYPE_COLUMN = 1; private static final String[] myColumnNames = { "Dynamic Element", "Type" }; private final Project myProject; private ToolWindow myToolWindow = null; private JPanel myTreeTablePanel; private SimpleToolWindowPanel myBigPanel; private ListTreeTableModelOnColumns myTreeTableModel; private MyTreeTable myTreeTable; public DynamicToolWindowWrapper(Project project) { myProject = project; } public static DynamicToolWindowWrapper getInstance(Project project) { return ServiceManager.getService(project, DynamicToolWindowWrapper.class); } public TreeTable getTreeTable() { getToolWindow(); return myTreeTable; } public ToolWindow getToolWindow() { if (myToolWindow == null) { myToolWindow = ToolWindowManager.getInstance(myProject).registerToolWindow( GroovyBundle.message("dynamic.tool.window.id"), true, ToolWindowAnchor.RIGHT); myToolWindow.setIcon(JetgroovyIcons.Groovy.DynamicProperty_13); myToolWindow.setTitle(GroovyBundle.message("dynamic.window")); myToolWindow.setToHideOnEmptyContent(true); final JPanel panel = buildBigPanel(); final ContentManager contentManager = myToolWindow.getContentManager(); final Content content = contentManager.getFactory().createContent(panel, "", false); content.setPreferredFocusableComponent(myTreeTable); contentManager.addContent(content); } return myToolWindow; } private JPanel buildBigPanel() { myBigPanel = new SimpleToolWindowPanel(true); final ActionManager actionManager = ActionManager.getInstance(); final ActionGroup actionGroup = (ActionGroup) actionManager.getAction("Groovy.Dynamic.Toolbar"); ActionToolbar actionToolbar = actionManager.createActionToolbar("Groovy.Dynamic.Toolbar", actionGroup, true); myBigPanel.setToolbar(actionToolbar.getComponent()); myBigPanel.setBackground(UIUtil.getFieldForegroundColor()); final JPanel panel = new JPanel(new BorderLayout()); myBigPanel.add(panel, BorderLayout.CENTER); myTreeTablePanel = new JPanel(new BorderLayout()); rebuildTreePanel(); panel.add(myTreeTablePanel); myBigPanel.setPreferredSize(new Dimension(200, myBigPanel.getHeight())); myBigPanel.revalidate(); return myBigPanel; } public void rebuildTreePanel() { DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(); buildTree(rootNode); rebuildTreeView(rootNode, false); } private void rebuildTreeView(DefaultMutableTreeNode root, boolean expandAll) { PsiDocumentManager.getInstance(myProject).commitAllDocuments(); myTreeTablePanel.removeAll(); final JScrollPane treeTable = createTable(root); if (expandAll) { TreeUtil.expandAll(myTreeTable.getTree()); } myTreeTablePanel.add(treeTable); myTreeTablePanel.revalidate(); } private DefaultMutableTreeNode buildTree(DefaultMutableTreeNode rootNode) { final Collection<DClassElement> containingClasses = DynamicManager.getInstance(myProject) .getAllContainingClasses(); DefaultMutableTreeNode containingClassNode; for (DClassElement containingClassElement : containingClasses) { containingClassNode = new DefaultMutableTreeNode(containingClassElement); final Collection<DPropertyElement> properties = DynamicManager.getInstance(myProject) .findDynamicPropertiesOfClass(containingClassElement.getName()); // if (properties.length == 0) continue; DefaultMutableTreeNode propertyTreeNode; for (DPropertyElement property : properties) { propertyTreeNode = new DefaultMutableTreeNode(property); containingClassNode.add(propertyTreeNode); } DefaultMutableTreeNode methodTreeNode; final Set<DMethodElement> methods = containingClassElement.getMethods(); for (DMethodElement methodElement : methods) { final String[] psiTypes = QuickfixUtil.getArgumentsTypes(methodElement.getPairs()); final DMethodElement method = DynamicManager.getInstance(myProject).findConcreteDynamicMethod( containingClassElement.getName(), methodElement.getName(), psiTypes); methodTreeNode = new DefaultMutableTreeNode(method); containingClassNode.add(methodTreeNode); } rootNode.add(containingClassNode); } return rootNode; } private JScrollPane createTable(final MutableTreeNode myTreeRoot) { ColumnInfo[] columnInfos = { new ClassColumnInfo(myColumnNames[CLASS_OR_ELEMENT_NAME_COLUMN]), new PropertyTypeColumnInfo(myColumnNames[TYPE_COLUMN]) }; myTreeTableModel = new ListTreeTableModelOnColumns(myTreeRoot, columnInfos); myTreeTable = new MyTreeTable(myTreeTableModel); new TreeTableSpeedSearch(myTreeTable, new Convertor<TreePath, String>() { @Override public String convert(TreePath o) { final Object node = o.getLastPathComponent(); if (node instanceof DefaultMutableTreeNode) { final Object object = ((DefaultMutableTreeNode) node).getUserObject(); if (object instanceof DNamedElement) { return ((DNamedElement) object).getName(); } } return ""; } }); DefaultActionGroup group = new DefaultActionGroup(); group.add(ActionManager.getInstance().getAction(RemoveDynamicAction.GROOVY_DYNAMIC_REMOVE)); PopupHandler.installUnknownPopupHandler(myTreeTable, group, ActionManager.getInstance()); final MyColoredTreeCellRenderer treeCellRenderer = new MyColoredTreeCellRenderer(); myTreeTable.setDefaultRenderer(String.class, new TableCellRenderer() { public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { if (value instanceof String) { try { final PsiType type = JavaPsiFacade.getElementFactory(myProject) .createTypeFromText((String) value, null); String shortName = type.getPresentableText(); return new JLabel(shortName); } catch (IncorrectOperationException e) { LOG.debug("Type cannot be created", e); } return new JLabel(QuickfixUtil.shortenType((String) value)); } return new JLabel(); } }); myTreeTable.setTreeCellRenderer(treeCellRenderer); myTreeTable.setRootVisible(false); myTreeTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); final MyPropertyTypeCellEditor typeCellEditor = new MyPropertyTypeCellEditor(); typeCellEditor.addCellEditorListener(new CellEditorListener() { public void editingStopped(ChangeEvent e) { final TreeTableTree tree = getTree(); String newTypeValue = ((MyPropertyTypeCellEditor) e.getSource()).getCellEditorValue(); if (newTypeValue == null || tree == null) { myTreeTable.editingStopped(e); return; } try { final PsiType type = JavaPsiFacade.getElementFactory(myProject).createTypeFromText(newTypeValue, null); String canonical = type.getCanonicalText(); if (canonical != null) newTypeValue = canonical; } catch (IncorrectOperationException ex) { //do nothing in case bad string is entered } final TreePath editingTypePath = tree.getSelectionPath(); if (editingTypePath == null) return; final TreePath editingClassPath = editingTypePath.getParentPath(); Object oldTypeValue = myTreeTable.getValueAt(tree.getRowForPath(editingTypePath), TYPE_COLUMN); if (!(oldTypeValue instanceof String)) { myTreeTable.editingStopped(e); return; } final Object editingPropertyObject = myTreeTable.getValueAt(tree.getRowForPath(editingTypePath), CLASS_OR_ELEMENT_NAME_COLUMN); final Object editingClassObject = myTreeTable.getValueAt(tree.getRowForPath(editingClassPath), CLASS_OR_ELEMENT_NAME_COLUMN); if (!(editingPropertyObject instanceof DItemElement) || !(editingClassObject instanceof DClassElement)) { myTreeTable.editingStopped(e); return; } final DItemElement dynamicElement = (DItemElement) editingPropertyObject; final String name = dynamicElement.getName(); final String className = ((DClassElement) editingClassObject).getName(); if (dynamicElement instanceof DPropertyElement) { DynamicManager.getInstance(myProject).replaceDynamicPropertyType(className, name, (String) oldTypeValue, newTypeValue); } else if (dynamicElement instanceof DMethodElement) { final List<ParamInfo> myPairList = ((DMethodElement) dynamicElement).getPairs(); DynamicManager.getInstance(myProject).replaceDynamicMethodType(className, name, myPairList, (String) oldTypeValue, newTypeValue); } } public void editingCanceled(ChangeEvent e) { myTreeTable.editingCanceled(e); } }); RefactoringListenerManager.getInstance(myProject) .addListenerProvider(new RefactoringElementListenerProvider() { @Nullable public RefactoringElementListener getListener(final PsiElement element) { if (element instanceof PsiClass) { final String qualifiedName = ((PsiClass) element).getQualifiedName(); return new RefactoringElementListener() { public void elementMoved(@NotNull PsiElement newElement) { renameElement(qualifiedName, newElement); } public void elementRenamed(@NotNull PsiElement newElement) { renameElement(qualifiedName, newElement); } private void renameElement(String oldClassName, PsiElement newElement) { if (newElement instanceof PsiClass) { final String newClassName = ((PsiClass) newElement).getQualifiedName(); final DRootElement rootElement = DynamicManager.getInstance(myProject) .getRootElement(); final DClassElement oldClassElement = rootElement .getClassElement(oldClassName); final TreeNode oldClassNode = TreeUtil.findNodeWithObject( (DefaultMutableTreeNode) myTreeRoot, oldClassElement); DynamicManager.getInstance(myProject).replaceClassName(oldClassElement, newClassName); myTreeTableModel.nodeChanged(oldClassNode); } } }; } return null; } }); myTreeTable.setDefaultEditor(String.class, typeCellEditor); myTreeTable.registerKeyboardAction(new ActionListener() { public void actionPerformed(ActionEvent event) { final int selectionRow = myTreeTable.getTree().getLeadSelectionRow(); myTreeTable.editCellAt(selectionRow, CLASS_OR_ELEMENT_NAME_COLUMN, event); } }, KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0), JComponent.WHEN_FOCUSED); myTreeTable.registerKeyboardAction(new ActionListener() { public void actionPerformed(ActionEvent event) { final int selectionRow = myTreeTable.getTree().getLeadSelectionRow(); myTreeTable.editCellAt(selectionRow, TYPE_COLUMN, event); } }, KeyStroke.getKeyStroke(KeyEvent.VK_F2, InputEvent.CTRL_MASK), JComponent.WHEN_FOCUSED); myTreeTable.getTree().setShowsRootHandles(true); myTreeTable.getTableHeader().setReorderingAllowed(false); myTreeTable.setPreferredScrollableViewportSize(new Dimension(300, myTreeTable.getRowHeight() * 10)); myTreeTable.getColumn(myColumnNames[CLASS_OR_ELEMENT_NAME_COLUMN]).setPreferredWidth(200); myTreeTable.getColumn(myColumnNames[TYPE_COLUMN]).setPreferredWidth(160); JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(myTreeTable); scrollPane.setPreferredSize(new Dimension(600, 400)); return scrollPane; } void deleteRow() { boolean isShowDialog = true; final int rowsCount = myTreeTable.getSelectedRows().length; int i = 0; final TreePath[] paths = myTreeTable.getTree().getSelectionPaths(); if (paths == null) return; for (TreePath selectionPath : paths) { if (rowsCount > 1) isShowDialog = false; if (i == 0) isShowDialog = true; i++; //class final TreePath parent = selectionPath.getParentPath(); if (parent.getParentPath() == null) { //selectionPath is class final Object classRow = selectionPath.getLastPathComponent(); if (!(classRow instanceof DefaultMutableTreeNode)) return; if (!removeClass(((DefaultMutableTreeNode) classRow), isShowDialog, rowsCount)) return; } else { //selectionPath is dynamic item final Object classRow = parent.getLastPathComponent(); final Object dynamicRow = selectionPath.getLastPathComponent(); if (!(classRow instanceof DefaultMutableTreeNode)) return; if (!(dynamicRow instanceof DefaultMutableTreeNode)) return; final DefaultMutableTreeNode dynamicItemNode = (DefaultMutableTreeNode) dynamicRow; final DefaultMutableTreeNode classNode = (DefaultMutableTreeNode) classRow; final boolean removeClass = classNode.getChildCount() == 1; if (!removeDynamicElement(dynamicItemNode, isShowDialog, rowsCount)) return; if (removeClass) { removeNamedElement((DNamedElement) classNode.getUserObject()); } } } DynamicManager.getInstance(myProject).fireChange(); } private boolean removeClass(DefaultMutableTreeNode classNode, boolean isShowDialog, int rowsCount) { final TreeNode rootObject = classNode.getParent(); return rootObject instanceof DefaultMutableTreeNode && removeDynamicElement(classNode, isShowDialog, rowsCount); } private boolean removeDynamicElement(DefaultMutableTreeNode child, boolean isShowDialog, int rowsCount) { Object namedElement = child.getUserObject(); if (!(namedElement instanceof DNamedElement)) return false; if (isShowDialog) { int result; if (rowsCount > 1) { result = Messages.showOkCancelDialog(myBigPanel, GroovyBundle.message("are.you.sure.to.delete.elements", String.valueOf(rowsCount)), GroovyBundle.message("dynamic.element.deletion"), Messages.getQuestionIcon()); } else { result = Messages.showOkCancelDialog(myBigPanel, GroovyBundle.message("are.you.sure.to.delete.dynamic.property", ((DNamedElement) namedElement).getName()), GroovyBundle.message("dynamic.property.deletion"), Messages.getQuestionIcon()); } if (result != DialogWrapper.OK_EXIT_CODE) return false; } removeNamedElement(((DNamedElement) namedElement)); return true; } private void removeNamedElement(DNamedElement namedElement) { if (namedElement instanceof DClassElement) { DynamicManager.getInstance(myProject).removeClassElement((DClassElement) namedElement); } else if (namedElement instanceof DItemElement) { DynamicManager.getInstance(myProject).removeItemElement((DItemElement) namedElement); } } public void setSelectedNode(DefaultMutableTreeNode node) { JTree tree = myTreeTable.getTree(); TreePath path = new TreePath(node.getPath()); tree.expandPath(path.getParentPath()); int row = tree.getRowForPath(path); myTreeTable.getSelectionModel().setSelectionInterval(row, row); myTreeTable.scrollRectToVisible(myTreeTable.getCellRect(row, 0, true)); IdeFocusManager.getInstance(myProject).requestFocus(myTreeTable, true); } public void removeFromParent(DefaultMutableTreeNode parent, DefaultMutableTreeNode child) { int idx = myTreeTableModel.getIndexOfChild(parent, child); child.removeFromParent(); myTreeTableModel.nodesWereRemoved(parent, new int[] { idx }, new TreeNode[] { child }); } @Nullable private TreeTableTree getTree() { return myTreeTable != null ? myTreeTable.getTree() : null; } private static class PropertyTypeColumnInfo extends ColumnInfo<DefaultMutableTreeNode, String> { public PropertyTypeColumnInfo(String name) { super(name); } public boolean isCellEditable(DefaultMutableTreeNode node) { final Object value = node.getUserObject(); return !(value instanceof DClassElement); } public String valueOf(DefaultMutableTreeNode treeNode) { Object userObject = treeNode.getUserObject(); if (userObject instanceof DItemElement) return ((DItemElement) userObject).getType(); return null; } } private static class ClassColumnInfo extends ColumnInfo<DefaultMutableTreeNode, DNamedElement> { public ClassColumnInfo(String name) { super(name); } public boolean isCellEditable(DefaultMutableTreeNode treeNode) { final Object userObject = treeNode.getUserObject(); return userObject instanceof DPropertyElement; } public Class getColumnClass() { return TreeTableModel.class; } public DNamedElement valueOf(DefaultMutableTreeNode treeNode) { Object userObject = treeNode.getUserObject(); if (userObject instanceof DClassElement) return ((DClassElement) userObject); if (userObject instanceof DPropertyElement) return ((DPropertyElement) userObject); if (userObject instanceof DMethodElement) return ((DMethodElement) userObject); return null; } } public ListTreeTableModelOnColumns getTreeTableModel() { getToolWindow(); return myTreeTableModel; } private static class MyColoredTreeCellRenderer extends ColoredTreeCellRenderer { public void customizeCellRenderer(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { value = ((DefaultMutableTreeNode) value).getUserObject(); setPaintFocusBorder(false); if (!(value instanceof DNamedElement)) return; if (value instanceof DClassElement) { final String containingClassName = ((DClassElement) value).getName(); // append(className, SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); final String classShortName = QuickfixUtil.shortenType(containingClassName); append(classShortName, SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); } if (value instanceof DItemElement) { final DItemElement itemElement = ((DItemElement) value); final String substringToHighlight = itemElement.getHighlightedText(); final String name = itemElement.getName(); if (substringToHighlight != null) { appendHighlightName(substringToHighlight, name); } else { appendName(name); } if (value instanceof DMethodElement) { appendMethodParameters((DMethodElement) value); } } } private void appendHighlightName(String substringToHighlight, String name) { final int begin = name.indexOf(substringToHighlight); // if (name.length() <= begin) return; final String first = name.substring(0, begin); append(first, SimpleTextAttributes.SIMPLE_CELL_ATTRIBUTES); final TextAttributes textAttributes = new TextAttributes(); textAttributes.setBackgroundColor(UIUtil.getListSelectionBackground()); append(substringToHighlight, SimpleTextAttributes.fromTextAttributes(textAttributes)); append(name.substring(first.length() + substringToHighlight.length()), SimpleTextAttributes.SIMPLE_CELL_ATTRIBUTES); } private void appendName(String name) { append(name, SimpleTextAttributes.SIMPLE_CELL_ATTRIBUTES); } private void appendMethodParameters(DMethodElement value) { StringBuilder buffer = new StringBuilder(); buffer.append("("); final String[] types = mapToUnqualified(QuickfixUtil.getArgumentsNames(value.getPairs())); for (int i = 0; i < types.length; i++) { if (i != 0) buffer.append(", "); String type = types[i]; buffer.append(type); } buffer.append(")"); append(buffer.toString(), SimpleTextAttributes.SIMPLE_CELL_ATTRIBUTES); } private static String[] mapToUnqualified(final String[] argumentsNames) { return ContainerUtil.map2Array(argumentsNames, String.class, new NullableFunction<String, String>() { @Nullable public String fun(final String s) { if (s == null) return null; int index = s.lastIndexOf("."); if (index > 0 && index < s.length() - 1) return s.substring(index + 1); return s; } }); } } private class MyPropertyTypeCellEditor extends AbstractTableCellEditor { final EditorTextField field; public MyPropertyTypeCellEditor() { final Document document = PsiDocumentManager.getInstance(myProject) .getDocument(new GroovyCodeFragment(myProject, "")); field = new EditorTextField(document, myProject, GroovyFileType.GROOVY_FILE_TYPE); } public String getCellEditorValue() { return field.getText(); } public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { if (value instanceof String) { field.setText(((String) value)); } return field; } } private class MyTreeTable extends TreeTable implements DataProvider { public MyTreeTable(TreeTableModel treeTableModel) { super(treeTableModel); } @Nullable public Object getData(@NonNls String dataId) { if (LangDataKeys.PSI_ELEMENT.is(dataId)) { return getSelectedElement(); } else if (LangDataKeys.PSI_FILE.is(dataId)) { final PsiElement element = getSelectedElement(); if (element == null) return null; return element.getContainingFile(); } else if (PlatformDataKeys.DELETE_ELEMENT_PROVIDER.is(dataId)) { return new DeleteProvider() { @Override public void deleteElement(@NotNull DataContext dataContext) { deleteRow(); } @Override public boolean canDeleteElement(@NotNull DataContext dataContext) { return myTreeTable.getTree().getSelectionPaths() != null; } }; } return null; } private PsiElement getSelectedElement() { final TreePath path = getTree().getSelectionPath(); if (path == null) return null; final Object selectedObject = path.getLastPathComponent(); if (!(selectedObject instanceof DefaultMutableTreeNode)) return null; final DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) selectedObject; final Object userObject = selectedNode.getUserObject(); if (!(userObject instanceof DNamedElement)) return null; if (userObject instanceof DClassElement) { final DClassElement classElement = (DClassElement) userObject; try { PsiType type = JavaPsiFacade.getElementFactory(myProject) .createTypeFromText(classElement.getName(), null); if (type instanceof PsiPrimitiveType) { type = ((PsiPrimitiveType) type).getBoxedType(PsiManager.getInstance(myProject), GlobalSearchScope.allScope(myProject)); } if (!(type instanceof PsiClassType)) return null; return ((PsiClassType) type).resolve(); } catch (IncorrectOperationException e) { return null; } } else if (userObject instanceof DItemElement) { final DItemElement itemElement = (DItemElement) userObject; final TreeNode parentNode = selectedNode.getParent(); if (!(parentNode instanceof DefaultMutableTreeNode)) return null; final Object classObject = ((DefaultMutableTreeNode) parentNode).getUserObject(); if (!(classObject instanceof DClassElement)) return null; final String className = ((DClassElement) classObject).getName(); return itemElement.getPsi(PsiManager.getInstance(myProject), className); } return null; } } }