Skip to main content

JXTable.setColumnSequence() stopped working as of 1.6.2. Any suggestions?

1 reply [Last post]
tjwolf
Offline
Joined: 2004-10-28
Points: 0

Our JXTable "state saving" is broken as of swingx 1.6.2. Before this release, our users could save the visibility of columns (among other things). Now this no longer works. If you run the attached program, simply hide one of the columns using JXTable's column control popup and click on "Get State". This extracts the column-related information from the JXTable. Now use the column control popup to make the column visible again. If you click on "Set State Column Sequence", the previously saved state gets restored, so the column you previously hid should disappear again- but it doesn't....at least not with swingx 1.6.2. The problem appears to be the JXTable.setColumnSequence() call. If we leave that out (in the test program, click the "Set State No Column Sequence", the column does disappear as expected. Unfortunately, that's not a good workaround as we're also trying to save column order as part of our state.
Two questions: is this a known bug (there's a comment in that method about this not having been tested at all) that might already be fixed? Alternatively, perhaps we're not doing the state retrieval/setting in the prescribed way - how else could we accomplish what we want to do?
Thanks for all information.
Tom
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SortOrder;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;

import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.table.TableColumnExt;

public class Main {

final private JFrame frame = new JFrame("Test");
private Table table = new Table();
private TableState tableState;

public static void main(String[] args) {
new Main();
}
public Main() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BorderLayout());

table.setModel(new TableModel());
table.setColumnControlVisible(true);

JButton getStateButton = new JButton("Get State");
getStateButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEventIn) {
tableState = table.getState();
}
});

JButton setStateButton = new JButton("Set State ColumnSequence");
setStateButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEventIn) {
if (tableState != null)
table.setState(tableState, true);
}
});
JButton setStateButton2 = new JButton("Set State NO ColumnSequence");
setStateButton2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEventIn) {
if (tableState != null)
table.setState(tableState, false);
}
});

JPanel buttonPanel = new JPanel();
buttonPanel.add(getStateButton);
buttonPanel.add(setStateButton);
buttonPanel.add(setStateButton2);

frame.add(new JScrollPane(table), BorderLayout.CENTER);
frame.add(buttonPanel, BorderLayout.SOUTH);

frame.pack();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
frame.setVisible(true);
frame.setBounds(200, 200, 700, 200);
}
});
}
public class Table extends JXTable {

public TableState getState() {

List<TableColumnState> tableColumnStateList = new ArrayList<TableColumnState>();
List<TableColumn> allColumns = getColumns(true); // Get both hidden and un-hidden columns.

for (TableColumn tableColumn : allColumns) {
TableColumnExt tableColumnExt = (TableColumnExt) tableColumn;
String identifier = tableColumnExt.getIdentifier().toString();
tableColumnStateList.add(new TableColumnState(identifier, tableColumn.getWidth(), tableColumnExt.isVisible(), getSortOrder(identifier)));
}
/*
* When some columns are hidden, there is no API call which will get you the correct sequence of the columns.
* The hidden columns are always put at the end of the visible columns after the state is saved. (Bad)
* To retain the proper sequence, first make all the columns visible.
* Make the call to get all the visible columns which WILL be in the proper sequence.
* Revert the table to its original state by hiding the columns which should really be hidden.
* I was concerned that it might cause flicker because the visibility is turned on and off quickly but it seems ok.
*/
List<TableColumnExt> hiddenColumns = new ArrayList<TableColumnExt>();
List<String> columnSequence = new ArrayList<String>(); // The sequence of columns to be saved with the state.

// Set all the columns visible or not hidden.
for (TableColumn tableColumn : allColumns) {
TableColumnExt tableColumnExt = (TableColumnExt) tableColumn;
if (tableColumnExt.isVisible() == false) {
/*
* If the column is hidden, then make it visible.
* Save this information so we can make it hidden again later.
*/
tableColumnExt.setVisible(true);
hiddenColumns.add(tableColumnExt);
}
}
/*
* Now that all the columns are visible, getColumns(false) will give the columns in the proper sequence.
* Save this order in the state.
*/
List<TableColumn> visibleColumnsInOrder = getColumns(false);

for (TableColumn t : visibleColumnsInOrder)
columnSequence.add(((TableColumnExt)t).getIdentifier().toString());

// Now put the visibility back to what it was.
for (TableColumnExt tableColumnExt : hiddenColumns) {
tableColumnExt.setVisible(false);
}
return (new TableState(tableColumnStateList, isHorizontalScrollEnabled(), columnSequence));
}

public void setState(final TableState tableStateIn, boolean doColumnSequenceIn) {

List<TableColumnState> tableColumnStateList = tableStateIn.getTableColumnStateList();

for (TableColumnState tableColumnState : tableColumnStateList) {
TableColumnExt tableColumnExt = getColumnExt(tableColumnState.getIdentifier());
if (tableColumnExt != null) {
tableColumnExt.setPreferredWidth(tableColumnState.getWidth());
tableColumnExt.setVisible(tableColumnState.isVisible());
}
}
setHorizontalScrollEnabled(tableStateIn.isHorizontalScrollEnabled());
/*
* Here is the problem.
* If setColumnSequence() is called, then all of the columns are made visible, even though they were specifically made hidden above.
*/
if (doColumnSequenceIn)
setColumnSequence(tableStateIn.getColumnSequence().toArray(new String[0]));

for (TableColumnState tableColumnState : tableColumnStateList) {
SortOrder sortOrder = tableColumnState.getSortOrder();
if (sortOrder != SortOrder.UNSORTED) {
setSortOrder(tableColumnState.getIdentifier(), sortOrder);
}
}
}
}

