Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

TreeScroller.java 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /*
  2. * Copyright (c) 2006-2014 DMDirc Developers
  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.components;
  23. import com.dmdirc.addons.ui_swing.UIUtilities;
  24. import java.awt.event.MouseWheelEvent;
  25. import java.awt.event.MouseWheelListener;
  26. import javax.swing.JTree;
  27. import javax.swing.tree.DefaultMutableTreeNode;
  28. import javax.swing.tree.DefaultTreeModel;
  29. import javax.swing.tree.TreePath;
  30. import javax.swing.tree.TreeSelectionModel;
  31. /**
  32. * Utility class to provide mouse wheel scrolling to a JTree.
  33. */
  34. public class TreeScroller implements MouseWheelListener {
  35. /** Tree to scroll. */
  36. private final DefaultTreeModel model;
  37. /** Tree to scroll. */
  38. private final TreeSelectionModel selectionModel;
  39. /** Root visible. */
  40. private final boolean rootVisible;
  41. /** Root node. */
  42. private final DefaultMutableTreeNode rootNode;
  43. /** Tree. */
  44. private JTree tree;
  45. /**
  46. * Creates a new instance of TreeScroller.
  47. *
  48. * @param tree Tree to scroll over
  49. */
  50. public TreeScroller(final JTree tree) {
  51. this.tree = tree;
  52. this.model = (DefaultTreeModel) tree.getModel();
  53. this.selectionModel = tree.getSelectionModel();
  54. rootVisible = tree.isRootVisible();
  55. rootNode = (DefaultMutableTreeNode) tree.getModel().getRoot();
  56. tree.addMouseWheelListener(this);
  57. }
  58. /**
  59. * Creates a new instance of TreeScroller.
  60. *
  61. * @param model Tree model to scroll over
  62. * @param selectionModel Tree selection model to scroll over
  63. * @param rootVisible Is the root node visible
  64. */
  65. public TreeScroller(final DefaultTreeModel model,
  66. final TreeSelectionModel selectionModel,
  67. final boolean rootVisible) {
  68. this.model = model;
  69. this.selectionModel = selectionModel;
  70. this.rootVisible = rootVisible;
  71. rootNode = (DefaultMutableTreeNode) model.getRoot();
  72. }
  73. /**
  74. * Registers a new tree scroller on the specified tree.
  75. *
  76. * @param tree Tree to scroll
  77. */
  78. public static void register(final JTree tree) {
  79. UIUtilities.invokeLater(new Runnable() {
  80. /** {@inheritDoc} */
  81. @Override
  82. public void run() {
  83. new TreeScroller(tree);
  84. }
  85. });
  86. }
  87. /**
  88. * Registers a new tree scroller for the specified models.
  89. *
  90. * @param model Tree model.
  91. * @param selectionModel Selection model.
  92. * @param rootVisible Root visible
  93. */
  94. public static void register(final DefaultTreeModel model,
  95. final TreeSelectionModel selectionModel,
  96. final boolean rootVisible) {
  97. UIUtilities.invokeLater(new Runnable() {
  98. /** {@inheritDoc} */
  99. @Override
  100. public void run() {
  101. new TreeScroller(model, selectionModel, rootVisible);
  102. }
  103. });
  104. }
  105. /**
  106. * Removes this tree scroller from the tree.
  107. */
  108. public void unregister() {
  109. if (tree != null) {
  110. tree.removeMouseWheelListener(this);
  111. }
  112. }
  113. /**
  114. * {@inheritDoc}
  115. *
  116. * @param e Mouse wheel event
  117. */
  118. @Override
  119. public void mouseWheelMoved(final MouseWheelEvent e) {
  120. if (e.getWheelRotation() < 0) {
  121. changeFocus(true);
  122. } else {
  123. changeFocus(false);
  124. }
  125. }
  126. /**
  127. * Activates the node above or below the active node in the tree.
  128. *
  129. * @param direction true = up, false = down.
  130. */
  131. public void changeFocus(final boolean direction) {
  132. DefaultMutableTreeNode thisNode;
  133. DefaultMutableTreeNode nextNode;
  134. if (rootNode == null) {
  135. //no root node or root node not visible
  136. return;
  137. }
  138. if (!rootVisible && rootNode.getChildCount() == 0) {
  139. //root node has no children
  140. return;
  141. }
  142. if (selectionModel.isSelectionEmpty()) {
  143. if (rootVisible) {
  144. thisNode = rootNode;
  145. } else {
  146. thisNode = (DefaultMutableTreeNode) rootNode.getChildAt(0);
  147. }
  148. } else {
  149. thisNode = (DefaultMutableTreeNode) selectionModel
  150. .getSelectionPath().getLastPathComponent();
  151. }
  152. //are we going up or down?
  153. if (direction) {
  154. //up
  155. nextNode = changeFocusUp(thisNode);
  156. } else {
  157. //down
  158. nextNode = changeFocusDown(thisNode);
  159. }
  160. setPath(new TreePath(model.getPathToRoot(nextNode)));
  161. }
  162. /**
  163. * Sets the tree selection path.
  164. *
  165. * @param path Path
  166. */
  167. protected void setPath(final TreePath path) {
  168. selectionModel.setSelectionPath(path);
  169. }
  170. /**
  171. * Changes the tree focus up.
  172. *
  173. * @param node Start node
  174. *
  175. * @return next node
  176. */
  177. private DefaultMutableTreeNode changeFocusUp(
  178. final DefaultMutableTreeNode node) {
  179. DefaultMutableTreeNode nextNode;
  180. nextNode = node.getPreviousNode();
  181. if (nextNode == null || (nextNode == model.getRoot() && !rootVisible)) {
  182. nextNode = rootNode.getLastLeaf();
  183. }
  184. return nextNode;
  185. }
  186. /**
  187. * Changes the tree focus down.
  188. *
  189. * @param node Start node
  190. *
  191. * @return next node
  192. */
  193. private DefaultMutableTreeNode changeFocusDown(
  194. final DefaultMutableTreeNode node) {
  195. DefaultMutableTreeNode nextNode;
  196. nextNode = node.getNextNode();
  197. if (nextNode == null && !rootVisible) {
  198. nextNode =
  199. (DefaultMutableTreeNode) rootNode.getFirstChild();
  200. } else if (nextNode == null) {
  201. nextNode = (DefaultMutableTreeNode) model.getRoot();
  202. }
  203. return nextNode;
  204. }
  205. }