package org.pentaho.reporting.libraries.designtime.swing.table; import javax.swing.event.EventListenerList; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.TableModel; public abstract class RowMapperTableModel implements TableModel { private class EventForwardHandler implements TableModelListener { private EventForwardHandler() { } public void tableChanged( final TableModelEvent e ) { recomputeRowCount(); if ( e.getFirstRow() == 0 && e.getLastRow() == Integer.MAX_VALUE ) { fireTableModelEvent( new TableModelEvent( RowMapperTableModel.this, e.getFirstRow(), e.getLastRow(), e.getColumn(), e.getType() ) ); return; } final TableModelEvent event = new TableModelEvent( RowMapperTableModel.this, mapFromModel( e.getFirstRow() ), mapFromModel( e.getLastRow() ), e.getColumn(), e.getType() ); fireTableModelEvent( event ); } } private EventListenerList eventListenerList; private TableModel parent; private int rowCount; public RowMapperTableModel( final TableModel parent ) { if ( parent == null ) { throw new NullPointerException(); } this.eventListenerList = new EventListenerList(); this.parent = parent; this.parent.addTableModelListener( new EventForwardHandler() ); } protected void fireTableModelEvent( final TableModelEvent event ) { final TableModelListener[] listeners = eventListenerList.getListeners( TableModelListener.class ); for ( int i = 0; i < listeners.length; i++ ) { final TableModelListener listener = listeners[ i ]; listener.tableChanged( event ); } } protected void recomputeRowCount() { rowCount = mapFromModel( parent.getRowCount() ); } public int getRowCount() { return rowCount; } public int getColumnCount() { return parent.getColumnCount(); } public String getColumnName( final int columnIndex ) { return parent.getColumnName( columnIndex ); } public Class getColumnClass( final int columnIndex ) { return parent.getColumnClass( columnIndex ); } public boolean isCellEditable( final int rowIndex, final int columnIndex ) { final int index = mapToModel( rowIndex ); return parent.isCellEditable( index, columnIndex ); } public Object getValueAt( final int rowIndex, final int columnIndex ) { return parent.getValueAt( mapToModel( rowIndex ), columnIndex ); } public void setValueAt( final Object aValue, final int rowIndex, final int columnIndex ) { final int index = mapToModel( rowIndex ); parent.setValueAt( aValue, index, columnIndex ); } public void addTableModelListener( final TableModelListener l ) { eventListenerList.add( TableModelListener.class, l ); } public void removeTableModelListener( final TableModelListener l ) { eventListenerList.remove( TableModelListener.class, l ); } /** * Maps public row numbers to row numbers from the parent table model. * * @param row the row to map * @return the corresponding row in the parent table model. */ public int mapToModel( final int row ) { final int size = parent.getRowCount(); int effectiveRow = 0; for ( int i = 0; i < size; i++ ) { if ( isFiltered( i ) ) { continue; } if ( effectiveRow == row ) { return i; } effectiveRow += 1; } throw new IndexOutOfBoundsException( "Unable to map row to model: " + row ); } protected abstract boolean isFiltered( int row ); /** * Maps parent tablemodel row numbers to row numbers from the public view. * * @param row the row to map * @return the corresponding row in the public view. */ public int mapFromModel( final int row ) { if ( row < 0 ) { return row; } final int size = parent.getRowCount(); int retval = 0; for ( int i = 0; i < size; i++ ) { if ( isFiltered( i ) ) { continue; } if ( row == i ) { return retval; } retval += 1; } return retval; } }