/*******************************************************************************
* Breakout Cave Survey Visualizer
*
* Copyright (C) 2014 James Edwards
*
* jedwards8 at fastmail dot fm
*
* 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., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*******************************************************************************/
package org.andork.swing.table;
import java.util.Collections;
import java.util.NoSuchElementException;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
public class SectionHeaderRowSet {
private class ChangeHandler implements TableModelListener {
@Override
public void tableChanged(TableModelEvent e) {
if (e.getSource() != tableModel) {
return;
}
if (e.getLastRow() == Integer.MAX_VALUE || e.getColumn() == TableModelEvent.ALL_COLUMNS
|| e.getFirstRow() == TableModelEvent.HEADER_ROW) {
rebuild(0, Integer.MAX_VALUE);
}
switch (e.getType()) {
case TableModelEvent.UPDATE:
rebuild(e.getFirstRow(), e.getLastRow());
break;
case TableModelEvent.INSERT:
case TableModelEvent.DELETE:
rebuild(e.getFirstRow(), Integer.MAX_VALUE);
break;
}
}
}
private static Integer floor(SortedSet<Integer> set, int value) {
try {
return set.headSet(value + 1).last();
} catch (NoSuchElementException ex) {
return null;
}
}
private final TreeSet<Integer> rows = new TreeSet<Integer>();
private TableModel tableModel;
private SectionHeaderModel headerModel;
private ChangeHandler changeHandler;
private ChangeListener listener;
public SectionHeaderRowSet(TableModel tableModel, SectionHeaderModel headerModel) {
setTableModel(tableModel);
setSectionHeaderModel(headerModel);
}
public ChangeListener getListener() {
return listener;
}
public int getSectionHeaderRowCount() {
return rows.size();
}
public int getSectionHeaderRowFor(int rowIndex) {
Integer headerRow = floor(rows, rowIndex);
return headerRow == null ? -1 : headerRow;
}
public SortedSet<Integer> getSectionHeaderRows() {
return Collections.unmodifiableSortedSet(rows);
}
public boolean isSectionHeaderRow(int rowIndex) {
return headerModel != null && tableModel != null && headerModel.getSectionHeader(rowIndex) != null;
}
private void rebuild(int firstRow, int lastRow) {
int subSetEnd = lastRow;
if (subSetEnd < Integer.MAX_VALUE) {
subSetEnd++;
}
SortedSet<Integer> oldValues = rows.subSet(firstRow, subSetEnd);
SortedSet<Integer> newValues = new TreeSet<Integer>();
if (headerModel != null && tableModel != null) {
for (int row = firstRow; row <= lastRow && row < tableModel.getRowCount(); row++) {
if (headerModel.getSectionHeader(row) != null) {
newValues.add(row);
}
}
}
if (!newValues.equals(oldValues)) {
oldValues.clear();
rows.addAll(newValues);
if (listener != null) {
try {
listener.stateChanged(new ChangeEvent(this));
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
public void setListener(ChangeListener listener) {
this.listener = listener;
}
public void setSectionHeaderModel(SectionHeaderModel newModel) {
if (headerModel != newModel) {
headerModel = newModel;
rebuild(0, Integer.MAX_VALUE);
}
}
public void setTableModel(TableModel newModel) {
if (tableModel != newModel) {
if (tableModel != null) {
tableModel.removeTableModelListener(changeHandler);
changeHandler = null;
}
tableModel = newModel;
if (tableModel != null) {
tableModel.addTableModelListener(changeHandler = new ChangeHandler());
}
rebuild(0, Integer.MAX_VALUE);
}
}
}