1 package fr.ifremer.quadrige3.ui.swing.table.state;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 import fr.ifremer.quadrige3.core.dao.technical.Assert;
27 import fr.ifremer.quadrige3.ui.swing.table.*;
28 import fr.ifremer.quadrige3.ui.swing.table.action.AdditionalTableActions;
29 import jaxx.runtime.swing.session.State;
30 import org.apache.commons.lang3.StringUtils;
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.jdesktop.swingx.action.AbstractActionExt;
34 import org.jdesktop.swingx.table.TableColumnExt;
35
36 import javax.swing.Action;
37 import javax.swing.RowSorter;
38 import javax.swing.SortOrder;
39 import javax.swing.SwingUtilities;
40 import javax.swing.table.AbstractTableModel;
41 import java.util.*;
42
43
44
45
46
47
48 public class SwingTableSessionState implements ExtendedState {
49
50 private static final Log LOG = LogFactory.getLog(SwingTableSessionState.class);
51
52 protected static final String SEPARATOR = "|";
53
54
55 private Map<String, SwingTableState> sessionStates;
56
57
58 private Set<String> selectedActions;
59
60
61
62
63 public SwingTableSessionState() {
64 sessionStates = new HashMap<>();
65 selectedActions = new HashSet<>();
66 }
67
68
69
70
71
72
73
74 protected SwingTable checkComponent(Object object) {
75 Assert.notNull(object);
76 Assert.isInstanceOf(SwingTable.class, object);
77 Assert.isInstanceOf(AbstractTableModel.class, ((SwingTable) object).getModel());
78 return (SwingTable) object;
79 }
80
81
82
83
84 @Override
85 public State getState(Object o) {
86
87 return getState(o, null, null);
88 }
89
90
91
92
93 @Override
94 @SuppressWarnings("unchecked")
95 public State getState(Object o, State previousState, String stateContextToSave) {
96
97 SwingTable table = checkComponent(o);
98
99
100
101 String stateContext = stateContextToSave != null ? stateContextToSave : table.getTableModel().getStateContext();
102
103
104 SwingTableSessionState tableSessionState;
105 if (previousState instanceof SwingTableSessionState) {
106 tableSessionState = (SwingTableSessionState) previousState;
107 } else {
108 tableSessionState = new SwingTableSessionState();
109 }
110 try {
111
112 SwingTableState tableState = tableSessionState.getSessionStates().computeIfAbsent(stateContext, k -> new SwingTableState());
113
114
115 List<ColumnIdentifier> identifiers = new ArrayList<>(table.getTableModel().getIdentifiers());
116
117 Map<Integer, Integer> sortOrderPriority = new HashMap<>();
118 if (table.getRowSorter() != null && table.getRowSorter().getSortKeys() != null) {
119 for (int priority = 0; priority < table.getRowSorter().getSortKeys().size(); priority++) {
120 RowSorter.SortKey sortKey = table.getRowSorter().getSortKeys().get(priority);
121 sortOrderPriority.put(sortKey.getColumn(), priority);
122 }
123 }
124
125
126 for (ColumnIdentifier identifier : identifiers) {
127 TableColumnExt column = table.getColumnExt(identifier);
128 if (column == null || column instanceof FixedColumn) {
129
130 continue;
131 }
132
133 int columnViewIndex = table.convertColumnIndexToView(column.getModelIndex());
134 boolean isPmfmColumn = identifier instanceof PmfmColumnIdentifier;
135 boolean isHidden = column instanceof HiddenColumn;
136
137
138
139
140
141
142
143 if (isPmfmColumn) {
144
145 if (isHidden) {
146 tableState.getPmfmVisibility().remove(((PmfmColumnIdentifier) identifier).getPmfmId());
147 tableState.getPmfmWidth().remove(((PmfmColumnIdentifier) identifier).getPmfmId());
148 } else {
149 tableState.getPmfmVisibility().put(((PmfmColumnIdentifier) identifier).getPmfmId(), columnViewIndex);
150 tableState.getPmfmWidth().put(((PmfmColumnIdentifier) identifier).getPmfmId(), column.getPreferredWidth());
151 }
152
153 } else {
154
155 if (isHidden) {
156 tableState.getVisibility().remove(identifier.getPropertyName());
157 tableState.getWidth().remove(identifier.getPropertyName());
158 } else {
159 tableState.getVisibility().put(identifier.getPropertyName(), columnViewIndex);
160 tableState.getWidth().put(identifier.getPropertyName(), column.getPreferredWidth());
161 }
162 }
163
164
165
166 if (table.getRowSorter() != null) {
167 SortOrder sortOrder = table.getSortOrder(identifier);
168 if (sortOrder != SortOrder.UNSORTED) {
169 String propertyName = identifier.getPropertyName() + (isPmfmColumn ? SEPARATOR + ((PmfmColumnIdentifier) identifier).getPmfmId() : "");
170 String order = sortOrder.name() + SEPARATOR + sortOrderPriority.get(column.getModelIndex());
171 tableState.getSortOrder().put(propertyName, order);
172 }
173 }
174 }
175
176
177 tableSessionState.getSelectedActions().clear();
178 AdditionalTableActions additionalTableActions = getAdditionalTableActions(table);
179 if (additionalTableActions != null) {
180 additionalTableActions.getActions().stream()
181
182 .filter(action -> (action instanceof AbstractActionExt) && ((AbstractActionExt) action).isStateAction() && ((AbstractActionExt) action).isSelected())
183 .forEach(action -> tableSessionState.getSelectedActions().add(action.getClass().getName()));
184 }
185
186 } catch (Exception e) {
187 LOG.error("Something goes wrong on getState", e);
188 }
189 return tableSessionState;
190 }
191
192
193
194
195 @Override
196 @SuppressWarnings("unchecked")
197 public void setState(Object o, State state) {
198 if (state == null) {
199 return;
200 }
201 if (!(state instanceof SwingTableSessionState)) {
202 throw new IllegalArgumentException("invalid state");
203 }
204 SwingTable table = checkComponent(o);
205
206
207 SwingTableSessionState tableSessionState = (SwingTableSessionState) state;
208 SwingTableState tableState = tableSessionState.getSessionStates().get(table.getTableModel().getStateContext());
209 if (tableState == null) {
210
211 return;
212 }
213
214 try {
215
216 List<ColumnIdentifier> identifiers = new ArrayList<>(table.getTableModel().getIdentifiers());
217 Map<Integer, SortOrder> sortOrderByModelIndex = new HashMap<>();
218 Map<Integer, Integer> sortPriority = new HashMap<>();
219 Map<Integer, Integer> deferredMove = new HashMap<>();
220
221 for (ColumnIdentifier identifier : identifiers) {
222 TableColumnExt column = table.getColumnExt(identifier);
223 if (column == null || column instanceof FixedColumn) {
224
225 continue;
226 }
227 boolean isPmfmColumn = identifier instanceof PmfmColumnIdentifier;
228 boolean isHidden = column instanceof HiddenColumn;
229
230
231 if (isHidden) {
232
233 column.setVisible(false);
234 } else {
235 Integer visibility;
236 if (isPmfmColumn) {
237
238 visibility = tableState.getPmfmVisibility().get(((PmfmColumnIdentifier) identifier).getPmfmId());
239 } else {
240
241 visibility = tableState.getVisibility().get(identifier.getPropertyName());
242 }
243 if (visibility != null && visibility > -1) {
244
245 column.setVisible(true);
246
247 deferredMove.put(visibility, column.getModelIndex());
248 } else if (column.isHideable()) {
249
250 column.setVisible(false);
251 }
252 }
253
254
255 if (column.getResizable() && !isHidden) {
256 Integer width;
257 if (isPmfmColumn) {
258
259 width = tableState.getPmfmWidth().get(((PmfmColumnIdentifier) identifier).getPmfmId());
260
261 } else {
262
263 width = tableState.getWidth().get(identifier.getPropertyName());
264 }
265 if (width != null) {
266 column.setPreferredWidth(width);
267 }
268 }
269
270
271 if (column.isSortable()) {
272 String propertyName = identifier.getPropertyName() + (isPmfmColumn ? SEPARATOR + ((PmfmColumnIdentifier) identifier).getPmfmId() : "");
273 String order = tableState.getSortOrder().get(propertyName);
274 if (order != null) {
275
276 String[] orderAndPriority = StringUtils.split(order, SEPARATOR);
277 SortOrder sortOrder = SortOrder.valueOf(orderAndPriority[0]);
278 Integer priority = Integer.parseInt(orderAndPriority[1]);
279
280 sortOrderByModelIndex.put(column.getModelIndex(), sortOrder);
281 sortPriority.put(priority, column.getModelIndex());
282 }
283 }
284 }
285
286
287 if (!deferredMove.isEmpty()) {
288
289 for (Integer newColumnViewIndex : deferredMove.keySet()) {
290 int columnViewIndex = table.convertColumnIndexToView(deferredMove.get(newColumnViewIndex));
291
292
293
294
295
296 if (newColumnViewIndex >= table.getColumnCount()) {
297 newColumnViewIndex = table.getColumnCount() - 1;
298 }
299
300
301 table.moveColumn(columnViewIndex, newColumnViewIndex);
302 }
303 }
304
305
306 if (!sortOrderByModelIndex.isEmpty()) {
307 SortedSet<Integer> priorityOrder = new TreeSet<>(sortPriority.keySet());
308 List<RowSorter.SortKey> sortKeys = new ArrayList<>();
309 for (Integer priority : priorityOrder) {
310 Integer modelIndex = sortPriority.get(priority);
311 SortOrder sortOrder = sortOrderByModelIndex.get(modelIndex);
312 RowSorter.SortKey sortKey = new RowSorter.SortKey(modelIndex, sortOrder);
313 sortKeys.add(sortKey);
314 }
315 table.getRowSorter().setSortKeys(sortKeys);
316 }
317
318
319 AdditionalTableActions additionalTableActions = getAdditionalTableActions(table);
320 if (additionalTableActions != null) {
321 tableSessionState.getSelectedActions().forEach(selectedActionName -> additionalTableActions.getActions().stream()
322 .filter(action -> (action instanceof AbstractActionExt) && ((AbstractActionExt) action).isStateAction())
323 .filter(action -> action.getClass().getName().equals(selectedActionName))
324 .findFirst()
325 .ifPresent(action ->
326 {
327 AbstractActionExt stateAction = (AbstractActionExt) action;
328 stateAction.setSelected(true);
329 SwingUtilities.invokeLater(() -> stateAction.actionPerformed(null));
330 }
331 ));
332 }
333
334 } catch (Exception e) {
335 LOG.error("Something goes wrong on setState", e);
336 }
337 }
338
339
340
341 public Map<String, SwingTableState> getSessionStates() {
342 return sessionStates;
343 }
344
345 public void setSessionStates(Map<String, SwingTableState> sessionStates) {
346 this.sessionStates = sessionStates;
347 }
348
349 public Set<String> getSelectedActions() {
350 return selectedActions;
351 }
352
353 public void setSelectedActions(Set<String> selectedActions) {
354 this.selectedActions = selectedActions;
355 }
356
357
358
359 private AdditionalTableActions getAdditionalTableActions(SwingTable table) {
360 Action additionalActions = table.getActionMap().get(AdditionalTableActions.ACTION_NAME);
361 return (additionalActions instanceof AdditionalTableActions) ? (AdditionalTableActions) additionalActions : null;
362 }
363 }