// This file is part of Penn TotalRecall <http://memory.psych.upenn.edu/TotalRecall>. // // TotalRecall 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, version 3 only. // // TotalRecall 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 TotalRecall. If not, see <http://www.gnu.org/licenses/>. package components.annotations; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.TableModel; /** * Custom <code>TableModel</code> for storing annotations of the open audio file. * * @author Yuvi Masory */ public class AnnotationTableModel implements TableModel { private HashSet<TableModelListener> listeners; private ArrayList<Annotation> sortedAnns; //editing the table layout (e.g., adding a new column, switching the order of two columns) involves more than changing the next three lines //some of the methods below make assumptions about the number of columns and the Annotation methods they hook up to //doing this in a perfectly programmed worled would involve storing an array of Method objects private static final int columnCount = 3; private static final Class<?>[] columnClasses = new Class<?>[] {Double.class, String.class, Integer.class}; private static final String[] columnNames = new String[] {"Time (ms)", "Word", "Word #"}; private static final String colErr = "column index out of range"; private static final String rowErr = "row index out of range"; private static final String stateErr = "inconsistency in internal column handling"; protected AnnotationTableModel() { if(columnCount != columnClasses.length || columnCount != columnNames.length) { throw new IllegalStateException(stateErr); } listeners = new HashSet<TableModelListener>(); sortedAnns = new ArrayList<Annotation>(); } public int getColumnCount() { return columnCount; } public int getRowCount() { return sortedAnns.size(); } public Class<?> getColumnClass(int columnIndex) { if(columnIndex > columnClasses.length || columnIndex < 0) { throw new IllegalArgumentException(colErr); } return columnClasses[columnIndex]; } public boolean isCellEditable(int row, int col) { return false; } public void addTableModelListener(TableModelListener l) { listeners.add(l); } public void removeTableModelListener(TableModelListener l) { listeners.remove(l); } public String getColumnName(int columnIndex) { if(columnIndex > columnClasses.length || columnIndex < 0) { throw new IllegalArgumentException(colErr); } return columnNames[columnIndex]; } public Object getValueAt(int rowIndex, int columnIndex) { if(rowIndex < 0 || rowIndex > sortedAnns.size()) { throw new IllegalArgumentException(rowErr); } if(columnIndex > columnCount - 1) { throw new IllegalArgumentException(colErr); } Annotation ann = sortedAnns.get(rowIndex); if(columnIndex == 0) { return ann.getTime(); } if(columnIndex == 1) { return ann.getText(); } if(columnIndex == 2) { return ann.getWordNum(); } throw new IllegalStateException(stateErr); } public void setValueAt(Object aValue, int rowIndex, int columnIndex) { throw new UnsupportedOperationException("setting table values not supported, use add/remove annotation methods"); } protected Annotation getAnnotationAt(int rowIndex) { if(rowIndex < 0 || rowIndex > sortedAnns.size()) { throw new IllegalArgumentException(rowErr); } return sortedAnns.get(rowIndex); } protected Annotation[] toArray() { return sortedAnns.toArray(new Annotation[sortedAnns.size()]); } //adding duplicates is prevented by annotation-over deleting first annotation, performed in annotateaction protected void addElement(Annotation ann) { sortedAnns.add(ann); //then remove batch adding option below Collections.sort(sortedAnns); for(TableModelListener tml: listeners) { tml.tableChanged(new TableModelEvent(this)); } } //duplicate adds are possible with this method protected void addElements(Iterable<Annotation> batch) { for(Annotation el: batch) { sortedAnns.add(el); } Collections.sort(sortedAnns); for(TableModelListener tml: listeners) { tml.tableChanged(new TableModelEvent(this)); } } protected void removeElementAt(int index) { if(index < 0 || index > sortedAnns.size()) { throw new IllegalArgumentException(rowErr); } sortedAnns.remove(index); for(TableModelListener tml: listeners) { tml.tableChanged(new TableModelEvent(this, Math.min(index, sortedAnns.size()), sortedAnns.size())); } } protected void removeAllElements() { sortedAnns.clear(); } public int size() { return sortedAnns.size(); } }