/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* 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 Lesser General Public License for more details.
*
* Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.reporting.designer.core.util.table;
import javax.swing.event.EventListenerList;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
public class GroupedTableModel 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(GroupedTableModel.this,
e.getFirstRow(), e.getLastRow(), e.getColumn(), e.getType()));
return;
}
final TableModelEvent event = new TableModelEvent(GroupedTableModel.this,
mapFromModel(e.getFirstRow()), mapFromModel(e.getLastRow()), e.getColumn(), e.getType());
fireTableModelEvent(event);
}
}
private EventListenerList eventListenerList;
private GroupingModel parent;
private int rowCount;
public GroupedTableModel(final GroupingModel parent)
{
if (parent == null)
{
throw new NullPointerException();
}
this.eventListenerList = new EventListenerList();
this.parent = parent;
this.parent.addTableModelListener(new EventForwardHandler());
recomputeRowCount();
}
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);
if (parent.isHeaderRow(index))
{
return true;
}
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);
if (parent.isHeaderRow(index))
{
recomputeRowCount();
fireTableModelEvent(new TableModelEvent(this));
return;
}
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++)
{
final GroupingHeader groupHeader = parent.getGroupHeader(i);
if (groupHeader == null ||
groupHeader.isCollapsed() == false ||
parent.isHeaderRow(i))
{
if (effectiveRow == row)
{
return i;
}
effectiveRow += 1;
}
}
throw new IndexOutOfBoundsException("Unable to map row to model: " + 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++)
{
final GroupingHeader groupHeader = parent.getGroupHeader(i);
if (groupHeader == null ||
groupHeader.isCollapsed() == false ||
parent.isHeaderRow(i))
{
if (row == i)
{
return retval;
}
retval += 1;
}
else if (groupHeader.isCollapsed())
{
if (row == i)
{
return retval - 1;
}
}
}
return retval;
}
}