private class TableState {

private List<TableColumnState> tableColumnStateList;
private boolean horizontalScrollEnabled;
private List<String> columnSequence;

public TableState(List<TableColumnState> tableColumnStateListIn, boolean horizontalScrollEnabledIn, List<String> columnSequenceIn) {
tableColumnStateList = tableColumnStateListIn;
horizontalScrollEnabled = horizontalScrollEnabledIn;
columnSequence = columnSequenceIn;
}
public boolean isHorizontalScrollEnabled() { return (horizontalScrollEnabled); }
public List<String> getColumnSequence() { return (columnSequence); }
public List<TableColumnState> getTableColumnStateList() { return (tableColumnStateList); }

@Override
public String toString() {
StringBuffer stringBuffer = new StringBuffer("Table State:\n");
for (TableColumnState tableColumnState : tableColumnStateList) {
stringBuffer.append(tableColumnState).append('\n');
}
stringBuffer.append("Horizontal scroll enabled: " + horizontalScrollEnabled);
return (stringBuffer.toString());
}
}
private class TableColumnState {

private boolean visible;
private int width;
private SortOrder sortOrder;
private String identifier;

public TableColumnState(String identifierIn, int widthIn, boolean visibleIn, SortOrder sortOrderIn) {
identifier = identifierIn;
width = widthIn;
visible = visibleIn;
sortOrder = sortOrderIn;
}
public boolean isVisible() { return (visible); }
public int getWidth() { return (width); }
public SortOrder getSortOrder() { return (sortOrder); }
public String getIdentifier() { return identifier; }

@Override
public String toString() {
return ("Identifier=" + identifier + ", visible=" + visible + ", width=" + width + ", sort order=" + sortOrder);
}
}
private class TableModel extends AbstractTableModel {

private String[] columnNames = new String[] {"Column 1", "Column 2", "Column 3", "Column 4"};

@Override
public int getColumnCount() { return (columnNames == null) ? 0 : columnNames.length; }
@Override
public String getColumnName(int columnIndexIn) { return (columnNames[columnIndexIn]); }

@Override
public int getRowCount() { return (5); }

@Override
public Object getValueAt(int rowIndexIn, int columnIndexIn) { return (rowIndexIn + ", " + columnIndexIn); }
}

}

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
kschaefe
Offline
Joined: 2006-06-08
Points: 0

For those following along at home, this issue was reported and fixed.

http://java.net/jira/browse/SWINGX-1422

Karl