335 lines
7.0 KiB
Java
335 lines
7.0 KiB
Java
package net.filebot.ui.sfv;
|
|
|
|
import java.beans.PropertyChangeEvent;
|
|
import java.beans.PropertyChangeListener;
|
|
import java.beans.PropertyChangeSupport;
|
|
import java.io.File;
|
|
import java.util.AbstractList;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
import javax.swing.table.AbstractTableModel;
|
|
|
|
import net.filebot.hash.HashType;
|
|
import net.filebot.util.FastFile;
|
|
import net.filebot.util.FileUtilities;
|
|
|
|
class ChecksumTableModel extends AbstractTableModel {
|
|
|
|
private final IndexedMap<String, ChecksumRow> rows = new IndexedMap<String, ChecksumRow>() {
|
|
|
|
@Override
|
|
public String key(ChecksumRow value) {
|
|
return value.getName();
|
|
}
|
|
};
|
|
|
|
private final List<File> checksumColumns = new ArrayList<File>(4);
|
|
|
|
public static final String HASH_TYPE_PROPERTY = "hashType";
|
|
private HashType hashType = HashType.SFV;
|
|
|
|
@Override
|
|
public String getColumnName(int columnIndex) {
|
|
switch (columnIndex) {
|
|
case 0:
|
|
return "State";
|
|
case 1:
|
|
return "Name";
|
|
default:
|
|
// works for files too and simply returns the name unchanged
|
|
return FileUtilities.getFolderName(getColumnRoot(columnIndex));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public Class<?> getColumnClass(int columnIndex) {
|
|
switch (columnIndex) {
|
|
case 0:
|
|
return ChecksumRow.State.class;
|
|
case 1:
|
|
return String.class;
|
|
default:
|
|
return ChecksumCell.class;
|
|
}
|
|
}
|
|
|
|
protected int getColumnIndex(ChecksumCell cell) {
|
|
int index = checksumColumns.indexOf(cell.getRoot());
|
|
|
|
if (index < 0)
|
|
return -1;
|
|
|
|
// add checksum column offset
|
|
return index + 2;
|
|
}
|
|
|
|
public File getColumnRoot(int columnIndex) {
|
|
// substract checksum column offset
|
|
return checksumColumns.get(columnIndex - 2);
|
|
}
|
|
|
|
public boolean isVerificationColumn(int columnIndex) {
|
|
return columnIndex >= 2 && getColumnRoot(columnIndex).isFile();
|
|
}
|
|
|
|
public List<File> getChecksumColumns() {
|
|
return Collections.unmodifiableList(checksumColumns);
|
|
}
|
|
|
|
@Override
|
|
public int getColumnCount() {
|
|
// add checksum column offset
|
|
return checksumColumns.size() + 2;
|
|
}
|
|
|
|
protected int getRowIndex(ChecksumRow row) {
|
|
return rows.getIndexByKey(row.getName());
|
|
}
|
|
|
|
protected int getRowIndex(ChecksumCell cell) {
|
|
return rows.getIndexByKey(cell.getName());
|
|
}
|
|
|
|
public List<ChecksumRow> rows() {
|
|
return Collections.unmodifiableList(rows);
|
|
}
|
|
|
|
@Override
|
|
public int getRowCount() {
|
|
return rows.size();
|
|
}
|
|
|
|
public void setHashType(HashType hashType) {
|
|
HashType old = this.hashType;
|
|
|
|
this.hashType = hashType;
|
|
|
|
// update table
|
|
fireTableDataChanged();
|
|
|
|
// notify listeners
|
|
pcs.firePropertyChange(HASH_TYPE_PROPERTY, old, hashType);
|
|
}
|
|
|
|
public HashType getHashType() {
|
|
return hashType;
|
|
}
|
|
|
|
@Override
|
|
public Object getValueAt(int rowIndex, int columnIndex) {
|
|
ChecksumRow row = rows.get(rowIndex);
|
|
|
|
switch (columnIndex) {
|
|
case 0:
|
|
return row.getState();
|
|
case 1:
|
|
return row.getName();
|
|
}
|
|
|
|
ChecksumCell cell = row.getChecksum(getColumnRoot(columnIndex));
|
|
|
|
// empty cell
|
|
if (cell == null)
|
|
return null;
|
|
|
|
switch (cell.getState()) {
|
|
case READY:
|
|
return cell.getChecksum(hashType);
|
|
case ERROR:
|
|
return cell.getError();
|
|
default: // PENDING or PROGRESS
|
|
return cell.getTask();
|
|
}
|
|
}
|
|
|
|
public void addAll(Collection<ChecksumCell> values) {
|
|
List<ChecksumCell> replacements = new ArrayList<ChecksumCell>();
|
|
|
|
int rowCount = getRowCount();
|
|
int columnCount = getColumnCount();
|
|
|
|
for (ChecksumCell cell : values) {
|
|
int rowIndex = getRowIndex(cell);
|
|
|
|
ChecksumRow row;
|
|
|
|
if (rowIndex >= 0) {
|
|
// get existing row
|
|
row = rows.get(rowIndex);
|
|
} else {
|
|
// add new row
|
|
row = new ChecksumRow(cell.getName());
|
|
row.addPropertyChangeListener(stateListener);
|
|
rows.add(row);
|
|
}
|
|
|
|
// add cell to row
|
|
ChecksumCell old = row.put(cell);
|
|
|
|
// dispose of old cell
|
|
if (old != null) {
|
|
old.dispose();
|
|
replacements.add(cell);
|
|
}
|
|
|
|
// listen to changes (progress, state)
|
|
cell.addPropertyChangeListener(progressListener);
|
|
|
|
if (!checksumColumns.contains(cell.getRoot())) {
|
|
checksumColumns.add(new FastFile(cell.getRoot().getPath()));
|
|
}
|
|
}
|
|
|
|
// fire table events
|
|
if (columnCount != getColumnCount()) {
|
|
// number of columns has changed
|
|
fireTableStructureChanged();
|
|
return;
|
|
}
|
|
|
|
for (ChecksumCell replacement : replacements) {
|
|
int row = getRowIndex(replacement);
|
|
|
|
// update this row
|
|
fireTableRowsUpdated(row, row);
|
|
}
|
|
|
|
if (rowCount != getRowCount()) {
|
|
// some rows have been inserted
|
|
fireTableRowsInserted(rowCount, getRowCount() - 1);
|
|
}
|
|
}
|
|
|
|
public void remove(int... index) {
|
|
// sort index array
|
|
Arrays.sort(index);
|
|
|
|
for (int i : index) {
|
|
rows.get(i).dispose();
|
|
}
|
|
|
|
// remove rows
|
|
rows.removeAll(index);
|
|
|
|
fireTableRowsDeleted(index[0], index[index.length - 1]);
|
|
}
|
|
|
|
public void clear() {
|
|
checksumColumns.clear();
|
|
rows.clear();
|
|
|
|
fireTableStructureChanged();
|
|
}
|
|
|
|
private final PropertyChangeListener stateListener = new PropertyChangeListener() {
|
|
|
|
@Override
|
|
public void propertyChange(PropertyChangeEvent evt) {
|
|
int row = getRowIndex((ChecksumRow) evt.getSource());
|
|
|
|
if (row >= 0) {
|
|
// update row
|
|
fireTableRowsUpdated(row, row);
|
|
}
|
|
}
|
|
};
|
|
|
|
private final PropertyChangeListener progressListener = new PropertyChangeListener() {
|
|
|
|
@Override
|
|
public void propertyChange(PropertyChangeEvent evt) {
|
|
ChecksumCell cell = (ChecksumCell) evt.getSource();
|
|
|
|
int row = getRowIndex(cell);
|
|
int column = getColumnIndex(cell);
|
|
|
|
if (row >= 0 && column >= 0) {
|
|
fireTableCellUpdated(row, column);
|
|
}
|
|
}
|
|
};
|
|
|
|
protected static abstract class IndexedMap<K, V> extends AbstractList<V> {
|
|
|
|
private final Map<K, Integer> indexMap = new HashMap<K, Integer>(64);
|
|
private final List<V> list = new ArrayList<V>(64);
|
|
|
|
public abstract K key(V value);
|
|
|
|
@Override
|
|
public V get(int index) {
|
|
return list.get(index);
|
|
}
|
|
|
|
public int getIndexByKey(K key) {
|
|
Integer index = indexMap.get(key);
|
|
|
|
if (index == null)
|
|
return -1;
|
|
|
|
return index;
|
|
}
|
|
|
|
@Override
|
|
public boolean add(V value) {
|
|
K key = key(value);
|
|
Integer index = indexMap.get(key);
|
|
|
|
if (index == null && list.add(value)) {
|
|
indexMap.put(key, lastIndexOf(value));
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public void removeAll(int... index) {
|
|
// sort index array
|
|
Arrays.sort(index);
|
|
|
|
// remove in reverse
|
|
for (int i = index.length - 1; i >= 0; i--) {
|
|
V value = list.remove(index[i]);
|
|
indexMap.remove(key(value));
|
|
}
|
|
|
|
updateIndexMap();
|
|
}
|
|
|
|
private void updateIndexMap() {
|
|
for (int i = 0; i < list.size(); i++) {
|
|
indexMap.put(key(list.get(i)), i);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int size() {
|
|
return list.size();
|
|
}
|
|
|
|
@Override
|
|
public void clear() {
|
|
list.clear();
|
|
indexMap.clear();
|
|
}
|
|
|
|
}
|
|
|
|
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
|
|
|
|
public void addPropertyChangeListener(PropertyChangeListener listener) {
|
|
pcs.addPropertyChangeListener(listener);
|
|
}
|
|
|
|
public void removePropertyChangeListener(PropertyChangeListener listener) {
|
|
pcs.removePropertyChangeListener(listener);
|
|
}
|
|
|
|
}
|