import java.awt.Component;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
/**
* The purpose of this class is to update a map which states which cells are selected
*
* This class may be set up as a listener for a Table to keep track of selected
* cells.
*
* This renderer updates the selection map based on the TableUpdateIfc's unique Object.
*
* The renderer holds two maps. The first is a selection map. The renderer will ask the TableUpdateIfc
* for the unique object for a given row and a unique object for a given column.
*
* In many of the tables I use, I put a unique object in the first cell in the row and
* use the column name as a unique object for the column.
*
* The reason the columns and rows aren't stored is because the cells may change location.
* To track down the objects, the unique identifiers are used. The first map, holds a Boolean object.
* A Boolean may be true, false or null as opposed to a boolean which may only be true or false.
*
* To indicate selection, null means not selected (by default all things are null) and not null
* means selected (a Boolean with false value is non null, so this may be confusing).
*
* The last RenderedTextMap may be used to grab the last rendered string given the current row and column.
*
*
* @author scott.izu
*/
public class MultipleSelectionRenderer extends DefaultTableCellRenderer implements MouseListener {
private JTable table;
private Map<Object, Map<Object, Boolean>> selectedMap = new LinkedHashMap<Object, Map<Object, Boolean>>();
private Map<Object, Map<Object, String>> lastRenderedTextMap = new LinkedHashMap<Object, Map<Object, String>>();
TableUpdateIfc updater;
public static final String SELECTION_RGB = "bf65a5";
public MultipleSelectionRenderer(TableUpdateIfc updater, JTable table) {
this.table = table;
this.updater = updater;
}
@Override
public void mouseReleased(MouseEvent e) {
if(e.getSource() == table){
if(e.getButton() == MouseEvent.BUTTON1) {
boolean selectionChanged = false;
if(!e.isControlDown()) {
selectedMap.clear();
selectionChanged = true;
}
// for(int row: table.getSelectedRows())
// for(int col: table.getSelectedColumns())
// System.err.println(row+""+col);
// Store selections in terms of model, since table view may change
Object rowObject = updater.getUniqueRowObject(table, table.getSelectedRow());
Object colObject = updater.getUniqueColumnObject(table, table.getSelectedColumn());
if(updater.canSelectColumn(colObject)){
if(selectedMap.get(rowObject) == null)
selectedMap.put(rowObject, new LinkedHashMap<Object, Boolean>());
if(selectedMap.get(rowObject).get(colObject) != null)
selectedMap.get(rowObject).remove(colObject); // Deselect
else
selectedMap.get(rowObject).put(colObject, true); // Select
selectionChanged = true;
}
if(selectionChanged)
updater.updateMultipleSelection(table);
}
}
}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) { }
public void mouseClicked(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
/**
*
* @param table
* @param value
* @param isSelected
* @param hasFocus
* @param row
* @param column
* @return
*/
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int tableRow, int tableColumn) {
Component result = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, tableRow, tableColumn);
Object rowObject = updater.getUniqueRowObject(table, tableRow);
Object colObject = updater.getUniqueColumnObject(table, tableColumn);
if(isCellSelected(rowObject, colObject))
this.setText(getHTMLString(value));
if(lastRenderedTextMap.get(rowObject) == null)
lastRenderedTextMap.put(rowObject, new LinkedHashMap<Object, String>());
lastRenderedTextMap.get(rowObject).put(colObject, this.getText());
return result;
}
private String getHTMLString(Object value){
String valueString = value.toString();
if(valueString.equals(""))
valueString = " ";
String html = "<html><body><table cellpadding=0><tr>";
html = html + "<td bgcolor=#" + SELECTION_RGB + ">";
html = html + valueString;
html = html + "</td>";
html = html + "</tr></table></body></html>";
return html;
}
public String getLastRenderedText(JTable table, int tableRow, int tableColumn){
Object rowObject = updater.getUniqueRowObject(table, tableRow);
Object colObject = updater.getUniqueColumnObject(table, tableColumn);
return lastRenderedTextMap.get(rowObject).get(colObject);
}
public void clearSelectedCells(){
selectedMap.clear();
}
public boolean isCellSelected(Object rowObject, Object colObject){
return (selectedMap.get(rowObject) != null && selectedMap.get(rowObject).get(colObject) != null);
}
public void selectCell(Object rowObject, Object colObject){
if(selectedMap.get(rowObject) == null)
selectedMap.put(rowObject, new LinkedHashMap<Object, Boolean>());
selectedMap.get(rowObject).put(colObject, true);
}
public static interface TableUpdateIfc {
public void updateMultipleSelection(JTable table);
public Object getUniqueRowObject(JTable table, int tableRow);
public Object getUniqueColumnObject(JTable table, int tableColumn);
public boolean canSelectColumn(Object colObject); // Determines if this column is used for multiple selection
}
}