Package com.intellij.ui.treeStructure

Source Code of com.intellij.ui.treeStructure.SimpleTree$MyMouseListener

/*
* Copyright 2000-2007 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 com.intellij.ui.treeStructure;

import com.intellij.ide.util.treeView.AbstractTreeBuilder;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.ActionPopupMenu;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.peer.PeerFactory;
import com.intellij.ui.UIHelper;
import com.intellij.util.ui.tree.TreeUtil;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;

public class SimpleTree extends JTree implements CellEditorListener {

  protected final MouseListener myMouseListener = new MyMouseListener();

  private ActionGroup myPopupGroup;
  private String myPlace;

  private static final SimpleNode NULL_NODE = new NullNode();

  // From FTree:
  private static final int INVALID = -1;
  private JComponent myEditorComponent;
  private boolean myEscapePressed;
  private int myEditingRow;
  private boolean myIgnoreSelectionChange;

  private int myMinHeightInRows = 5;

  public SimpleTree() {
    setModel(new DefaultTreeModel(new PatchedDefaultMutableTreeNode()));
    TreeUtil.installActions(this);

    final UIHelper helper = PeerFactory.getInstance().getUIHelper();
    helper.installTreeSpeedSearch(this);
    helper.installToolTipHandler(this);

    addMouseListener(myMouseListener);
    setCellRenderer(new SimpleNodeRenderer());

    setEditable(false);
    getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
    ToolTipManager.sharedInstance().registerComponent(this);

    getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
      public void valueChanged(TreeSelectionEvent e) {
        if (!myIgnoreSelectionChange && hasSingleSelection()) {
          getNodeFor(getSelectionPath()).handleSelection(SimpleTree.this);
        }
      }
    });

    addKeyListener(new KeyAdapter() {
      public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_ENTER && hasSingleSelection()) {
          handleDoubleClickOrEnter(getSelectionPath(), e);
        }
        if (e.getKeyCode() == KeyEvent.VK_F2 && e.getModifiers() == 0) {
          e.consume(); // ignore start editing by F2
        }
      }
    });

    putClientProperty("JTree.lineStyle", "Angled");
    setUI(new BasicTreeUI());   // In WindowsXP UI handles are not shown :(
  }

  public SimpleTree(TreeModel aModel) {
    this();
    setModel(aModel);
  }

  public boolean accept(AbstractTreeBuilder builder, SimpleNodeVisitor visitor) {
    final DefaultMutableTreeNode root = (DefaultMutableTreeNode) getModel().getRoot();
    return visitDown(builder, (SimpleNode) root.getUserObject(), visitor);
  }

  public void setPopupGroup(ActionGroup aPopupGroup, String aPlace) {
    myPopupGroup = aPopupGroup;
    myPlace = aPlace;
  }

  public SimpleNode getNodeFor(int row) {
    return getNodeFor(getPathForRow(row));
  }

  public SimpleNode getNodeFor(TreePath aPath) {
    if (aPath == null) {
      return NULL_NODE;
    }

    DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)aPath.getLastPathComponent();
    if (treeNode == null) {
      return NULL_NODE;
    }

    final Object userObject = treeNode.getUserObject();
    if (userObject instanceof SimpleNode) {
      return (SimpleNode) userObject;
    }
    else {
      return NULL_NODE;
    }
  }

  @Nullable
  public TreePath getPathFor(SimpleNode node) {
    final TreeNode nodeWithObject = TreeUtil.findNodeWithObject((DefaultMutableTreeNode) getModel().getRoot(), node);
    if (nodeWithObject != null) {
      return TreeUtil.getPathFromRoot(nodeWithObject);
    }
    return null;
  }

  @Nullable
  public SimpleNode getSelectedNode() {
    if (isSelectionEmpty()) {
      return null;
    }

    return getNodeFor(getSelectionPath());
  }

  public boolean isSelectionEmpty() {
    final TreePath selection = super.getSelectionPath();
    return selection == null || getNodeFor(selection) == NULL_NODE;

  }

  public SimpleNode[] getSelectedNodesIfUniform() {
    List<SimpleNode> result = new ArrayList<SimpleNode>();
    TreePath[] selectionPaths = getSelectionPaths();
    if (selectionPaths != null) {
      SimpleNode lastNode = null;
      for (TreePath selectionPath : selectionPaths) {
        SimpleNode nodeFor = getNodeFor(selectionPath);

        if (lastNode != null && lastNode.getClass() != nodeFor.getClass()) {
          return new SimpleNode[0];
        }

        result.add(nodeFor);
        lastNode = nodeFor;
      }
    }
    return result.toArray(new SimpleNode[result.size()]);
  }

  public void setSelectedNode(AbstractTreeBuilder builder, SimpleNode node, boolean expand) {
    final TreePath selected = getSelectionPath();
    if (selected != null) {
      final SimpleNode selectedNode = getNodeFor(selected);
      if (selectedNode.equals(node)) {
        return;
      }
    }

    if (expand) {
      builder.buildNodeForElement(node);
    }

    final TreePath path = getPathFor(node);
    setSelectionPath(path);
    scrollPathToVisible(path);
  }

  private static boolean visitDown(AbstractTreeBuilder builder, final SimpleNode node, SimpleNodeVisitor visitor) {
    if (visitor.accept(node)) {
      return true;
    }

    final Object[] children = builder.getTreeStructure().getChildElements(node);

    for (Object aChildren : children) {
      if (visitDown(builder, (SimpleNode) aChildren, visitor)) {
        return true;
      }
    }
    return false;
  }

  protected void paintChildren(Graphics g) {
    super.paintChildren(g);
    g.setColor(UIManager.getColor("Tree.line"));

    for (int row = 0; row < getRowCount(); row++) {
      final TreePath path = getPathForRow(row);
      if (!getNodeFor(path).shouldHaveSeparator()) {
        continue;
      }

      final Rectangle bounds = getRowBounds(row);
      int x = (int)bounds.getMaxX();
      int y = (int) (bounds.getY() + bounds.height / 2);
      g.drawLine(x, y, getWidth() - 5, y);
    }
  }

  public void doClick(int row) {
    setSelectionRow(row);
  }

  // From FTree:

  public void cancelEditing() {
    if (isEditing()) {
      cellEditor.cancelCellEditing();
      doStopEditing();
    }
  }

  public void editingStopped(ChangeEvent e) {
    doStopEditing();
  }

  public void editingCanceled(ChangeEvent e) {
    doStopEditing();
  }

  public JComponent getEditorComponent() {
    return myEditorComponent;
  }

  public boolean isEditing() {
    return myEditorComponent != null;
  }

  public TreePath getEditingPath() {
    if (isEditing()) {
      return getPathForRow(myEditingRow);
    }
    return super.getEditingPath();
  }

  public boolean isPathEditable(TreePath path) {
    return true;
  }

  protected void paintComponent(Graphics g) {
    super.paintComponent(g);

    if (isEditing()) {
      Rectangle editedNodeRect = getRowBounds(myEditingRow);
      if (editedNodeRect == null) return;
      g.setColor(getBackground());
      g.fillRect(editedNodeRect.x, editedNodeRect.y, editedNodeRect.width, editedNodeRect.height);
    }
  }

  public void setCellEditor(TreeCellEditor aCellEditor) {
    if (cellEditor != null) {
      cellEditor.removeCellEditorListener(this);
    }
    super.setCellEditor(aCellEditor);

    if (cellEditor != null) {
      cellEditor.addCellEditorListener(this);
    }
  }

  public boolean stopEditing() {
    boolean result = isEditing();
    if (result) {
      if (!cellEditor.stopCellEditing()) {
        cellEditor.cancelCellEditing();
      }
      doStopEditing();
    }
    return result;
  }

  public void startEditingAtPath(final TreePath path) {
    if (path != null && isVisible(path)) {

      if (isEditing() && !stopEditing()) {
        return;
      }

      startEditing(path);
    }
  }

  private void startEditing(final TreePath path) {

    CellEditor editor = getCellEditor();
    if (editor != null && editor.isCellEditable(null) && isPathEditable(path)) {

      getSelectionModel().clearSelection();
      getSelectionModel().setSelectionPath(path);

      myEditingRow = getRowForPath(path);
      myEditorComponent = (JComponent) getCellEditor().getTreeCellEditorComponent(this,
          path.getLastPathComponent(),
          isPathSelected(path), isExpanded(path),
          treeModel.isLeaf(path.getLastPathComponent()), myEditingRow);

      putEditor(path);

      if (myEditorComponent.isFocusable()) {
        myEditorComponent.requestFocusInWindow();
      }

      SwingUtilities.invokeLater(new Runnable() {
        public void run() {
          scrollPathToVisible(path);
        }
      });
    }
  }

  private void putEditor(TreePath path) {

    add(myEditorComponent);
    Rectangle nodeBounds = getPathBounds(path);
    Dimension editorPrefSize = myEditorComponent.getPreferredSize();
    if (editorPrefSize.height > nodeBounds.height) {
      nodeBounds.y -= (editorPrefSize.height - nodeBounds.height) / 2;
      nodeBounds.height = editorPrefSize.height;
    }

    myEditorComponent.setBounds(nodeBounds);

    myEscapePressed = false;
  }

  private void doStopEditing() {
    if (isEditing()) {
      remove(myEditorComponent);
      myEditorComponent = null;
      setSelectionRow(myEditingRow);
      myEditingRow = INVALID;
      repaint();
    }
  }

  public boolean isEscapePressed() {
    return myEscapePressed;
  }

  public void setEscapePressed() {
    myEscapePressed = true;
  }

  public void addSelectionPath(TreePath path) {
    myIgnoreSelectionChange = true;
    super.addSelectionPath(path);
    myIgnoreSelectionChange = false;
  }

  public void addSelectionPaths(TreePath[] path) {
    myIgnoreSelectionChange = true;
    super.addSelectionPaths(path);
    myIgnoreSelectionChange = false;
  }

  private boolean isSelected(TreePath path) {
    TreePath[] selectionPaths = getSelectionPaths();
    if (selectionPaths != null) {
      for (TreePath selectionPath : selectionPaths) {
        if (path.equals(selectionPath)) {
          return true;
        }
      }
    }
    return false;
  }

  public boolean isMultipleSelection() {
    return getSelectionRows() != null && getSelectionRows().length > 1;
  }

  private void handleDoubleClickOrEnter(final TreePath treePath, final InputEvent e) {
    Runnable runnable = new Runnable() {
      public void run() {
        getNodeFor(treePath).handleDoubleClickOrEnter(SimpleTree.this, e);
      }
    };
    ApplicationManager.getApplication().invokeLater(runnable, ModalityState.stateForComponent(this));
  }

  // TODO: move to some util?
  public static boolean isDoubleClick(MouseEvent e) {
    return e != null && e.getClickCount() > 0 && e.getClickCount() % 2 == 0;
  }

  protected ActionGroup getPopupGroup() {
    return myPopupGroup;
  }

  protected void invokeContextMenu(final MouseEvent e) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        final ActionPopupMenu menu = ActionManager.getInstance().createActionPopupMenu(myPlace, myPopupGroup);
        menu.getComponent().show(e.getComponent(), e.getPoint().x, e.getPoint().y);
      }
    });
  }

  private class MyMouseListener extends MouseAdapter {
    public void mousePressed(MouseEvent e) {
      if (e.isPopupTrigger()) {
        invokePopup(e);
      }
      else if (isDoubleClick(e)) {
        handleDoubleClickOrEnter(getClosestPathForLocation(e.getX(), e.getY()), e);
        /*
        if (!TreeWizardPopupImpl.isLocationInExpandControl(SimpleTree.this, getSelectionPath(), e.getX(), e.getY())) {
          TreePath treePath = getClosestPathForLocation(e.getX(), e.getY());
          handleDoubleClickOrEnter(treePath, e);
        }
        */
      }
    }

    public void mouseReleased(MouseEvent e) {
      invokePopup(e);
    }

    public void mouseClicked(MouseEvent e) {
      invokePopup(e);
    }

    private void invokePopup(final MouseEvent e) {
      if (e.isPopupTrigger() && insideTreeItemsArea(e)) {

        selectPathUnderCursorIfNeeded(e);

        if (myPopupGroup != null) {
          invokeContextMenu(e);
        }
      }
    }

    private void selectPathUnderCursorIfNeeded(final MouseEvent e) {
      TreePath pathForLocation = getClosestPathForLocation(e.getX(), e.getY());
      if (!isSelected(pathForLocation)) {
        setSelectionPath(pathForLocation);
      }
    }

    private boolean insideTreeItemsArea(MouseEvent e) {
      Rectangle rowBounds = getRowBounds(getRowCount() - 1);
      if (rowBounds == null) {
        return false;
      }
      double lastItemBottomLine = rowBounds.getMaxY();
      return e.getY() <= lastItemBottomLine;
    }
  }

  public boolean select(AbstractTreeBuilder aBuilder, final SimpleNodeVisitor aVisitor, boolean shouldExpand) {
    final SimpleNode[] found = new SimpleNode[1];
    boolean wasFound = accept(aBuilder, new SimpleNodeVisitor() {
      public boolean accept(SimpleNode simpleNode) {
        if (aVisitor.accept(simpleNode)) {
          found[0] = simpleNode;
          return true;
        }

        return false;
      }
    });

    if (wasFound) {

      //debugTree(aBuilder);

      setSelectedNode(aBuilder, found[0], shouldExpand);
    }

    return wasFound;
  }

  private void debugTree(AbstractTreeBuilder aBuilder) {
    TreeUtil.traverseDepth((TreeNode) aBuilder.getTree().getModel().getRoot(), new TreeUtil.Traverse() {
      public boolean accept(Object node) {
        System.out.println("Node: " + node);
        return true;
      }
    });
  }

  private boolean hasSingleSelection() {
    return !isSelectionEmpty() && getSelectionPaths().length == 1;
  }

  public DefaultTreeModel getBuilderModel() {
    return (DefaultTreeModel) getModel();
  }

  public Dimension getPreferredScrollableViewportSize() {
    return super.getPreferredSize();
  }

  public SimpleNodeRenderer getRenderer() {
    return (SimpleNodeRenderer) getCellRenderer();
  }

  public String toString() {
    return getClass().getName() + '#' + System.identityHashCode(this);
  }

  public final void setMinSizeInRows(int rows) {
    myMinHeightInRows = rows;
  }

  public Dimension getMinimumSize() {
    Dimension superSize = super.getMinimumSize();

    if (myMinHeightInRows == -1) return superSize;
    int rowCount = getRowCount();
    if (rowCount == 0) return superSize;

    double rowHeight = getRowBounds(0).getHeight();
    return new Dimension(superSize.width, (int) (rowHeight * myMinHeightInRows));
  }

  public final int getToggleClickCount() {
    SimpleNode node = getSelectedNode();
    if (node != null) {
        if (!node.expandOnDoubleClick()) return -1;
    }
    return super.getToggleClickCount();
  }

}
TOP

Related Classes of com.intellij.ui.treeStructure.SimpleTree$MyMouseListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.