org.twodividedbyzero.idea.findbugs.gui.tree.view.BugTree.java Source code

Java tutorial

Introduction

Here is the source code for org.twodividedbyzero.idea.findbugs.gui.tree.view.BugTree.java

Source

/*
 * Copyright 2008-2015 Andre Pfeiler
 *
 * This file is part of FindBugs-IDEA.
 *
 * FindBugs-IDEA is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * FindBugs-IDEA is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with FindBugs-IDEA.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.twodividedbyzero.idea.findbugs.gui.tree.view;

import com.intellij.ide.OccurenceNavigator;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogBuilder;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.ui.PopupHandler;
import com.intellij.ui.content.Content;
import com.intellij.util.EditSourceOnDoubleClickHandler;
import com.intellij.util.OpenSourceUtil;
import com.intellij.util.ui.UIUtil;
import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.jetbrains.annotations.NonNls;
import org.twodividedbyzero.idea.findbugs.common.FindBugsPluginConstants;
import org.twodividedbyzero.idea.findbugs.common.util.IdeaUtilImpl;
import org.twodividedbyzero.idea.findbugs.gui.common.AnalysisRunDetailsDialog;
import org.twodividedbyzero.idea.findbugs.gui.toolwindow.view.BugTreePanel;
import org.twodividedbyzero.idea.findbugs.gui.toolwindow.view.ToolWindowPanel;
import org.twodividedbyzero.idea.findbugs.gui.tree.BugTreeHelper;
import org.twodividedbyzero.idea.findbugs.gui.tree.ScrollToSourceHandler;
import org.twodividedbyzero.idea.findbugs.gui.tree.TreeOccurenceNavigator;
import org.twodividedbyzero.idea.findbugs.gui.tree.model.AbstractNodeDescriptor;
import org.twodividedbyzero.idea.findbugs.gui.tree.model.AbstractTreeNode;
import org.twodividedbyzero.idea.findbugs.gui.tree.model.BugInstanceNode;
import org.twodividedbyzero.idea.findbugs.gui.tree.model.VisitableTreeNode;

import javax.swing.SwingUtilities;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;

/**
 * $Date$
 *
 * @author Andre Pfeiler<andrepdo@dev.java.net>
 * @version $Revision$
 * @since 0.9.8-dev
 */
@SuppressFBWarnings("SE_BAD_FIELD")
public class BugTree extends Tree implements DataProvider, OccurenceNavigator {

    private static final Logger LOGGER = Logger.getInstance(BugTree.class.getName());

    private final BugTreePanel _bugTreePanel;
    private final Project _project;
    private BugTreeHelper _treeHelper;
    private ScrollToSourceHandler _scrollToSourceHandler;
    private final TreeOccurenceNavigator _occurenceNavigator;

    public BugTree(final TreeModel treeModel, final BugTreePanel bugTreePanel, final Project project) {
        super(treeModel);
        _project = project;
        _bugTreePanel = bugTreePanel;
        _occurenceNavigator = new TreeOccurenceNavigator(this);
        init();
    }

    public final void init() {
        _treeHelper = BugTreeHelper.create(this, _project);

        addTreeSelectionListener(new SelectionListenerImpl());
        addMouseMotionListener(new MouseMotionListenerImpl());
        addMouseListener(new MouseListenerImpl());

        if (UIUtil.isUnderDarcula()) {
            putClientProperty("JTree.lineStyle", "None");
        } else {
            UIUtil.setLineStyleAngled(this);
        }
        setScrollsOnExpand(true);
        getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
        setRootVisible(true);
        setShowsRootHandles(true);
        setCellRenderer(new TreeNodeCellRenderer());

        installHandlers();
    }

