You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Tree.java 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /*
  2. * Copyright (c) 2006-2010 Chris Smith, Shane Mc Cormack, Gregory Holmes
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. package com.dmdirc.addons.ui_swing.framemanager.tree;
  23. import com.dmdirc.addons.ui_swing.UIUtilities;
  24. import com.dmdirc.config.IdentityManager;
  25. import com.dmdirc.interfaces.ConfigChangeListener;
  26. import com.dmdirc.addons.ui_swing.actions.CloseFrameContainerAction;
  27. import com.dmdirc.addons.ui_swing.components.TreeScroller;
  28. import com.dmdirc.addons.ui_swing.components.frames.TextFrame;
  29. import java.awt.Rectangle;
  30. import java.awt.event.ActionEvent;
  31. import java.awt.event.ActionListener;
  32. import java.awt.event.MouseEvent;
  33. import java.awt.event.MouseListener;
  34. import java.awt.event.MouseMotionListener;
  35. import javax.swing.BorderFactory;
  36. import javax.swing.JComponent;
  37. import javax.swing.JMenuItem;
  38. import javax.swing.JPopupMenu;
  39. import javax.swing.JTree;
  40. import javax.swing.tree.TreeModel;
  41. import javax.swing.tree.TreePath;
  42. import javax.swing.tree.TreeSelectionModel;
  43. import net.miginfocom.layout.PlatformDefaults;
  44. /**
  45. * Specialised JTree for the frame manager.
  46. */
  47. public class Tree extends JTree implements MouseMotionListener,
  48. ConfigChangeListener, MouseListener, ActionListener {
  49. /**
  50. * A version number for this class. It should be changed whenever the class
  51. * structure is changed (or anything else that would prevent serialized
  52. * objects being unserialized with the new class).
  53. */
  54. private static final long serialVersionUID = 1;
  55. /** Drag selection enabled? */
  56. private boolean dragSelect;
  57. /** Drag button 1? */
  58. private boolean dragButton;
  59. /** Tree frame manager. */
  60. private TreeFrameManager manager;
  61. /**
  62. * Specialised JTree for frame manager.
  63. *
  64. * @param manager Frame manager
  65. * @param model tree model.
  66. */
  67. public Tree(final TreeFrameManager manager, final TreeModel model) {
  68. super(model);
  69. this.manager = manager;
  70. putClientProperty("JTree.lineStyle", "Angled");
  71. getInputMap().setParent(null);
  72. getInputMap(JComponent.WHEN_FOCUSED).clear();
  73. getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).clear();
  74. getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).clear();
  75. getSelectionModel().setSelectionMode(
  76. TreeSelectionModel.SINGLE_TREE_SELECTION);
  77. setRootVisible(false);
  78. setRowHeight(0);
  79. setShowsRootHandles(false);
  80. setOpaque(true);
  81. setBorder(BorderFactory.createEmptyBorder(
  82. (int) PlatformDefaults.getUnitValueX("related").getValue(),
  83. (int) PlatformDefaults.getUnitValueX("related").getValue(),
  84. (int) PlatformDefaults.getUnitValueX("related").getValue(),
  85. (int) PlatformDefaults.getUnitValueX("related").getValue()));
  86. new TreeScroller(this) {
  87. /** {@inheritDoc} */
  88. @Override
  89. protected void setPath(final TreePath path) {
  90. super.setPath(path);
  91. ((TreeViewNode) path.getLastPathComponent()).getFrameContainer().
  92. activateFrame();
  93. }
  94. };
  95. setFocusable(false);
  96. dragSelect = IdentityManager.getGlobalConfig().getOptionBool("treeview",
  97. "dragSelection");
  98. IdentityManager.getGlobalConfig().addChangeListener("treeview", this);
  99. addMouseListener(this);
  100. addMouseMotionListener(this);
  101. }
  102. /** {@inheritDoc} */
  103. @Override
  104. public void scrollRectToVisible(final Rectangle aRect) {
  105. final Rectangle rect = new Rectangle(0, aRect.y,
  106. aRect.width, aRect.height);
  107. super.scrollRectToVisible(rect);
  108. }
  109. /**
  110. * Set path.
  111. *
  112. * @param path Path
  113. */
  114. public void setTreePath(final TreePath path) {
  115. UIUtilities.invokeLater(new Runnable() {
  116. @Override
  117. public void run() {
  118. setSelectionPath(path);
  119. }
  120. });
  121. }
  122. /**
  123. * Returns the node for the specified location, returning null if rollover
  124. * is disabled or there is no node at the specified location.
  125. *
  126. * @param x x coordiantes
  127. * @param y y coordiantes
  128. *
  129. * @return node or null
  130. */
  131. public TreeViewNode getNodeForLocation(final int x,
  132. final int y) {
  133. TreeViewNode node = null;
  134. final TreePath selectedPath = getPathForLocation(x, y);
  135. if (selectedPath != null) {
  136. node = (TreeViewNode) selectedPath.getLastPathComponent();
  137. }
  138. return node;
  139. }
  140. /** {@inheritDoc} */
  141. @Override
  142. public void configChanged(final String domain, final String key) {
  143. if ("dragSelection".equals(key)) {
  144. dragSelect = IdentityManager.getGlobalConfig().getOptionBool(
  145. "treeview",
  146. "dragSelection");
  147. }
  148. }
  149. /**
  150. * {@inheritDoc}
  151. *
  152. * @param e Mouse event
  153. */
  154. @Override
  155. public void mouseDragged(final MouseEvent e) {
  156. if (dragSelect && dragButton) {
  157. final TreeViewNode node = getNodeForLocation(e.getX(), e.getY());
  158. if (node != null) {
  159. ((TreeViewNode) new TreePath(node.getPath()).
  160. getLastPathComponent()).getFrameContainer().
  161. activateFrame();
  162. }
  163. }
  164. manager.checkRollover(e);
  165. }
  166. /**
  167. * {@inheritDoc}
  168. *
  169. * @param e Mouse event
  170. */
  171. @Override
  172. public void mouseMoved(final MouseEvent e) {
  173. manager.checkRollover(e);
  174. }
  175. /**
  176. * {@inheritDoc}
  177. *
  178. * @param e Mouse event
  179. */
  180. @Override
  181. public void mouseClicked(MouseEvent e) {
  182. processMouseEvents(e);
  183. }
  184. /**
  185. * {@inheritDoc}
  186. *
  187. * @param e Mouse event
  188. */
  189. @Override
  190. public void mousePressed(MouseEvent e) {
  191. if (e.getButton() == MouseEvent.BUTTON1) {
  192. dragButton = true;
  193. final TreePath selectedPath = getPathForLocation(e.getX(), e.getY());
  194. if (selectedPath != null) {
  195. ((TreeViewNode) selectedPath.getLastPathComponent()).
  196. getFrameContainer().activateFrame();
  197. }
  198. }
  199. processMouseEvents(e);
  200. }
  201. /**
  202. * {@inheritDoc}
  203. *
  204. * @param e Mouse event
  205. */
  206. @Override
  207. public void mouseReleased(MouseEvent e) {
  208. dragButton = false;
  209. processMouseEvents(e);
  210. }
  211. /**
  212. * {@inheritDoc}
  213. *
  214. * @param e Mouse event
  215. */
  216. @Override
  217. public void mouseEntered(MouseEvent e) {
  218. //Ignore
  219. }
  220. /**
  221. * {@inheritDoc}
  222. *
  223. * @param e Mouse event
  224. */
  225. @Override
  226. public void mouseExited(MouseEvent e) {
  227. manager.checkRollover(null);
  228. }
  229. /**
  230. * Processes every mouse button event to check for a popup trigger.
  231. * @param e mouse event
  232. */
  233. public void processMouseEvents(final MouseEvent e) {
  234. final TreePath localPath = getPathForLocation(e.getX(), e.getY());
  235. if (localPath != null) {
  236. if (e.isPopupTrigger()) {
  237. final TextFrame frame = (TextFrame) ((TreeViewNode) localPath.
  238. getLastPathComponent()).getFrameContainer().
  239. getFrame();
  240. final JPopupMenu popupMenu = frame.getPopupMenu(null, "");
  241. frame.addCustomPopupItems(popupMenu);
  242. if (popupMenu.getComponentCount() > 0) {
  243. popupMenu.addSeparator();
  244. }
  245. final TreeViewNodeMenuItem moveUp =
  246. new TreeViewNodeMenuItem("Move Up", "Up",
  247. (TreeViewNode) localPath.getLastPathComponent());
  248. final TreeViewNodeMenuItem moveDown =
  249. new TreeViewNodeMenuItem("Move Down", "Down",
  250. (TreeViewNode) localPath.getLastPathComponent());
  251. moveUp.addActionListener(this);
  252. moveDown.addActionListener(this);
  253. popupMenu.add(moveUp);
  254. popupMenu.add(moveDown);
  255. popupMenu.add(new JMenuItem(new CloseFrameContainerAction(frame.
  256. getContainer())));
  257. popupMenu.show(this, e.getX(), e.getY());
  258. }
  259. }
  260. }
  261. /**
  262. * {@inheritDoc}
  263. *
  264. * @param e Action event
  265. */
  266. @Override
  267. public void actionPerformed(final ActionEvent e) {
  268. final TreeViewNode node = ((TreeViewNodeMenuItem) e.getSource()).
  269. getTreeNode();
  270. int index = getModel().getIndexOfChild(node.getParent(), node);
  271. if ("Up".equals(e.getActionCommand())) {
  272. if (index == 0) {
  273. index = node.getSiblingCount() - 1;
  274. } else {
  275. index--;
  276. }
  277. } else if ("Down".equals(e.getActionCommand())) {
  278. if (index == (node.getSiblingCount() - 1)) {
  279. index = 0;
  280. } else {
  281. index++;
  282. }
  283. }
  284. final TreeViewNode parentNode = (TreeViewNode) node.getParent();
  285. final TreePath nodePath = new TreePath(node.getPath());
  286. final boolean isExpanded = isExpanded(nodePath);
  287. ((TreeViewModel) getModel()).removeNodeFromParent(node);
  288. ((TreeViewModel) getModel()).insertNodeInto(node, parentNode, index);
  289. setExpandedState(nodePath, isExpanded);
  290. }
  291. }