org.jetbrains.plugins.groovy.annotator.intentions.dynamic.DynamicToolWindowWrapper.java Source code

Java tutorial

Introduction

Here is the source code for org.jetbrains.plugins.groovy.annotator.intentions.dynamic.DynamicToolWindowWrapper.java

Source

/*
 * 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;
        }
    }
}