// BlogBridge -- RSS feed reader, manager, and web based service // Copyright (C) 2002-2006 by R. Pito Salas // // This program is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free Software Foundation; // either version 2 of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along with this program; // if not, write to the Free Software Foundation, Inc., 59 Temple Place, // Suite 330, Boston, MA 02111-1307 USA // // Contact: R. Pito Salas // mailto:pitosalas@users.sourceforge.net // More information: about BlogBridge // http://www.blogbridge.com // http://sourceforge.net/projects/blogbridge // // $Id: TreeTableModelAdapter.java,v 1.5 2006/05/29 12:50:07 spyromus Exp $ // package com.salas.bb.utils.uif.treetable; import com.salas.bb.utils.i18n.Strings; import javax.swing.table.AbstractTableModel; import javax.swing.*; import javax.swing.tree.TreePath; import javax.swing.event.TreeExpansionListener; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeModelListener; import javax.swing.event.TreeModelEvent; import java.util.logging.Logger; import java.text.MessageFormat; /** * Adapter for tree table model. */ public class TreeTableModelAdapter extends AbstractTableModel implements TreeModelListener { private static final Logger LOG = Logger.getLogger(TreeTableModelAdapter.class.getName()); private JTree tree; private TreeTableModel model; /** * Creates adapater. * * @param aModel model to adopt. * @param aTree tree component model applied to. */ public TreeTableModelAdapter(TreeTableModel aModel, JTree aTree) { tree = aTree; model = aModel; model.addTreeModelListener(this); tree.addTreeExpansionListener(new TreeExpansionListener() { public void treeExpanded(TreeExpansionEvent event) { // Don't use fireTableRowsInserted() here; // the selection model would get updated twice. fireTableDataChanged(); } public void treeCollapsed(TreeExpansionEvent event) { fireTableDataChanged(); } }); } /** * Returns the number of columns in the model. A * <code>JTable</code> uses this method to determine how many columns it * should create and display by default. * * @return the number of columns in the model * @see #getRowCount */ public int getColumnCount() { return model.getColumnCount(); } /** * Returns a default name for the column using spreadsheet conventions: * A, B, C, ... Z, AA, AB, etc. If <code>column</code> cannot be found, * returns an empty string. * * @param column the column being queried. * * @return a string containing the default name of <code>column</code>. */ public String getColumnName(int column) { return model.getColumnName(column); } /** * Returns <code>Object.class</code> regardless of <code>columnIndex</code>. * * @param column the column being queried. * * @return the Object.class */ public Class getColumnClass(int column) { return model.getColumnClass(column); } /** * Returns the number of rows in the model. A <code>JTable</code> uses this method to * determine how many rows it should display. This method should be quick, as it * is called frequently during rendering. * * @return the number of rows in the model. * * @see #getColumnCount */ public int getRowCount() { return tree.getRowCount(); } /** * Returns the value for the cell at <code>columnIndex</code> and * <code>rowIndex</code>. * * @param row the row whose value is to be queried. * @param column the column whose value is to be queried. * * @return the value Object at the specified cell. */ public Object getValueAt(int row, int column) { return model.getValueAt(nodeForRow(row), column); } /** * Returns TRUE if the cell is editable. * * @param row the row being queried. * @param column the column being queried. * * @return TRUE if the cell is editable. */ public boolean isCellEditable(int row, int column) { return model.isCellEditable(nodeForRow(row), column); } /** * This empty implementation is provided so users don't have to implement * this method if their data model is not editable. * * @param value value to assign to cell. * @param row row of cell. * @param column column of cell. */ public void setValueAt(Object value, int row, int column) { model.setValueAt(value, nodeForRow(row), column); } /** * Returns node for a given row specified by index. * * @param row row index. * * @return node. */ private Object nodeForRow(int row) { TreePath treePath = tree.getPathForRow(row); if (treePath == null) LOG.warning(MessageFormat.format(Strings.error("no.path.for.row"), new Object[] { new Integer(row) })); return treePath == null ? null : treePath.getLastPathComponent(); } /** * <p>Invoked after a node (or a set of siblings) has changed in some way. The node(s) have not * changed locations in the tree or altered their children arrays, but other attributes have * changed and may affect presentation. Example: the name of a file has changed, but it is in * the same location in the file system.</p> <p>To indicate the root has changed, childIndices * and children will be null. </p> * <p/> * <p>Use <code>e.getPath()</code> to get the parent of the changed node(s). * <code>e.getChildIndices()</code> returns the index(es) of the changed node(s).</p> */ public void treeNodesChanged(TreeModelEvent e) { TreePath treePath = e.getTreePath(); if (tree.isExpanded(treePath)) { int row = tree.getRowForPath(treePath) + e.getChildIndices()[0] + 1; fireTableRowsUpdated(row, row); } } /** * <p>Invoked after nodes have been inserted into the tree.</p> * <p/> * <p>Use <code>e.getPath()</code> to get the parent of the new node(s). * <code>e.getChildIndices()</code> returns the index(es) of the new node(s) in ascending * order.</p> */ public void treeNodesInserted(TreeModelEvent e) { TreePath treePath = e.getTreePath(); if (tree.isExpanded(treePath)) { int row = tree.getRowForPath(treePath) + e.getChildIndices()[0]; fireTableRowsInserted(row, row); } } /** * <p>Invoked after nodes have been removed from the tree. Note that if a subtree is removed * from the tree, this method may only be invoked once for the root of the removed subtree, not * once for each individual set of siblings removed.</p> * <p/> * <p>Use <code>e.getPath()</code> to get the former parent of the deleted node(s). * <code>e.getChildIndices()</code> returns, in ascending order, the index(es) the node(s) had * before being deleted.</p> */ public void treeNodesRemoved(TreeModelEvent e) { TreePath treePath = e.getTreePath(); if (tree.isExpanded(treePath)) { int row = tree.getRowForPath(treePath) + e.getChildIndices()[0]; fireTableRowsDeleted(row, row); } } /** * <p>Invoked after the tree has drastically changed structure from a given node down. If the * path returned by e.getPath() is of length one and the first element does not identify the * current root node the first element should become the new root of the tree.<p> * <p/> * <p>Use <code>e.getPath()</code> to get the path to the node. <code>e.getChildIndices()</code> * returns null.</p> */ public void treeStructureChanged(TreeModelEvent e) { } }