]> git.xonotic.org Git - xonotic/xonotic.git/blob - misc/tools/NexuizDemoRecorder/main/src/main/java/com/nexuiz/demorecorder/ui/swinggui/utils/XProperties.java
Merge branch 'master' of ssh://git.xonotic.org/xonotic
[xonotic/xonotic.git] / misc / tools / NexuizDemoRecorder / main / src / main / java / com / nexuiz / demorecorder / ui / swinggui / utils / XProperties.java
1 /*
2  * Created on 08.02.2007
3  *
4  */
5 package com.nexuiz.demorecorder.ui.swinggui.utils;
6
7 import java.awt.Component;
8 import java.beans.DefaultPersistenceDelegate;
9 import java.beans.XMLEncoder;
10 import java.io.Serializable;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.Comparator;
14 import java.util.List;
15
16 import javax.swing.SortOrder;
17 import javax.swing.RowSorter.SortKey;
18 import javax.swing.table.TableColumn;
19 import javax.swing.table.TableColumnModel;
20
21 import org.jdesktop.swingx.JXTable;
22 import org.jdesktop.swingx.JXTaskPane;
23 import org.jdesktop.swingx.sort.SortUtils;
24 import org.jdesktop.swingx.table.TableColumnExt;
25
26 /**
27  * Container class for SwingX specific SessionStorage Properties. Is Factory for
28  * custom PersistanceDelegates
29  */
30 public class XProperties {
31
32         /**
33          * 
34          * Registers all custom PersistenceDelegates needed by contained Property
35          * classes.
36          * <p>
37          * 
38          * PersistenceDelegates are effectively static properties shared by all
39          * encoders. In other words: Register once on an arbitrary encoder makes
40          * them available for all. Example usage:
41          * 
42          * <pre>
43          * <code>
44          * new XProperties.registerPersistenceDelegates();
45          * </code>
46          * </pre>
47          * 
48          * PENDING JW: cleanup for 1.6 sorting/filtering incomplete. Missing storage
49          * - multiple sort keys
50          * 
51          * PENDING JW: except for comparators: didn't before and is not state that's
52          * configurable by users ... so probably won't, not sure, need to revisit -
53          * comparator (?) - filters (?) - renderers/stringvalues (?) - enhanced
54          * sort-related table state (?)
55          */
56         public void registerPersistenceDelegates() {
57                 XMLEncoder encoder = new XMLEncoder(System.out);
58                 encoder.setPersistenceDelegate(SortKeyState.class, new DefaultPersistenceDelegate(
59                                 new String[] { "ascending", "modelIndex" }));
60                 encoder.setPersistenceDelegate(ColumnState.class, new DefaultPersistenceDelegate(
61                                 new String[] { "width", "preferredWidth", "modelIndex", "visible", "viewIndex" }));
62                 encoder.setPersistenceDelegate(XTableState.class, new DefaultPersistenceDelegate(
63                                 new String[] { "columnStates", "sortKeyState", "horizontalScrollEnabled" }));
64         }
65
66         /**
67          * Session storage support for JXTaskPane.
68          */
69         public static class XTaskPaneProperty implements Serializable {
70
71                 private static final long serialVersionUID = -4069436038178318216L;
72
73                 public Object getSessionState(Component c) {
74                         checkComponent(c);
75                         return new XTaskPaneState(((JXTaskPane) c).isCollapsed());
76                 }
77
78                 public void setSessionState(Component c, Object state) {
79                         checkComponent(c);
80                         if ((state != null) && !(state instanceof XTaskPaneState)) {
81                                 throw new IllegalArgumentException("invalid state");
82                         }
83                         ((JXTaskPane) c).setCollapsed(((XTaskPaneState) state).isCollapsed());
84                 }
85
86                 private void checkComponent(Component component) {
87                         if (component == null) {
88                                 throw new IllegalArgumentException("null component");
89                         }
90                         if (!(component instanceof JXTaskPane)) {
91                                 throw new IllegalArgumentException("invalid component");
92                         }
93                 }
94
95         }
96
97         public static class XTaskPaneState implements Serializable {
98                 private static final long serialVersionUID = 3363688961112031969L;
99                 private boolean collapsed;
100
101                 public XTaskPaneState() {
102                         this(false);
103                 }
104
105                 /**
106                  * @param b
107                  */
108                 public XTaskPaneState(boolean collapsed) {
109                         this.setCollapsed(collapsed);
110                 }
111
112                 /**
113                  * @param collapsed
114                  *            the collapsed to set
115                  */
116                 public void setCollapsed(boolean collapsed) {
117                         this.collapsed = collapsed;
118                 }
119
120                 /**
121                  * @return the collapsed
122                  */
123                 public boolean isCollapsed() {
124                         return collapsed;
125                 }
126
127         }
128
129         /**
130          * Session storage support for JXTable.
131          */
132         public static class XTableProperty implements Serializable {
133
134                 private static final long serialVersionUID = -5064142292091374301L;
135
136                 public Object getSessionState(Component c) {
137                         checkComponent(c);
138                         JXTable table = (JXTable) c;
139                         List<ColumnState> columnStates = new ArrayList<ColumnState>();
140                         List<TableColumn> columns = table.getColumns(true);
141                         List<TableColumn> visibleColumns = table.getColumns();
142                         for (TableColumn column : columns) {
143                                 columnStates.add(new ColumnState((TableColumnExt) column, visibleColumns
144                                                 .indexOf(column)));
145                         }
146                         XTableState tableState = new XTableState(columnStates
147                                         .toArray(new ColumnState[columnStates.size()]));
148                         tableState.setHorizontalScrollEnabled(table.isHorizontalScrollEnabled());
149                         List<? extends SortKey> sortKeys = null;
150                         if (table.getRowSorter() != null) {
151                                 sortKeys = table.getRowSorter().getSortKeys();
152                         }
153                         // PENDING: store all!
154                         if ((sortKeys != null) && (sortKeys.size() > 0)) {
155                                 tableState.setSortKey(sortKeys.get(0));
156                         }
157                         return tableState;
158                 }
159
160                 public void setSessionState(Component c, Object state) {
161                         checkComponent(c);
162                         JXTable table = (JXTable) c;
163                         XTableState tableState = ((XTableState) state);
164                         ColumnState[] columnState = tableState.getColumnStates();
165                         List<TableColumn> columns = table.getColumns(true);
166                         if (canRestore(columnState, columns)) {
167                                 for (int i = 0; i < columnState.length; i++) {
168                                         columnState[i].configureColumn((TableColumnExt) columns.get(i));
169                                 }
170                                 restoreVisibleSequence(columnState, table.getColumnModel());
171                         }
172                         table.setHorizontalScrollEnabled(tableState.getHorizontalScrollEnabled());
173                         if (tableState.getSortKey() != null) {
174                                 table.getRowSorter()
175                                                 .setSortKeys(Collections.singletonList(tableState.getSortKey()));
176                         }
177                 }
178
179                 private void restoreVisibleSequence(ColumnState[] columnStates, TableColumnModel model) {
180                         List<ColumnState> visibleStates = getSortedVisibleColumnStates(columnStates);
181                         for (int i = 0; i < visibleStates.size(); i++) {
182                                 TableColumn column = model.getColumn(i);
183                                 int modelIndex = visibleStates.get(i).getModelIndex();
184                                 if (modelIndex != column.getModelIndex()) {
185                                         int currentIndex = -1;
186                                         for (int j = i + 1; j < model.getColumnCount(); j++) {
187                                                 TableColumn current = model.getColumn(j);
188                                                 if (current.getModelIndex() == modelIndex) {
189                                                         currentIndex = j;
190                                                         break;
191                                                 }
192                                         }
193                                         model.moveColumn(currentIndex, i);
194                                 }
195                         }
196
197                 }
198
199                 private List<ColumnState> getSortedVisibleColumnStates(ColumnState[] columnStates) {
200                         List<ColumnState> visibleStates = new ArrayList<ColumnState>();
201                         for (ColumnState columnState : columnStates) {
202                                 if (columnState.getVisible()) {
203                                         visibleStates.add(columnState);
204                                 }
205                         }
206                         Collections.sort(visibleStates, new VisibleColumnIndexComparator());
207                         return visibleStates;
208                 }
209
210                 /**
211                  * Returns a boolean to indicate if it's reasonably safe to restore the
212                  * properties of columns in the list from the columnStates. Here:
213                  * returns true if the length of both are the same and the modelIndex of
214                  * the items at the same position are the same, otherwise returns false.
215                  * 
216                  * @param columnState
217                  * @param columns
218                  * @return
219                  */
220                 private boolean canRestore(ColumnState[] columnState, List<TableColumn> columns) {
221                         if ((columnState == null) || (columnState.length != columns.size()))
222                                 return false;
223                         for (int i = 0; i < columnState.length; i++) {
224                                 if (columnState[i].getModelIndex() != columns.get(i).getModelIndex()) {
225                                         return false;
226                                 }
227                         }
228                         return true;
229                 }
230
231                 private void checkComponent(Component component) {
232                         if (component == null) {
233                                 throw new IllegalArgumentException("null component");
234                         }
235                         if (!(component instanceof JXTable)) {
236                                 throw new IllegalArgumentException("invalid component - expected JXTable");
237                         }
238                 }
239
240         }
241
242         public static class XTableState implements Serializable {
243                 private static final long serialVersionUID = -3566913244872587438L;
244                 ColumnState[] columnStates = new ColumnState[0];
245                 boolean horizontalScrollEnabled;
246                 SortKeyState sortKeyState;
247
248                 public XTableState(ColumnState[] columnStates, SortKeyState sortKeyState,
249                                 boolean horizontalScrollEnabled) {
250                         this.columnStates = copyColumnStates(columnStates);
251                         this.sortKeyState = sortKeyState;
252                         setHorizontalScrollEnabled(horizontalScrollEnabled);
253
254                 }
255
256                 public void setSortKey(SortKey sortKey) {
257                         this.sortKeyState = new SortKeyState(sortKey);
258
259                 }
260
261                 private SortKey getSortKey() {
262                         if (sortKeyState != null) {
263                                 return sortKeyState.getSortKey();
264                         }
265                         return null;
266                 }
267
268                 public XTableState(ColumnState[] columnStates) {
269                         this.columnStates = copyColumnStates(columnStates);
270                 }
271
272                 public ColumnState[] getColumnStates() {
273                         return copyColumnStates(this.columnStates);
274                 }
275
276                 public boolean getHorizontalScrollEnabled() {
277                         return horizontalScrollEnabled;
278                 }
279
280                 public void setHorizontalScrollEnabled(boolean horizontalScrollEnabled) {
281                         this.horizontalScrollEnabled = horizontalScrollEnabled;
282                 }
283
284                 private ColumnState[] copyColumnStates(ColumnState[] states) {
285                         if (states == null) {
286                                 throw new IllegalArgumentException("invalid columnWidths");
287                         }
288                         ColumnState[] copy = new ColumnState[states.length];
289                         System.arraycopy(states, 0, copy, 0, states.length);
290                         return copy;
291                 }
292
293                 public SortKeyState getSortKeyState() {
294                         return sortKeyState;
295                 }
296         }
297
298         /**
299          * Quick hack to make SortKey encodable. How to write a PersistenceDelegate
300          * for a SortKey? Boils down to how to write a delegate for the
301          * uninstantiable class (SwingX) SortOrder which does enum-mimickry (defines
302          * privately intantiated constants)
303          * 
304          */
305         public static class SortKeyState implements Serializable {
306                 private static final long serialVersionUID = 5819342622261460894L;
307
308                 int modelIndex;
309
310                 boolean ascending;
311
312                 /**
313                  * Constructor used by the custom PersistenceDelegate.
314                  * 
315                  * @param ascending
316                  * @param modelIndex
317                  * @param comparator
318                  */
319                 public SortKeyState(boolean ascending, int modelIndex) {
320                         this.ascending = ascending;
321                         this.modelIndex = modelIndex;
322                 }
323
324                 /**
325                  * Constructor used by property.
326                  * 
327                  * @param sortKey
328                  */
329                 public SortKeyState(SortKey sortKey) {
330                         this(SortUtils.isAscending(sortKey.getSortOrder()), sortKey.getColumn());
331                 }
332
333                 protected SortKey getSortKey() {
334                         SortOrder sortOrder = getAscending() ? SortOrder.ASCENDING : SortOrder.DESCENDING;
335                         return new SortKey(getModelIndex(), sortOrder);
336                 }
337
338                 public boolean getAscending() {
339                         return ascending;
340                 }
341
342                 public int getModelIndex() {
343                         return modelIndex;
344                 }
345         }
346
347         public static class ColumnState implements Serializable {
348                 private static final long serialVersionUID = 6037947151025126049L;
349                 private int width;
350                 private int preferredWidth;
351                 private int modelIndex;
352                 private boolean visible;
353                 private int viewIndex;
354
355                 /**
356                  * Constructor used by the custom PersistenceDelegate.
357                  * 
358                  * @param width
359                  * @param preferredWidth
360                  * @param modelColumn
361                  * @param visible
362                  * @param viewIndex
363                  */
364                 public ColumnState(int width, int preferredWidth, int modelColumn, boolean visible,
365                                 int viewIndex) {
366                         this.width = width;
367                         this.preferredWidth = preferredWidth;
368                         this.modelIndex = modelColumn;
369                         this.visible = visible;
370                         this.viewIndex = viewIndex;
371                 }
372
373                 /**
374                  * Constructor used by the Property.
375                  * 
376                  * @param columnExt
377                  * @param viewIndex
378                  */
379                 public ColumnState(TableColumnExt columnExt, int viewIndex) {
380                         this(columnExt.getWidth(), columnExt.getPreferredWidth(), columnExt.getModelIndex(),
381                                         columnExt.isVisible(), viewIndex);
382                 }
383
384                 /**
385                  * Restores column properties if the model index is the same as the
386                  * column's model index. Does nothing otherwise.
387                  * <p>
388                  * 
389                  * Here the properties are: width, preferredWidth, visible.
390                  * 
391                  * @param columnExt
392                  *            the column to configure
393                  */
394                 public void configureColumn(TableColumnExt columnExt) {
395                         if (modelIndex != columnExt.getModelIndex())
396                                 return;
397                         columnExt.setPreferredWidth(preferredWidth);
398                         columnExt.setWidth(width);
399                         columnExt.setVisible(visible);
400                 }
401
402                 public int getModelIndex() {
403                         return modelIndex;
404                 }
405
406                 public int getViewIndex() {
407                         return viewIndex;
408                 }
409
410                 public boolean getVisible() {
411                         return visible;
412                 }
413
414                 public int getWidth() {
415                         return width;
416                 }
417
418                 public int getPreferredWidth() {
419                         return preferredWidth;
420                 }
421
422         }
423
424         public static class VisibleColumnIndexComparator implements Comparator<Object> {
425
426                 public int compare(Object o1, Object o2) {
427                         return ((ColumnState) o1).getViewIndex() - ((ColumnState) o2).getViewIndex();
428                 }
429
430         }
431
432 }