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 }