]> git.xonotic.org Git - xonotic/xonotic.git/blobdiff - misc/tools/NexuizDemoRecorder/main/src/main/java/com/nexuiz/demorecorder/ui/swinggui/utils/XProperties.java
fix lots of CRLFs
[xonotic/xonotic.git] / misc / tools / NexuizDemoRecorder / main / src / main / java / com / nexuiz / demorecorder / ui / swinggui / utils / XProperties.java
index 004b626223fad6881866333f0b12f6a64dfada14..757d802baa18351689cbd1d7b23c578baa5e7db5 100644 (file)
-/*\r
- * Created on 08.02.2007\r
- *\r
- */\r
-package com.nexuiz.demorecorder.ui.swinggui.utils;\r
-\r
-import java.awt.Component;\r
-import java.beans.DefaultPersistenceDelegate;\r
-import java.beans.XMLEncoder;\r
-import java.io.Serializable;\r
-import java.util.ArrayList;\r
-import java.util.Collections;\r
-import java.util.Comparator;\r
-import java.util.List;\r
-\r
-import javax.swing.SortOrder;\r
-import javax.swing.RowSorter.SortKey;\r
-import javax.swing.table.TableColumn;\r
-import javax.swing.table.TableColumnModel;\r
-\r
-import org.jdesktop.swingx.JXTable;\r
-import org.jdesktop.swingx.JXTaskPane;\r
-import org.jdesktop.swingx.sort.SortUtils;\r
-import org.jdesktop.swingx.table.TableColumnExt;\r
-\r
-/**\r
- * Container class for SwingX specific SessionStorage Properties. Is Factory for\r
- * custom PersistanceDelegates\r
- */\r
-public class XProperties {\r
-\r
-       /**\r
-        * \r
-        * Registers all custom PersistenceDelegates needed by contained Property\r
-        * classes.\r
-        * <p>\r
-        * \r
-        * PersistenceDelegates are effectively static properties shared by all\r
-        * encoders. In other words: Register once on an arbitrary encoder makes\r
-        * them available for all. Example usage:\r
-        * \r
-        * <pre>\r
-        * <code>\r
-        * new XProperties.registerPersistenceDelegates();\r
-        * </code>\r
-        * </pre>\r
-        * \r
-        * PENDING JW: cleanup for 1.6 sorting/filtering incomplete. Missing storage\r
-        * - multiple sort keys\r
-        * \r
-        * PENDING JW: except for comparators: didn't before and is not state that's\r
-        * configurable by users ... so probably won't, not sure, need to revisit -\r
-        * comparator (?) - filters (?) - renderers/stringvalues (?) - enhanced\r
-        * sort-related table state (?)\r
-        */\r
-       public void registerPersistenceDelegates() {\r
-               XMLEncoder encoder = new XMLEncoder(System.out);\r
-               encoder.setPersistenceDelegate(SortKeyState.class, new DefaultPersistenceDelegate(\r
-                               new String[] { "ascending", "modelIndex" }));\r
-               encoder.setPersistenceDelegate(ColumnState.class, new DefaultPersistenceDelegate(\r
-                               new String[] { "width", "preferredWidth", "modelIndex", "visible", "viewIndex" }));\r
-               encoder.setPersistenceDelegate(XTableState.class, new DefaultPersistenceDelegate(\r
-                               new String[] { "columnStates", "sortKeyState", "horizontalScrollEnabled" }));\r
-       }\r
-\r
-       /**\r
-        * Session storage support for JXTaskPane.\r
-        */\r
-       public static class XTaskPaneProperty implements Serializable {\r
-\r
-               private static final long serialVersionUID = -4069436038178318216L;\r
-\r
-               public Object getSessionState(Component c) {\r
-                       checkComponent(c);\r
-                       return new XTaskPaneState(((JXTaskPane) c).isCollapsed());\r
-               }\r
-\r
-               public void setSessionState(Component c, Object state) {\r
-                       checkComponent(c);\r
-                       if ((state != null) && !(state instanceof XTaskPaneState)) {\r
-                               throw new IllegalArgumentException("invalid state");\r
-                       }\r
-                       ((JXTaskPane) c).setCollapsed(((XTaskPaneState) state).isCollapsed());\r
-               }\r
-\r
-               private void checkComponent(Component component) {\r
-                       if (component == null) {\r
-                               throw new IllegalArgumentException("null component");\r
-                       }\r
-                       if (!(component instanceof JXTaskPane)) {\r
-                               throw new IllegalArgumentException("invalid component");\r
-                       }\r
-               }\r
-\r
-       }\r
-\r
-       public static class XTaskPaneState implements Serializable {\r
-               private static final long serialVersionUID = 3363688961112031969L;\r
-               private boolean collapsed;\r
-\r
-               public XTaskPaneState() {\r
-                       this(false);\r
-               }\r
-\r
-               /**\r
-                * @param b\r
-                */\r
-               public XTaskPaneState(boolean collapsed) {\r
-                       this.setCollapsed(collapsed);\r
-               }\r
-\r
-               /**\r
-                * @param collapsed\r
-                *            the collapsed to set\r
-                */\r
-               public void setCollapsed(boolean collapsed) {\r
-                       this.collapsed = collapsed;\r
-               }\r
-\r
-               /**\r
-                * @return the collapsed\r
-                */\r
-               public boolean isCollapsed() {\r
-                       return collapsed;\r
-               }\r
-\r
-       }\r
-\r
-       /**\r
-        * Session storage support for JXTable.\r
-        */\r
-       public static class XTableProperty implements Serializable {\r
-\r
-               private static final long serialVersionUID = -5064142292091374301L;\r
-\r
-               public Object getSessionState(Component c) {\r
-                       checkComponent(c);\r
-                       JXTable table = (JXTable) c;\r
-                       List<ColumnState> columnStates = new ArrayList<ColumnState>();\r
-                       List<TableColumn> columns = table.getColumns(true);\r
-                       List<TableColumn> visibleColumns = table.getColumns();\r
-                       for (TableColumn column : columns) {\r
-                               columnStates.add(new ColumnState((TableColumnExt) column, visibleColumns\r
-                                               .indexOf(column)));\r
-                       }\r
-                       XTableState tableState = new XTableState(columnStates\r
-                                       .toArray(new ColumnState[columnStates.size()]));\r
-                       tableState.setHorizontalScrollEnabled(table.isHorizontalScrollEnabled());\r
-                       List<? extends SortKey> sortKeys = null;\r
-                       if (table.getRowSorter() != null) {\r
-                               sortKeys = table.getRowSorter().getSortKeys();\r
-                       }\r
-                       // PENDING: store all!\r
-                       if ((sortKeys != null) && (sortKeys.size() > 0)) {\r
-                               tableState.setSortKey(sortKeys.get(0));\r
-                       }\r
-                       return tableState;\r
-               }\r
-\r
-               public void setSessionState(Component c, Object state) {\r
-                       checkComponent(c);\r
-                       JXTable table = (JXTable) c;\r
-                       XTableState tableState = ((XTableState) state);\r
-                       ColumnState[] columnState = tableState.getColumnStates();\r
-                       List<TableColumn> columns = table.getColumns(true);\r
-                       if (canRestore(columnState, columns)) {\r
-                               for (int i = 0; i < columnState.length; i++) {\r
-                                       columnState[i].configureColumn((TableColumnExt) columns.get(i));\r
-                               }\r
-                               restoreVisibleSequence(columnState, table.getColumnModel());\r
-                       }\r
-                       table.setHorizontalScrollEnabled(tableState.getHorizontalScrollEnabled());\r
-                       if (tableState.getSortKey() != null) {\r
-                               table.getRowSorter()\r
-                                               .setSortKeys(Collections.singletonList(tableState.getSortKey()));\r
-                       }\r
-               }\r
-\r
-               private void restoreVisibleSequence(ColumnState[] columnStates, TableColumnModel model) {\r
-                       List<ColumnState> visibleStates = getSortedVisibleColumnStates(columnStates);\r
-                       for (int i = 0; i < visibleStates.size(); i++) {\r
-                               TableColumn column = model.getColumn(i);\r
-                               int modelIndex = visibleStates.get(i).getModelIndex();\r
-                               if (modelIndex != column.getModelIndex()) {\r
-                                       int currentIndex = -1;\r
-                                       for (int j = i + 1; j < model.getColumnCount(); j++) {\r
-                                               TableColumn current = model.getColumn(j);\r
-                                               if (current.getModelIndex() == modelIndex) {\r
-                                                       currentIndex = j;\r
-                                                       break;\r
-                                               }\r
-                                       }\r
-                                       model.moveColumn(currentIndex, i);\r
-                               }\r
-                       }\r
-\r
-               }\r
-\r
-               private List<ColumnState> getSortedVisibleColumnStates(ColumnState[] columnStates) {\r
-                       List<ColumnState> visibleStates = new ArrayList<ColumnState>();\r
-                       for (ColumnState columnState : columnStates) {\r
-                               if (columnState.getVisible()) {\r
-                                       visibleStates.add(columnState);\r
-                               }\r
-                       }\r
-                       Collections.sort(visibleStates, new VisibleColumnIndexComparator());\r
-                       return visibleStates;\r
-               }\r
-\r
-               /**\r
-                * Returns a boolean to indicate if it's reasonably safe to restore the\r
-                * properties of columns in the list from the columnStates. Here:\r
-                * returns true if the length of both are the same and the modelIndex of\r
-                * the items at the same position are the same, otherwise returns false.\r
-                * \r
-                * @param columnState\r
-                * @param columns\r
-                * @return\r
-                */\r
-               private boolean canRestore(ColumnState[] columnState, List<TableColumn> columns) {\r
-                       if ((columnState == null) || (columnState.length != columns.size()))\r
-                               return false;\r
-                       for (int i = 0; i < columnState.length; i++) {\r
-                               if (columnState[i].getModelIndex() != columns.get(i).getModelIndex()) {\r
-                                       return false;\r
-                               }\r
-                       }\r
-                       return true;\r
-               }\r
-\r
-               private void checkComponent(Component component) {\r
-                       if (component == null) {\r
-                               throw new IllegalArgumentException("null component");\r
-                       }\r
-                       if (!(component instanceof JXTable)) {\r
-                               throw new IllegalArgumentException("invalid component - expected JXTable");\r
-                       }\r
-               }\r
-\r
-       }\r
-\r
-       public static class XTableState implements Serializable {\r
-               private static final long serialVersionUID = -3566913244872587438L;\r
-               ColumnState[] columnStates = new ColumnState[0];\r
-               boolean horizontalScrollEnabled;\r
-               SortKeyState sortKeyState;\r
-\r
-               public XTableState(ColumnState[] columnStates, SortKeyState sortKeyState,\r
-                               boolean horizontalScrollEnabled) {\r
-                       this.columnStates = copyColumnStates(columnStates);\r
-                       this.sortKeyState = sortKeyState;\r
-                       setHorizontalScrollEnabled(horizontalScrollEnabled);\r
-\r
-               }\r
-\r
-               public void setSortKey(SortKey sortKey) {\r
-                       this.sortKeyState = new SortKeyState(sortKey);\r
-\r
-               }\r
-\r
-               private SortKey getSortKey() {\r
-                       if (sortKeyState != null) {\r
-                               return sortKeyState.getSortKey();\r
-                       }\r
-                       return null;\r
-               }\r
-\r
-               public XTableState(ColumnState[] columnStates) {\r
-                       this.columnStates = copyColumnStates(columnStates);\r
-               }\r
-\r
-               public ColumnState[] getColumnStates() {\r
-                       return copyColumnStates(this.columnStates);\r
-               }\r
-\r
-               public boolean getHorizontalScrollEnabled() {\r
-                       return horizontalScrollEnabled;\r
-               }\r
-\r
-               public void setHorizontalScrollEnabled(boolean horizontalScrollEnabled) {\r
-                       this.horizontalScrollEnabled = horizontalScrollEnabled;\r
-               }\r
-\r
-               private ColumnState[] copyColumnStates(ColumnState[] states) {\r
-                       if (states == null) {\r
-                               throw new IllegalArgumentException("invalid columnWidths");\r
-                       }\r
-                       ColumnState[] copy = new ColumnState[states.length];\r
-                       System.arraycopy(states, 0, copy, 0, states.length);\r
-                       return copy;\r
-               }\r
-\r
-               public SortKeyState getSortKeyState() {\r
-                       return sortKeyState;\r
-               }\r
-       }\r
-\r
-       /**\r
-        * Quick hack to make SortKey encodable. How to write a PersistenceDelegate\r
-        * for a SortKey? Boils down to how to write a delegate for the\r
-        * uninstantiable class (SwingX) SortOrder which does enum-mimickry (defines\r
-        * privately intantiated constants)\r
-        * \r
-        */\r
-       public static class SortKeyState implements Serializable {\r
-               private static final long serialVersionUID = 5819342622261460894L;\r
-\r
-               int modelIndex;\r
-\r
-               boolean ascending;\r
-\r
-               /**\r
-                * Constructor used by the custom PersistenceDelegate.\r
-                * \r
-                * @param ascending\r
-                * @param modelIndex\r
-                * @param comparator\r
-                */\r
-               public SortKeyState(boolean ascending, int modelIndex) {\r
-                       this.ascending = ascending;\r
-                       this.modelIndex = modelIndex;\r
-               }\r
-\r
-               /**\r
-                * Constructor used by property.\r
-                * \r
-                * @param sortKey\r
-                */\r
-               public SortKeyState(SortKey sortKey) {\r
-                       this(SortUtils.isAscending(sortKey.getSortOrder()), sortKey.getColumn());\r
-               }\r
-\r
-               protected SortKey getSortKey() {\r
-                       SortOrder sortOrder = getAscending() ? SortOrder.ASCENDING : SortOrder.DESCENDING;\r
-                       return new SortKey(getModelIndex(), sortOrder);\r
-               }\r
-\r
-               public boolean getAscending() {\r
-                       return ascending;\r
-               }\r
-\r
-               public int getModelIndex() {\r
-                       return modelIndex;\r
-               }\r
-       }\r
-\r
-       public static class ColumnState implements Serializable {\r
-               private static final long serialVersionUID = 6037947151025126049L;\r
-               private int width;\r
-               private int preferredWidth;\r
-               private int modelIndex;\r
-               private boolean visible;\r
-               private int viewIndex;\r
-\r
-               /**\r
-                * Constructor used by the custom PersistenceDelegate.\r
-                * \r
-                * @param width\r
-                * @param preferredWidth\r
-                * @param modelColumn\r
-                * @param visible\r
-                * @param viewIndex\r
-                */\r
-               public ColumnState(int width, int preferredWidth, int modelColumn, boolean visible,\r
-                               int viewIndex) {\r
-                       this.width = width;\r
-                       this.preferredWidth = preferredWidth;\r
-                       this.modelIndex = modelColumn;\r
-                       this.visible = visible;\r
-                       this.viewIndex = viewIndex;\r
-               }\r
-\r
-               /**\r
-                * Constructor used by the Property.\r
-                * \r
-                * @param columnExt\r
-                * @param viewIndex\r
-                */\r
-               public ColumnState(TableColumnExt columnExt, int viewIndex) {\r
-                       this(columnExt.getWidth(), columnExt.getPreferredWidth(), columnExt.getModelIndex(),\r
-                                       columnExt.isVisible(), viewIndex);\r
-               }\r
-\r
-               /**\r
-                * Restores column properties if the model index is the same as the\r
-                * column's model index. Does nothing otherwise.\r
-                * <p>\r
-                * \r
-                * Here the properties are: width, preferredWidth, visible.\r
-                * \r
-                * @param columnExt\r
-                *            the column to configure\r
-                */\r
-               public void configureColumn(TableColumnExt columnExt) {\r
-                       if (modelIndex != columnExt.getModelIndex())\r
-                               return;\r
-                       columnExt.setPreferredWidth(preferredWidth);\r
-                       columnExt.setWidth(width);\r
-                       columnExt.setVisible(visible);\r
-               }\r
-\r
-               public int getModelIndex() {\r
-                       return modelIndex;\r
-               }\r
-\r
-               public int getViewIndex() {\r
-                       return viewIndex;\r
-               }\r
-\r
-               public boolean getVisible() {\r
-                       return visible;\r
-               }\r
-\r
-               public int getWidth() {\r
-                       return width;\r
-               }\r
-\r
-               public int getPreferredWidth() {\r
-                       return preferredWidth;\r
-               }\r
-\r
-       }\r
-\r
-       public static class VisibleColumnIndexComparator implements Comparator<Object> {\r
-\r
-               public int compare(Object o1, Object o2) {\r
-                       return ((ColumnState) o1).getViewIndex() - ((ColumnState) o2).getViewIndex();\r
-               }\r
-\r
-       }\r
-\r
-}\r
+/*
+ * Created on 08.02.2007
+ *
+ */
+package com.nexuiz.demorecorder.ui.swinggui.utils;
+
+import java.awt.Component;
+import java.beans.DefaultPersistenceDelegate;
+import java.beans.XMLEncoder;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import javax.swing.SortOrder;
+import javax.swing.RowSorter.SortKey;
+import javax.swing.table.TableColumn;
+import javax.swing.table.TableColumnModel;
+
+import org.jdesktop.swingx.JXTable;
+import org.jdesktop.swingx.JXTaskPane;
+import org.jdesktop.swingx.sort.SortUtils;
+import org.jdesktop.swingx.table.TableColumnExt;
+
+/**
+ * Container class for SwingX specific SessionStorage Properties. Is Factory for
+ * custom PersistanceDelegates
+ */
+public class XProperties {
+
+       /**
+        * 
+        * Registers all custom PersistenceDelegates needed by contained Property
+        * classes.
+        * <p>
+        * 
+        * PersistenceDelegates are effectively static properties shared by all
+        * encoders. In other words: Register once on an arbitrary encoder makes
+        * them available for all. Example usage:
+        * 
+        * <pre>
+        * <code>
+        * new XProperties.registerPersistenceDelegates();
+        * </code>
+        * </pre>
+        * 
+        * PENDING JW: cleanup for 1.6 sorting/filtering incomplete. Missing storage
+        * - multiple sort keys
+        * 
+        * PENDING JW: except for comparators: didn't before and is not state that's
+        * configurable by users ... so probably won't, not sure, need to revisit -
+        * comparator (?) - filters (?) - renderers/stringvalues (?) - enhanced
+        * sort-related table state (?)
+        */
+       public void registerPersistenceDelegates() {
+               XMLEncoder encoder = new XMLEncoder(System.out);
+               encoder.setPersistenceDelegate(SortKeyState.class, new DefaultPersistenceDelegate(
+                               new String[] { "ascending", "modelIndex" }));
+               encoder.setPersistenceDelegate(ColumnState.class, new DefaultPersistenceDelegate(
+                               new String[] { "width", "preferredWidth", "modelIndex", "visible", "viewIndex" }));
+               encoder.setPersistenceDelegate(XTableState.class, new DefaultPersistenceDelegate(
+                               new String[] { "columnStates", "sortKeyState", "horizontalScrollEnabled" }));
+       }
+
+       /**
+        * Session storage support for JXTaskPane.
+        */
+       public static class XTaskPaneProperty implements Serializable {
+
+               private static final long serialVersionUID = -4069436038178318216L;
+
+               public Object getSessionState(Component c) {
+                       checkComponent(c);
+                       return new XTaskPaneState(((JXTaskPane) c).isCollapsed());
+               }
+
+               public void setSessionState(Component c, Object state) {
+                       checkComponent(c);
+                       if ((state != null) && !(state instanceof XTaskPaneState)) {
+                               throw new IllegalArgumentException("invalid state");
+                       }
+                       ((JXTaskPane) c).setCollapsed(((XTaskPaneState) state).isCollapsed());
+               }
+
+               private void checkComponent(Component component) {
+                       if (component == null) {
+                               throw new IllegalArgumentException("null component");
+                       }
+                       if (!(component instanceof JXTaskPane)) {
+                               throw new IllegalArgumentException("invalid component");
+                       }
+               }
+
+       }
+
+       public static class XTaskPaneState implements Serializable {
+               private static final long serialVersionUID = 3363688961112031969L;
+               private boolean collapsed;
+
+               public XTaskPaneState() {
+                       this(false);
+               }
+
+               /**
+                * @param b
+                */
+               public XTaskPaneState(boolean collapsed) {
+                       this.setCollapsed(collapsed);
+               }
+
+               /**
+                * @param collapsed
+                *            the collapsed to set
+                */
+               public void setCollapsed(boolean collapsed) {
+                       this.collapsed = collapsed;
+               }
+
+               /**
+                * @return the collapsed
+                */
+               public boolean isCollapsed() {
+                       return collapsed;
+               }
+
+       }
+
+       /**
+        * Session storage support for JXTable.
+        */
+       public static class XTableProperty implements Serializable {
+
+               private static final long serialVersionUID = -5064142292091374301L;
+
+               public Object getSessionState(Component c) {
+                       checkComponent(c);
+                       JXTable table = (JXTable) c;
+                       List<ColumnState> columnStates = new ArrayList<ColumnState>();
+                       List<TableColumn> columns = table.getColumns(true);
+                       List<TableColumn> visibleColumns = table.getColumns();
+                       for (TableColumn column : columns) {
+                               columnStates.add(new ColumnState((TableColumnExt) column, visibleColumns
+                                               .indexOf(column)));
+                       }
+                       XTableState tableState = new XTableState(columnStates
+                                       .toArray(new ColumnState[columnStates.size()]));
+                       tableState.setHorizontalScrollEnabled(table.isHorizontalScrollEnabled());
+                       List<? extends SortKey> sortKeys = null;
+                       if (table.getRowSorter() != null) {
+                               sortKeys = table.getRowSorter().getSortKeys();
+                       }
+                       // PENDING: store all!
+                       if ((sortKeys != null) && (sortKeys.size() > 0)) {
+                               tableState.setSortKey(sortKeys.get(0));
+                       }
+                       return tableState;
+               }
+
+               public void setSessionState(Component c, Object state) {
+                       checkComponent(c);
+                       JXTable table = (JXTable) c;
+                       XTableState tableState = ((XTableState) state);
+                       ColumnState[] columnState = tableState.getColumnStates();
+                       List<TableColumn> columns = table.getColumns(true);
+                       if (canRestore(columnState, columns)) {
+                               for (int i = 0; i < columnState.length; i++) {
+                                       columnState[i].configureColumn((TableColumnExt) columns.get(i));
+                               }
+                               restoreVisibleSequence(columnState, table.getColumnModel());
+                       }
+                       table.setHorizontalScrollEnabled(tableState.getHorizontalScrollEnabled());
+                       if (tableState.getSortKey() != null) {
+                               table.getRowSorter()
+                                               .setSortKeys(Collections.singletonList(tableState.getSortKey()));
+                       }
+               }
+
+               private void restoreVisibleSequence(ColumnState[] columnStates, TableColumnModel model) {
+                       List<ColumnState> visibleStates = getSortedVisibleColumnStates(columnStates);
+                       for (int i = 0; i < visibleStates.size(); i++) {
+                               TableColumn column = model.getColumn(i);
+                               int modelIndex = visibleStates.get(i).getModelIndex();
+                               if (modelIndex != column.getModelIndex()) {
+                                       int currentIndex = -1;
+                                       for (int j = i + 1; j < model.getColumnCount(); j++) {
+                                               TableColumn current = model.getColumn(j);
+                                               if (current.getModelIndex() == modelIndex) {
+                                                       currentIndex = j;
+                                                       break;
+                                               }
+                                       }
+                                       model.moveColumn(currentIndex, i);
+                               }
+                       }
+
+               }
+
+               private List<ColumnState> getSortedVisibleColumnStates(ColumnState[] columnStates) {
+                       List<ColumnState> visibleStates = new ArrayList<ColumnState>();
+                       for (ColumnState columnState : columnStates) {
+                               if (columnState.getVisible()) {
+                                       visibleStates.add(columnState);
+                               }
+                       }
+                       Collections.sort(visibleStates, new VisibleColumnIndexComparator());
+                       return visibleStates;
+               }
+
+               /**
+                * Returns a boolean to indicate if it's reasonably safe to restore the
+                * properties of columns in the list from the columnStates. Here:
+                * returns true if the length of both are the same and the modelIndex of
+                * the items at the same position are the same, otherwise returns false.
+                * 
+                * @param columnState
+                * @param columns
+                * @return
+                */
+               private boolean canRestore(ColumnState[] columnState, List<TableColumn> columns) {
+                       if ((columnState == null) || (columnState.length != columns.size()))
+                               return false;
+                       for (int i = 0; i < columnState.length; i++) {
+                               if (columnState[i].getModelIndex() != columns.get(i).getModelIndex()) {
+                                       return false;
+                               }
+                       }
+                       return true;
+               }
+
+               private void checkComponent(Component component) {
+                       if (component == null) {
+                               throw new IllegalArgumentException("null component");
+                       }
+                       if (!(component instanceof JXTable)) {
+                               throw new IllegalArgumentException("invalid component - expected JXTable");
+                       }
+               }
+
+       }
+
+       public static class XTableState implements Serializable {
+               private static final long serialVersionUID = -3566913244872587438L;
+               ColumnState[] columnStates = new ColumnState[0];
+               boolean horizontalScrollEnabled;
+               SortKeyState sortKeyState;
+
+               public XTableState(ColumnState[] columnStates, SortKeyState sortKeyState,
+                               boolean horizontalScrollEnabled) {
+                       this.columnStates = copyColumnStates(columnStates);
+                       this.sortKeyState = sortKeyState;
+                       setHorizontalScrollEnabled(horizontalScrollEnabled);
+
+               }
+
+               public void setSortKey(SortKey sortKey) {
+                       this.sortKeyState = new SortKeyState(sortKey);
+
+               }
+
+               private SortKey getSortKey() {
+                       if (sortKeyState != null) {
+                               return sortKeyState.getSortKey();
+                       }
+                       return null;
+               }
+
+               public XTableState(ColumnState[] columnStates) {
+                       this.columnStates = copyColumnStates(columnStates);
+               }
+
+               public ColumnState[] getColumnStates() {
+                       return copyColumnStates(this.columnStates);
+               }
+
+               public boolean getHorizontalScrollEnabled() {
+                       return horizontalScrollEnabled;
+               }
+
+               public void setHorizontalScrollEnabled(boolean horizontalScrollEnabled) {
+                       this.horizontalScrollEnabled = horizontalScrollEnabled;
+               }
+
+               private ColumnState[] copyColumnStates(ColumnState[] states) {
+                       if (states == null) {
+                               throw new IllegalArgumentException("invalid columnWidths");
+                       }
+                       ColumnState[] copy = new ColumnState[states.length];
+                       System.arraycopy(states, 0, copy, 0, states.length);
+                       return copy;
+               }
+
+               public SortKeyState getSortKeyState() {
+                       return sortKeyState;
+               }
+       }
+
+       /**
+        * Quick hack to make SortKey encodable. How to write a PersistenceDelegate
+        * for a SortKey? Boils down to how to write a delegate for the
+        * uninstantiable class (SwingX) SortOrder which does enum-mimickry (defines
+        * privately intantiated constants)
+        * 
+        */
+       public static class SortKeyState implements Serializable {
+               private static final long serialVersionUID = 5819342622261460894L;
+
+               int modelIndex;
+
+               boolean ascending;
+
+               /**
+                * Constructor used by the custom PersistenceDelegate.
+                * 
+                * @param ascending
+                * @param modelIndex
+                * @param comparator
+                */
+               public SortKeyState(boolean ascending, int modelIndex) {
+                       this.ascending = ascending;
+                       this.modelIndex = modelIndex;
+               }
+
+               /**
+                * Constructor used by property.
+                * 
+                * @param sortKey
+                */
+               public SortKeyState(SortKey sortKey) {
+                       this(SortUtils.isAscending(sortKey.getSortOrder()), sortKey.getColumn());
+               }
+
+               protected SortKey getSortKey() {
+                       SortOrder sortOrder = getAscending() ? SortOrder.ASCENDING : SortOrder.DESCENDING;
+                       return new SortKey(getModelIndex(), sortOrder);
+               }
+
+               public boolean getAscending() {
+                       return ascending;
+               }
+
+               public int getModelIndex() {
+                       return modelIndex;
+               }
+       }
+
+       public static class ColumnState implements Serializable {
+               private static final long serialVersionUID = 6037947151025126049L;
+               private int width;
+               private int preferredWidth;
+               private int modelIndex;
+               private boolean visible;
+               private int viewIndex;
+
+               /**
+                * Constructor used by the custom PersistenceDelegate.
+                * 
+                * @param width
+                * @param preferredWidth
+                * @param modelColumn
+                * @param visible
+                * @param viewIndex
+                */
+               public ColumnState(int width, int preferredWidth, int modelColumn, boolean visible,
+                               int viewIndex) {
+                       this.width = width;
+                       this.preferredWidth = preferredWidth;
+                       this.modelIndex = modelColumn;
+                       this.visible = visible;
+                       this.viewIndex = viewIndex;
+               }
+
+               /**
+                * Constructor used by the Property.
+                * 
+                * @param columnExt
+                * @param viewIndex
+                */
+               public ColumnState(TableColumnExt columnExt, int viewIndex) {
+                       this(columnExt.getWidth(), columnExt.getPreferredWidth(), columnExt.getModelIndex(),
+                                       columnExt.isVisible(), viewIndex);
+               }
+
+               /**
+                * Restores column properties if the model index is the same as the
+                * column's model index. Does nothing otherwise.
+                * <p>
+                * 
+                * Here the properties are: width, preferredWidth, visible.
+                * 
+                * @param columnExt
+                *            the column to configure
+                */
+               public void configureColumn(TableColumnExt columnExt) {
+                       if (modelIndex != columnExt.getModelIndex())
+                               return;
+                       columnExt.setPreferredWidth(preferredWidth);
+                       columnExt.setWidth(width);
+                       columnExt.setVisible(visible);
+               }
+
+               public int getModelIndex() {
+                       return modelIndex;
+               }
+
+               public int getViewIndex() {
+                       return viewIndex;
+               }
+
+               public boolean getVisible() {
+                       return visible;
+               }
+
+               public int getWidth() {
+                       return width;
+               }
+
+               public int getPreferredWidth() {
+                       return preferredWidth;
+               }
+
+       }
+
+       public static class VisibleColumnIndexComparator implements Comparator<Object> {
+
+               public int compare(Object o1, Object o2) {
+                       return ((ColumnState) o1).getViewIndex() - ((ColumnState) o2).getViewIndex();
+               }
+
+       }
+
+}