/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package com.bearsoft.gui.grid.data; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.TableModel; /** * This is TableModel implementation class, that delegates all the work to delegate model. * It caches results of delegate model work, rotating cache by maximum size. * It raises events from itself and from delegate model as if they * appeared straight in this model. * @see TableModel * @author Gala */ public class CachingTableModel implements TableModelWrapper { protected class TabledKey { protected int row; protected int column; public TabledKey(int aRow, int aColumn) { super(); row = aRow; column = aColumn; } public int getRow() { return row; } public int getColumn() { return column; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final TabledKey other = (TabledKey) obj; if (this.row != other.row) { return false; } if (this.column != other.column) { return false; } return true; } @Override public int hashCode() { int hash = 7; hash = 41 * hash + this.row; hash = 41 * hash + this.column; return hash; } } protected class DelegateListener implements TableModelListener { @Override public void tableChanged(TableModelEvent e) { clearCache(); TableModelEvent event = new TableModelEvent(CachingTableModel.this, e.getFirstRow(), e.getLastRow(), e.getColumn(), e.getType()); listeners.stream().forEach((l) -> { l.tableChanged(event); }); } } protected TableModel delegate; protected Set<TableModelListener> listeners = new HashSet<>(); protected Map<TabledKey, Object> cache = new HashMap<>(); protected int maxCacheSize = 4096;// 64^2; /** * Constructs an instance of CachingTableModel with default cache size. * @param aDelegate Model the work been delegated to. */ public CachingTableModel(TableModel aDelegate) { super(); delegate = aDelegate; delegate.addTableModelListener(new DelegateListener()); } /** * Constructs an instance of CachingTableModel with default cache size. * @param aDelegate Model the work been delegated to. * @param aMaxCacheSize Maximum size of the cache, inclusive. */ public CachingTableModel(TableModel aDelegate, int aMaxCacheSize) { this(aDelegate); maxCacheSize = aMaxCacheSize; if (maxCacheSize < 0) { maxCacheSize = 0; } } /** * Returns maximum cache size of the model. * @return Maximum size of the cache, inclusive. */ public int getMaxCacheSize() { return maxCacheSize; } /** * Sets maximum cache size of the model. * @param aMaxCacheSize Maximum size of the cache, inclusive. */ public void setMaxCacheSize(int aMaxCacheSize) { maxCacheSize = aMaxCacheSize; if (maxCacheSize < 0) { maxCacheSize = 0; } } protected Object put(int aRow, int aColumn, Object aValue) { if (cache.size() > maxCacheSize) { clearCache(); } return cache.put(new TabledKey(aRow, aColumn), aValue); } protected Object get(int aRow, int aColumn) { return cache.get(new TabledKey(aRow, aColumn)); } protected Object remove(int aRow, int aColumn, Object aValue) { return cache.remove(new TabledKey(aRow, aColumn)); } public void clearCache() { cache.clear(); } /** * {@inheritDoc} */ @Override public void addTableModelListener(TableModelListener l) { listeners.add(l); } /** * {@inheritDoc} */ @Override public void removeTableModelListener(TableModelListener l) { listeners.remove(l); } /** * {@inheritDoc} */ @Override public int getColumnCount() { return delegate.getColumnCount(); } /** * {@inheritDoc} */ @Override public Class<?> getColumnClass(int columnIndex) { return delegate.getColumnClass(columnIndex); } /** * {@inheritDoc} */ @Override public String getColumnName(int columnIndex) { return delegate.getColumnName(columnIndex); } /** * {@inheritDoc} */ @Override public Object getValueAt(int rowIndex, int columnIndex) { Object value = get(rowIndex, columnIndex); if (value == null) { value = delegate.getValueAt(rowIndex, columnIndex); put(rowIndex, columnIndex, value); } return value; } /** * {@inheritDoc} */ @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { delegate.setValueAt(aValue, rowIndex, columnIndex); } /** * {@inheritDoc} */ @Override public boolean isCellEditable(int rowIndex, int columnIndex) { return delegate.isCellEditable(rowIndex, columnIndex); } /** * {@inheritDoc} */ @Override public int getRowCount() { return delegate.getRowCount(); } @Override public TableModel unwrap() { return delegate; } }