package org.limewire.ui.swing.table;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.table.TableColumn;
import org.jdesktop.swingx.decorator.SortController;
import org.jdesktop.swingx.decorator.SortKey;
import org.jdesktop.swingx.decorator.SortOrder;
import org.jdesktop.swingx.table.TableColumnExt;
import org.limewire.ui.swing.settings.TablesHandler;
/**
* Saves the state of columns in a given table.
*/
public class ColumnStateHandler implements TableColumnModelListener, MouseListener, PropertyChangeListener {
private final GlazedJXTable table;
private final VisibleTableFormat format;
private boolean columnMoved = false;
private boolean visibleChangeEnabled = true;
public ColumnStateHandler(GlazedJXTable table, VisibleTableFormat format) {
this.table = table;
this.format = format;
startListening();
for(int i = 0; i < format.getColumnCount(); i++) {
table.getColumnExt(i).addPropertyChangeListener(this);
}
}
private void startListening() {
table.getTableHeader().addMouseListener(this);
table.getColumnModel().addColumnModelListener(this);
// for(int i = 0; i < format.getColumnCount(); i++) {
// table.getColumnExt(i).addPropertyChangeListener(this);
// }
}
private void stopListening() {
table.getTableHeader().removeMouseListener(this);
table.getColumnModel().removeColumnModelListener(this);
// for(int i = 0; i < format.getColumnCount(); i++) {
// table.getColumnExt(i).removePropertyChangeListener(this);
// }
}
public void removeListeners() {
stopListening();
for(int i = 0; i < format.getColumnCount(); i++) {
table.getColumnExt(format.getColumnName(i)).removePropertyChangeListener(this);
}
}
@Override
public void columnAdded(TableColumnModelEvent e) {}
@Override
public void columnMarginChanged(ChangeEvent e) {}
@Override
public void columnMoved(TableColumnModelEvent e) {
if( e.getFromIndex() == e.getToIndex() || !table.isShowing()) return;
// wait till after the mouse was released to save new column ordering
columnMoved = true;
}
@Override
public void columnRemoved(TableColumnModelEvent e) {}
@Override
public void columnSelectionChanged(ListSelectionEvent e) {}
@Override
public void mouseClicked(MouseEvent e) {
if(SwingUtilities.isLeftMouseButton(e)) {
TableColumn column = table.getSortedColumn();
if(column != null) {
SortOrder sortOrder = getSortOrder(table, column.getModelIndex());
setSortedColumn(column.getModelIndex(), sortOrder.isAscending());
}
}
}
private SortOrder getSortOrder(GlazedJXTable table, int modelColumn) {
SortController sortController = table.getSortController();
if (sortController == null) {
return SortOrder.UNSORTED;
}
List<? extends SortKey> sortKeys = sortController.getSortKeys();
if (sortKeys == null) {
return SortOrder.UNSORTED;
}
SortKey firstKey = SortKey.getFirstSortingKey(sortKeys);
if ((firstKey != null) && (firstKey.getColumn() == modelColumn)) {
return firstKey.getSortOrder();
} else {
return SortOrder.UNSORTED;
}
}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseExited(MouseEvent e) {}
@Override
public void mousePressed(MouseEvent e) {}
@Override
public void mouseReleased(MouseEvent e) {
//if columns were moved, save any changes after the moving stopped
if(columnMoved) {
columnMoved = false;
saveColumnOrder();
}
}
/**
* Saves the current column ordering to disk if a column is not in its default
* index. Ignores hidden columns and saves the current ordering of visible
* columns.
*/
private void saveColumnOrder() {
for(int i = 0; i < table.getColumnCount(); i++) {
TableColumn column = table.getColumn(i);
ColumnStateInfo info = format.getColumnInfo(column.getModelIndex());
if(info.getPreferredViewIndex() != i) {
info.setPreferredViewIndex(i);
setOrder(info, i);
}
}
}
public void revertToDefault() {
// stopListening();
//TODO: revert to defaults
// startListening();
}
public void setupColumnWidths() {
for(int i = 0; i < format.getColumnCount(); i++) {
if(format.getMaxsWidth(i) != -1) {
table.getColumn(i).setMaxWidth(format.getMaxsWidth(i));
}
table.getColumn(i).setPreferredWidth(format.getInitialWidth(i));
}
}
/**
* Sets the column order of the table based on the preffered index of each column.
* Because table.getColumnModel.move is not stable. Meaning moving an item to index 2 might
* move the item already there to the left, or maybe to the right. We have to jump through a few
* hoops to make it stable.
* First we make a list ordering all columns in the reverse preferred order, then move each item
* from where it currently is in the column model to the zero index. Since items cannot be moved to
* the left of the zero index this makes the move stable, and places the items in the proper
* preferred index order.
*/
public void setupColumnOrder() {
stopListening();
List<TableColumn> columns = new ArrayList<TableColumn>();
for(int i = 0; i < table.getColumnCount(); i++) {
TableColumn tableColumn = table.getColumn(i);
columns.add(tableColumn);
}
Collections.sort(columns, new Comparator<TableColumn> () {
@Override
public int compare(TableColumn o1, TableColumn o2) {
ColumnStateInfo info1 = format.getColumnInfo(o1.getModelIndex());
ColumnStateInfo info2 = format.getColumnInfo(o2.getModelIndex());
Integer prefferedIndex1 = info1.getPreferredViewIndex();
Integer prefferedIndex2 = info2.getPreferredViewIndex();
return prefferedIndex1.compareTo(prefferedIndex2) * -1;
}
});
for(TableColumn tableColumn : columns) {
int currentIndex = getCurrentIndex(tableColumn);
if(currentIndex > 0 && currentIndex < table.getColumnCount()) {
table.getColumnModel().moveColumn(currentIndex, 0);
}
}
startListening();
}
private int getCurrentIndex(TableColumn tableColumn) {
for(int i = 0; i < table.getColumnCount(); i++) {
if(table.getColumn(i) == tableColumn) {
return i;
}
}
return -1;
}
public void setupColumnVisibility() {
setupColumnVisibility(true);
}
/**
* Applies the column visibility attributes to the table columns. If
* <code>propertyChangeEnabled</code> is false, then changes to the visible
* property in the columns are NOT handled. This is useful in situations
* where the column visibility is initialized before the column order has
* been set up. (This occurs when the search results table format changes.)
* In this situation, handling the visible property change would cause the
* default column order to be saved, thereby overwriting any custom column
* reordering done by the user.
* @see #propertyChange(PropertyChangeEvent)
*/
public void setupColumnVisibility(boolean propertyChangeEnabled) {
visibleChangeEnabled = propertyChangeEnabled;
stopListening();
for(int i = format.getColumnCount()-1; i >= 0; i--) {
TableColumnExt column = table.getColumnExt(i);
column.setVisible(format.isVisibleAtStartup(column.getModelIndex()));
}
startListening();
visibleChangeEnabled = true;
}
private void setVisibility(ColumnStateInfo info, boolean isVisible) {
TablesHandler.getVisibility(info.getId(), info.isDefaultlyShown()).setValue(isVisible);
}
private void setOrder(ColumnStateInfo column, int order) {
TablesHandler.getOrder(column.getId(), column.getModelIndex()).setValue(order);
}
private void setWidth(ColumnStateInfo column, int width) {
TablesHandler.getWidth(column.getId(), column.getDefaultWidth()).setValue(width);
}
private void setSortedColumn(int sortedColumn, boolean sortOrder) {
TablesHandler.getSortedColumn(format.getSortOrderID(), format.getSortedColumn()).setValue(sortedColumn);
TablesHandler.getSortedOrder(format.getSortOrderID(), format.getSortOrder()).setValue(sortOrder);
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
//width of column changed
if(evt.getPropertyName().equals("width") && table.isShowing()) {
ColumnStateInfo info = format.getColumnInfo(((TableColumnExt)evt.getSource()).getModelIndex());
setWidth(info,(Integer) evt.getNewValue() );
}
//visibility changed
if(evt.getPropertyName().equals("visible") && table.isShowing() && visibleChangeEnabled) {
ColumnStateInfo info = format.getColumnInfo(((TableColumnExt)evt.getSource()).getModelIndex());
setVisibility(info, Boolean.TRUE.equals(evt.getNewValue()));
//column visibility changed, so check the ordering
saveColumnOrder();
}
}
}