Frames | No Frames |
1: /** 2: * ======================================== 3: * JFreeReport : a free Java report library 4: * ======================================== 5: * 6: * Project Info: http://reporting.pentaho.org/ 7: * 8: * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors. 9: * 10: * This library is free software; you can redistribute it and/or modify it under the terms 11: * of the GNU Lesser General Public License as published by the Free Software Foundation; 12: * either version 2.1 of the License, or (at your option) any later version. 13: * 14: * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 15: * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 16: * See the GNU Lesser General Public License for more details. 17: * 18: * You should have received a copy of the GNU Lesser General Public License along with this 19: * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, 20: * Boston, MA 02111-1307, USA. 21: * 22: * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 23: * in the United States and other countries.] 24: * 25: * ------------ 26: * $Id: SubSetTableModel.java 2725 2007-04-01 18:49:29Z taqua $ 27: * ------------ 28: * (C) Copyright 2000-2005, by Object Refinery Limited. 29: * (C) Copyright 2005-2007, by Pentaho Corporation. 30: */ 31: 32: package org.jfree.report.modules.misc.tablemodel; 33: 34: import java.util.ArrayList; 35: import javax.swing.event.TableModelEvent; 36: import javax.swing.event.TableModelListener; 37: import javax.swing.table.TableModel; 38: 39: /** 40: * A TableModel that proxies an other tablemodel and cuts rows from the start and/or the 41: * end of the other tablemodel. 42: * 43: * @author Thomas Morgner 44: */ 45: public class SubSetTableModel implements TableModel 46: { 47: /** 48: * A helper class, that translates tableevents received from the wrapped table model and 49: * forwards them with changed indices to the registered listeners. 50: */ 51: private final class TableEventTranslator implements TableModelListener 52: { 53: /** 54: * the registered listeners. 55: */ 56: private final ArrayList listeners; 57: 58: /** 59: * Default Constructor. 60: */ 61: private TableEventTranslator () 62: { 63: listeners = new ArrayList(); 64: } 65: 66: /** 67: * This fine grain notification tells listeners the exact range of cells, rows, or 68: * columns that changed. The received rows are translated to fit the external 69: * tablemodel size. 70: * 71: * @param e the event, that should be translated. 72: */ 73: public void tableChanged (final TableModelEvent e) 74: { 75: int firstRow = e.getFirstRow(); 76: if (e.getFirstRow() > 0) 77: { 78: firstRow -= getStart(); 79: } 80: 81: int lastRow = e.getLastRow(); 82: if (lastRow > 0) 83: { 84: lastRow -= getStart(); 85: lastRow -= (getEnclosedModel().getRowCount() - getEnd()); 86: } 87: final int type = e.getType(); 88: final int column = e.getColumn(); 89: 90: final TableModelEvent event = 91: new TableModelEvent(SubSetTableModel.this, firstRow, lastRow, column, type); 92: 93: for (int i = 0; i < listeners.size(); i++) 94: { 95: final TableModelListener l = (TableModelListener) listeners.get(i); 96: l.tableChanged(event); 97: } 98: } 99: 100: /** 101: * Adds the TableModelListener to this Translator. 102: * 103: * @param l the tablemodel listener 104: */ 105: protected void addTableModelListener (final TableModelListener l) 106: { 107: listeners.add(l); 108: } 109: 110: /** 111: * Removes the TableModelListener from this Translator. 112: * 113: * @param l the tablemodel listener 114: */ 115: protected void removeTableModelListener (final TableModelListener l) 116: { 117: listeners.remove(l); 118: } 119: } 120: 121: /** 122: * the row that should be the first row. 123: */ 124: private int start; 125: 126: /** 127: * the row that should be the last row. 128: */ 129: private int end; 130: 131: /** 132: * the model. 133: */ 134: private TableModel model; 135: 136: /** 137: * the event translator. 138: */ 139: private TableEventTranslator eventHandler; 140: 141: /** 142: * Creates a new SubSetTableModel, the start and the end parameters define the new 143: * tablemodel row count. The parameter <code>start</code> must be a positive integer and 144: * denotes the number or rows removed from the start of the tablemodel. <code>end</code> 145: * is the number of the last translated row. Any row after <code>end</code> is ignored. 146: * End must be greater or equal the given start row. 147: * 148: * @param start the number of rows that should be removed. 149: * @param end the last row. 150: * @param model the wrapped model 151: * @throws NullPointerException if the given model is null 152: * @throws IllegalArgumentException if start or end are invalid. 153: */ 154: public SubSetTableModel (final int start, final int end, final TableModel model) 155: { 156: if (start < 0) 157: { 158: throw new IllegalArgumentException("Start < 0"); 159: } 160: if (end <= start) 161: { 162: throw new IllegalArgumentException("end < start"); 163: } 164: if (model == null) 165: { 166: throw new NullPointerException(); 167: } 168: if (end >= model.getRowCount()) 169: { 170: throw new IllegalArgumentException("End >= Model.RowCount"); 171: } 172: 173: this.start = start; 174: this.end = end; 175: this.model = model; 176: this.eventHandler = new TableEventTranslator(); 177: } 178: 179: /** 180: * Translates the given row to fit for the wrapped tablemodel. 181: * 182: * @param rowIndex the original row index. 183: * @return the translated row index. 184: */ 185: private int getClientRowIndex (final int rowIndex) 186: { 187: return rowIndex + start; 188: } 189: 190: /** 191: * Returns the number of rows in the model. A <code>JTable</code> uses this method to 192: * determine how many rows it should display. This method should be quick, as it is 193: * called frequently during rendering. 194: * 195: * @return the number of rows in the model 196: * 197: * @see #getColumnCount 198: */ 199: public int getRowCount () 200: { 201: final int rowCount = model.getRowCount(); 202: return rowCount - start - (rowCount - end); 203: } 204: 205: /** 206: * Returns the number of columns in the model. A <code>JTable</code> uses this method to 207: * determine how many columns it should create and display by default. 208: * 209: * @return the number of columns in the model 210: * 211: * @see #getRowCount 212: */ 213: public int getColumnCount () 214: { 215: return model.getColumnCount(); 216: } 217: 218: /** 219: * Returns the name of the column at <code>columnIndex</code>. This is used to 220: * initialize the table's column header name. Note: this name does not need to be 221: * unique; two columns in a table can have the same name. 222: * 223: * @param columnIndex the index of the column 224: * @return the name of the column 225: */ 226: public String getColumnName (final int columnIndex) 227: { 228: return model.getColumnName(columnIndex); 229: } 230: 231: /** 232: * Returns the most specific superclass for all the cell values in the column. This is 233: * used by the <code>JTable</code> to set up a default renderer and editor for the 234: * column. 235: * 236: * @param columnIndex the index of the column 237: * @return the base ancestor class of the object values in the model. 238: */ 239: public Class getColumnClass (final int columnIndex) 240: { 241: return model.getColumnClass(columnIndex); 242: } 243: 244: /** 245: * Returns true if the cell at <code>rowIndex</code> and <code>columnIndex</code> is 246: * editable. Otherwise, <code>setValueAt</code> on the cell will not change the value 247: * of that cell. 248: * 249: * @param rowIndex the row whose value to be queried 250: * @param columnIndex the column whose value to be queried 251: * @return true if the cell is editable 252: * 253: * @see #setValueAt 254: */ 255: public boolean isCellEditable (final int rowIndex, final int columnIndex) 256: { 257: return model.isCellEditable(getClientRowIndex(rowIndex), columnIndex); 258: } 259: 260: /** 261: * Returns the value for the cell at <code>columnIndex</code> and 262: * <code>rowIndex</code>. 263: * 264: * @param rowIndex the row whose value is to be queried 265: * @param columnIndex the column whose value is to be queried 266: * @return the value Object at the specified cell 267: */ 268: public Object getValueAt (final int rowIndex, final int columnIndex) 269: { 270: return model.getValueAt(getClientRowIndex(rowIndex), columnIndex); 271: } 272: 273: /** 274: * Sets the value in the cell at <code>columnIndex</code> and <code>rowIndex</code> to 275: * <code>aValue</code>. 276: * 277: * @param aValue the new value 278: * @param rowIndex the row whose value is to be changed 279: * @param columnIndex the column whose value is to be changed 280: * @see #getValueAt 281: * @see #isCellEditable 282: */ 283: public void setValueAt (final Object aValue, final int rowIndex, final int columnIndex) 284: { 285: model.setValueAt(aValue, getClientRowIndex(rowIndex), columnIndex); 286: } 287: 288: /** 289: * Adds a listener to the list that is notified each time a change to the data model 290: * occurs. 291: * 292: * @param l the TableModelListener 293: */ 294: public void addTableModelListener (final TableModelListener l) 295: { 296: eventHandler.addTableModelListener(l); 297: } 298: 299: /** 300: * Removes a listener from the list that is notified each time a change to the data 301: * model occurs. 302: * 303: * @param l the TableModelListener 304: */ 305: public void removeTableModelListener (final TableModelListener l) 306: { 307: eventHandler.removeTableModelListener(l); 308: } 309: 310: /** 311: * Returns the enclosed tablemodel, which is wrapped by this subset table model. 312: * 313: * @return the enclosed table model, never null. 314: */ 315: protected TableModel getEnclosedModel () 316: { 317: return model; 318: } 319: 320: /** 321: * Returns the start row that should be mapped to row 0 of this model. 322: * 323: * @return the first row that should be visible. 324: */ 325: protected int getStart () 326: { 327: return start; 328: } 329: 330: /** 331: * Returns the last row that should be visible. 332: * 333: * @return the number of the last row. 334: */ 335: protected int getEnd () 336: { 337: return end; 338: } 339: }