Main Page   Packages   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

JTreeTable.java

00001 package edu.ksu.cis.bandera.abstraction.gui;
00002 
00003 /*
00004  * @(#)JTreeTable.java  1.2 98/10/27
00005  *
00006  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
00007  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
00008  * All rights reserved.
00009  *
00010  * This software is the confidential and proprietary information
00011  * of Sun Microsystems, Inc. ("Confidential Information").  You
00012  * shall not disclose such Confidential Information and shall use
00013  * it only in accordance with the terms of the license agreement
00014  * you entered into with Sun.
00015  */
00016 
00017 import javax.swing.*;
00018 import javax.swing.event.*;
00019 import javax.swing.tree.*;
00020 import javax.swing.table.*;
00021 import java.awt.Dimension;
00022 import java.awt.Component;
00023 import java.awt.Graphics;
00024 import java.awt.Rectangle;
00025 import java.awt.event.MouseEvent;
00026 import java.awt.Color;
00027 import java.util.*;
00028 import ca.mcgill.sable.soot.*;
00029 import edu.ksu.cis.bandera.abstraction.*;
00030 import edu.ksu.cis.bandera.abstraction.util.*;
00031 
00032 /**
00033  * This example shows how to create a simple JTreeTable component, 
00034  * by using a JTree as a renderer (and editor) for the cells in a 
00035  * particular column in the JTable.  
00036  *
00037  * @version 1.2 10/27/98
00038  *
00039  * @author Philip Milne
00040  * @author Scott Violet
00041  */
00042 public class JTreeTable extends JTable {
00043     /** A subclass of JTree. */
00044     protected TreeTableCellRenderer tree;
00045     public static java.util.Hashtable absTable;
00046 
00047     /**
00048      * A TreeCellRenderer that displays a JTree.
00049      */
00050     public class TreeTableCellRenderer extends JTree implements TableCellRenderer {
00051         /** Last table/tree row asked to renderer. */
00052         protected int visibleRow;
00053         public TreeTableCellRenderer(TreeModel model) {
00054             super(model);
00055             putClientProperty("JTree.lineStyle", "Angled");
00056         }
00057 
00058         /**
00059          * updateUI is overridden to set the colors of the Tree's renderer
00060          * to match that of the table.
00061          */
00062         public void updateUI() {
00063             super.updateUI();
00064             // Make the tree's cell renderer use the table's cell selection
00065             // colors. 
00066             TreeCellRenderer tcr = this.getCellRenderer();
00067             if (tcr instanceof DefaultTreeCellRenderer) {
00068                 DefaultTreeCellRenderer dtcr = ((DefaultTreeCellRenderer) tcr);
00069                 // For 1.1 uncomment this, 1.2 has a bug that will cause an
00070                 // exception to be thrown if the border selection color is
00071                 // null.
00072                 // dtcr.setBorderSelectionColor(null);
00073                 dtcr.setTextSelectionColor(UIManager.getColor("Table.selectionForeground"));
00074                 dtcr.setBackgroundSelectionColor(UIManager.getColor("Table.selectionBackground"));
00075             }
00076         }
00077 
00078         /**
00079          * Sets the row height of the tree, and forwards the row height to
00080          * the table.
00081          */
00082         public void setRowHeight(int rowHeight) {
00083             if (rowHeight > 0) {
00084                 super.setRowHeight(rowHeight);
00085                 if (JTreeTable.this != null && JTreeTable.this.getRowHeight() != rowHeight) {
00086                     JTreeTable.this.setRowHeight(getRowHeight());
00087                 }
00088             }
00089         }
00090 
00091         /**
00092          * This is overridden to set the height to match that of the JTable.
00093          */
00094         public void setBounds(int x, int y, int w, int h) {
00095             super.setBounds(x, 0, w, JTreeTable.this.getHeight());
00096         }
00097 
00098         /**
00099          * Sublcassed to translate the graphics such that the last visible
00100          * row will be drawn at 0,0.
00101          */
00102         public void paint(Graphics g) {
00103             g.translate(0, -visibleRow * getRowHeight());
00104             super.paint(g);
00105         }
00106 
00107         /**
00108          * TreeCellRenderer method. Overridden to update the visible row.
00109          */
00110         public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
00111             if (isSelected)
00112                 setBackground(table.getSelectionBackground());
00113             else
00114                 setBackground(table.getBackground());
00115             visibleRow = row;
00116             return this;
00117         }
00118     }
00119 
00120 
00121     /**
00122      * TreeTableCellEditor implementation. Component returned is the
00123      * JTree.
00124      */
00125     public class TreeTableCellEditor extends AbstractCellEditor implements TableCellEditor {
00126         public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int r, int c) {
00127             return tree;
00128         }
00129 
00130         /**
00131          * Overridden to return false, and if the event is a mouse event
00132          * it is forwarded to the tree.<p>
00133          * The behavior for this is debatable, and should really be offered
00134          * as a property. By returning false, all keyboard actions are
00135          * implemented in terms of the table. By returning true, the
00136          * tree would get a chance to do something with the keyboard
00137          * events. For the most part this is ok. But for certain keys,
00138          * such as left/right, the tree will expand/collapse where as
00139          * the table focus should really move to a different column. Page
00140          * up/down should also be implemented in terms of the table.
00141          * By returning false this also has the added benefit that clicking
00142          * outside of the bounds of the tree node, but still in the tree
00143          * column will select the row, whereas if this returned true
00144          * that wouldn't be the case.
00145          * <p>By returning false we are also enforcing the policy that
00146          * the tree will never be editable (at least by a key sequence).
00147          */
00148         public boolean isCellEditable(EventObject e) {
00149             if (e instanceof MouseEvent) {
00150                 for (int counter = getColumnCount() - 1; counter >= 0; counter--) {
00151                     if (getColumnClass(counter) == TreeTableModel.class) {
00152                         MouseEvent me = (MouseEvent) e;
00153                         MouseEvent newME = new MouseEvent(tree, me.getID(), me.getWhen(), me.getModifiers(), me.getX() - getCellRect(0, counter, true).x, me.getY(), me.getClickCount(), me.isPopupTrigger());
00154                         tree.dispatchEvent(newME);
00155                         break;
00156                     }
00157                 }
00158             }
00159             return false;
00160         }
00161     }
00162 
00163 
00164     /**
00165      * ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel
00166      * to listen for changes in the ListSelectionModel it maintains. Once
00167      * a change in the ListSelectionModel happens, the paths are updated
00168      * in the DefaultTreeSelectionModel.
00169      */
00170     class ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel {
00171         /** Set to true when we are updating the ListSelectionModel. */
00172         protected boolean updatingListSelectionModel;
00173         public ListToTreeSelectionModelWrapper() {
00174             super();
00175             getListSelectionModel().addListSelectionListener(createListSelectionListener());
00176         }
00177 
00178         /**
00179          * Returns the list selection model. ListToTreeSelectionModelWrapper
00180          * listens for changes to this model and updates the selected paths
00181          * accordingly.
00182          */
00183         ListSelectionModel getListSelectionModel() {
00184             return listSelectionModel;
00185         }
00186 
00187         /**
00188          * This is overridden to set <code>updatingListSelectionModel</code>
00189          * and message super. This is the only place DefaultTreeSelectionModel
00190          * alters the ListSelectionModel.
00191          */
00192         public void resetRowSelection() {
00193             if (!updatingListSelectionModel) {
00194                 updatingListSelectionModel = true;
00195                 try {
00196                     super.resetRowSelection();
00197                 } finally {
00198                     updatingListSelectionModel = false;
00199                 }
00200             }
00201             // Notice how we don't message super if
00202             // updatingListSelectionModel is true. If
00203             // updatingListSelectionModel is true, it implies the
00204             // ListSelectionModel has already been updated and the
00205             // paths are the only thing that needs to be updated.
00206         }
00207 
00208         /**
00209          * Creates and returns an instance of ListSelectionHandler.
00210          */
00211         protected ListSelectionListener createListSelectionListener() {
00212             return new ListSelectionHandler();
00213         }
00214 
00215         /**
00216          * If <code>updatingListSelectionModel</code> is false, this will
00217          * reset the selected paths from the selected rows in the list
00218          * selection model.
00219          */
00220         protected void updateSelectedPathsFromSelectedRows() {
00221             if (!updatingListSelectionModel) {
00222                 updatingListSelectionModel = true;
00223                 try {
00224                     // This is way expensive, ListSelectionModel needs an
00225                     // enumerator for iterating.
00226                     int min = listSelectionModel.getMinSelectionIndex();
00227                     int max = listSelectionModel.getMaxSelectionIndex();
00228                     clearSelection();
00229                     if (min != -1 && max != -1) {
00230                         for (int counter = min; counter <= max; counter++) {
00231                             if (listSelectionModel.isSelectedIndex(counter)) {
00232                                 TreePath selPath = tree.getPathForRow(counter);
00233                                 if (selPath != null) {
00234                                     addSelectionPath(selPath);
00235                                 }
00236                             }
00237                         }
00238                     }
00239                 } finally {
00240                     updatingListSelectionModel = false;
00241                 }
00242             }
00243         }
00244 
00245         /**
00246          * Class responsible for calling updateSelectedPathsFromSelectedRows
00247          * when the selection of the list changse.
00248          */
00249         class ListSelectionHandler implements ListSelectionListener {
00250             public void valueChanged(ListSelectionEvent e) {
00251                 updateSelectedPathsFromSelectedRows();
00252             }
00253         }
00254     }
00255 public JTreeTable(TreeTableModel treeTableModel) {
00256     super();
00257 
00258     // Create the tree. It will be used as a renderer and editor. 
00259     tree = new TreeTableCellRenderer(treeTableModel);
00260 
00261     // Install a tableModel representing the visible rows in the tree. 
00262     super.setModel(new TreeTableModelAdapter(treeTableModel, tree));
00263 
00264     // Force the JTable and JTree to share their row selection models. 
00265     ListToTreeSelectionModelWrapper selectionWrapper = new ListToTreeSelectionModelWrapper();
00266     tree.setSelectionModel(selectionWrapper);
00267     setSelectionModel(selectionWrapper.getListSelectionModel());
00268 
00269     // Install the tree editor renderer and editor. 
00270     setDefaultRenderer(TreeTableModel.class, tree);
00271     setDefaultEditor(TreeTableModel.class, new TreeTableCellEditor());
00272 
00273     // No grid.
00274     setShowGrid(true);
00275 
00276     // No intercell spacing
00277     setIntercellSpacing(new Dimension(1, 0));
00278 
00279     // And update the height of the trees row to match that of
00280     // the table.
00281     if (tree.getRowHeight() < 1) {
00282         // Metal looks better like this.
00283         setRowHeight(18);
00284     }
00285 }
00286 /**
00287  * Insert the method's description here.
00288  * Creation date: (3/24/00 12:20:36 AM)
00289  * @return javax.swing.table.TableCellRenderer
00290  * @param row int
00291  * @param column int
00292  */
00293 public TableCellEditor getCellEditor(int row, int column) {
00294     TableCellEditor editor;
00295     if (((TreeTableModelAdapter) getModel()).nodeForRow(row) instanceof TypeTreeNode)
00296         if ((editor = ((AbstractTreeNode) ((TreeTableModelAdapter) getModel()).nodeForRow(row)).getCellEditor(column)) == null)
00297             return super.getCellEditor(row, column);
00298         else
00299             return editor;
00300     else
00301         return super.getCellEditor(row, column);
00302     /*
00303     if (column == 2) {
00304     if (getValueAt(row, 0) != null)
00305     System.out.println(getValueAt(row, 0).getClass());
00306     System.out.print(((TreeTableModelAdapter) getModel()).nodeForRow(row).getClass() + "\t");
00307     System.out.print(absTable.get(getValueAt(row, column - 1)) + "\t");
00308     System.out.println(getValueAt(row, column - 1).getClass());
00309     TableCellEditor editor;
00310     if (((TreeTableModelAdapter) getModel()).nodeForRow(row) instanceof TypeTreeNode)
00311     if ((editor = ((TypeTreeNode) ((TreeTableModelAdapter) getModel()).nodeForRow(row)).getCellEditor(column)) == null)
00312     return super.getCellEditor(row, column);
00313     else
00314     return editor;
00315     else
00316     if (getValueAt(row, column) instanceof Boolean) {
00317     JCheckBox checkBox = new JCheckBox("Include", !((Boolean) getValueAt(row, column)).booleanValue());
00318     return new DefaultCellEditor(checkBox);
00319     }
00320     if (absTable.get(getValueAt(row, column - 1)) != null) {
00321     JComboBox comboBox = new JComboBox((Vector) absTable.get(getValueAt(row, column - 1)));
00322     comboBox.setSelectedItem(edu.ksu.cis.bandera.abps.lib.ConcreteIntAbstraction.v().getType());
00323     System.out.println("1");
00324     ////comboBox.setPopupVisible(true);
00325     return new DefaultCellEditor(comboBox);
00326     } else
00327     if (getValueAt(row, column - 1).getClass() == RefType.class) {
00328     JComboBox comboBox = new JComboBox();
00329     comboBox.addItem(ObjectAbstraction.v(AbstractRefType.v((RefType) getValueAt(row, column - 1))).getType());
00330     System.out.println("2");
00331     //comboBox.setPopupVisible(true);
00332     return new DefaultCellEditor(comboBox);
00333     } else
00334     if (getValueAt(row, column - 1).getClass() == AbstractRefType.class) {
00335     JComboBox comboBox = new JComboBox();
00336     comboBox.addItem(ObjectAbstraction.v((AbstractRefType) getValueAt(row, column - 1)).getType());
00337     System.out.println("3");
00338     //comboBox.setPopupVisible(true);
00339     return new DefaultCellEditor(comboBox);
00340     } else
00341     if (getValueAt(row, column - 1).getClass() == IntType.class) {
00342     JComboBox comboBox = new JComboBox();
00343     comboBox.addItem("4");
00344     comboBox.addItem(new Integer(3));
00345     comboBox.addItem("");
00346     comboBox.addItem("None");
00347     System.out.println("4");
00348     //comboBox.setPopupVisible(true);
00349     return new DefaultCellEditor(comboBox);
00350     }
00351     }
00352     System.out.println("Going to super editor:  " + getValueAt(row, column - 1).getClass());
00353     return super.getCellEditor(row, column);
00354     */
00355 }
00356 /**
00357  * Insert the method's description here.
00358  * Creation date: (3/24/00 12:20:36 AM)
00359  * @return javax.swing.table.TableCellRenderer
00360  * @param row int
00361  * @param column int
00362  */
00363 public TableCellRenderer getCellRenderer(int row, int column) {
00364     //  System.out.println("Renderer:  " + ((TreeTableModelAdapter) getModel()).nodeForRow(row).getClass() + "\t");
00365     //  System.out.println(getValueAt(row, column - 1).getClass());
00366     TableCellRenderer renderer;
00367     if (((TreeTableModelAdapter) getModel()).nodeForRow(row) instanceof TypeTreeNode) {
00368         renderer = ((AbstractTreeNode) ((TreeTableModelAdapter) getModel()).nodeForRow(row)).getCellRenderer(column);
00369         //      System.out.println("\t" + renderer);
00370         if (renderer == null)
00371             return super.getCellRenderer(row, column);
00372         else
00373             return renderer;
00374     } else
00375         return super.getCellRenderer(row, column);
00376     /*
00377     if (column == 2) {
00378     if (getValueAt(row, 0) != null)
00379     System.out.println(getValueAt(row, 0).getClass());
00380     System.out.print(((TreeTableModelAdapter) getModel()).nodeForRow(row).getClass() + "\t");
00381     System.out.print(absTable.get(getValueAt(row, column - 1)) + "\t");
00382     System.out.println(getValueAt(row, column - 1).getClass());
00383     TableCellEditor editor;
00384     if (((TreeTableModelAdapter) getModel()).nodeForRow(row) instanceof TypeTreeNode)
00385     if ((editor = ((TypeTreeNode) ((TreeTableModelAdapter) getModel()).nodeForRow(row)).getCellEditor(column)) == null)
00386     return super.getCellEditor(row, column);
00387     else
00388     return editor;
00389     else
00390     if (getValueAt(row, column) instanceof Boolean) {
00391     JCheckBox checkBox = new JCheckBox("Include", !((Boolean) getValueAt(row, column)).booleanValue());
00392     return new DefaultCellEditor(checkBox);
00393     }
00394     if (absTable.get(getValueAt(row, column - 1)) != null) {
00395     JComboBox comboBox = new JComboBox((Vector) absTable.get(getValueAt(row, column - 1)));
00396     comboBox.setSelectedItem(edu.ksu.cis.bandera.abps.lib.ConcreteIntAbstraction.v().getType());
00397     System.out.println("1");
00398     ////comboBox.setPopupVisible(true);
00399     return new DefaultCellEditor(comboBox);
00400     } else
00401     if (getValueAt(row, column - 1).getClass() == RefType.class) {
00402     JComboBox comboBox = new JComboBox();
00403     comboBox.addItem(ObjectAbstraction.v(AbstractRefType.v((RefType) getValueAt(row, column - 1))).getType());
00404     System.out.println("2");
00405     //comboBox.setPopupVisible(true);
00406     return new DefaultCellEditor(comboBox);
00407     } else
00408     if (getValueAt(row, column - 1).getClass() == AbstractRefType.class) {
00409     JComboBox comboBox = new JComboBox();
00410     comboBox.addItem(ObjectAbstraction.v((AbstractRefType) getValueAt(row, column - 1)).getType());
00411     System.out.println("3");
00412     //comboBox.setPopupVisible(true);
00413     return new DefaultCellEditor(comboBox);
00414     } else
00415     if (getValueAt(row, column - 1).getClass() == IntType.class) {
00416     JComboBox comboBox = new JComboBox();
00417     comboBox.addItem("4");
00418     comboBox.addItem(new Integer(3));
00419     comboBox.addItem("");
00420     comboBox.addItem("None");
00421     System.out.println("4");
00422     //comboBox.setPopupVisible(true);
00423     return new DefaultCellEditor(comboBox);
00424     }
00425     }
00426     System.out.println("Going to super editor:  " + getValueAt(row, column - 1).getClass());
00427     return super.getCellEditor(row, column);
00428     */
00429 }
00430 /* Workaround for BasicTableUI anomaly. Make sure the UI never tries to 
00431  * paint the editor. The UI currently uses different techniques to 
00432  * paint the renderers and editors and overriding setBounds() below 
00433  * is not the right thing to do for an editor. Returning -1 for the 
00434  * editing row in this case, ensures the editor is never painted. 
00435  */
00436 public int getEditingRow() {
00437     return (getColumnClass(editingColumn) == TreeTableModel.class) ? -1 : editingRow;
00438 }
00439 /**
00440  * Returns the tree that is being shared between the model.
00441  */
00442 public JTree getTree() {
00443     return tree;
00444 }
00445 /**
00446  * This method was created in VisualAge.
00447  * @param abs java.util.Collection
00448  */
00449 public static void processAbstractions(Collection abstractions) {
00450     absTable = new java.util.Hashtable();
00451     Type[] integralTypes = new Type[] {ByteType.v(), CharType.v(), ShortType.v(), IntType.v()};
00452     Type[] realTypes = new Type[] {FloatType.v(), DoubleType.v()};
00453     for (Iterator i = abstractions.iterator(); i.hasNext();) {
00454         try {
00455             String s = (String) i.next();
00456             Abstraction a = (Abstraction) AbstractionClassLoader.invokeMethod(s, "v", new Class[0], null, new Object[0]);
00457             for (int j = 0; (j < integralTypes.length) && (a instanceof IntegralAbstraction); j++) {
00458                 java.util.Vector abstractions2 = (java.util.Vector) absTable.get(integralTypes[j]);
00459                 if (abstractions2 == null) {
00460                     abstractions2 = new java.util.Vector();
00461                     abstractions2.addElement("No Selection");
00462                     absTable.put(integralTypes[j], abstractions2);
00463                 }
00464                 abstractions2.addElement(a);
00465             }
00466             for (int j = 0; (j < realTypes.length) && (a instanceof RealAbstraction); j++) {
00467                 java.util.Vector abstractions2 = (java.util.Vector) absTable.get(realTypes[j]);
00468                 if (abstractions2 == null) {
00469                     abstractions2 = new java.util.Vector();
00470                     abstractions2.addElement("No Selection");
00471                     absTable.put(realTypes[j], abstractions2);
00472                 }
00473                 abstractions2.addElement(a);
00474             }
00475         } catch (Exception e) {
00476         }
00477     }
00478 }
00479 /**
00480  * Overridden to pass the new rowHeight to the tree.
00481  */
00482 public void setRowHeight(int rowHeight) {
00483     super.setRowHeight(rowHeight);
00484     if (tree != null && tree.getRowHeight() != rowHeight) {
00485         tree.setRowHeight(getRowHeight());
00486     }
00487 }
00488 /**
00489  * Overridden to message super and forward the method to the tree.
00490  * Since the tree is not actually in the component hieachy it will
00491  * never receive this unless we forward it in this manner.
00492  */
00493 public void updateUI() {
00494     super.updateUI();
00495     if (tree != null) {
00496         tree.updateUI();
00497     }
00498     // Use the tree's default foreground and background colors in the
00499     // table. 
00500     LookAndFeel.installColorsAndFont(this, "Tree.background", "Tree.foreground", "Tree.font");
00501 }
00502 }

Generated at Thu Feb 7 06:49:02 2002 for Bandera by doxygen1.2.10 written by Dimitri van Heesch, © 1997-2001