View Javadoc

1   package de.matthias_burbach.mosaique.swing;
2   
3   import java.awt.event.ActionEvent;
4   import java.awt.event.MouseAdapter;
5   import java.awt.event.MouseEvent;
6   import java.util.ArrayList;
7   import java.util.Collections;
8   import java.util.Comparator;
9   import java.util.Enumeration;
10  import java.util.Iterator;
11  import java.util.List;
12  
13  import javax.swing.AbstractAction;
14  import javax.swing.JPopupMenu;
15  import javax.swing.JTree;
16  import javax.swing.event.TreeSelectionEvent;
17  import javax.swing.event.TreeSelectionListener;
18  import javax.swing.tree.TreeModel;
19  import javax.swing.tree.TreeNode;
20  import javax.swing.tree.TreePath;
21  import javax.swing.tree.TreeSelectionModel;
22  
23  import de.matthias_burbach.mosaique.core.Mosaique;
24  import de.matthias_burbach.mosaique.core.model.AbstractFileItem;
25  
26  /***
27   * Features various popup menus whose action items depend on the type of the
28   * selected node.
29   *
30   * @author Matthias Burbach
31   */
32  public class MosaiqueTree extends JTree implements TreeSelectionListener {
33      /***
34       * Collapses the selected node deeply, i. e.
35       * all descendant nodes are collapsed as well.
36       * <p/>
37       * Is available on all types of nodes.
38       *
39       * @author Matthias Burbach
40       */
41      private class CollapseAllAction extends AbstractAction {
42          /***
43           * Constructs this action.
44           */
45          public CollapseAllAction() {
46              super("Collapse All");
47          }
48  
49          /*
50           * (non-Javadoc)
51           * @see java.awt.event.ActionListener#actionPerformed(
52           *          java.awt.event.ActionEvent)
53           */
54          /***
55           * {@inheritDoc}
56           */
57          public void actionPerformed(final ActionEvent e) {
58              TreePath treePath = getSelectionPath();
59              if (treePath != null) {
60                  Enumeration descsEnum = getDescendantToggledPaths(treePath);
61                  List descsList = enumToList(descsEnum);
62                  sortListByPathCountDescending(descsList);
63                  Iterator iter = descsList.iterator();
64                  while (iter.hasNext()) {
65                      TreePath descTreePath = (TreePath) iter.next();
66                      collapsePath(descTreePath);
67                  }
68              }
69          }
70  
71          /***
72           * @param anEnumeration The enumeration to be converted to a list.
73           * @return The list holding the elements of <code>enum</code>.
74           */
75          private List enumToList(final Enumeration anEnumeration) {
76              List result = new ArrayList();
77              while (anEnumeration.hasMoreElements()) {
78                  result.add(anEnumeration.nextElement());
79              }
80              return result;
81          }
82  
83          /***
84           * @param treePaths The tree paths to be sorted.
85           */
86          private void sortListByPathCountDescending(final List treePaths) {
87              Comparator comparator = new Comparator() {
88                  public int compare(final Object o1, final Object o2) {
89                      TreePath tp1 = (TreePath) o1;
90                      TreePath tp2 = (TreePath) o2;
91                      return tp2.getPathCount() - tp1.getPathCount();
92                  }
93              };
94              Collections.sort(treePaths, comparator);
95          }
96      }
97  
98      /***
99       * Pops up the appropriate menu depending on the type of node selected.
100      *
101      * @author Matthias Burbach
102      */
103     private class PopupTrigger extends MouseAdapter {
104         /*
105          * (non-Javadoc)
106          * @see java.awt.event.MouseListener#mouseReleased(
107          *              java.awt.event.MouseEvent)
108          */
109         /***
110          * {@inheritDoc}
111          */
112         public void mouseReleased(final MouseEvent e) {
113             if (e.isPopupTrigger()) {
114                 int x = e.getX();
115                 int y = e.getY();
116 
117                 int selectedRow =
118                     MosaiqueTree.this.getClosestRowForLocation(x, y);
119                 MosaiqueTree.this.setSelectionRow(selectedRow);
120                 treeNodePopupMenu.show(MosaiqueTree.this, x, y);
121             }
122         }
123     }
124 
125     /***
126      * The popup menu on general tree nodes.
127      */
128     private JPopupMenu treeNodePopupMenu;
129 
130     /***
131      * The main GUI application object.
132      */
133     private MosaiqueFrame mosaiqueFrame;
134 
135     /***
136      * @param mosaique The core application object.
137      * @param mosaiqueFrame The gui application object.
138      * @param treeModel The tree model to delegate change operations to.
139      */
140     public MosaiqueTree(
141             final Mosaique mosaique,
142             final MosaiqueFrame mosaiqueFrame,
143             final TreeModel treeModel) {
144         this.mosaiqueFrame = mosaiqueFrame;
145 
146         setModel(treeModel);
147         getSelectionModel().setSelectionMode(
148             TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
149 
150         MosaiqueTreeCellRenderer treeCellRenderer =
151             new MosaiqueTreeCellRenderer(mosaique);
152         setCellRenderer(treeCellRenderer);
153 
154         treeNodePopupMenu = new JPopupMenu();
155         treeNodePopupMenu.add(new CollapseAllAction());
156         add(treeNodePopupMenu);
157 
158         addMouseListener(new PopupTrigger());
159 
160         addTreeSelectionListener(this);
161     }
162 
163     /***
164      * @return The currently selected tree node or <code>null</code>.
165      */
166     public TreeNode getSelectedNode() {
167         TreeNode result = null;
168         TreePath treePath = getSelectionPath();
169         if (treePath != null) {
170             result = (TreeNode) treePath.getLastPathComponent();
171         }
172         return result;
173     }
174 
175     /***
176      * @return The list of currently selected nodes of type {@link TreeNode}.
177      */
178     public List getSelectedNodes() {
179         List result = new ArrayList();
180         TreePath[] treePaths = getSelectionPaths();
181         if (treePaths != null) {
182             for (int i = 0; i < treePaths.length; i++) {
183                 TreeNode candidateNode =
184                     (TreeNode) treePaths[i].getLastPathComponent();
185                 result.add(candidateNode);
186             }
187         }
188         return result;
189     }
190 
191     /*
192      * (non-Javadoc)
193      * @see javax.swing.event.TreeSelectionListener#valueChanged(
194      *          javax.swing.event.TreeSelectionEvent)
195      */
196     /***
197      * {@inheritDoc}
198      */
199     public void valueChanged(final TreeSelectionEvent e) {
200         TreeNode selectedNode = getSelectedNode();
201         if (selectedNode instanceof AbstractFileItemNode) {
202             AbstractFileItemNode node = (AbstractFileItemNode) selectedNode;
203             AbstractFileItem fileItem = node.getFileItem();
204             mosaiqueFrame.openFile(
205                     fileItem.getFilePath(),
206                     fileItem.getPrimarySearchText(),
207                     fileItem.getSecondarySearchText(),
208                     fileItem.getBegin(),
209                     fileItem.getEnd());
210         }
211     }
212 }