|
JTreeTable |
|
1 /* 2 * Copyright (c) 1998-2001, The University of Sheffield. 3 * 4 * This file is part of GATE (see http://gate.ac.uk/), and is free 5 * software, licenced under the GNU Library General Public License, 6 * Version 2, June 1991 (in the distribution as file licence.html, 7 * and also available at http://gate.ac.uk/gate/licence.html). 8 * 9 * Valentin Tablan 06/03/2001 10 * 11 * $Id: JTreeTable.java,v 1.7 2001/07/16 13:20:57 valyt Exp $ 12 * 13 */ 14 package gate.swing; 15 16 import javax.swing.*; 17 import javax.swing.event.*; 18 import javax.swing.tree.*; 19 import javax.swing.table.*; 20 import javax.swing.event.TreeExpansionEvent; 21 import javax.swing.event.TreeExpansionListener; 22 23 24 import java.awt.Dimension; 25 import java.awt.Component; 26 import java.awt.Graphics; 27 import java.awt.Rectangle; 28 import java.awt.Color; 29 import java.awt.image.BufferedImage; 30 import java.awt.event.*; 31 import java.util.EventObject; 32 33 import java.beans.*; 34 35 36 /** 37 * A TreeTable component. That is a component that looks like a table apart 38 * from the first column that contains a tree. 39 */ 40 public class JTreeTable extends XJTable { 41 42 /**The tree used to render the first column*/ 43 protected CustomJTree tree; 44 45 /**The model for this component*/ 46 protected TreeTableModel treeTableModel; 47 48 /** 49 * Constructs a JTreeTable from a model 50 */ 51 public JTreeTable(TreeTableModel model) { 52 super(); 53 this.treeTableModel = model; 54 55 initLocalData(); 56 initGuiComponents(); 57 initListeners(); 58 59 super.setSortable(false); 60 } 61 62 protected void initLocalData(){ 63 } 64 65 protected void initGuiComponents(){ 66 // Create the tree. It will be used by the table renderer to draw the cells 67 //in the first column 68 tree = new CustomJTree(); 69 tree.setModel(treeTableModel); 70 tree.setEditable(false); 71 72 // Install a tableModel representing the visible rows in the tree. 73 super.setModel(new TreeTableModelAdapter(treeTableModel)); 74 75 // Force the JTable and JTree to share their row selection models. 76 tree.setSelectionModel(new DefaultTreeSelectionModel() { 77 //extend the constructor 78 { 79 setSelectionModel(listSelectionModel); 80 } 81 }); 82 83 setAutoCreateColumnsFromModel(false); 84 //Install the renderer and editor 85 getColumnModel().getColumn(0).setCellRenderer(new TreeTableCellRenderer()); 86 getColumnModel().getColumn(0).setCellEditor(new TreeTableCellEditor()); 87 88 setShowGrid(false); 89 } 90 91 protected void initListeners(){ 92 //install the mouse listener that will forward the mouse events to the tree 93 addMouseListener(new MouseHandler()); 94 95 getColumnModel().getColumn(0).addPropertyChangeListener(new PropertyChangeListener() { 96 public void propertyChange(PropertyChangeEvent e) { 97 if(e.getPropertyName().equals("width")){ 98 int width = ((Number)e.getNewValue()).intValue(); 99 int height = tree.getSize().height; 100 tree.setSize(width, height); 101 } 102 } 103 }); 104 } 105 106 /** 107 * Overrides the setSortable() method from {@link XJTable} so the table is NOT 108 * sortable. In a tree-table component the ordering for the rows is given by 109 * the structure of the tree and they cannot be reordered. 110 */ 111 public void setSortable(boolean b){ 112 throw new UnsupportedOperationException( 113 "A JTreeTable component cannot be sortable!\n" + 114 "The rows order is defined by the tree structure."); 115 } 116 117 public JTree getTree(){ 118 return tree; 119 } 120 121 public void expandPath(TreePath path){ 122 tree.expandPath(path); 123 } 124 125 public void expandRow(int row){ 126 tree.expandRow(row); 127 } 128 129 /** 130 * The renderer used to display the table cells containing tree nodes. 131 * Will use an internal JTree object to paint the nodes. 132 */ 133 public class TreeTableCellRenderer extends DefaultTableCellRenderer { 134 public Component getTableCellRendererComponent(JTable table, 135 Object value, 136 boolean isSelected, 137 boolean hasFocus, 138 int row, int column) { 139 tree.setVisibleRow(row); 140 return tree; 141 } 142 }//public class TreeTableCellRenderer extends DefaultTableCellRenderer 143 144 /** 145 * The editor used to edit the nodes in the tree. It only forwards the 146 * requests to the tree's editor. 147 */ 148 class TreeTableCellEditor extends DefaultCellEditor 149 implements TableCellEditor { 150 TreeTableCellEditor(){ 151 super(new JTextField()); 152 //placeHolder = new PlaceHolder(); 153 editor = tree.getCellEditor(); 154 setClickCountToStart(0); 155 } 156 157 public Component getTableCellEditorComponent(JTable table, 158 Object value, 159 boolean isSelected, 160 int row, 161 int column) { 162 163 editor = tree.getCellEditor(); 164 165 editor.addCellEditorListener(new CellEditorListener() { 166 public void editingStopped(ChangeEvent e) { 167 fireEditingStopped(); 168 } 169 170 public void editingCanceled(ChangeEvent e) { 171 fireEditingCanceled(); 172 } 173 }); 174 175 editorComponent = editor.getTreeCellEditorComponent( 176 tree, tree.getPathForRow(row).getLastPathComponent(), 177 isSelected, tree.isExpanded(row), 178 tree.getModel().isLeaf( 179 tree.getPathForRow(row).getLastPathComponent() 180 ), 181 row); 182 Box box = Box.createHorizontalBox(); 183 box.add(Box.createHorizontalStrut(tree.getRowBounds(row).x)); 184 box.add(editorComponent); 185 return box; 186 // return editorComponent; 187 } 188 189 public Object getCellEditorValue() { 190 return editor == null ? null : editor.getCellEditorValue(); 191 } 192 193 public boolean stopCellEditing(){ 194 return editor == null ? true : editor.stopCellEditing(); 195 } 196 197 public void cancelCellEditing(){ 198 if(editor != null) editor.cancelCellEditing(); 199 } 200 201 TreeCellEditor editor; 202 Component editorComponent; 203 } 204 205 /** 206 * Class used to convert the mouse events from the JTreeTable component space 207 * into the JTree space. It is used to forward the mouse events to the tree 208 * if they occured in the space used by the tree. 209 */ 210 class MouseHandler extends MouseAdapter { 211 public void mousePressed(MouseEvent e) { 212 if(columnAtPoint(e.getPoint()) == 0){ 213 tree.dispatchEvent(convertEvent(e)); 214 } 215 } 216 217 public void mouseReleased(MouseEvent e) { 218 if(columnAtPoint(e.getPoint()) == 0){ 219 tree.dispatchEvent(convertEvent(e)); 220 } 221 } 222 223 public void mouseClicked(MouseEvent e) { 224 if(columnAtPoint(e.getPoint()) == 0){ 225 tree.dispatchEvent(convertEvent(e)); 226 } 227 } 228 229 230 public void mouseEntered(MouseEvent e) { 231 if(columnAtPoint(e.getPoint()) == 0){ 232 tree.dispatchEvent(convertEvent(e)); 233 } 234 } 235 236 public void mouseExited(MouseEvent e) { 237 if(columnAtPoint(e.getPoint()) == 0){ 238 tree.dispatchEvent(convertEvent(e)); 239 } 240 } 241 242 protected MouseEvent convertEvent(MouseEvent e){ 243 int column = 0; 244 int row = rowAtPoint(e.getPoint()); 245 246 //move the event from table to tree coordinates 247 Rectangle tableCellRect = getCellRect(row, column, false); 248 Rectangle treeCellRect = tree.getRowBounds(row); 249 int dx = 0; 250 if(tableCellRect != null) dx = -tableCellRect.x; 251 int dy = 0; 252 if(tableCellRect !=null && treeCellRect != null) 253 dy = treeCellRect.y -tableCellRect.y; 254 e.translatePoint(dx, dy); 255 256 257 return new MouseEvent( 258 tree, e.getID(), e.getWhen(), e.getModifiers(), 259 e.getX(), e.getY(), e.getClickCount(), e.isPopupTrigger() 260 ); 261 } 262 } 263 264 /** 265 * A wrapper that reads a TreeTableModel and behaves as a TableModel 266 */ 267 class TreeTableModelAdapter extends AbstractTableModel{ 268 public TreeTableModelAdapter(TreeTableModel treeTableModel) { 269 tree.addTreeExpansionListener(new TreeExpansionListener() { 270 // Don't use fireTableRowsInserted() here; 271 // the selection model would get updated twice. 272 public void treeExpanded(TreeExpansionEvent event) { 273 fireTableDataChanged(); 274 } 275 public void treeCollapsed(TreeExpansionEvent event) { 276 fireTableDataChanged(); 277 } 278 }); 279 tree.getModel().addTreeModelListener(new TreeModelListener() { 280 public void treeNodesChanged(TreeModelEvent e) { 281 fireTableDataChanged(); 282 } 283 public void treeNodesInserted(TreeModelEvent e) { 284 fireTableDataChanged(); 285 } 286 public void treeNodesRemoved(TreeModelEvent e) { 287 fireTableDataChanged(); 288 } 289 public void treeStructureChanged(TreeModelEvent e) { 290 fireTableDataChanged(); 291 } 292 }); 293 } 294 295 296 297 // Wrappers, implementing TableModel interface. 298 public int getColumnCount() { 299 return treeTableModel.getColumnCount(); 300 } 301 302 public String getColumnName(int column) { 303 return treeTableModel.getColumnName(column); 304 } 305 306 public Class getColumnClass(int column) { 307 if(column == 0) return TreeTableModel.class; 308 else return treeTableModel.getColumnClass(column); 309 } 310 311 public int getRowCount() { 312 return tree.getRowCount(); 313 } 314 315 protected Object nodeForRow(int row) { 316 TreePath treePath = tree.getPathForRow(row); 317 return treePath.getLastPathComponent(); 318 } 319 320 public Object getValueAt(int row, int column) { 321 if(column == 0) return treeTableModel; 322 else return treeTableModel.getValueAt(nodeForRow(row), column); 323 } 324 325 public boolean isCellEditable(int row, int column) { 326 return treeTableModel.isCellEditable(nodeForRow(row), column); 327 } 328 329 public void setValueAt(Object value, int row, int column) { 330 Object node = nodeForRow(row); 331 treeTableModel.setValueAt(value, node, column); 332 } 333 }//class TreeTableModelAdapter extends AbstractTableModel 334 335 /** 336 * The JTree used for rendering the first column. 337 */ 338 class CustomJTree extends JTree { 339 340 public void updateUI(){ 341 super.updateUI(); 342 setRowHeight(0); 343 } 344 345 346 public void setVisibleRow(int row){ 347 visibleRow = row; 348 } 349 350 /** 351 * Paints only the current cell in the table 352 */ 353 public void paint(Graphics g){ 354 Rectangle rect = getRowBounds(visibleRow); 355 Rectangle bounds = g.getClipBounds(); 356 g.translate(0, -rect.y); 357 g.setClip(bounds.x, rect.y, bounds.width, rect.height); 358 super.paint(g); 359 } 360 361 362 public Dimension getPreferredSize(){ 363 return new Dimension(super.getPreferredSize().width, 364 getRowBounds(visibleRow).height); 365 } 366 367 368 public void validate(){} 369 public void revalidate(){} 370 public void repaint(long tm, int x, int y, int width, int height){} 371 public void repaint(Rectangle r){} 372 373 protected int visibleRow; 374 } 375 376 /* 377 class SmartTreeCellRenderer implements TreeCellRenderer{ 378 379 SmartTreeCellRenderer(TreeCellRenderer renderer){ 380 originalRenderer = renderer; 381 } 382 383 public Component getTreeCellRendererComponent(JTree tree, 384 Object value, 385 boolean selected, 386 boolean expanded, 387 boolean leaf, 388 int row, 389 boolean hasFocus){ 390 Component comp = originalRenderer.getTreeCellRendererComponent( 391 tree, value, selected, expanded, leaf, row, hasFocus); 392 if(comp instanceof JComponent && 393 comp.getPreferredSize().height < getRowHeight(row)){ 394 ((JComponent)comp).setPreferredSize( 395 new Dimension(comp.getPreferredSize().width, 396 getRowHeight(row)) 397 ); 398 } 399 return comp; 400 } 401 402 public TreeCellRenderer getOriginalRenderer(){ 403 return originalRenderer; 404 } 405 406 TreeCellRenderer originalRenderer; 407 } 408 */ 409 }//public class JTreeTable extends XJTable 410
|
JTreeTable |
|