2 * Created on 08.02.2007
\r
5 package com.nexuiz.demorecorder.ui.swinggui.utils;
\r
7 import java.awt.Component;
\r
8 import java.beans.DefaultPersistenceDelegate;
\r
9 import java.beans.XMLEncoder;
\r
10 import java.io.Serializable;
\r
11 import java.util.ArrayList;
\r
12 import java.util.Collections;
\r
13 import java.util.Comparator;
\r
14 import java.util.List;
\r
16 import javax.swing.SortOrder;
\r
17 import javax.swing.RowSorter.SortKey;
\r
18 import javax.swing.table.TableColumn;
\r
19 import javax.swing.table.TableColumnModel;
\r
21 import org.jdesktop.swingx.JXTable;
\r
22 import org.jdesktop.swingx.JXTaskPane;
\r
23 import org.jdesktop.swingx.sort.SortUtils;
\r
24 import org.jdesktop.swingx.table.TableColumnExt;
\r
27 * Container class for SwingX specific SessionStorage Properties. Is Factory for
\r
28 * custom PersistanceDelegates
\r
30 public class XProperties {
\r
34 * Registers all custom PersistenceDelegates needed by contained Property
\r
38 * PersistenceDelegates are effectively static properties shared by all
\r
39 * encoders. In other words: Register once on an arbitrary encoder makes
\r
40 * them available for all. Example usage:
\r
44 * new XProperties.registerPersistenceDelegates();
\r
48 * PENDING JW: cleanup for 1.6 sorting/filtering incomplete. Missing storage
\r
49 * - multiple sort keys
\r
51 * PENDING JW: except for comparators: didn't before and is not state that's
\r
52 * configurable by users ... so probably won't, not sure, need to revisit -
\r
53 * comparator (?) - filters (?) - renderers/stringvalues (?) - enhanced
\r
54 * sort-related table state (?)
\r
56 public void registerPersistenceDelegates() {
\r
57 XMLEncoder encoder = new XMLEncoder(System.out);
\r
58 encoder.setPersistenceDelegate(SortKeyState.class, new DefaultPersistenceDelegate(
\r
59 new String[] { "ascending", "modelIndex" }));
\r
60 encoder.setPersistenceDelegate(ColumnState.class, new DefaultPersistenceDelegate(
\r
61 new String[] { "width", "preferredWidth", "modelIndex", "visible", "viewIndex" }));
\r
62 encoder.setPersistenceDelegate(XTableState.class, new DefaultPersistenceDelegate(
\r
63 new String[] { "columnStates", "sortKeyState", "horizontalScrollEnabled" }));
\r
67 * Session storage support for JXTaskPane.
\r
69 public static class XTaskPaneProperty implements Serializable {
\r
71 private static final long serialVersionUID = -4069436038178318216L;
\r
73 public Object getSessionState(Component c) {
\r
75 return new XTaskPaneState(((JXTaskPane) c).isCollapsed());
\r
78 public void setSessionState(Component c, Object state) {
\r
80 if ((state != null) && !(state instanceof XTaskPaneState)) {
\r
81 throw new IllegalArgumentException("invalid state");
\r
83 ((JXTaskPane) c).setCollapsed(((XTaskPaneState) state).isCollapsed());
\r
86 private void checkComponent(Component component) {
\r
87 if (component == null) {
\r
88 throw new IllegalArgumentException("null component");
\r
90 if (!(component instanceof JXTaskPane)) {
\r
91 throw new IllegalArgumentException("invalid component");
\r
97 public static class XTaskPaneState implements Serializable {
\r
98 private static final long serialVersionUID = 3363688961112031969L;
\r
99 private boolean collapsed;
\r
101 public XTaskPaneState() {
\r
108 public XTaskPaneState(boolean collapsed) {
\r
109 this.setCollapsed(collapsed);
\r
114 * the collapsed to set
\r
116 public void setCollapsed(boolean collapsed) {
\r
117 this.collapsed = collapsed;
\r
121 * @return the collapsed
\r
123 public boolean isCollapsed() {
\r
130 * Session storage support for JXTable.
\r
132 public static class XTableProperty implements Serializable {
\r
134 private static final long serialVersionUID = -5064142292091374301L;
\r
136 public Object getSessionState(Component c) {
\r
138 JXTable table = (JXTable) c;
\r
139 List<ColumnState> columnStates = new ArrayList<ColumnState>();
\r
140 List<TableColumn> columns = table.getColumns(true);
\r
141 List<TableColumn> visibleColumns = table.getColumns();
\r
142 for (TableColumn column : columns) {
\r
143 columnStates.add(new ColumnState((TableColumnExt) column, visibleColumns
\r
144 .indexOf(column)));
\r
146 XTableState tableState = new XTableState(columnStates
\r
147 .toArray(new ColumnState[columnStates.size()]));
\r
148 tableState.setHorizontalScrollEnabled(table.isHorizontalScrollEnabled());
\r
149 List<? extends SortKey> sortKeys = null;
\r
150 if (table.getRowSorter() != null) {
\r
151 sortKeys = table.getRowSorter().getSortKeys();
\r
153 // PENDING: store all!
\r
154 if ((sortKeys != null) && (sortKeys.size() > 0)) {
\r
155 tableState.setSortKey(sortKeys.get(0));
\r
160 public void setSessionState(Component c, Object state) {
\r
162 JXTable table = (JXTable) c;
\r
163 XTableState tableState = ((XTableState) state);
\r
164 ColumnState[] columnState = tableState.getColumnStates();
\r
165 List<TableColumn> columns = table.getColumns(true);
\r
166 if (canRestore(columnState, columns)) {
\r
167 for (int i = 0; i < columnState.length; i++) {
\r
168 columnState[i].configureColumn((TableColumnExt) columns.get(i));
\r
170 restoreVisibleSequence(columnState, table.getColumnModel());
\r
172 table.setHorizontalScrollEnabled(tableState.getHorizontalScrollEnabled());
\r
173 if (tableState.getSortKey() != null) {
\r
174 table.getRowSorter()
\r
175 .setSortKeys(Collections.singletonList(tableState.getSortKey()));
\r
179 private void restoreVisibleSequence(ColumnState[] columnStates, TableColumnModel model) {
\r
180 List<ColumnState> visibleStates = getSortedVisibleColumnStates(columnStates);
\r
181 for (int i = 0; i < visibleStates.size(); i++) {
\r
182 TableColumn column = model.getColumn(i);
\r
183 int modelIndex = visibleStates.get(i).getModelIndex();
\r
184 if (modelIndex != column.getModelIndex()) {
\r
185 int currentIndex = -1;
\r
186 for (int j = i + 1; j < model.getColumnCount(); j++) {
\r
187 TableColumn current = model.getColumn(j);
\r
188 if (current.getModelIndex() == modelIndex) {
\r
193 model.moveColumn(currentIndex, i);
\r
199 private List<ColumnState> getSortedVisibleColumnStates(ColumnState[] columnStates) {
\r
200 List<ColumnState> visibleStates = new ArrayList<ColumnState>();
\r
201 for (ColumnState columnState : columnStates) {
\r
202 if (columnState.getVisible()) {
\r
203 visibleStates.add(columnState);
\r
206 Collections.sort(visibleStates, new VisibleColumnIndexComparator());
\r
207 return visibleStates;
\r
211 * Returns a boolean to indicate if it's reasonably safe to restore the
\r
212 * properties of columns in the list from the columnStates. Here:
\r
213 * returns true if the length of both are the same and the modelIndex of
\r
214 * the items at the same position are the same, otherwise returns false.
\r
216 * @param columnState
\r
220 private boolean canRestore(ColumnState[] columnState, List<TableColumn> columns) {
\r
221 if ((columnState == null) || (columnState.length != columns.size()))
\r
223 for (int i = 0; i < columnState.length; i++) {
\r
224 if (columnState[i].getModelIndex() != columns.get(i).getModelIndex()) {
\r
231 private void checkComponent(Component component) {
\r
232 if (component == null) {
\r
233 throw new IllegalArgumentException("null component");
\r
235 if (!(component instanceof JXTable)) {
\r
236 throw new IllegalArgumentException("invalid component - expected JXTable");
\r
242 public static class XTableState implements Serializable {
\r
243 private static final long serialVersionUID = -3566913244872587438L;
\r
244 ColumnState[] columnStates = new ColumnState[0];
\r
245 boolean horizontalScrollEnabled;
\r
246 SortKeyState sortKeyState;
\r
248 public XTableState(ColumnState[] columnStates, SortKeyState sortKeyState,
\r
249 boolean horizontalScrollEnabled) {
\r
250 this.columnStates = copyColumnStates(columnStates);
\r
251 this.sortKeyState = sortKeyState;
\r
252 setHorizontalScrollEnabled(horizontalScrollEnabled);
\r
256 public void setSortKey(SortKey sortKey) {
\r
257 this.sortKeyState = new SortKeyState(sortKey);
\r
261 private SortKey getSortKey() {
\r
262 if (sortKeyState != null) {
\r
263 return sortKeyState.getSortKey();
\r
268 public XTableState(ColumnState[] columnStates) {
\r
269 this.columnStates = copyColumnStates(columnStates);
\r
272 public ColumnState[] getColumnStates() {
\r
273 return copyColumnStates(this.columnStates);
\r
276 public boolean getHorizontalScrollEnabled() {
\r
277 return horizontalScrollEnabled;
\r
280 public void setHorizontalScrollEnabled(boolean horizontalScrollEnabled) {
\r
281 this.horizontalScrollEnabled = horizontalScrollEnabled;
\r
284 private ColumnState[] copyColumnStates(ColumnState[] states) {
\r
285 if (states == null) {
\r
286 throw new IllegalArgumentException("invalid columnWidths");
\r
288 ColumnState[] copy = new ColumnState[states.length];
\r
289 System.arraycopy(states, 0, copy, 0, states.length);
\r
293 public SortKeyState getSortKeyState() {
\r
294 return sortKeyState;
\r
299 * Quick hack to make SortKey encodable. How to write a PersistenceDelegate
\r
300 * for a SortKey? Boils down to how to write a delegate for the
\r
301 * uninstantiable class (SwingX) SortOrder which does enum-mimickry (defines
\r
302 * privately intantiated constants)
\r
305 public static class SortKeyState implements Serializable {
\r
306 private static final long serialVersionUID = 5819342622261460894L;
\r
313 * Constructor used by the custom PersistenceDelegate.
\r
316 * @param modelIndex
\r
317 * @param comparator
\r
319 public SortKeyState(boolean ascending, int modelIndex) {
\r
320 this.ascending = ascending;
\r
321 this.modelIndex = modelIndex;
\r
325 * Constructor used by property.
\r
329 public SortKeyState(SortKey sortKey) {
\r
330 this(SortUtils.isAscending(sortKey.getSortOrder()), sortKey.getColumn());
\r
333 protected SortKey getSortKey() {
\r
334 SortOrder sortOrder = getAscending() ? SortOrder.ASCENDING : SortOrder.DESCENDING;
\r
335 return new SortKey(getModelIndex(), sortOrder);
\r
338 public boolean getAscending() {
\r
342 public int getModelIndex() {
\r
347 public static class ColumnState implements Serializable {
\r
348 private static final long serialVersionUID = 6037947151025126049L;
\r
350 private int preferredWidth;
\r
351 private int modelIndex;
\r
352 private boolean visible;
\r
353 private int viewIndex;
\r
356 * Constructor used by the custom PersistenceDelegate.
\r
359 * @param preferredWidth
\r
360 * @param modelColumn
\r
364 public ColumnState(int width, int preferredWidth, int modelColumn, boolean visible,
\r
366 this.width = width;
\r
367 this.preferredWidth = preferredWidth;
\r
368 this.modelIndex = modelColumn;
\r
369 this.visible = visible;
\r
370 this.viewIndex = viewIndex;
\r
374 * Constructor used by the Property.
\r
379 public ColumnState(TableColumnExt columnExt, int viewIndex) {
\r
380 this(columnExt.getWidth(), columnExt.getPreferredWidth(), columnExt.getModelIndex(),
\r
381 columnExt.isVisible(), viewIndex);
\r
385 * Restores column properties if the model index is the same as the
\r
386 * column's model index. Does nothing otherwise.
\r
389 * Here the properties are: width, preferredWidth, visible.
\r
392 * the column to configure
\r
394 public void configureColumn(TableColumnExt columnExt) {
\r
395 if (modelIndex != columnExt.getModelIndex())
\r
397 columnExt.setPreferredWidth(preferredWidth);
\r
398 columnExt.setWidth(width);
\r
399 columnExt.setVisible(visible);
\r
402 public int getModelIndex() {
\r
406 public int getViewIndex() {
\r
410 public boolean getVisible() {
\r
414 public int getWidth() {
\r
418 public int getPreferredWidth() {
\r
419 return preferredWidth;
\r
424 public static class VisibleColumnIndexComparator implements Comparator<Object> {
\r
426 public int compare(Object o1, Object o2) {
\r
427 return ((ColumnState) o1).getViewIndex() - ((ColumnState) o2).getViewIndex();
\r