    private void installHandlers() {

        final DefaultActionGroup defaultactiongroup = new DefaultActionGroup();
        defaultactiongroup.add(ActionManager.getInstance().getAction("EditSource"));
        defaultactiongroup.addSeparator();
        defaultactiongroup.add(ActionManager.getInstance().getAction("VersionControlsGroup"));
        PopupHandler.installPopupHandler(this, defaultactiongroup, "FoundBugsViewPopup",
                ActionManager.getInstance());
        addKeyListener(createKeyAdapter());

        EditSourceOnDoubleClickHandler.install(this);
        _scrollToSourceHandler = new ScrollToSourceHandler(_bugTreePanel);
        _scrollToSourceHandler.install(this);
    }

    private KeyAdapter createKeyAdapter() {
        return new KeyAdapter() {

            @Override
            public void keyPressed(final KeyEvent keyevent) {

                if (!keyevent.isConsumed() && 10 == keyevent.getKeyCode()) {
                    final TreePath treepath = getSelectionPath();
                    if (treepath == null) {
                        return;
                    }

                    @SuppressWarnings({ "unchecked" })
                    final AbstractNodeDescriptor<VisitableTreeNode> nodedescriptor = (AbstractNodeDescriptor<VisitableTreeNode>) treepath
                            .getLastPathComponent();
                    if (!(nodedescriptor instanceof BugInstanceNode)) {
                        return;
                    }
                    OpenSourceUtil.openSourcesFrom(BugTree.this, true);
                }
            }

        };
    }

    public Object getData(@NonNls final String s) {
        final TreePath treepath = getSelectionPath();
        if (treepath == null) {
            return null;
        }

        @SuppressWarnings({ "unchecked" })
        final AbstractTreeNode<VisitableTreeNode> treeNode = (AbstractTreeNode<VisitableTreeNode>) treepath
                .getLastPathComponent();
        if (!(treeNode instanceof BugInstanceNode)) {
            return null;
        }
        final BugInstanceNode node = (BugInstanceNode) treeNode;

        if ("virtualFile".equals(s)) {
            final PsiFile psiFile = _treeHelper.getSelectedFile();
            return psiFile == null ? null : psiFile.getVirtualFile();
        }
        if ("Navigatable".equals(s)) {
            final PsiFile psiFile = _treeHelper.getSelectedFile();
            if (psiFile != null) {
                final VirtualFile virtualFile = psiFile.getVirtualFile();
                //LOGGER.debug("PsiFile: " + psiFile + " VirtualFile: " + virtualFile.getName() + " - Line: " + node.getSourceLines()[0]);
                final int[] lines = node.getSourceLines();
                if (lines[0] == -1 && lines[1] == -1) { // find anonymous classes
                    final PsiElement psiElement = IdeaUtilImpl.findAnonymousClassPsiElement(psiFile, node,
                            _project);
                    if (psiElement != null) {
                        return psiElement;
                    }
                } else if (virtualFile != null) {
                    return new OpenFileDescriptor(_project, virtualFile, node.getSourceLines()[0] - 1, 0);
                } else {
                    return null;
                }
            } else {
                return null;
            }
        }
        if ("psi.Element".equals(s)) {
            final int[] lines = node.getSourceLines();
            if (lines[0] == -1 && lines[1] == -1) { // find anonymous classes
                final PsiFile psiFile = _treeHelper.getSelectedFile();
                final PsiElement psiElement = IdeaUtilImpl.findAnonymousClassPsiElement(psiFile, node, _project);
                if (psiElement != null) {
                    return psiElement;
                }
            }
            return _treeHelper.getSelectedElement();
        }
        if ("virtualFileArray".equals(s)) {
            final PsiFile psiFile = _treeHelper.getSelectedFile();
            if (psiFile != null) {
                LOGGER.debug("PsiFile: " + psiFile);
                return new VirtualFile[] { psiFile.getVirtualFile() };
            } else {
                return VirtualFile.EMPTY_ARRAY;
            }
        }
        /*if ("helpId".equals(s)) {
           return "find.todoList";
        } else {
           return null;
        }*/
        return null;
    }

