001    package nl.cwi.sen1.visbase.factbrowser;
002    
003    import java.awt.Component;
004    import java.awt.GridBagConstraints;
005    import java.awt.GridBagLayout;
006    import java.awt.Insets;
007    import java.awt.Rectangle;
008    import java.awt.event.MouseEvent;
009    import java.awt.event.MouseListener;
010    import java.util.Enumeration;
011    import java.util.Iterator;
012    
013    import javax.swing.Icon;
014    import javax.swing.ImageIcon;
015    import javax.swing.JPanel;
016    import javax.swing.JScrollBar;
017    import javax.swing.JScrollPane;
018    import javax.swing.JTree;
019    import javax.swing.tree.DefaultMutableTreeNode;
020    import javax.swing.tree.DefaultTreeCellRenderer;
021    import javax.swing.tree.DefaultTreeModel;
022    import javax.swing.tree.TreePath;
023    
024    import nl.cwi.sen1.visbase.factbrowser.data.FactBrowserDataManager;
025    import nl.cwi.sen1.visbase.factbrowser.data.RStore;
026    import nl.cwi.sen1.visbase.factbrowser.data.RStoreFact;
027    import nl.cwi.sen1.visbase.factbrowser.data.VisualisationPlugin;
028    
029    /**
030     * This is the FactBrowserWindow responsible for displaying the tree containing
031     * the rstores with all the facts for this RStore. For every fact is displays
032     * the possible visualisations
033     * 
034     * This class has no testUnit because it is mostly GUI Related.
035     * 
036     * @author Renze de Vries
037     * @date 12-02-2007
038     * 
039     */
040    public class FactBrowserWindow extends JPanel {
041        private static final int INVALID_RSTORE = -1;
042    
043        private static final long serialVersionUID = 5095665207477698127L;
044    
045        private JScrollPane scrlTreeScroller;
046    
047        private JTree treeRstores;
048    
049        private DefaultMutableTreeNode rootNode;
050    
051        private DefaultTreeModel mdlTree;
052    
053        private FactBrowserDataManager m_dataManager;
054    
055        private Enumeration<TreePath> expansionState;
056    
057        /**
058         * The constructor calling the method responsible for building the panel
059         * containing the JTree
060         * 
061         * @author Renze de Vries
062         * @date 12-02-2007
063         */
064        public FactBrowserWindow() {
065            initComponents();
066            m_dataManager = FactBrowserDataManager.getInstance();
067        }
068    
069        /**
070         * This method is responsible for adding the TreeListener so that a click or
071         * event from the tree is responded to by the listener
072         * 
073         * @param listener
074         *            The listener which will respond to events
075         * 
076         * @author Renze de Vries
077         * @date 12-02-2007
078         */
079        public void addMouseListener(MouseListener listener) {
080            treeRstores.addMouseListener(listener);
081        }
082    
083        /**
084         * This method returns the last selected node in the visual tree and returns
085         * it to the requestor
086         * 
087         * @return The last selected node in the tree
088         * 
089         * @author Renze de Vries
090         * @date 20-02-2007
091         */
092        public DefaultMutableTreeNode getSelectedNode() {
093            return (DefaultMutableTreeNode) this.treeRstores
094                    .getLastSelectedPathComponent();
095        }
096    
097        /**
098         * This method makes it possible to see mutations in the tree when a node is
099         * added.
100         * 
101         * @author Renze de Vries
102         * @date 23-02-2007
103         */
104        public void redrawTree() {
105            storeExpansionState();
106            this.mdlTree.reload();
107            this.treeRstores.repaint();
108            restoreExpansionState();
109        }
110        
111        /**
112         * Stores the current expansion state of treeRstores
113         */
114        private void storeExpansionState() {
115                    expansionState = treeRstores.getExpandedDescendants(new TreePath(treeRstores
116                                    .getModel().getRoot()));
117            }
118    
119        /**
120             * Restores the expansion state of treeRstores
121         */
122            private void restoreExpansionState() {
123                    if (expansionState != null) {
124                            while (expansionState.hasMoreElements()) {
125                                    TreePath treePath = expansionState.nextElement();
126                                    treeRstores.expandPath(treePath);
127                            }
128                    }
129            }
130    
131        /**
132         * This method will make it possible to display the loaded RStores with the
133         * facts contained within the RStore.
134         * 
135         * @param rstoreName
136         *            The name of the RStore
137         * @param rstoreFacts
138         *            A list containing all the Facts within the RStore
139         * 
140         * @author Renze de Vries
141         * @date 12-02-2007
142         */
143        public void addRStore(RStore rstoreNode) {
144            DefaultMutableTreeNode rstoreTreeNode;
145    
146            rstoreTreeNode = getRStoreNode(rstoreNode.getRstoreId());
147    
148            // if doesn't exists then create a new
149            if (rstoreTreeNode == null) {
150                rstoreTreeNode = new DefaultMutableTreeNode(rstoreNode); 
151                rootNode.add(rstoreTreeNode);
152            } else {
153                rstoreTreeNode.removeAllChildren();
154            }
155    
156            if (rstoreNode.getRstoreId() == INVALID_RSTORE) {
157                DefaultMutableTreeNode invalidRStore = new DefaultMutableTreeNode(
158                        "Invalid RStore");
159                rstoreTreeNode.add(invalidRStore);
160            }
161    
162            Iterator<RStoreFact> iterator = rstoreNode.getFactNodes().iterator();
163            while (iterator.hasNext()) {
164                RStoreFact rstoreFactNode = iterator.next();
165                rstoreTreeNode.add(rstoreFactNode);
166            }
167    
168            redrawTree();
169        }
170    
171        /**
172         * Gets the rstore tree node from the tree with a specified rstoreID.
173         * 
174         * @author Bas Basten
175         * @author Anton Lycklama a Nijeholt
176         * @date 19-03-2007
177         * 
178         * @param rstoreID
179         * @return
180         */
181        public DefaultMutableTreeNode getRStoreNode(int rstoreID) {
182            Enumeration enumeration = rootNode.breadthFirstEnumeration();
183    
184            while (enumeration.hasMoreElements()) {
185                Object element = enumeration.nextElement();
186                DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) element;
187                if (treeNode.getUserObject() instanceof RStore) {
188                    // RStoreTreeNode rstoreNode = (RStoreTreeNode) element;
189                    // RStore rstoreNode = (RStore) treeNode.getUserObject();
190    
191                    int nodeRStoreID = m_dataManager.getRStoreID(treeNode);
192    
193                    if (rstoreID == nodeRStoreID) {
194                        return treeNode;
195                    }
196                }
197            }
198    
199            return null;
200        }
201    
202        /**
203         * Removes a rstore tree node with a specified rstoreID from the tree.
204         * 
205         * @author Bas Basten
206         * @author Anton Lycklama a Nijeholt
207         * @date 19-03-2007
208         * 
209         * @param rstoreID
210         */
211        public void removeRStoreTreeNode(int rstoreID) {
212            DefaultMutableTreeNode rstoreNode = getRStoreNode(rstoreID);
213    
214            if (rstoreNode != null) {
215                rstoreNode.removeFromParent();
216    
217                redrawTree();
218            }
219        }
220    
221        /**
222         * This method builds a JPanel containing the elements to display the Tree
223         * with the RStores and nodes. It was generated by a GUI builder.
224         * 
225         * @author Renze de Vries
226         * @date 12-02-2007
227         */
228        private void initComponents() {
229            rootNode = new DefaultMutableTreeNode("ROOT");
230            mdlTree = new DefaultTreeModel(rootNode);
231            scrlTreeScroller = new JScrollPane();
232            treeRstores = new JTree(mdlTree) {
233                            private static final long serialVersionUID = 2356329800583434058L;
234    
235                            public String getToolTipText(MouseEvent e) {
236                                    Object tip = null;
237                                    TreePath path = getPathForLocation(e.getX(), e.getY());
238                                    if (path != null) {
239                                            tip = path.getLastPathComponent();
240                                    }
241                                    return tip == null ? null : tip.toString();
242                            }
243            };
244            treeRstores.setRootVisible(false);
245            treeRstores.setShowsRootHandles(true);
246            treeRstores.setToolTipText("hoi");
247    
248            ImageIcon factIcon = new ImageIcon(getClass().getResource(
249                    "/resources/images/fact.png"));
250            ImageIcon visIcon = new ImageIcon(getClass().getResource(
251                    "/resources/images/vis.png"));
252            ImageIcon novisIcon = new ImageIcon(getClass().getResource(
253                    "/resources/images/novis.png"));
254            ImageIcon rstoreIcon = new ImageIcon(getClass().getResource(
255                    "/resources/images/rstore.png"));
256    
257            treeRstores.setCellRenderer(new TreeIconCellRenderer(factIcon, visIcon,
258                    novisIcon, rstoreIcon));
259    
260            setLayout(new GridBagLayout());
261            ((GridBagLayout) getLayout()).columnWidths = new int[] { 200, 0 };
262            ((GridBagLayout) getLayout()).rowHeights = new int[] { 0, 0 };
263            ((GridBagLayout) getLayout()).columnWeights = new double[] { 1.0,
264                    1.0E-4 };
265            ((GridBagLayout) getLayout()).rowWeights = new double[] { 1.0, 1.0E-4 };
266    
267            scrlTreeScroller.setViewportView(treeRstores);
268            add(scrlTreeScroller, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0,
269                    GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(
270                            0, 0, 0, 0), 0, 0));
271        }
272    
273        /**
274         * Internal class responsible for painting the icons on the nodes in the
275         * Tree. For different types of nodes different icons will be used
276         * 
277         * @author Renze de Vries
278         * @date 14-02-2007
279         */
280        class TreeIconCellRenderer extends DefaultTreeCellRenderer {
281            private static final long serialVersionUID = 7775610665094841024L;
282    
283            private Icon factIcon;
284    
285            private Icon visIcon;
286    
287            private Icon novisIcon;
288    
289            private Icon rstoreIcon;
290    
291            public TreeIconCellRenderer(Icon factIcon, Icon visIcon,
292                    Icon novisIcon, Icon rstoreIcon) {
293                this.factIcon = factIcon;
294                this.visIcon = visIcon;
295                this.novisIcon = novisIcon;
296                this.rstoreIcon = rstoreIcon;
297            }
298    
299            public Component getTreeCellRendererComponent(JTree tree, Object value,
300                    boolean sel, boolean expanded, boolean leaf, int row,
301                    boolean hasFocus) {
302    
303                super.getTreeCellRendererComponent(tree, value, sel, expanded,
304                        leaf, row, hasFocus);
305    
306                DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) value;
307                Object userObject = treeNode.getUserObject();
308    
309                if (value instanceof RStoreFact) {
310                    setIcon(factIcon);
311                    setText(((RStoreFact) value).getFactName());
312                } else if (userObject instanceof RStore) {
313                    setIcon(rstoreIcon);
314                } else if (userObject instanceof VisualisationPlugin) {
315                    setIcon(visIcon);
316                } else {
317                    setIcon(novisIcon);
318                }
319    
320                return this;
321            }
322        }
323    
324        /**
325         * Select a node at a given position (X & Y).
326         * If no node can be selected the selection of the
327         * tree will be cleared.
328         * 
329         * If we don't do this you can select a node in the
330         * tree and at any point you can double click or right
331         * click. With this method you need to double click or
332         * right click at a specific node.
333         * 
334         * @author Bas Basten
335         * @author Anton Lycklama a Nijeholt
336         * @date 19-03-2007
337         * 
338         * @param x
339         * @param y
340         */
341        public void selectNodeAtPosition(int x, int y) {
342            int row = treeRstores.getRowForLocation(x, y);
343    
344            if (row != INVALID_RSTORE) {
345                Rectangle rect = treeRstores.getRowBounds(row);
346                if (rect.contains(x, y)) {
347                    treeRstores.setSelectionRow(row);
348                    return;
349                }
350            }
351    
352            // No row has been selected so the selection should be cleared.
353            treeRstores.clearSelection();
354        }
355        
356        
357        /**
358         * Get the vertical scrollbar offset.
359         * @return Offset integer
360         * @author A.Belgraver
361         * @date 19-03-2007
362         */
363        public int getVerticalBarOffset() {
364           JScrollBar vScroll = scrlTreeScroller.getVerticalScrollBar();
365           return vScroll.getValue();
366        }
367    
368        /**
369         * Get the horizontal scrollbar offset.
370         * @return Offset integer
371         * @author A.Belgraver
372         * @date 19-03-2007 
373         */
374        public int getHorizontalBarOffset() {
375            JScrollBar hScroll = scrlTreeScroller.getHorizontalScrollBar();
376            return hScroll.getValue();
377        }
378        
379    }