mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:19:59 +07:00
515 lines
17 KiB
Java
515 lines
17 KiB
Java
package com.intellij.ide.errorTreeView;
|
|
|
|
import com.intellij.ide.ExporterToTextFile;
|
|
import com.intellij.ide.OccurenceNavigator;
|
|
import com.intellij.ide.OccurenceNavigatorSupport;
|
|
import com.intellij.ide.TreeExpander;
|
|
import com.intellij.ide.actions.*;
|
|
import com.intellij.ide.errorTreeView.impl.ErrorTreeViewConfiguration;
|
|
import com.intellij.ide.errorTreeView.impl.ErrorViewTextExporter;
|
|
import com.intellij.openapi.actionSystem.*;
|
|
import com.intellij.openapi.actionSystem.ex.DataConstantsEx;
|
|
import com.intellij.openapi.diagnostic.Logger;
|
|
import com.intellij.openapi.project.Project;
|
|
import com.intellij.openapi.util.IconLoader;
|
|
import com.intellij.openapi.vfs.VirtualFile;
|
|
import com.intellij.openapi.wm.ex.ActionToolbarEx;
|
|
import com.intellij.pom.Navigatable;
|
|
import com.intellij.ui.AutoScrollToSourceHandler;
|
|
import com.intellij.ui.PopupHandler;
|
|
import com.intellij.ui.content.Content;
|
|
import com.intellij.ui.content.MessageView;
|
|
import com.intellij.util.EditSourceOnDoubleClickHandler;
|
|
import com.intellij.util.ui.ErrorTreeView;
|
|
import com.intellij.util.ui.Tree;
|
|
import com.intellij.util.ui.tree.TreeUtil;
|
|
|
|
import javax.swing.*;
|
|
import javax.swing.tree.DefaultMutableTreeNode;
|
|
import javax.swing.tree.DefaultTreeModel;
|
|
import javax.swing.tree.TreeNode;
|
|
import javax.swing.tree.TreePath;
|
|
import java.awt.*;
|
|
import java.awt.event.KeyAdapter;
|
|
import java.awt.event.KeyEvent;
|
|
|
|
public class NewErrorTreeViewPanel extends JPanel implements DataProvider, OccurenceNavigator, ErrorTreeView {
|
|
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.errorTreeView.NewErrorTreeViewPanel");
|
|
private String myProgressText = "";
|
|
private final boolean myCreateExitAction;
|
|
private ErrorViewStructure myErrorViewStructure;
|
|
private ErrorViewTreeBuilder myBuilder;
|
|
|
|
public static interface ProcessController {
|
|
void stopProcess();
|
|
|
|
boolean isProcessStopped();
|
|
}
|
|
|
|
private ActionToolbarEx myLeftToolbar;
|
|
private ActionToolbarEx myRightToolbar;
|
|
private TreeExpander myTreeExpander = new MyTreeExpander();
|
|
private ExporterToTextFile myExporterToTextFile;
|
|
protected Project myProject;
|
|
private String myHelpId;
|
|
protected Tree myTree;
|
|
private JPanel myMessagePanel;
|
|
private ProcessController myProcessController;
|
|
|
|
private JLabel myProgressTextLabel;
|
|
private JLabel myProgressStatisticsLabel;
|
|
private JPanel myProgressPanel;
|
|
|
|
private AutoScrollToSourceHandler myAutoScrollToSourceHandler;
|
|
private MyOccurenceNavigatorSupport myOccurenceNavigatorSupport;
|
|
|
|
public NewErrorTreeViewPanel(Project project, String helpId) {
|
|
this(project, helpId, true);
|
|
}
|
|
|
|
public NewErrorTreeViewPanel(Project project, String helpId, boolean createExitAction) {
|
|
this(project, helpId, createExitAction, true);
|
|
}
|
|
|
|
public NewErrorTreeViewPanel(Project project, String helpId, boolean createExitAction, boolean createToolbar) {
|
|
myProject = project;
|
|
myHelpId = helpId;
|
|
myCreateExitAction = createExitAction;
|
|
setLayout(new BorderLayout());
|
|
|
|
myAutoScrollToSourceHandler = new AutoScrollToSourceHandler(myProject) {
|
|
protected boolean isAutoScrollMode() {
|
|
return ErrorTreeViewConfiguration.getInstance(myProject).isAutoscrollToSource();
|
|
}
|
|
|
|
protected void setAutoScrollMode(boolean state) {
|
|
ErrorTreeViewConfiguration.getInstance(myProject).setAutoscrollToSource(state);
|
|
}
|
|
};
|
|
|
|
myMessagePanel = new JPanel(new BorderLayout());
|
|
|
|
myErrorViewStructure = new ErrorViewStructure(project);
|
|
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
|
|
root.setUserObject(myErrorViewStructure.createDescriptor(myErrorViewStructure.getRootElement(), null));
|
|
final DefaultTreeModel treeModel = new DefaultTreeModel(root);
|
|
myTree = new Tree(treeModel) {
|
|
public void setRowHeight(int i) {
|
|
super.setRowHeight(0);
|
|
// this is needed in order to make UI calculate the height for each particular row
|
|
}
|
|
};
|
|
myBuilder = new ErrorViewTreeBuilder(myTree, treeModel, myErrorViewStructure);
|
|
|
|
myExporterToTextFile = new ErrorViewTextExporter(myErrorViewStructure);
|
|
myOccurenceNavigatorSupport = new MyOccurenceNavigatorSupport(myTree);
|
|
|
|
myAutoScrollToSourceHandler.install(myTree);
|
|
TreeUtil.installActions(myTree);
|
|
myTree.putClientProperty("JTree.lineStyle", "Angled");
|
|
myTree.setRootVisible(false);
|
|
myTree.setShowsRootHandles(true);
|
|
myTree.setLargeModel(true);
|
|
myTree.setLargeModel(true);
|
|
|
|
JScrollPane scrollPane = NewErrorTreeRenderer.install(myTree);
|
|
myMessagePanel.add(scrollPane, BorderLayout.CENTER);
|
|
|
|
if (createToolbar) {
|
|
add(createToolbarPanel(), BorderLayout.WEST);
|
|
}
|
|
|
|
add(myMessagePanel, BorderLayout.CENTER);
|
|
|
|
myTree.addKeyListener(new KeyAdapter() {
|
|
public void keyPressed(KeyEvent e) {
|
|
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
|
|
navigateToSource(false);
|
|
}
|
|
}
|
|
});
|
|
|
|
myTree.addMouseListener(new PopupHandler() {
|
|
public void invokePopup(Component comp, int x, int y) {
|
|
popupInvoked(comp, x, y);
|
|
}
|
|
});
|
|
|
|
EditSourceOnDoubleClickHandler.install(myTree);
|
|
}
|
|
|
|
public Object getData(String dataId) {
|
|
if (DataConstants.NAVIGATABLE.equals(dataId)) {
|
|
final NavigatableMessageElement selectedMessageElement = getSelectedMessageElement();
|
|
return selectedMessageElement != null? selectedMessageElement.getNavigatable() : null;
|
|
}
|
|
else if (DataConstants.HELP_ID.equals(dataId)) {
|
|
return myHelpId;
|
|
}
|
|
else if (DataConstantsEx.TREE_EXPANDER.equals(dataId)) {
|
|
return myTreeExpander;
|
|
}
|
|
else if (DataConstants.EXPORTER_TO_TEXT_FILE.equals(dataId)) {
|
|
return myExporterToTextFile;
|
|
}
|
|
else if (CURRENT_EXCEPTION_DATA.equals(dataId)) {
|
|
NavigatableMessageElement selectedMessageElement = getSelectedMessageElement();
|
|
return selectedMessageElement != null? selectedMessageElement.getData() : null;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public void selectFirstMessage() {
|
|
final ErrorTreeElement firstError = myErrorViewStructure.getFirstMessage(ErrorTreeElementKind.ERROR);
|
|
if (firstError != null) {
|
|
selectElement(firstError);
|
|
if (shouldShowFirstErrorInEditor()) {
|
|
navigateToSource(false);
|
|
}
|
|
}
|
|
else {
|
|
ErrorTreeElement firstWarning = myErrorViewStructure.getFirstMessage(ErrorTreeElementKind.WARNING);
|
|
if (firstWarning != null) {
|
|
selectElement(firstWarning);
|
|
}
|
|
else {
|
|
TreeUtil.selectFirstNode(myTree);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void selectElement(final ErrorTreeElement element) {
|
|
myBuilder.updateFromRoot();
|
|
DefaultMutableTreeNode node = myBuilder.getNodeForElement(element);
|
|
if (node == null) {
|
|
myBuilder.buildNodeForElement(element);
|
|
node = myBuilder.getNodeForElement(element);
|
|
}
|
|
LOG.assertTrue(node != null);
|
|
TreeNode[] pathToRoot = ((DefaultTreeModel)myTree.getModel()).getPathToRoot(node);
|
|
TreeUtil.selectPath(myTree, new TreePath(pathToRoot));
|
|
}
|
|
|
|
protected boolean shouldShowFirstErrorInEditor() {
|
|
return false;
|
|
}
|
|
public void clearMessages() {
|
|
myErrorViewStructure.clear();
|
|
myBuilder.updateTree();
|
|
}
|
|
|
|
public void addMessage(int type, String[] text, VirtualFile file, int line, int column, Object data) {
|
|
myErrorViewStructure.addMessage(ErrorTreeElementKind.convertMessageFromCompilerErrorType(type), text, file, line, column, data);
|
|
myBuilder.updateTree();
|
|
}
|
|
|
|
public void addMessage(int type, String[] text, String groupName, Navigatable navigatable, String exportTextPrefix, String rendererTextPrefix, Object data) {
|
|
myErrorViewStructure.addNavigatableMessage(groupName, navigatable, ErrorTreeElementKind.convertMessageFromCompilerErrorType(type), text, data, exportTextPrefix, rendererTextPrefix);
|
|
myBuilder.updateTree();
|
|
}
|
|
|
|
public static String createExportPrefix(int line) {
|
|
return line < 0? "" : "line (" + line + ")";
|
|
}
|
|
|
|
public static String createRendererPrefix(int line, int column) {
|
|
return line < 0? "" : "(" + line + ", " + column + ")";
|
|
}
|
|
|
|
public JComponent getComponent() {
|
|
return this;
|
|
}
|
|
|
|
private NavigatableMessageElement getSelectedMessageElement() {
|
|
final ErrorTreeElement selectedElement = getSelectedErrorTreeElement();
|
|
return selectedElement instanceof NavigatableMessageElement? (NavigatableMessageElement)selectedElement : null;
|
|
}
|
|
|
|
public ErrorTreeElement getSelectedErrorTreeElement() {
|
|
ErrorTreeNodeDescriptor treeNodeDescriptor = getSelectedNodeDescriptor();
|
|
if (treeNodeDescriptor == null) return null;
|
|
|
|
return treeNodeDescriptor.getElement();
|
|
}
|
|
|
|
public ErrorTreeNodeDescriptor getSelectedNodeDescriptor() {
|
|
TreePath path = myTree.getSelectionPath();
|
|
if (path == null) {
|
|
return null;
|
|
}
|
|
DefaultMutableTreeNode lastPathNode = (DefaultMutableTreeNode)path.getLastPathComponent();
|
|
Object userObject = lastPathNode.getUserObject();
|
|
if (!(userObject instanceof ErrorTreeNodeDescriptor)) {
|
|
return null;
|
|
}
|
|
ErrorTreeNodeDescriptor treeNodeDescriptor = (ErrorTreeNodeDescriptor)userObject;
|
|
return treeNodeDescriptor;
|
|
}
|
|
|
|
private void navigateToSource(final boolean focusEditor) {
|
|
NavigatableMessageElement element = getSelectedMessageElement();
|
|
if (element == null) {
|
|
return;
|
|
}
|
|
final Navigatable navigatable = element.getNavigatable();
|
|
if (navigatable.canNavigate()) {
|
|
navigatable.navigate(focusEditor);
|
|
}
|
|
}
|
|
|
|
public static String getQualifiedName(final VirtualFile file) {
|
|
return file.getPresentableUrl();
|
|
}
|
|
|
|
private void popupInvoked(Component component, int x, int y) {
|
|
final TreePath path = myTree.getLeadSelectionPath();
|
|
if (path == null) {
|
|
return;
|
|
}
|
|
DefaultActionGroup group = new DefaultActionGroup();
|
|
if (getData(DataConstants.NAVIGATABLE) != null) {
|
|
group.add(ActionManager.getInstance().getAction(IdeActions.ACTION_EDIT_SOURCE));
|
|
}
|
|
addExtraPopupMenuActions(group);
|
|
|
|
ActionPopupMenu menu = ActionManager.getInstance().createActionPopupMenu(ActionPlaces.COMPILER_MESSAGES_POPUP, group);
|
|
menu.getComponent().show(component, x, y);
|
|
}
|
|
|
|
protected void addExtraPopupMenuActions(DefaultActionGroup group) {
|
|
}
|
|
|
|
public void setProcessController(ProcessController controller) {
|
|
myProcessController = controller;
|
|
}
|
|
|
|
public void stopProcess() {
|
|
myProcessController.stopProcess();
|
|
}
|
|
|
|
public boolean canControlProcess() {
|
|
return myProcessController != null;
|
|
}
|
|
|
|
public boolean isProcessStopped() {
|
|
return myProcessController.isProcessStopped();
|
|
}
|
|
|
|
public void close() {
|
|
MessageView messageView = myProject.getComponent(MessageView.class);
|
|
Content content = messageView.getContent(this);
|
|
if (content != null) {
|
|
messageView.removeContent(content);
|
|
}
|
|
}
|
|
|
|
public void setProgressStatistics(final String s) {
|
|
initProgressPanel();
|
|
SwingUtilities.invokeLater(new Runnable() {
|
|
public void run() {
|
|
myProgressStatisticsLabel.setText(s);
|
|
}
|
|
});
|
|
}
|
|
|
|
public void setProgressText(final String s) {
|
|
initProgressPanel();
|
|
SwingUtilities.invokeLater(new Runnable() {
|
|
public void run() {
|
|
myProgressText = s;
|
|
myProgressTextLabel.setText(myProgressText);
|
|
}
|
|
});
|
|
}
|
|
|
|
public void setFraction(final double fraction) {
|
|
initProgressPanel();
|
|
SwingUtilities.invokeLater(new Runnable() {
|
|
public void run() {
|
|
myProgressTextLabel.setText(myProgressText + " " + (int)(fraction * 100 + 0.5) + "%");
|
|
}
|
|
});
|
|
}
|
|
|
|
private void initProgressPanel() {
|
|
if (myProgressPanel == null) {
|
|
myProgressPanel = new JPanel(new GridLayout(1, 2));
|
|
myProgressStatisticsLabel = new JLabel();
|
|
myProgressPanel.add(myProgressStatisticsLabel);
|
|
myProgressTextLabel = new JLabel();
|
|
myProgressPanel.add(myProgressTextLabel);
|
|
myMessagePanel.add(myProgressPanel, BorderLayout.SOUTH);
|
|
myMessagePanel.validate();
|
|
}
|
|
}
|
|
|
|
public void collapseAll() {
|
|
TreeUtil.collapseAll(myTree, 2);
|
|
}
|
|
|
|
|
|
public void expandAll() {
|
|
TreePath[] selectionPaths = myTree.getSelectionPaths();
|
|
TreePath leadSelectionPath = myTree.getLeadSelectionPath();
|
|
int row = 0;
|
|
while (row < myTree.getRowCount()) {
|
|
myTree.expandRow(row);
|
|
row++;
|
|
}
|
|
|
|
if (selectionPaths != null) {
|
|
// restore selection
|
|
myTree.setSelectionPaths(selectionPaths);
|
|
}
|
|
if (leadSelectionPath != null) {
|
|
// scroll to lead selection path
|
|
myTree.scrollPathToVisible(leadSelectionPath);
|
|
}
|
|
}
|
|
|
|
private JPanel createToolbarPanel() {
|
|
AnAction closeMessageViewAction = new CloseTabToolbarAction() {
|
|
public void actionPerformed(AnActionEvent e) {
|
|
close();
|
|
}
|
|
};
|
|
|
|
DefaultActionGroup leftUpdateableActionGroup = new DefaultActionGroup();
|
|
leftUpdateableActionGroup.add(new StopAction());
|
|
if (myCreateExitAction) {
|
|
leftUpdateableActionGroup.add(closeMessageViewAction);
|
|
}
|
|
leftUpdateableActionGroup.add(new PreviousOccurenceToolbarAction(this));
|
|
leftUpdateableActionGroup.add(new NextOccurenceToolbarAction(this));
|
|
leftUpdateableActionGroup.add(new ExportToTextFileToolbarAction(myExporterToTextFile));
|
|
leftUpdateableActionGroup.add(new ToolbarHelpAction(myHelpId));
|
|
|
|
DefaultActionGroup rightUpdateableActionGroup = new DefaultActionGroup();
|
|
fillRightToolbarGroup(rightUpdateableActionGroup);
|
|
|
|
JPanel toolbarPanel = new JPanel(new GridLayout(1, 2));
|
|
final ActionManager actionManager = ActionManager.getInstance();
|
|
myLeftToolbar =
|
|
(ActionToolbarEx)actionManager.createActionToolbar(ActionPlaces.COMPILER_MESSAGES_TOOLBAR, leftUpdateableActionGroup, false);
|
|
toolbarPanel.add(myLeftToolbar.getComponent());
|
|
myRightToolbar =
|
|
(ActionToolbarEx)actionManager.createActionToolbar(ActionPlaces.COMPILER_MESSAGES_TOOLBAR, rightUpdateableActionGroup, false);
|
|
toolbarPanel.add(myRightToolbar.getComponent());
|
|
|
|
return toolbarPanel;
|
|
}
|
|
|
|
protected void fillRightToolbarGroup(DefaultActionGroup group) {
|
|
group.add(new ExpandAllToolbarAction(myTreeExpander));
|
|
group.add(new CollapseAllToolbarAction(myTreeExpander));
|
|
group.add(new HideWarningsAction());
|
|
group.add(myAutoScrollToSourceHandler.createToggleAction());
|
|
}
|
|
|
|
public OccurenceInfo goNextOccurence() {
|
|
return myOccurenceNavigatorSupport.goNextOccurence();
|
|
}
|
|
|
|
public OccurenceInfo goPreviousOccurence() {
|
|
return myOccurenceNavigatorSupport.goPreviousOccurence();
|
|
}
|
|
|
|
public boolean hasNextOccurence() {
|
|
return myOccurenceNavigatorSupport.hasNextOccurence();
|
|
}
|
|
|
|
public boolean hasPreviousOccurence() {
|
|
return myOccurenceNavigatorSupport.hasPreviousOccurence();
|
|
}
|
|
|
|
public String getNextOccurenceActionName() {
|
|
return myOccurenceNavigatorSupport.getNextOccurenceActionName();
|
|
}
|
|
|
|
public String getPreviousOccurenceActionName() {
|
|
return myOccurenceNavigatorSupport.getPreviousOccurenceActionName();
|
|
}
|
|
|
|
private class StopAction extends AnAction {
|
|
public StopAction() {
|
|
super("Stop", null, IconLoader.getIcon("/actions/suspend.png"));
|
|
}
|
|
|
|
public void actionPerformed(AnActionEvent e) {
|
|
if (canControlProcess()) {
|
|
stopProcess();
|
|
}
|
|
myLeftToolbar.updateActions();
|
|
myRightToolbar.updateActions();
|
|
}
|
|
|
|
public void update(AnActionEvent event) {
|
|
Presentation presentation = event.getPresentation();
|
|
presentation.setEnabled(canControlProcess() && !isProcessStopped());
|
|
}
|
|
}
|
|
|
|
private class HideWarningsAction extends ToggleAction {
|
|
public HideWarningsAction() {
|
|
super("Hide warnings", null, IconLoader.getIcon("/compiler/hideWarnings.png"));
|
|
}
|
|
|
|
public boolean isSelected(AnActionEvent event) {
|
|
return ErrorTreeViewConfiguration.getInstance(myProject).isHideWarnings();
|
|
}
|
|
|
|
public void setSelected(AnActionEvent event, boolean flag) {
|
|
final ErrorTreeViewConfiguration configuration = ErrorTreeViewConfiguration.getInstance(myProject);
|
|
final boolean hideWarnings = configuration.isHideWarnings();
|
|
if (hideWarnings != flag) {
|
|
configuration.setHideWarnings(flag);
|
|
myBuilder.updateTree();
|
|
}
|
|
}
|
|
}
|
|
|
|
private class MyTreeExpander implements TreeExpander {
|
|
public void expandAll() {
|
|
NewErrorTreeViewPanel.this.expandAll();
|
|
}
|
|
|
|
public boolean canExpand() {
|
|
return true;
|
|
}
|
|
|
|
public void collapseAll() {
|
|
NewErrorTreeViewPanel.this.collapseAll();
|
|
}
|
|
|
|
public boolean canCollapse() {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
private class MyOccurenceNavigatorSupport extends OccurenceNavigatorSupport {
|
|
public MyOccurenceNavigatorSupport(final Tree tree) {
|
|
super(tree);
|
|
}
|
|
|
|
protected Navigatable createDescriptorForNode(DefaultMutableTreeNode node) {
|
|
Object userObject = node.getUserObject();
|
|
if (!(userObject instanceof ErrorTreeNodeDescriptor)) {
|
|
return null;
|
|
}
|
|
final ErrorTreeNodeDescriptor descriptor = (ErrorTreeNodeDescriptor)userObject;
|
|
final ErrorTreeElement element = descriptor.getElement();
|
|
if (element instanceof NavigatableMessageElement) {
|
|
return ((NavigatableMessageElement)element).getNavigatable();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public String getNextOccurenceActionName() {
|
|
return "Next Message";
|
|
}
|
|
|
|
public String getPreviousOccurenceActionName() {
|
|
return "Previous Message";
|
|
}
|
|
}
|
|
} |