    public ScrollToSourceHandler getScrollToSourceHandler() {
        return _scrollToSourceHandler;
    }

    public void gotoNode(final BugInstance bugInstance) {
        _treeHelper.gotoNode(bugInstance);
    }

    public Project getProject() {
        return _project;
    }

    public BugTreeHelper getTreeHelper() {
        return _treeHelper;
    }

    public boolean hasNextOccurence() {
        return _occurenceNavigator.hasNextOccurence();
    }

    public boolean hasPreviousOccurence() {
        return _occurenceNavigator.hasPreviousOccurence();
    }

    public OccurenceInfo goNextOccurence() {
        return _occurenceNavigator.goNextOccurence();
    }

    public OccurenceInfo goPreviousOccurence() {
        return _occurenceNavigator.goPreviousOccurence();
    }

    public String getNextOccurenceActionName() {
        return _occurenceNavigator.getNextOccurenceActionName();
    }

    public String getPreviousOccurenceActionName() {
        return _occurenceNavigator.getPreviousOccurenceActionName();
    }

    private class MouseMotionListenerImpl extends MouseMotionAdapter {

        @Override
        public void mouseMoved(final MouseEvent e) {
            if (_bugTreePanel.getBugCollection() != null && getRowForLocation(e.getX(), e.getY()) != 0) {
                setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            } else if (_bugTreePanel.getBugCollection() != null) {
                final Object root = getModel().getRoot();
                final Component rendererComponent = getCellRenderer().getTreeCellRendererComponent(BugTree.this,
                        root, true, true, false, 0, true);
                final int width = rendererComponent.getPreferredSize().width;
                final int mouseX = e.getX();
                if (mouseX <= width && mouseX >= width - 100) {
                    setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                }
            }
        }
    }

    /** Listen for clicks and scroll to the error's source as necessary. */
    private class MouseListenerImpl extends MouseAdapter {

        @Override
        public void mouseClicked(final MouseEvent e) {
            if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() < 2) {
                if (_bugTreePanel.getBugCollection() != null && getRowForLocation(e.getX(), e.getY()) == 0) {
                    final Object root = getModel().getRoot();
                    final Component rendererComponent = getCellRenderer().getTreeCellRendererComponent(BugTree.this,
                            root, true, true, false, 0, true);
                    final int width = rendererComponent.getPreferredSize().width;
                    final int mouseX = e.getX();
                    if (mouseX <= width + 10 && mouseX >= width - 40) {
                        final ToolWindow toolWindow = ToolWindowManager.getInstance(_project)
                                .getToolWindow(FindBugsPluginConstants.TOOL_WINDOW_ID);
                        final Content content = toolWindow.getContentManager().getContent(0);
                        if (content != null) {
                            final ToolWindowPanel panel = (ToolWindowPanel) content.getComponent();
                            final DialogBuilder dialog = AnalysisRunDetailsDialog.create(panel.getProject(),
                                    panel.getBugTreePanel().getGroupModel().getBugCount(),
                                    panel.getBugCollection().getProjectStats(), panel.getBugsProject());
                            dialog.showModal(false);
                        }
                    }
                }
            }
        }

        @Override
        public void mouseExited(final MouseEvent e) {
            if (_bugTreePanel.getBugCollection() != null) {
                setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            }
        }
    }

    /** Listen for tree selection events and scroll to the error's source as necessary. */
    private class SelectionListenerImpl implements TreeSelectionListener {
        @Override
        public void valueChanged(final TreeSelectionEvent e) {
            final TreePath path = BugTree.this.getSelectionPath();
            setHighlightPath(path);

            _bugTreePanel.setDetails(path);

            if (_bugTreePanel.isScrollToSource() && path != null) {
                _scrollToSourceHandler.scollToSelectionSource();
            }
            if (_bugTreePanel.isPreviewEnabled()) {
                _bugTreePanel.setPreview(path);
            }
        }
    }
}