]> git.xonotic.org Git - xonotic/xonotic.git/blob - misc/tools/NexuizDemoRecorder/main/src/main/java/com/nexuiz/demorecorder/ui/swinggui/utils/XProperties.java
initial checkin from nexuiz svn r8756
[xonotic/xonotic.git] / misc / tools / NexuizDemoRecorder / main / src / main / java / com / nexuiz / demorecorder / ui / swinggui / utils / XProperties.java
1 /*\r
2  * Created on 08.02.2007\r
3  *\r
4  */\r
5 package com.nexuiz.demorecorder.ui.swinggui.utils;\r
6 \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
15 \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
20 \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
25 \r
26 /**\r
27  * Container class for SwingX specific SessionStorage Properties. Is Factory for\r
28  * custom PersistanceDelegates\r
29  */\r
30 public class XProperties {\r
31 \r
32         /**\r
33          * \r
34          * Registers all custom PersistenceDelegates needed by contained Property\r
35          * classes.\r
36          * <p>\r
37          * \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
41          * \r
42          * <pre>\r
43          * <code>\r
44          * new XProperties.registerPersistenceDelegates();\r
45          * </code>\r
46          * </pre>\r
47          * \r
48          * PENDING JW: cleanup for 1.6 sorting/filtering incomplete. Missing storage\r
49          * - multiple sort keys\r
50          * \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
55          */\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
64         }\r
65 \r
66         /**\r
67          * Session storage support for JXTaskPane.\r
68          */\r
69         public static class XTaskPaneProperty implements Serializable {\r
70 \r
71                 private static final long serialVersionUID = -4069436038178318216L;\r
72 \r
73                 public Object getSessionState(Component c) {\r
74                         checkComponent(c);\r
75                         return new XTaskPaneState(((JXTaskPane) c).isCollapsed());\r
76                 }\r
77 \r
78                 public void setSessionState(Component c, Object state) {\r
79                         checkComponent(c);\r
80                         if ((state != null) && !(state instanceof XTaskPaneState)) {\r
81                                 throw new IllegalArgumentException("invalid state");\r
82                         }\r
83                         ((JXTaskPane) c).setCollapsed(((XTaskPaneState) state).isCollapsed());\r
84                 }\r
85 \r
86                 private void checkComponent(Component component) {\r
87                         if (component == null) {\r
88                                 throw new IllegalArgumentException("null component");\r
89                         }\r
90                         if (!(component instanceof JXTaskPane)) {\r
91                                 throw new IllegalArgumentException("invalid component");\r
92                         }\r
93                 }\r
94 \r
95         }\r
96 \r
97         public static class XTaskPaneState implements Serializable {\r
98                 private static final long serialVersionUID = 3363688961112031969L;\r
99                 private boolean collapsed;\r
100 \r
101                 public XTaskPaneState() {\r
102                         this(false);\r
103                 }\r
104 \r
105                 /**\r
106                  * @param b\r
107                  */\r
108                 public XTaskPaneState(boolean collapsed) {\r
109                         this.setCollapsed(collapsed);\r
110                 }\r
111 \r
112                 /**\r
113                  * @param collapsed\r
114                  *            the collapsed to set\r
115                  */\r
116                 public void setCollapsed(boolean collapsed) {\r
117                         this.collapsed = collapsed;\r
118                 }\r
119 \r
120                 /**\r
121                  * @return the collapsed\r
122                  */\r
123                 public boolean isCollapsed() {\r
124                         return collapsed;\r
125                 }\r
126 \r
127         }\r
128 \r
129         /**\r
130          * Session storage support for JXTable.\r
131          */\r
132         public static class XTableProperty implements Serializable {\r
133 \r
134                 private static final long serialVersionUID = -5064142292091374301L;\r
135 \r
136                 public Object getSessionState(Component c) {\r
137                         checkComponent(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
145                         }\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
152                         }\r
153                         // PENDING: store all!\r
154                         if ((sortKeys != null) && (sortKeys.size() > 0)) {\r
155                                 tableState.setSortKey(sortKeys.get(0));\r
156                         }\r
157                         return tableState;\r
158                 }\r
159 \r
160                 public void setSessionState(Component c, Object state) {\r
161                         checkComponent(c);\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
169                                 }\r
170                                 restoreVisibleSequence(columnState, table.getColumnModel());\r
171                         }\r
172                         table.setHorizontalScrollEnabled(tableState.getHorizontalScrollEnabled());\r
173                         if (tableState.getSortKey() != null) {\r
174                                 table.getRowSorter()\r
175                                                 .setSortKeys(Collections.singletonList(tableState.getSortKey()));\r
176                         }\r
177                 }\r
178 \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
189                                                         currentIndex = j;\r
190                                                         break;\r
191                                                 }\r
192                                         }\r
193                                         model.moveColumn(currentIndex, i);\r
194                                 }\r
195                         }\r
196 \r
197                 }\r
198 \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
204                                 }\r
205                         }\r
206                         Collections.sort(visibleStates, new VisibleColumnIndexComparator());\r
207                         return visibleStates;\r
208                 }\r
209 \r
210                 /**\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
215                  * \r
216                  * @param columnState\r
217                  * @param columns\r
218                  * @return\r
219                  */\r
220                 private boolean canRestore(ColumnState[] columnState, List<TableColumn> columns) {\r
221                         if ((columnState == null) || (columnState.length != columns.size()))\r
222                                 return false;\r
223                         for (int i = 0; i < columnState.length; i++) {\r
224                                 if (columnState[i].getModelIndex() != columns.get(i).getModelIndex()) {\r
225                                         return false;\r
226                                 }\r
227                         }\r
228                         return true;\r
229                 }\r
230 \r
231                 private void checkComponent(Component component) {\r
232                         if (component == null) {\r
233                                 throw new IllegalArgumentException("null component");\r
234                         }\r
235                         if (!(component instanceof JXTable)) {\r
236                                 throw new IllegalArgumentException("invalid component - expected JXTable");\r
237                         }\r
238                 }\r
239 \r
240         }\r
241 \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
247 \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
253 \r
254                 }\r
255 \r
256                 public void setSortKey(SortKey sortKey) {\r
257                         this.sortKeyState = new SortKeyState(sortKey);\r
258 \r
259                 }\r
260 \r
261                 private SortKey getSortKey() {\r
262                         if (sortKeyState != null) {\r
263                                 return sortKeyState.getSortKey();\r
264                         }\r
265                         return null;\r
266                 }\r
267 \r
268                 public XTableState(ColumnState[] columnStates) {\r
269                         this.columnStates = copyColumnStates(columnStates);\r
270                 }\r
271 \r
272                 public ColumnState[] getColumnStates() {\r
273                         return copyColumnStates(this.columnStates);\r
274                 }\r
275 \r
276                 public boolean getHorizontalScrollEnabled() {\r
277                         return horizontalScrollEnabled;\r
278                 }\r
279 \r
280                 public void setHorizontalScrollEnabled(boolean horizontalScrollEnabled) {\r
281                         this.horizontalScrollEnabled = horizontalScrollEnabled;\r
282                 }\r
283 \r
284                 private ColumnState[] copyColumnStates(ColumnState[] states) {\r
285                         if (states == null) {\r
286                                 throw new IllegalArgumentException("invalid columnWidths");\r
287                         }\r
288                         ColumnState[] copy = new ColumnState[states.length];\r
289                         System.arraycopy(states, 0, copy, 0, states.length);\r
290                         return copy;\r
291                 }\r
292 \r
293                 public SortKeyState getSortKeyState() {\r
294                         return sortKeyState;\r
295                 }\r
296         }\r
297 \r
298         /**\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
303          * \r
304          */\r
305         public static class SortKeyState implements Serializable {\r
306                 private static final long serialVersionUID = 5819342622261460894L;\r
307 \r
308                 int modelIndex;\r
309 \r
310                 boolean ascending;\r
311 \r
312                 /**\r
313                  * Constructor used by the custom PersistenceDelegate.\r
314                  * \r
315                  * @param ascending\r
316                  * @param modelIndex\r
317                  * @param comparator\r
318                  */\r
319                 public SortKeyState(boolean ascending, int modelIndex) {\r
320                         this.ascending = ascending;\r
321                         this.modelIndex = modelIndex;\r
322                 }\r
323 \r
324                 /**\r
325                  * Constructor used by property.\r
326                  * \r
327                  * @param sortKey\r
328                  */\r
329                 public SortKeyState(SortKey sortKey) {\r
330                         this(SortUtils.isAscending(sortKey.getSortOrder()), sortKey.getColumn());\r
331                 }\r
332 \r
333                 protected SortKey getSortKey() {\r
334                         SortOrder sortOrder = getAscending() ? SortOrder.ASCENDING : SortOrder.DESCENDING;\r
335                         return new SortKey(getModelIndex(), sortOrder);\r
336                 }\r
337 \r
338                 public boolean getAscending() {\r
339                         return ascending;\r
340                 }\r
341 \r
342                 public int getModelIndex() {\r
343                         return modelIndex;\r
344                 }\r
345         }\r
346 \r
347         public static class ColumnState implements Serializable {\r
348                 private static final long serialVersionUID = 6037947151025126049L;\r
349                 private int width;\r
350                 private int preferredWidth;\r
351                 private int modelIndex;\r
352                 private boolean visible;\r
353                 private int viewIndex;\r
354 \r
355                 /**\r
356                  * Constructor used by the custom PersistenceDelegate.\r
357                  * \r
358                  * @param width\r
359                  * @param preferredWidth\r
360                  * @param modelColumn\r
361                  * @param visible\r
362                  * @param viewIndex\r
363                  */\r
364                 public ColumnState(int width, int preferredWidth, int modelColumn, boolean visible,\r
365                                 int viewIndex) {\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
371                 }\r
372 \r
373                 /**\r
374                  * Constructor used by the Property.\r
375                  * \r
376                  * @param columnExt\r
377                  * @param viewIndex\r
378                  */\r
379                 public ColumnState(TableColumnExt columnExt, int viewIndex) {\r
380                         this(columnExt.getWidth(), columnExt.getPreferredWidth(), columnExt.getModelIndex(),\r
381                                         columnExt.isVisible(), viewIndex);\r
382                 }\r
383 \r
384                 /**\r
385                  * Restores column properties if the model index is the same as the\r
386                  * column's model index. Does nothing otherwise.\r
387                  * <p>\r
388                  * \r
389                  * Here the properties are: width, preferredWidth, visible.\r
390                  * \r
391                  * @param columnExt\r
392                  *            the column to configure\r
393                  */\r
394                 public void configureColumn(TableColumnExt columnExt) {\r
395                         if (modelIndex != columnExt.getModelIndex())\r
396                                 return;\r
397                         columnExt.setPreferredWidth(preferredWidth);\r
398                         columnExt.setWidth(width);\r
399                         columnExt.setVisible(visible);\r
400                 }\r
401 \r
402                 public int getModelIndex() {\r
403                         return modelIndex;\r
404                 }\r
405 \r
406                 public int getViewIndex() {\r
407                         return viewIndex;\r
408                 }\r
409 \r
410                 public boolean getVisible() {\r
411                         return visible;\r
412                 }\r
413 \r
414                 public int getWidth() {\r
415                         return width;\r
416                 }\r
417 \r
418                 public int getPreferredWidth() {\r
419                         return preferredWidth;\r
420                 }\r
421 \r
422         }\r
423 \r
424         public static class VisibleColumnIndexComparator implements Comparator<Object> {\r
425 \r
426                 public int compare(Object o1, Object o2) {\r
427                         return ((ColumnState) o1).getViewIndex() - ((ColumnState) o2).getViewIndex();\r
428                 }\r
429 \r
430         }\r
431 \r
432 }\r