Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
CheckListModel |
|
| 1.3928571428571428;1.393 | ||||
CheckListModel$1 |
|
| 1.3928571428571428;1.393 | ||||
CheckListModel$ColumnType |
|
| 1.3928571428571428;1.393 | ||||
CheckListModel$ColumnType$1 |
|
| 1.3928571428571428;1.393 | ||||
CheckListModel$ColumnType$2 |
|
| 1.3928571428571428;1.393 | ||||
CheckListModel$PoolListener |
|
| 1.3928571428571428;1.393 | ||||
CheckListModel$SelectionListener |
|
| 1.3928571428571428;1.393 |
1 | /* | |
2 | * Copyright (c) 2009, Swiss Federal Department of Defence Civil Protection and Sport | |
3 | * (http://www.vbs.admin.ch) | |
4 | * Copyright (c) 2009, Ergon Informatik AG (http://www.ergon.ch) | |
5 | * All rights reserved. | |
6 | * | |
7 | * Licensed under the Open Permis License which accompanies this distribution, | |
8 | * and is available at http://www.openpermis.org/BSDlicenceKent.txt | |
9 | */ | |
10 | package org.openpermis.editor.policy.gui.checklist; | |
11 | ||
12 | import java.util.List; | |
13 | import java.util.ListIterator; | |
14 | ||
15 | import javax.swing.table.AbstractTableModel; | |
16 | ||
17 | import org.jdesktop.observablecollections.ObservableList; | |
18 | import org.jdesktop.observablecollections.ObservableListListener; | |
19 | ||
20 | import org.openpermis.editor.policy.gui.binding.ObservableListAdapter; | |
21 | import org.openpermis.policy.Role; | |
22 | ||
23 | ||
24 | /** | |
25 | * Creates a model that manages a pool of items and a selection list from the pool. | |
26 | * @param <T> type of the items in the check list model. | |
27 | * @since 0.1.0 | |
28 | */ | |
29 | 24 | public class CheckListModel<T> |
30 | extends AbstractTableModel | |
31 | { | |
32 | ||
33 | //---- State | |
34 | ||
35 | /** | |
36 | * @since 0.3.0 | |
37 | */ | |
38 | private static final long serialVersionUID = 4791486544723792077L; | |
39 | ||
40 | /** | |
41 | * The pool of available items that can be chosen. | |
42 | * @since 0.1.0 | |
43 | */ | |
44 | private final ObservableList<T> pool; | |
45 | ||
46 | /** | |
47 | * Listener that synchronizes the state of the table model and the pool list. | |
48 | * @since 0.1.0 | |
49 | */ | |
50 | private final PoolListener poolListener; | |
51 | ||
52 | /** | |
53 | * The currently selected items from the pool. | |
54 | * @since 0.1.0 | |
55 | */ | |
56 | private final ObservableList<T> selection; | |
57 | ||
58 | /** | |
59 | * Listener that refreshes the check list whenever a change occurs. | |
60 | * @since 0.1.0 | |
61 | */ | |
62 | private final SelectionListener selectionListener; | |
63 | ||
64 | //---- Constructors | |
65 | ||
66 | /** | |
67 | * Creates a new check list model. | |
68 | * @param pool the poolof available items that can be chosen. | |
69 | * @param selection the currently selected items from the pool. | |
70 | * @since 0.1.0 | |
71 | */ | |
72 | 7 | public CheckListModel (ObservableList<T> pool, ObservableList<T> selection) { |
73 | 7 | this.pool = pool; |
74 | 7 | this.poolListener = new PoolListener(); |
75 | 7 | this.selection = selection; |
76 | 7 | this.selectionListener = new SelectionListener(); |
77 | 7 | } |
78 | ||
79 | //---- Methods | |
80 | ||
81 | /** | |
82 | * Adds listeners to synchronize the list with the table model. | |
83 | * @since 0.1.0 | |
84 | */ | |
85 | public void configureListeners () { | |
86 | 7 | this.pool.addObservableListListener(this.poolListener); |
87 | 7 | this.selection.addObservableListListener(this.selectionListener); |
88 | 7 | } |
89 | ||
90 | /** | |
91 | * Removes the listeners to synchronize the list with the table model added in | |
92 | * {@link #configureListeners()}. | |
93 | * @since 0.1.0 | |
94 | */ | |
95 | public void unconfigureListeners () { | |
96 | 7 | this.pool.removeObservableListListener(this.poolListener); |
97 | 7 | this.selection.removeObservableListListener(this.selectionListener); |
98 | 7 | } |
99 | ||
100 | /** | |
101 | * Returns the type of the column at the specified index. | |
102 | * @param columnIndex the index for which to retrieve the column type. | |
103 | * @return the type requested. | |
104 | * @since 0.1.0 | |
105 | */ | |
106 | private ColumnType getColumnType (int columnIndex) { | |
107 | 320 | return ColumnType.values()[columnIndex]; |
108 | } | |
109 | ||
110 | //---- TableModel | |
111 | ||
112 | /** | |
113 | * @since 0.1.0 | |
114 | */ | |
115 | @Override | |
116 | public boolean isCellEditable (int rowIndex, int columnIndex) { | |
117 | 0 | return getColumnType(columnIndex).isEditable(); |
118 | } | |
119 | ||
120 | /** | |
121 | * @since 0.1.0 | |
122 | */ | |
123 | @Override | |
124 | public Class<?> getColumnClass (int columnIndex) { | |
125 | 0 | return getColumnType(columnIndex).getColumnClass(); |
126 | } | |
127 | ||
128 | /** | |
129 | * @since 0.1.0 | |
130 | */ | |
131 | @Override | |
132 | public String getColumnName (int columnIndex) { | |
133 | 0 | return getColumnType(columnIndex).getColumnName(); |
134 | } | |
135 | ||
136 | /** | |
137 | * @since 0.1.0 | |
138 | */ | |
139 | public int getColumnCount () { | |
140 | 0 | return ColumnType.values().length; |
141 | } | |
142 | ||
143 | /** | |
144 | * @since 0.1.0 | |
145 | */ | |
146 | public int getRowCount () { | |
147 | 9 | return this.pool.size(); |
148 | } | |
149 | ||
150 | /** | |
151 | * @since 0.1.0 | |
152 | */ | |
153 | public Object getValueAt (int rowIndex, int columnIndex) { | |
154 | 320 | return getColumnType(columnIndex).getValue(rowIndex, this.pool, this.selection); |
155 | } | |
156 | ||
157 | /** | |
158 | * @since 0.1.0 | |
159 | */ | |
160 | @Override | |
161 | public void setValueAt (Object value, int rowIndex, int columnIndex) { | |
162 | 0 | getColumnType(columnIndex).setValue(rowIndex, value, this.pool, this.selection); |
163 | 0 | } |
164 | ||
165 | //---- ColumnType | |
166 | ||
167 | /** | |
168 | * Describes the type of a column, including getters and setters. | |
169 | * @since 0.1.0 | |
170 | */ | |
171 | 323 | enum ColumnType { |
172 | ||
173 | 1 | CHECKBOX("Checkbox", Boolean.class, true) { |
174 | @Override | |
175 | public Object getValue (int rowIndex, List<?> itemPool, List<?> selectionList) { | |
176 | 160 | return Boolean.valueOf(contains(selectionList, itemPool.get(rowIndex))); |
177 | } | |
178 | @Override | |
179 | 1 | public <T> void setValue ( |
180 | int rowIndex, Object value, List<T> itemPool, List<T> selectionList | |
181 | ) { | |
182 | 0 | final boolean add = Boolean.TRUE.equals(value); |
183 | 0 | final T item = itemPool.get(rowIndex); |
184 | 0 | if (add != contains(selectionList, item)) { |
185 | 0 | if (add) { |
186 | 0 | selectionList.add(item); |
187 | } else { | |
188 | 0 | selectionList.remove(indexOf(selectionList, item)); |
189 | } | |
190 | } | |
191 | 0 | } |
192 | }, | |
193 | 1 | ITEM("Item", Object.class, false) { |
194 | @Override | |
195 | public Object getValue (int rowIndex, List<?> itemPool, List<?> selectionList) { | |
196 | 160 | return itemPool.get(rowIndex); |
197 | } | |
198 | @Override | |
199 | 1 | public <T> void setValue ( |
200 | int rowIndex, Object value, List<T> itemPool, List<T> selectionList | |
201 | ) { | |
202 | 0 | throw new IllegalStateException( |
203 | "Editing of column [" + getColumnName() + "] not supported." | |
204 | ); | |
205 | } | |
206 | }; | |
207 | ||
208 | //---- State | |
209 | ||
210 | private final String columnName; | |
211 | private final Class<?> columnClass; | |
212 | private final boolean editable; | |
213 | ||
214 | //---- Constructors | |
215 | ||
216 | 2 | private ColumnType (String columnName, Class<?> columnClass, boolean editable) { |
217 | 2 | this.columnName = columnName; |
218 | 2 | this.columnClass = columnClass; |
219 | 2 | this.editable = editable; |
220 | 2 | } |
221 | ||
222 | //---- Methods | |
223 | ||
224 | /** | |
225 | * Returns the index of the specified item in the given list. | |
226 | * @param list the list to find the item in. | |
227 | * @param item the item to search for by identity. | |
228 | * @return the index requested or -1 if there is no such item. | |
229 | * @since 0.1.0 | |
230 | */ | |
231 | protected int indexOf (List<?> list, Object item) { | |
232 | 955 | for (int i = 0; i < list.size(); i++) { |
233 | 846 | if ( |
234 | // The class Role role has an implementation of equals. | |
235 | list.get(i) instanceof Role && list.get(i).equals(item) | |
236 | || list.get(i) == item | |
237 | ) { | |
238 | 51 | return i; |
239 | } | |
240 | } | |
241 | 109 | return -1; |
242 | } | |
243 | ||
244 | /** | |
245 | * Checks if the specified item is in the given list. | |
246 | * @param list the list to search. | |
247 | * @param item the item to check. | |
248 | * @return {@code true} if the item is in the list, {@code false} otherwise. | |
249 | * @since 0.1.0 | |
250 | */ | |
251 | protected boolean contains (List<?> list, Object item) { | |
252 | 160 | return indexOf(list, item) != -1; |
253 | } | |
254 | ||
255 | /** | |
256 | * Returns the value of this column at the specified row index. | |
257 | * @param rowIndex the index for which to retrieve the value. | |
258 | * @param itemPool the pool of items. | |
259 | * @param selectionList the list of currently selected items. | |
260 | * @return the value at the given row/column. | |
261 | * @since 0.1.0 | |
262 | */ | |
263 | public abstract Object getValue (int rowIndex, List<?> itemPool, List<?> selectionList); | |
264 | ||
265 | /** | |
266 | * Sets the value of this column at the specified row index. | |
267 | * @param rowIndex the index for which to set the value. | |
268 | * @param itemPool the pool of items. | |
269 | * @param selectionList the list of currently selected items. | |
270 | * @since 0.1.0 | |
271 | */ | |
272 | public abstract <T> void setValue ( | |
273 | int rowIndex, Object value, List<T> itemPool, List<T> selectionList | |
274 | ); | |
275 | ||
276 | /** | |
277 | * The name of this column. | |
278 | * @return the name of this column. | |
279 | * @since 0.1.0 | |
280 | */ | |
281 | public String getColumnName () { | |
282 | 0 | return this.columnName; |
283 | } | |
284 | ||
285 | /** | |
286 | * The value class of this column. | |
287 | * @return the value class of this column. | |
288 | * @since 0.1.0 | |
289 | */ | |
290 | public Class<?> getColumnClass () { | |
291 | 0 | return this.columnClass; |
292 | } | |
293 | ||
294 | /** | |
295 | * @return the editable. | |
296 | * @since 0.1.0 | |
297 | */ | |
298 | public boolean isEditable () { | |
299 | 0 | return this.editable; |
300 | } | |
301 | ||
302 | } | |
303 | ||
304 | //---- PoolListener | |
305 | ||
306 | /** | |
307 | * Synchronizes the check list model if a change in the pool list occurs. | |
308 | * @since 0.1.0 | |
309 | */ | |
310 | @SuppressWarnings("unchecked") | |
311 | 14 | private class PoolListener |
312 | implements ObservableListListener | |
313 | { | |
314 | ||
315 | /** | |
316 | * @since 0.1.0 | |
317 | */ | |
318 | public void listElementPropertyChanged (ObservableList list, int index) { | |
319 | 0 | CheckListModel.this.fireTableRowsUpdated(index, index); |
320 | 0 | } |
321 | ||
322 | /** | |
323 | * @since 0.1.0 | |
324 | */ | |
325 | public void listElementReplaced (ObservableList list, int index, Object oldElement) { | |
326 | 0 | CheckListModel.this.fireTableRowsUpdated(index, index); |
327 | 0 | } |
328 | ||
329 | /** | |
330 | * @since 0.1.0 | |
331 | */ | |
332 | public void listElementsAdded (ObservableList list, int index, int length) { | |
333 | 4 | CheckListModel.this.fireTableRowsInserted(index, index + length); |
334 | 4 | } |
335 | ||
336 | /** | |
337 | * @since 0.1.0 | |
338 | */ | |
339 | public void listElementsRemoved (ObservableList list, int index, List oldElements) { | |
340 | 5 | for (final Object obj : oldElements) { |
341 | 24 | final ListIterator<T> iterator = CheckListModel.this.selection.listIterator(); |
342 | 119 | while (iterator.hasNext()) { |
343 | 95 | final T item = iterator.next(); |
344 | 95 | if (obj == item) { |
345 | 9 | iterator.remove(); |
346 | } | |
347 | 95 | } |
348 | 24 | } |
349 | 5 | CheckListModel.this.fireTableDataChanged(); |
350 | 5 | } |
351 | ||
352 | } | |
353 | ||
354 | //---- SelectionListener | |
355 | ||
356 | /** | |
357 | * Synchronizes the check list model if a change in the selection list occurs. | |
358 | * @since 0.1.0 | |
359 | */ | |
360 | @SuppressWarnings("unchecked") | |
361 | 14 | private class SelectionListener |
362 | extends ObservableListAdapter | |
363 | { | |
364 | ||
365 | /** | |
366 | * @since 0.3.0 | |
367 | */ | |
368 | @Override | |
369 | protected void listChanged (ObservableList list) { | |
370 | 18 | CheckListModel.this.fireTableDataChanged(); |
371 | 18 | } |
372 | ||
373 | } | |
374 | ||
375 | } |