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 }