package com.limegroup.gnutella.gui.tables;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Iterator;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.table.TableColumnModel;
import com.limegroup.gnutella.settings.TablesHandler;
/**
* Handles column preferences through a settings file.
*
* This is the default implementation for ColumnPreferences.
*/
public class DefaultColumnPreferenceHandler
implements ColumnPreferenceHandler,
TableColumnModelListener,
MouseListener {
/**
* The table that this is storing the column preferences for.
*/
protected final LimeJTable table;
/**
* The current SimpleColumnListener for callbacks.
*/
protected SimpleColumnListener listener = null;
/**
* Indicates a margin has been changed since we last released the mouse.
*/
protected boolean marginChanged;
/**
* Constructs a new DefaultColumnPreferences object for this table.
*/
public DefaultColumnPreferenceHandler(LimeJTable t) {
table = t;
startListening();
}
/**
* Sets the SimpleColumnListener. If one already was listening, it is
* removed.
*/
public void setSimpleColumnListener(SimpleColumnListener scl) {
listener = scl;
}
/**
* Triggered from a column being added.
* The 'to' index of the TableColumnModelEvent is the index
* in the TableColumn of the newly added column.
*/
public void columnAdded(TableColumnModelEvent e) {
LimeTableColumn addedColumn = getToColumn(e);
LimeTableColumn ltc = addedColumn;
setVisibility(ltc, true);
TableColumnModel tcm = table.getColumnModel();
int order = getOrder(ltc);
int current = tcm.getColumnIndex(ltc.getId());
int max = tcm.getColumnCount();
// move this column to where we want it.
if( order != current ) {
stopListening();
// make sure we don't try to put this after the end.
order = Math.min(order, max-1);
tcm.moveColumn(current, order);
// traverse through and reset the saved order of columns.
for(current = order+1; current < max; current++) {
ltc = (LimeTableColumn)tcm.getColumn(current);
setOrder(ltc, current);
}
// traverse through the hidden columns and tell them to
// move back up a notch if they're above us.
for(Iterator i = table.getHiddenColumns(); i.hasNext(); ) {
ltc = (LimeTableColumn)i.next();
current = getOrder(ltc);
if( current > order )
setOrder(ltc, current+1);
}
startListening();
}
if(listener != null)
listener.columnAdded(addedColumn, table);
save();
}
/**
* Triggered from a column's margin being changed.
* This is triggered whenever a table is made visible, whenever
* a scrollbar appears or disappears, and whenever the margins
* of the columns change.
* Currently does nothing.
*/
public void columnMarginChanged(ChangeEvent e) {
// see if we can avoid the system call...
// if this is null, it means we resized the app or a scrollbar appeared
if(table.getTableHeader().getResizingColumn() == null)
return;
marginChanged = true;
}
/**
* Triggered from a column being moved.
* This triggers whenever a column is touched. The 'from' and 'to'
* indexes may be the same -- if they are, we ignore the event.
*/
public void columnMoved(TableColumnModelEvent e) {
if( e.getFromIndex() == e.getToIndex() ) return;
LimeTableColumn from = getFromColumn(e);
LimeTableColumn to = getToColumn(e);
setOrder(from, e.getFromIndex());
setOrder(to, e.getToIndex());
save();
}
/**
* Triggered from a column being removed.
* The TableColumnModelEvent is supremely dumb here,
* not even giving us the TableColumn that was removed.
* So, we need to ask the table what the last removed column was.
*/
public void columnRemoved(TableColumnModelEvent e) {
LimeTableColumn ltc;
//save the reordered columns
TableColumnModel tcm = table.getColumnModel();
for(int i = 0; i < tcm.getColumnCount(); i++) {
ltc = (LimeTableColumn)tcm.getColumn(i);
setOrder(ltc, i);
}
LimeTableColumn removedColumn = table.getLastRemovedColumn();
ltc = removedColumn;
setVisibility(ltc, false);
//decrease the order in hidden columns by one if they were
//before the hidden column's order.
int order = getOrder(ltc);
for(Iterator i = table.getHiddenColumns(); i.hasNext(); ) {
ltc = (LimeTableColumn)i.next();
int current = getOrder(ltc);
if( current > order )
setOrder(ltc, current-1);
}
if(listener != null)
listener.columnRemoved(removedColumn, table);
save();
}
/**
* From a column's selection changing.
* Does nothing.
*/
public void columnSelectionChanged(ListSelectionEvent e) { }
/**
* The mouse was clicked on the table header.
*/
public void mouseClicked(MouseEvent e) { }
/**
* The mouse entered the table header.
*/
public void mouseEntered(MouseEvent e) { }
/**
* The mouse exited the table header.
*/
public void mouseExited(MouseEvent e) { }
/**
* The mouse pressed the table header.
*/
public void mousePressed(MouseEvent e) { }
/**
* The mouse released from the table header.
*/
public void mouseReleased(MouseEvent e) {
// if the margins haven't changed, exit.
if (!marginChanged) return;
// iterate through and save the widths we wanted.
TableColumnModel tcm = table.getColumnModel();
for(int i = 0; i < tcm.getColumnCount(); i++) {
LimeTableColumn ltc = (LimeTableColumn)tcm.getColumn(i);
setWidth(ltc, ltc.getWidth());
}
marginChanged = false;
save();
}
/**
* Reverts this table's header preferences to their default
* values.
*/
public void revertToDefault() {
stopListening();
// Traverse & change settings, and make everything visible
// so we can traverse back through & set the order and width.
DataLineModel dlm = (DataLineModel)table.getModel();
for(int i = 0; i < dlm.getColumnCount(); i++) {
LimeTableColumn ltc = dlm.getTableColumn(i);
setVisibility(ltc, ltc.getDefaultVisibility());
setOrder(ltc, ltc.getDefaultOrder());
setWidth(ltc, ltc.getDefaultWidth());
try {
if(!table.isColumnVisible(ltc.getId())) {
table.setColumnVisible(ltc.getId(), true);
if(listener != null)
listener.columnAdded(ltc, table);
}
} catch(LastColumnException impossible) {}
}
// traverse to set the order ...
TableColumnModel tcm = table.getColumnModel();
for(int i = 0; i < dlm.getColumnCount(); i++) {
LimeTableColumn ltc = dlm.getTableColumn(i);
int order = getOrder(ltc);
int current = tcm.getColumnIndex(ltc.getId());
if( current != order )
tcm.moveColumn(current, order);
ltc.setPreferredWidth( ltc.getDefaultWidth() );
}
// traverse to set the visibility ...
for(int i = 0; i < dlm.getColumnCount(); i++) {
LimeTableColumn ltc = dlm.getTableColumn(i);
boolean wantVis = getVisibility(ltc);
try {
if (!wantVis) {
table.setColumnVisible(ltc.getId(), false);
if(listener != null)
listener.columnRemoved(ltc, table);
}
} catch(LastColumnException ignored) {}
}
startListening();
save();
}
/**
* Determines whether the columns are already the default values.
*/
public boolean isDefault() {
DataLineModel dlm = (DataLineModel)table.getModel();
for(int i = 0; i < dlm.getColumnCount(); i++) {
LimeTableColumn ltc = dlm.getTableColumn(i);
if( !isDefaultWidth(ltc) ) return false;
if( !isDefaultOrder(ltc) ) return false;
if( !isDefaultVisibility(ltc) ) return false;
}
return true;
}
/**
* Sets the headers to the correct widths, depending on
* the user's preferences for this table. This will not set
* the table to exactly the user's widths, because the only
* way to set the width is to suggest it via setPreferredWidth.
*/
public void setWidths() {
stopListening();
//traverse through each possible column and set its preferred
//width. this MUST use the DataLineModel to traverse, to ensure
//that we set the future preferred width for any added columns.
DataLineModel dlm = (DataLineModel)table.getModel();
for(int i = 0; i < dlm.getColumnCount(); i++) {
LimeTableColumn ltc = dlm.getTableColumn(i);
int width = getWidth(ltc);
if( width != -1 ) {
ltc.setPreferredWidth(width);
}
}
startListening();
}
/**
* Sets the headers to the correct order, depending on the
* user's preferences for this table.
*/
public void setOrder() {
stopListening();
boolean changed = false;
//traverse through each possible column, and if it's visible,
//put it in the correct place. this MUST use the DataLineModel
//to traverse, so reordering doesn't confuse what we're looking at.
TableColumnModel tcm = table.getColumnModel();
DataLineModel dlm = (DataLineModel)table.getModel();
int max = dlm.getColumnCount();
for(int i = 0; i < max; i++) {
LimeTableColumn ltc = dlm.getTableColumn(i);
int order = getOrder(ltc);
if (table.isColumnVisible(ltc.getId())) {
int current = tcm.getColumnIndex(ltc.getId());
// can't go beyond boundary
if( order >= max ) {
order = max - 1;
setOrder(ltc, order);
changed = true;
}
if ( current != order )
tcm.moveColumn(current, order);
}
}
if(changed)
TablesHandler.instance().save();
startListening();
}
/**
* Sets the headers so that some may be invisible, depending
* on the user's preferences for this table.
*/
public void setVisibility() {
stopListening();
//traverse through each possible column, and set its
//visibility appropriately
DataLineModel dlm = (DataLineModel)table.getModel();
for(int i = 0; i < dlm.getColumnCount(); i++) {
LimeTableColumn ltc = (LimeTableColumn)dlm.getTableColumn(i);
boolean wantVis = getVisibility(ltc);
// if we want to see it and we don't currently see it, show it.
// if we don't want to see it and we currently see it, hide it.
boolean isVis = table.isColumnVisible(ltc.getId());
try {
if( wantVis && !isVis ) {
table.setColumnVisible(ltc.getId(), true);
if(listener != null)
listener.columnAdded(ltc, table);
} else if( !wantVis && isVis ) {
table.setColumnVisible(ltc.getId(), false);
if(listener != null)
listener.columnRemoved(ltc, table);
}
} catch (LastColumnException ee) {
// ignore it -- we can't show an error while starting up.
}
}
startListening();
}
protected void save() {
TablesHandler.instance().save();
}
protected void startListening() {
table.getTableHeader().addMouseListener(this);
table.getColumnModel().addColumnModelListener(this);
}
protected void stopListening() {
table.getTableHeader().removeMouseListener(this);
table.getColumnModel().removeColumnModelListener(this);
}
protected LimeTableColumn getToColumn(TableColumnModelEvent e) {
return (LimeTableColumn)table.getColumnModel().getColumn(
e.getToIndex());
}
protected LimeTableColumn getFromColumn(TableColumnModelEvent e) {
return (LimeTableColumn)table.getColumnModel().getColumn(
e.getFromIndex());
}
protected void setVisibility(LimeTableColumn col, boolean vis) {
TablesHandler.getVisibility(col.getId(), col.getDefaultVisibility()).
setValue(vis);
}
protected void setOrder(LimeTableColumn col, int order) {
TablesHandler.getOrder(col.getId(), col.getDefaultOrder()).
setValue(order);
}
protected void setWidth(LimeTableColumn col, int width) {
TablesHandler.getWidth(col.getId(), col.getDefaultWidth()).
setValue(width);
}
protected boolean getVisibility(LimeTableColumn col) {
return TablesHandler.getVisibility(
col.getId(), col.getDefaultVisibility()).getValue();
}
protected int getOrder(LimeTableColumn col) {
return TablesHandler.getOrder(col.getId(), col.getDefaultOrder()).
getValue();
}
protected int getWidth(LimeTableColumn col) {
return TablesHandler.getWidth(col.getId(), col.getDefaultWidth()).
getValue();
}
protected boolean isDefaultVisibility(LimeTableColumn col) {
return TablesHandler.getVisibility(
col.getId(), col.getDefaultVisibility()).isDefault();
}
protected boolean isDefaultOrder(LimeTableColumn col) {
return TablesHandler.getOrder(col.getId(), col.getDefaultOrder()).
isDefault();
}
protected boolean isDefaultWidth(LimeTableColumn col) {
return TablesHandler.getWidth(col.getId(), col.getDefaultWidth()).
isDefault();
}
}