001: /**
002: * ========================================
003: * JFreeReport : a free Java report library
004: * ========================================
005: *
006: * Project Info: http://reporting.pentaho.org/
007: *
008: * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors.
009: *
010: * This library is free software; you can redistribute it and/or modify it under the terms
011: * of the GNU Lesser General Public License as published by the Free Software Foundation;
012: * either version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015: * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: * See the GNU Lesser General Public License for more details.
017: *
018: * You should have received a copy of the GNU Lesser General Public License along with this
019: * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020: * Boston, MA 02111-1307, USA.
021: *
022: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023: * in the United States and other countries.]
024: *
025: * ------------
026: * $Id: SubSetTableModel.java 3048 2007-07-28 18:02:42Z tmorgner $
027: * ------------
028: * (C) Copyright 2000-2005, by Object Refinery Limited.
029: * (C) Copyright 2005-2007, by Pentaho Corporation.
030: */package org.jfree.report.modules.misc.tablemodel;
031:
032: import java.util.ArrayList;
033: import javax.swing.event.TableModelEvent;
034: import javax.swing.event.TableModelListener;
035: import javax.swing.table.TableModel;
036:
037: /**
038: * A TableModel that proxies an other tablemodel and cuts rows from the start and/or the
039: * end of the other tablemodel.
040: *
041: * @author Thomas Morgner
042: */
043: public class SubSetTableModel implements TableModel {
044: /**
045: * A helper class, that translates tableevents received from the wrapped table model and
046: * forwards them with changed indices to the registered listeners.
047: */
048: private final class TableEventTranslator implements
049: TableModelListener {
050: /**
051: * the registered listeners.
052: */
053: private final ArrayList listeners;
054:
055: /**
056: * Default Constructor.
057: */
058: private TableEventTranslator() {
059: listeners = new ArrayList();
060: }
061:
062: /**
063: * This fine grain notification tells listeners the exact range of cells, rows, or
064: * columns that changed. The received rows are translated to fit the external
065: * tablemodel size.
066: *
067: * @param e the event, that should be translated.
068: */
069: public void tableChanged(final TableModelEvent e) {
070: int firstRow = e.getFirstRow();
071: if (e.getFirstRow() > 0) {
072: firstRow -= getStart();
073: }
074:
075: int lastRow = e.getLastRow();
076: if (lastRow > 0) {
077: lastRow -= getStart();
078: lastRow -= (getEnclosedModel().getRowCount() - getEnd());
079: }
080: final int type = e.getType();
081: final int column = e.getColumn();
082:
083: final TableModelEvent event = new TableModelEvent(
084: SubSetTableModel.this , firstRow, lastRow, column,
085: type);
086:
087: for (int i = 0; i < listeners.size(); i++) {
088: final TableModelListener l = (TableModelListener) listeners
089: .get(i);
090: l.tableChanged(event);
091: }
092: }
093:
094: /**
095: * Adds the TableModelListener to this Translator.
096: *
097: * @param l the tablemodel listener
098: */
099: protected void addTableModelListener(final TableModelListener l) {
100: listeners.add(l);
101: }
102:
103: /**
104: * Removes the TableModelListener from this Translator.
105: *
106: * @param l the tablemodel listener
107: */
108: protected void removeTableModelListener(
109: final TableModelListener l) {
110: listeners.remove(l);
111: }
112: }
113:
114: /**
115: * the row that should be the first row.
116: */
117: private int start;
118:
119: /**
120: * the row that should be the last row.
121: */
122: private int end;
123:
124: /**
125: * the model.
126: */
127: private TableModel model;
128:
129: /**
130: * the event translator.
131: */
132: private TableEventTranslator eventHandler;
133:
134: /**
135: * Creates a new SubSetTableModel, the start and the end parameters define the new
136: * tablemodel row count. The parameter <code>start</code> must be a positive integer and
137: * denotes the number or rows removed from the start of the tablemodel. <code>end</code>
138: * is the number of the last translated row. Any row after <code>end</code> is ignored.
139: * End must be greater or equal the given start row.
140: *
141: * @param start the number of rows that should be removed.
142: * @param end the last row.
143: * @param model the wrapped model
144: * @throws NullPointerException if the given model is null
145: * @throws IllegalArgumentException if start or end are invalid.
146: */
147: public SubSetTableModel(final int start, final int end,
148: final TableModel model) {
149: if (start < 0) {
150: throw new IllegalArgumentException("Start < 0");
151: }
152: if (end <= start) {
153: throw new IllegalArgumentException("end < start");
154: }
155: if (model == null) {
156: throw new NullPointerException();
157: }
158: if (end >= model.getRowCount()) {
159: throw new IllegalArgumentException("End >= Model.RowCount");
160: }
161:
162: this .start = start;
163: this .end = end;
164: this .model = model;
165: this .eventHandler = new TableEventTranslator();
166: }
167:
168: /**
169: * Translates the given row to fit for the wrapped tablemodel.
170: *
171: * @param rowIndex the original row index.
172: * @return the translated row index.
173: */
174: private int getClientRowIndex(final int rowIndex) {
175: return rowIndex + start;
176: }
177:
178: /**
179: * Returns the number of rows in the model. A <code>JTable</code> uses this method to
180: * determine how many rows it should display. This method should be quick, as it is
181: * called frequently during rendering.
182: *
183: * @return the number of rows in the model
184: *
185: * @see #getColumnCount
186: */
187: public int getRowCount() {
188: final int rowCount = model.getRowCount();
189: return rowCount - start - (rowCount - end);
190: }
191:
192: /**
193: * Returns the number of columns in the model. A <code>JTable</code> uses this method to
194: * determine how many columns it should create and display by default.
195: *
196: * @return the number of columns in the model
197: *
198: * @see #getRowCount
199: */
200: public int getColumnCount() {
201: return model.getColumnCount();
202: }
203:
204: /**
205: * Returns the name of the column at <code>columnIndex</code>. This is used to
206: * initialize the table's column header name. Note: this name does not need to be
207: * unique; two columns in a table can have the same name.
208: *
209: * @param columnIndex the index of the column
210: * @return the name of the column
211: */
212: public String getColumnName(final int columnIndex) {
213: return model.getColumnName(columnIndex);
214: }
215:
216: /**
217: * Returns the most specific superclass for all the cell values in the column. This is
218: * used by the <code>JTable</code> to set up a default renderer and editor for the
219: * column.
220: *
221: * @param columnIndex the index of the column
222: * @return the base ancestor class of the object values in the model.
223: */
224: public Class getColumnClass(final int columnIndex) {
225: return model.getColumnClass(columnIndex);
226: }
227:
228: /**
229: * Returns true if the cell at <code>rowIndex</code> and <code>columnIndex</code> is
230: * editable. Otherwise, <code>setValueAt</code> on the cell will not change the value
231: * of that cell.
232: *
233: * @param rowIndex the row whose value to be queried
234: * @param columnIndex the column whose value to be queried
235: * @return true if the cell is editable
236: *
237: * @see #setValueAt
238: */
239: public boolean isCellEditable(final int rowIndex,
240: final int columnIndex) {
241: return model.isCellEditable(getClientRowIndex(rowIndex),
242: columnIndex);
243: }
244:
245: /**
246: * Returns the value for the cell at <code>columnIndex</code> and
247: * <code>rowIndex</code>.
248: *
249: * @param rowIndex the row whose value is to be queried
250: * @param columnIndex the column whose value is to be queried
251: * @return the value Object at the specified cell
252: */
253: public Object getValueAt(final int rowIndex, final int columnIndex) {
254: return model.getValueAt(getClientRowIndex(rowIndex),
255: columnIndex);
256: }
257:
258: /**
259: * Sets the value in the cell at <code>columnIndex</code> and <code>rowIndex</code> to
260: * <code>aValue</code>.
261: *
262: * @param aValue the new value
263: * @param rowIndex the row whose value is to be changed
264: * @param columnIndex the column whose value is to be changed
265: * @see #getValueAt
266: * @see #isCellEditable
267: */
268: public void setValueAt(final Object aValue, final int rowIndex,
269: final int columnIndex) {
270: model.setValueAt(aValue, getClientRowIndex(rowIndex),
271: columnIndex);
272: }
273:
274: /**
275: * Adds a listener to the list that is notified each time a change to the data model
276: * occurs.
277: *
278: * @param l the TableModelListener
279: */
280: public void addTableModelListener(final TableModelListener l) {
281: eventHandler.addTableModelListener(l);
282: }
283:
284: /**
285: * Removes a listener from the list that is notified each time a change to the data
286: * model occurs.
287: *
288: * @param l the TableModelListener
289: */
290: public void removeTableModelListener(final TableModelListener l) {
291: eventHandler.removeTableModelListener(l);
292: }
293:
294: /**
295: * Returns the enclosed tablemodel, which is wrapped by this subset table model.
296: *
297: * @return the enclosed table model, never null.
298: */
299: protected TableModel getEnclosedModel() {
300: return model;
301: }
302:
303: /**
304: * Returns the start row that should be mapped to row 0 of this model.
305: *
306: * @return the first row that should be visible.
307: */
308: protected int getStart() {
309: return start;
310: }
311:
312: /**
313: * Returns the last row that should be visible.
314: *
315: * @return the number of the last row.
316: */
317: protected int getEnd() {
318: return end;
319: }
320: }
|