svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.swing / org.gvsig.fmap.dal.swing.impl / src / main / java / org / gvsig / fmap / dal / swing / impl / featuretable / table / DefaultFeatureTableModel.java @ 42990
History | View | Annotate | Download (32.3 KB)
1 | 40559 | jjdelcerro | /**
|
---|---|---|---|
2 | * gvSIG. Desktop Geographic Information System.
|
||
3 | 40435 | jjdelcerro | *
|
4 | 40559 | jjdelcerro | * Copyright (C) 2007-2013 gvSIG Association.
|
5 | 40435 | jjdelcerro | *
|
6 | * This program is free software; you can redistribute it and/or
|
||
7 | * modify it under the terms of the GNU General Public License
|
||
8 | 40559 | jjdelcerro | * as published by the Free Software Foundation; either version 3
|
9 | 40435 | jjdelcerro | * of the License, or (at your option) any later version.
|
10 | *
|
||
11 | * This program is distributed in the hope that it will be useful,
|
||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
14 | * GNU General Public License for more details.
|
||
15 | *
|
||
16 | * You should have received a copy of the GNU General Public License
|
||
17 | * along with this program; if not, write to the Free Software
|
||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||
19 | * MA 02110-1301, USA.
|
||
20 | *
|
||
21 | 40559 | jjdelcerro | * For any additional information, do not hesitate to contact us
|
22 | * at info AT gvsig.com, or visit our website www.gvsig.com.
|
||
23 | 40435 | jjdelcerro | */
|
24 | |||
25 | 42775 | jjdelcerro | package org.gvsig.fmap.dal.swing.impl.featuretable.table; |
26 | |||
27 | import java.awt.event.ActionEvent; |
||
28 | import java.awt.event.ActionListener; |
||
29 | 40435 | jjdelcerro | import java.security.InvalidParameterException; |
30 | 41699 | jjdelcerro | import java.text.SimpleDateFormat; |
31 | 40435 | jjdelcerro | import java.util.ArrayList; |
32 | import java.util.HashMap; |
||
33 | 42807 | jjdelcerro | import java.util.HashSet; |
34 | 40435 | jjdelcerro | import java.util.Iterator; |
35 | import java.util.List; |
||
36 | 41699 | jjdelcerro | import java.util.Locale; |
37 | 40435 | jjdelcerro | import java.util.Map; |
38 | 42807 | jjdelcerro | import java.util.Set; |
39 | 42806 | fdiaz | |
40 | 42775 | jjdelcerro | import javax.swing.SwingUtilities; |
41 | import javax.swing.Timer; |
||
42 | 42807 | jjdelcerro | import javax.swing.event.ChangeEvent; |
43 | import javax.swing.event.ChangeListener; |
||
44 | 40435 | jjdelcerro | import javax.swing.event.TableModelEvent; |
45 | 42775 | jjdelcerro | import javax.swing.table.AbstractTableModel; |
46 | 40435 | jjdelcerro | |
47 | 42806 | fdiaz | import org.slf4j.Logger; |
48 | import org.slf4j.LoggerFactory; |
||
49 | |||
50 | 40435 | jjdelcerro | import org.gvsig.fmap.dal.DataTypes; |
51 | 42775 | jjdelcerro | import org.gvsig.fmap.dal.exception.DataException; |
52 | 40435 | jjdelcerro | import org.gvsig.fmap.dal.feature.EditableFeature; |
53 | import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor; |
||
54 | import org.gvsig.fmap.dal.feature.Feature; |
||
55 | import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor; |
||
56 | import org.gvsig.fmap.dal.feature.FeatureQuery; |
||
57 | import org.gvsig.fmap.dal.feature.FeatureQueryOrder; |
||
58 | 42775 | jjdelcerro | import org.gvsig.fmap.dal.feature.FeatureSelection; |
59 | 40435 | jjdelcerro | import org.gvsig.fmap.dal.feature.FeatureStore; |
60 | 42775 | jjdelcerro | import org.gvsig.fmap.dal.feature.FeatureStoreNotification; |
61 | 40435 | jjdelcerro | import org.gvsig.fmap.dal.feature.FeatureType; |
62 | 42775 | jjdelcerro | import org.gvsig.fmap.dal.feature.exception.ConcurrentDataModificationException; |
63 | import org.gvsig.fmap.dal.feature.paging.FeaturePagingHelper; |
||
64 | 42806 | fdiaz | import org.gvsig.fmap.dal.swing.impl.featuretable.table.renders.GetFeatureAtException; |
65 | 40435 | jjdelcerro | import org.gvsig.tools.exception.BaseException; |
66 | 42775 | jjdelcerro | import org.gvsig.tools.observer.ComplexNotification; |
67 | import org.gvsig.tools.observer.ComplexObserver; |
||
68 | import org.gvsig.tools.observer.Observable; |
||
69 | 40435 | jjdelcerro | |
70 | 42775 | jjdelcerro | public class DefaultFeatureTableModel extends AbstractTableModel implements org.gvsig.fmap.dal.swing.FeatureTableModel, ComplexObserver { |
71 | 40435 | jjdelcerro | |
72 | private static final long serialVersionUID = -8223987814719746492L; |
||
73 | 42806 | fdiaz | |
74 | 42775 | jjdelcerro | private static final Logger logger = LoggerFactory.getLogger(DefaultFeatureTableModel.class); |
75 | 40435 | jjdelcerro | |
76 | private List<String> columnNames; |
||
77 | |||
78 | private List<String> visibleColumnNames; |
||
79 | |||
80 | private List<String> visibleColumnNamesOriginal; |
||
81 | |||
82 | private Map<String, String> name2Alias; |
||
83 | |||
84 | private Map<String, String> name2AliasOriginal; |
||
85 | |||
86 | 41699 | jjdelcerro | private Map<String,String> patterns = null; |
87 | |||
88 | 42806 | fdiaz | private Locale localeOfData; |
89 | 42775 | jjdelcerro | |
90 | private final FeaturePagingHelper featurePager; |
||
91 | |||
92 | /** Used to know if a modification in the FeatureStore is created by us. */
|
||
93 | private EditableFeature editableFeature;
|
||
94 | |||
95 | private boolean selectionLocked=false; |
||
96 | 42806 | fdiaz | |
97 | 42775 | jjdelcerro | private final DelayAction delayAction = new DelayAction(); |
98 | |||
99 | 42807 | jjdelcerro | private FeatureSelection selection = null; |
100 | 42775 | jjdelcerro | |
101 | 42807 | jjdelcerro | private Set<ActionListener> changeListeners = null; |
102 | |||
103 | 42775 | jjdelcerro | public DefaultFeatureTableModel(FeaturePagingHelper featurePager) {
|
104 | this.featurePager = featurePager;
|
||
105 | 41699 | jjdelcerro | this.localeOfData = Locale.getDefault(); |
106 | 42775 | jjdelcerro | this.initialize();
|
107 | 40435 | jjdelcerro | } |
108 | |||
109 | 42775 | jjdelcerro | private void initialize() { |
110 | this.getFeatureStore().addObserver(this); |
||
111 | 42806 | fdiaz | |
112 | 42775 | jjdelcerro | int columns = this.getOriginalColumnCount(); |
113 | |||
114 | // Initilize visible columns
|
||
115 | columnNames = new ArrayList<>(columns); |
||
116 | visibleColumnNames = new ArrayList<>(columns); |
||
117 | for (int i = 0; i < columns; i++) { |
||
118 | FeatureAttributeDescriptor descriptor = this.getInternalColumnDescriptor(i);
|
||
119 | String columnName = descriptor.getName();
|
||
120 | columnNames.add(columnName); |
||
121 | |||
122 | // By default, geometry columns will not be visible
|
||
123 | if (descriptor.getType() != DataTypes.GEOMETRY) {
|
||
124 | visibleColumnNames.add(columnName); |
||
125 | } |
||
126 | } |
||
127 | visibleColumnNamesOriginal = new ArrayList<>(visibleColumnNames); |
||
128 | 42806 | fdiaz | |
129 | 42775 | jjdelcerro | // Initialize alias
|
130 | name2Alias = new HashMap<>(columns); |
||
131 | name2AliasOriginal = new HashMap<>(columns); |
||
132 | |||
133 | initializeFormatingPatterns(); |
||
134 | updatePagerWithHiddenColums(); |
||
135 | 40435 | jjdelcerro | } |
136 | |||
137 | 42775 | jjdelcerro | private void initializeFormatingPatterns() { |
138 | int columns = this.getOriginalColumnCount(); |
||
139 | 42806 | fdiaz | |
140 | 42775 | jjdelcerro | this.patterns = new HashMap<>(); |
141 | for (int i = 0; i < columns; i++) { |
||
142 | FeatureAttributeDescriptor descriptor = this.getInternalColumnDescriptor(i);
|
||
143 | String columnName = descriptor.getName();
|
||
144 | switch(descriptor.getDataType().getType()) {
|
||
145 | case DataTypes.BYTE:
|
||
146 | case DataTypes.INT:
|
||
147 | case DataTypes.LONG:
|
||
148 | String defaultIntegerPattern = "#,##0"; |
||
149 | this.patterns.put(columnName,defaultIntegerPattern);
|
||
150 | break;
|
||
151 | case DataTypes.DOUBLE:
|
||
152 | String defaultDoublePattern = "#,##0.0000000000"; |
||
153 | this.patterns.put(columnName,defaultDoublePattern);
|
||
154 | break;
|
||
155 | case DataTypes.FLOAT:
|
||
156 | String defaultFloatPattern = "#,##0.0000"; |
||
157 | this.patterns.put(columnName,defaultFloatPattern);
|
||
158 | break;
|
||
159 | case DataTypes.DATE:
|
||
160 | String defaultDatePattern = new SimpleDateFormat().toPattern(); |
||
161 | this.patterns.put(columnName,defaultDatePattern);
|
||
162 | break;
|
||
163 | default:
|
||
164 | this.patterns.put(columnName,null); |
||
165 | } |
||
166 | } |
||
167 | 42806 | fdiaz | |
168 | 42775 | jjdelcerro | } |
169 | 42806 | fdiaz | |
170 | 42775 | jjdelcerro | private void updatePagerWithHiddenColums() { |
171 | 42990 | jbadia | return;
|
172 | |||
173 | // FeatureQuery query = this.getFeaturePager().getFeatureQuery();
|
||
174 | // if (this.getFeaturePager().getFeatureStore().isEditing()) {
|
||
175 | // if (query.hasConstantsAttributeNames()) {
|
||
176 | // query.clearConstantsAttributeNames();
|
||
177 | // }
|
||
178 | // } else {
|
||
179 | // query.setConstantsAttributeNames(this.getHiddenColumnNames());
|
||
180 | // }
|
||
181 | // try {
|
||
182 | // this.getFeaturePager().reload();
|
||
183 | // } catch (BaseException ex) {
|
||
184 | // logger.warn("Can't reload paging-helper.", ex);
|
||
185 | // }
|
||
186 | 42775 | jjdelcerro | } |
187 | 42806 | fdiaz | |
188 | 40435 | jjdelcerro | @Override
|
189 | 42775 | jjdelcerro | public FeaturePagingHelper getFeaturePager() {
|
190 | return this.featurePager; |
||
191 | } |
||
192 | 42806 | fdiaz | |
193 | 42775 | jjdelcerro | @Override
|
194 | public FeatureQuery getFeatureQuery() {
|
||
195 | return this.getFeaturePager().getFeatureQuery(); |
||
196 | } |
||
197 | |||
198 | @Override
|
||
199 | public FeatureType getFeatureType() {
|
||
200 | return this.getFeaturePager().getFeatureType(); |
||
201 | } |
||
202 | 42806 | fdiaz | |
203 | 42775 | jjdelcerro | @Override
|
204 | public FeatureStore getFeatureStore() {
|
||
205 | return this.getFeaturePager().getFeatureStore(); |
||
206 | } |
||
207 | |||
208 | @Override
|
||
209 | 40435 | jjdelcerro | public int getColumnCount() { |
210 | return visibleColumnNames.size();
|
||
211 | } |
||
212 | |||
213 | public int getOriginalColumnCount() { |
||
214 | 42775 | jjdelcerro | FeatureType featureType = getFeatureType(); |
215 | return featureType.size();
|
||
216 | 40435 | jjdelcerro | } |
217 | |||
218 | @Override
|
||
219 | public String getColumnName(int column) { |
||
220 | 42775 | jjdelcerro | String columName = getOriginalColumnName(column);
|
221 | return this.getColumnAlias(columName); |
||
222 | 40435 | jjdelcerro | } |
223 | |||
224 | @Override
|
||
225 | public Class<?> getColumnClass(int columnIndex) { |
||
226 | int originalIndex = getOriginalColumnIndex(columnIndex);
|
||
227 | 42806 | fdiaz | |
228 | 42775 | jjdelcerro | // Return the class of the FeatureAttributeDescriptor for the value
|
229 | FeatureAttributeDescriptor attributeDesc = this.getInternalColumnDescriptor(originalIndex);
|
||
230 | if (attributeDesc == null) { |
||
231 | return super.getColumnClass(originalIndex); |
||
232 | } |
||
233 | Class<?> clazz = attributeDesc.getObjectClass();
|
||
234 | return (clazz == null ? super.getColumnClass(originalIndex) : clazz); |
||
235 | 40435 | jjdelcerro | } |
236 | |||
237 | @Override
|
||
238 | 42775 | jjdelcerro | public FeatureAttributeDescriptor getColumnDescriptor(int columnIndex) { |
239 | 40435 | jjdelcerro | int originalIndex = getOriginalColumnIndex(columnIndex);
|
240 | 42775 | jjdelcerro | return this.getInternalColumnDescriptor(originalIndex); |
241 | 40435 | jjdelcerro | } |
242 | 42806 | fdiaz | |
243 | 42775 | jjdelcerro | protected FeatureAttributeDescriptor getInternalColumnDescriptor(int columnIndex) { |
244 | FeatureType featureType = getFeatureType(); |
||
245 | if( featureType == null ) { |
||
246 | return null; |
||
247 | } |
||
248 | return featureType.getAttributeDescriptor(columnIndex);
|
||
249 | } |
||
250 | 40435 | jjdelcerro | |
251 | 42775 | jjdelcerro | @Override
|
252 | 40435 | jjdelcerro | public String getOriginalColumnName(int column) { |
253 | 42775 | jjdelcerro | return getInternalColumnDescriptor(column).getName();
|
254 | 40435 | jjdelcerro | } |
255 | |||
256 | 42775 | jjdelcerro | @Override
|
257 | public void setColumnVisible(String name, boolean visible) { |
||
258 | 40435 | jjdelcerro | if (!columnNames.contains(name)) {
|
259 | throw new InvalidParameterException(name); // FIXME |
||
260 | } |
||
261 | 42775 | jjdelcerro | if( visible ) {
|
262 | if ( !visibleColumnNames.contains(name) ) {
|
||
263 | visibleColumnNames.add(name); |
||
264 | setVisibleColumns(visibleColumnNames); |
||
265 | } |
||
266 | 40435 | jjdelcerro | } else {
|
267 | 42775 | jjdelcerro | if ( visibleColumnNames.contains(name) ) {
|
268 | visibleColumnNames.remove(name); |
||
269 | setVisibleColumns(visibleColumnNames); |
||
270 | fireTableStructureChanged(); |
||
271 | } |
||
272 | 40435 | jjdelcerro | } |
273 | } |
||
274 | |||
275 | public void setFeatureType(FeatureType featureType) { |
||
276 | // Check if there is a new column name
|
||
277 | 42775 | jjdelcerro | List<String> newColumns = new ArrayList<>(); |
278 | List<String> renamedColumnsNewName = new ArrayList<>(); |
||
279 | 42806 | fdiaz | |
280 | 40435 | jjdelcerro | Iterator<FeatureAttributeDescriptor> attrIter = featureType.iterator();
|
281 | 42775 | jjdelcerro | FeatureAttributeDescriptor fad ; |
282 | EditableFeatureAttributeDescriptor efad ; |
||
283 | 42806 | fdiaz | |
284 | 40435 | jjdelcerro | String colName;
|
285 | while (attrIter.hasNext()) {
|
||
286 | fad = attrIter.next(); |
||
287 | colName = fad.getName(); |
||
288 | if (!columnNames.contains(colName)) {
|
||
289 | if (fad instanceof EditableFeatureAttributeDescriptor) { |
||
290 | 42806 | fdiaz | efad = (EditableFeatureAttributeDescriptor) fad; |
291 | 40435 | jjdelcerro | /*
|
292 | * If editable att descriptor,
|
||
293 | * check original name
|
||
294 | */
|
||
295 | if (efad.getOriginalName() != null) { |
||
296 | if (!columnNames.contains(efad.getOriginalName())) {
|
||
297 | /*
|
||
298 | * Check with original name but add current name
|
||
299 | */
|
||
300 | newColumns.add(colName); |
||
301 | } else {
|
||
302 | /*
|
||
303 | * List of new names of renamed columns
|
||
304 | */
|
||
305 | renamedColumnsNewName.add(colName); |
||
306 | } |
||
307 | } else {
|
||
308 | newColumns.add(colName); |
||
309 | } |
||
310 | } else {
|
||
311 | newColumns.add(colName); |
||
312 | } |
||
313 | } |
||
314 | } |
||
315 | |||
316 | // Update column names
|
||
317 | columnNames.clear(); |
||
318 | @SuppressWarnings("unchecked") |
||
319 | Iterator<FeatureAttributeDescriptor> visibleAttrIter =
|
||
320 | featureType.iterator(); |
||
321 | while (visibleAttrIter.hasNext()) {
|
||
322 | fad = visibleAttrIter.next(); |
||
323 | colName = fad.getName(); |
||
324 | columnNames.add(colName); |
||
325 | //If the column is added has to be visible
|
||
326 | if (!visibleColumnNames.contains(colName)) {
|
||
327 | |||
328 | 41093 | jldominguez | if (((newColumns.contains(colName)
|
329 | || renamedColumnsNewName.contains(colName))) |
||
330 | && |
||
331 | fad.getType() != DataTypes.GEOMETRY) { |
||
332 | 40435 | jjdelcerro | // Add new columns and renamed
|
333 | visibleColumnNames.add(colName); |
||
334 | visibleColumnNamesOriginal.add(colName); |
||
335 | } |
||
336 | /*
|
||
337 | if (renamedColumnsNewName.contains(colName)) {
|
||
338 | // Add renamed
|
||
339 | insertWhereOldName(visibleColumnNames, colName, fad);
|
||
340 | insertWhereOldName(visibleColumnNamesOriginal, colName, fad);
|
||
341 | }
|
||
342 | */
|
||
343 | } |
||
344 | } |
||
345 | |||
346 | // remove from visible columns removed columns
|
||
347 | visibleColumnNames = intersectKeepOrder(columnNames, visibleColumnNames); |
||
348 | // instead of: visibleColumnNames.retainAll(columnNames);
|
||
349 | |||
350 | visibleColumnNamesOriginal = intersectKeepOrder(columnNames, visibleColumnNamesOriginal); |
||
351 | // instead of: visibleColumnNamesOriginal.retainAll(columnNames);
|
||
352 | |||
353 | // remove from alias map removed columns
|
||
354 | name2Alias.keySet().retainAll(columnNames); |
||
355 | name2AliasOriginal.keySet().retainAll(columnNames); |
||
356 | |||
357 | 42806 | fdiaz | initializeFormatingPatterns(); |
358 | |||
359 | 42775 | jjdelcerro | getFeatureQuery().setFeatureType(featureType); |
360 | reloadFeatures(); |
||
361 | //Selection must be locked to avoid losing it when the table is refreshed
|
||
362 | selectionLocked=true;
|
||
363 | //The table is refreshed
|
||
364 | try {
|
||
365 | fireTableStructureChanged(); |
||
366 | } catch (Exception e) { |
||
367 | logger.warn("Couldn't reload changed table");
|
||
368 | }finally{
|
||
369 | //The locked selection is unlocked.
|
||
370 | selectionLocked=false;
|
||
371 | 42806 | fdiaz | } |
372 | 40435 | jjdelcerro | |
373 | } |
||
374 | |||
375 | 42775 | jjdelcerro | private void reloadFeatures() { |
376 | try {
|
||
377 | this.getFeaturePager().reload();
|
||
378 | } catch (BaseException ex) {
|
||
379 | throw new FeaturesDataReloadException(ex); |
||
380 | } |
||
381 | } |
||
382 | 42806 | fdiaz | |
383 | 40435 | jjdelcerro | /**
|
384 | * keeps order of first parameter
|
||
385 | 42806 | fdiaz | *
|
386 | 40435 | jjdelcerro | * @param lista
|
387 | * @param listb
|
||
388 | * @return
|
||
389 | */
|
||
390 | private List<String> intersectKeepOrder(List<String> lista, List<String> listb) { |
||
391 | 42806 | fdiaz | |
392 | 42775 | jjdelcerro | List<String> resp = new ArrayList<>(); |
393 | 40435 | jjdelcerro | resp.addAll(lista); |
394 | resp.retainAll(listb); |
||
395 | return resp;
|
||
396 | } |
||
397 | |||
398 | public void setVisibleColumns(List<String> names) { |
||
399 | // Recreate the visible column names list
|
||
400 | 42806 | fdiaz | // to maintain the original order
|
401 | 42775 | jjdelcerro | visibleColumnNames = new ArrayList<>(names.size()); |
402 | 40435 | jjdelcerro | for (int i = 0; i < columnNames.size(); i++) { |
403 | String columnName = columnNames.get(i);
|
||
404 | if (names.contains(columnName)) {
|
||
405 | visibleColumnNames.add(columnName); |
||
406 | } |
||
407 | } |
||
408 | 42775 | jjdelcerro | updatePagerWithHiddenColums(); |
409 | 40435 | jjdelcerro | fireTableStructureChanged(); |
410 | } |
||
411 | |||
412 | 41212 | jjdelcerro | protected String[] getHiddenColumnNames() { |
413 | List<String> hiddenColumns = new ArrayList<String>(); |
||
414 | hiddenColumns.addAll(columnNames); |
||
415 | 42806 | fdiaz | |
416 | 41212 | jjdelcerro | for (int i = 0; i < visibleColumnNames.size(); i++) { |
417 | String columnName = visibleColumnNames.get(i);
|
||
418 | hiddenColumns.remove(columnName); |
||
419 | } |
||
420 | if( hiddenColumns.size()<1 ) { |
||
421 | return null; |
||
422 | } |
||
423 | return (String[]) hiddenColumns.toArray(new String[hiddenColumns.size()]); |
||
424 | } |
||
425 | 42806 | fdiaz | |
426 | 40435 | jjdelcerro | /**
|
427 | * Changes all columns to be visible.
|
||
428 | */
|
||
429 | public void setAllVisible() { |
||
430 | visibleColumnNames.clear(); |
||
431 | visibleColumnNames.addAll(columnNames); |
||
432 | fireTableStructureChanged(); |
||
433 | } |
||
434 | |||
435 | 42775 | jjdelcerro | @Override
|
436 | public void setColumnOrder(String name, boolean ascending) |
||
437 | 40435 | jjdelcerro | throws BaseException {
|
438 | 42775 | jjdelcerro | FeatureQueryOrder order = this.getFeatureQuery().getOrder();
|
439 | 40435 | jjdelcerro | if (order == null) { |
440 | order = new FeatureQueryOrder();
|
||
441 | 42775 | jjdelcerro | this.getFeatureQuery().setOrder(order);
|
442 | 40435 | jjdelcerro | } |
443 | order.clear(); |
||
444 | order.add(name, ascending); |
||
445 | 42775 | jjdelcerro | this.getFeaturePager().reload();
|
446 | fireTableChanged(new TableModelEvent(this, 0, this.getRowCount() - 1)); |
||
447 | 40435 | jjdelcerro | } |
448 | |||
449 | @Override
|
||
450 | 42775 | jjdelcerro | public int getRowCount() { |
451 | // Return the total size of the collection
|
||
452 | // If the size is bigger than INTEGER.MAX_VALUE, return that instead
|
||
453 | try {
|
||
454 | long totalSize = this.getFeaturePager().getTotalSize(); |
||
455 | if (totalSize > Integer.MAX_VALUE) { |
||
456 | return Integer.MAX_VALUE; |
||
457 | } else {
|
||
458 | return (int) totalSize; |
||
459 | } |
||
460 | } catch (ConcurrentDataModificationException e) {
|
||
461 | logger.debug("Error while getting the total size of the set", e);
|
||
462 | return 0; |
||
463 | } |
||
464 | 40435 | jjdelcerro | } |
465 | |||
466 | 42775 | jjdelcerro | @Override
|
467 | public boolean isColumnVisible(String name) { |
||
468 | 40435 | jjdelcerro | return visibleColumnNames.contains(name);
|
469 | } |
||
470 | |||
471 | 42775 | jjdelcerro | @Override
|
472 | public String getColumnAlias(String name) { |
||
473 | String alias = name2Alias.get(name);
|
||
474 | return alias == null ? name : alias; |
||
475 | 40435 | jjdelcerro | } |
476 | |||
477 | 42775 | jjdelcerro | @Override
|
478 | public void setColumnAlias(String name, String alias) { |
||
479 | name2Alias.put(name, alias); |
||
480 | fireTableStructureChanged(); |
||
481 | 40435 | jjdelcerro | } |
482 | |||
483 | 42775 | jjdelcerro | @Override
|
484 | 41707 | jjdelcerro | public int getOriginalColumnIndex(int columnIndex) { |
485 | 40435 | jjdelcerro | String columnName = visibleColumnNames.get(columnIndex);
|
486 | return columnNames.indexOf(columnName);
|
||
487 | } |
||
488 | |||
489 | @Override
|
||
490 | 42775 | jjdelcerro | public Object getValueAt(int rowIndex, int columnIndex) { |
491 | // Get the Feature at row "rowIndex", and return the value of the
|
||
492 | // attribute at "columnIndex"
|
||
493 | Feature feature = getFeatureAt(rowIndex); |
||
494 | return feature == null ? null : getFeatureValue(feature, columnIndex); |
||
495 | } |
||
496 | 42806 | fdiaz | |
497 | 42775 | jjdelcerro | @Override
|
498 | public Feature getFeatureAt(int rowIndex) { |
||
499 | try {
|
||
500 | return this.getFeaturePager().getFeatureAt(rowIndex); |
||
501 | } catch (BaseException ex) {
|
||
502 | throw new GetFeatureAtException(rowIndex, ex); |
||
503 | } |
||
504 | 42806 | fdiaz | } |
505 | |||
506 | 40435 | jjdelcerro | protected Object getFeatureValue(Feature feature, int columnIndex) { |
507 | int realColumnIndex = getOriginalColumnIndex(columnIndex);
|
||
508 | 42775 | jjdelcerro | return feature.get(realColumnIndex);
|
509 | 40435 | jjdelcerro | } |
510 | |||
511 | protected EditableFeature setFeatureValue(Feature feature, int columnIndex, |
||
512 | Object value) {
|
||
513 | int realColumnIndex = getOriginalColumnIndex(columnIndex);
|
||
514 | 42775 | jjdelcerro | EditableFeature editableFeature = feature.getEditable(); |
515 | editableFeature.set(realColumnIndex, value); |
||
516 | return editableFeature;
|
||
517 | 40435 | jjdelcerro | } |
518 | 42775 | jjdelcerro | |
519 | 42806 | fdiaz | |
520 | 40435 | jjdelcerro | public void acceptChanges() { |
521 | 42775 | jjdelcerro | visibleColumnNamesOriginal = new ArrayList<>(visibleColumnNames); |
522 | name2AliasOriginal = new HashMap<>(name2Alias); |
||
523 | 40435 | jjdelcerro | } |
524 | 42806 | fdiaz | |
525 | 40435 | jjdelcerro | public void cancelChanges() { |
526 | 42775 | jjdelcerro | visibleColumnNames = new ArrayList<>(visibleColumnNamesOriginal); |
527 | name2Alias = new HashMap<>(name2AliasOriginal); |
||
528 | 40435 | jjdelcerro | fireTableStructureChanged(); |
529 | } |
||
530 | 41699 | jjdelcerro | |
531 | 42806 | fdiaz | |
532 | 42775 | jjdelcerro | @Override
|
533 | public String getColumnFormattingPattern(int column) { |
||
534 | 41699 | jjdelcerro | String columnName = this.visibleColumnNames.get(column); |
535 | 42775 | jjdelcerro | return this.getColumnFormattingPattern(columnName); |
536 | 41699 | jjdelcerro | } |
537 | 42806 | fdiaz | |
538 | 42775 | jjdelcerro | @Override
|
539 | public String getColumnFormattingPattern(String columnName) { |
||
540 | 41707 | jjdelcerro | String pattern = this.patterns.get(columnName); |
541 | return pattern;
|
||
542 | 41699 | jjdelcerro | } |
543 | 42806 | fdiaz | |
544 | 42775 | jjdelcerro | @Override
|
545 | public void setColumnFormattingPattern(String columnName, String pattern) { |
||
546 | 41699 | jjdelcerro | this.patterns.put(columnName,pattern);
|
547 | } |
||
548 | 42806 | fdiaz | |
549 | 42775 | jjdelcerro | @Override
|
550 | 41699 | jjdelcerro | public Locale getLocaleOfData() { |
551 | return this.localeOfData; |
||
552 | } |
||
553 | 42806 | fdiaz | |
554 | 42775 | jjdelcerro | @Override
|
555 | 41699 | jjdelcerro | public void setLocaleOfData(Locale locale) { |
556 | this.localeOfData = locale;
|
||
557 | } |
||
558 | 42806 | fdiaz | |
559 | 42775 | jjdelcerro | public boolean isSelectionLocked() { |
560 | return selectionLocked;
|
||
561 | 42806 | fdiaz | } |
562 | 41699 | jjdelcerro | |
563 | 42775 | jjdelcerro | @Override
|
564 | public boolean isSelectionUp() { |
||
565 | return this.getFeaturePager().isSelectionUp(); |
||
566 | 42806 | fdiaz | } |
567 | 42775 | jjdelcerro | |
568 | @Override
|
||
569 | public void setSelectionUp(boolean selectionUp) { |
||
570 | this.getFeaturePager().setSelectionUp(selectionUp);
|
||
571 | fireTableChanged(new TableModelEvent(this, 0, getRowCount() - 1)); |
||
572 | } |
||
573 | 42806 | fdiaz | |
574 | 42775 | jjdelcerro | private class DelayAction extends Timer implements ActionListener, Runnable { |
575 | private static final int STATE_NONE = 0; |
||
576 | private static final int STATE_NEED_RELOADALL = 1; |
||
577 | private static final int STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED = 2; |
||
578 | private static final int STATE_NEED_RELOAD_IF_FEATURE_UPDATED = 4; |
||
579 | private static final int STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED = 8; |
||
580 | private static final int STATE_NEED_RELOAD_FEATURE_TYPE = 16; |
||
581 | private static final int STATE_NEED_SELECTION_UP = 32; |
||
582 | private static final int STATE_NEED_RELOAD_ALL_FEATURES=64; |
||
583 | 42806 | fdiaz | |
584 | 42775 | jjdelcerro | private static final long serialVersionUID = -5692569125344166705L; |
585 | |||
586 | private int state = STATE_NONE; |
||
587 | private Feature feature;
|
||
588 | private FeatureType featureType;
|
||
589 | private boolean isSelecctionUp; |
||
590 | |||
591 | public DelayAction() {
|
||
592 | super(1000,null); |
||
593 | this.setRepeats(false); |
||
594 | this.reset();
|
||
595 | this.addActionListener(this); |
||
596 | } |
||
597 | |||
598 | private void reset() { |
||
599 | this.state = STATE_NONE;
|
||
600 | this.isSelecctionUp = false; |
||
601 | this.feature = null; |
||
602 | this.featureType = null; |
||
603 | } |
||
604 | |||
605 | public void actionPerformed(ActionEvent ae) { |
||
606 | this.run();
|
||
607 | } |
||
608 | |||
609 | public void run() { |
||
610 | if( !SwingUtilities.isEventDispatchThread() ) { |
||
611 | SwingUtilities.invokeLater(this); |
||
612 | return;
|
||
613 | } |
||
614 | this.stop();
|
||
615 | logger.info("DelayAction.run["+this.state+"] begin"); |
||
616 | switch(this.state) { |
||
617 | case STATE_NEED_RELOADALL:
|
||
618 | reloadAll(); |
||
619 | break;
|
||
620 | case STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED:
|
||
621 | reloadIfFeatureCountChanged(feature); |
||
622 | break;
|
||
623 | case STATE_NEED_RELOAD_IF_FEATURE_UPDATED:
|
||
624 | reloadIfFeatureUpdated(feature); |
||
625 | break;
|
||
626 | case STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED:
|
||
627 | reloadIfTypeChanged(featureType); |
||
628 | break;
|
||
629 | case STATE_NEED_RELOAD_FEATURE_TYPE:
|
||
630 | reloadFeatureType(); |
||
631 | updatePagerWithHiddenColums(); |
||
632 | break;
|
||
633 | case STATE_NEED_RELOAD_ALL_FEATURES:
|
||
634 | reloadFeatures(); |
||
635 | fireTableChanged(new TableModelEvent(DefaultFeatureTableModel.this, 0, getRowCount())); |
||
636 | break;
|
||
637 | case STATE_NEED_SELECTION_UP:
|
||
638 | case STATE_NONE:
|
||
639 | default:
|
||
640 | break;
|
||
641 | } |
||
642 | if( isSelecctionUp ) {
|
||
643 | getFeaturePager().setSelectionUp(true);
|
||
644 | } |
||
645 | this.reset();
|
||
646 | logger.info("DelayAction.run["+this.state+"] end"); |
||
647 | } |
||
648 | |||
649 | public void nextState(int nextstate) { |
||
650 | this.nextState(nextstate, null, null); |
||
651 | } |
||
652 | |||
653 | public void nextState(int nextstate, Feature feature) { |
||
654 | this.nextState(nextstate, feature, null); |
||
655 | } |
||
656 | |||
657 | public void nextState(int nextstate, FeatureType featureType) { |
||
658 | this.nextState(nextstate, null, featureType); |
||
659 | } |
||
660 | |||
661 | public void nextState(int nextstate, Feature feature, FeatureType featureType) { |
||
662 | this.feature = feature;
|
||
663 | this.featureType = featureType;
|
||
664 | switch(nextstate) {
|
||
665 | case STATE_NEED_RELOADALL:
|
||
666 | case STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED:
|
||
667 | case STATE_NEED_RELOAD_IF_FEATURE_UPDATED:
|
||
668 | switch(this.state) { |
||
669 | case STATE_NEED_RELOADALL:
|
||
670 | case STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED:
|
||
671 | //case STATE_NEED_RELOAD_IF_FEATURE_UPDATED:
|
||
672 | this.state = STATE_NEED_RELOADALL;
|
||
673 | break;
|
||
674 | case STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED:
|
||
675 | case STATE_NEED_RELOAD_FEATURE_TYPE:
|
||
676 | this.state = STATE_NEED_RELOAD_FEATURE_TYPE;
|
||
677 | break;
|
||
678 | case STATE_NEED_RELOAD_IF_FEATURE_UPDATED:
|
||
679 | case STATE_NEED_RELOAD_ALL_FEATURES:
|
||
680 | this.state=STATE_NEED_RELOAD_ALL_FEATURES;
|
||
681 | break;
|
||
682 | case STATE_NEED_SELECTION_UP:
|
||
683 | this.state = nextstate;
|
||
684 | this.isSelecctionUp = true; |
||
685 | break;
|
||
686 | case STATE_NONE:
|
||
687 | default:
|
||
688 | this.state = nextstate;
|
||
689 | break;
|
||
690 | } |
||
691 | break;
|
||
692 | case STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED:
|
||
693 | case STATE_NEED_RELOAD_FEATURE_TYPE:
|
||
694 | switch(this.state) { |
||
695 | case STATE_NEED_RELOADALL:
|
||
696 | case STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED:
|
||
697 | case STATE_NEED_RELOAD_IF_FEATURE_UPDATED:
|
||
698 | case STATE_NEED_RELOAD_ALL_FEATURES:
|
||
699 | case STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED:
|
||
700 | case STATE_NEED_RELOAD_FEATURE_TYPE:
|
||
701 | this.state = STATE_NEED_RELOAD_FEATURE_TYPE;
|
||
702 | break;
|
||
703 | case STATE_NEED_SELECTION_UP:
|
||
704 | this.state = nextstate;
|
||
705 | this.isSelecctionUp = true; |
||
706 | break;
|
||
707 | case STATE_NONE:
|
||
708 | default:
|
||
709 | this.state = nextstate;
|
||
710 | break;
|
||
711 | } |
||
712 | break;
|
||
713 | case STATE_NEED_SELECTION_UP:
|
||
714 | switch(this.state) { |
||
715 | case STATE_NEED_RELOADALL:
|
||
716 | case STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED:
|
||
717 | case STATE_NEED_RELOAD_IF_FEATURE_UPDATED:
|
||
718 | case STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED:
|
||
719 | case STATE_NEED_RELOAD_ALL_FEATURES:
|
||
720 | case STATE_NEED_RELOAD_FEATURE_TYPE:
|
||
721 | case STATE_NEED_SELECTION_UP:
|
||
722 | this.isSelecctionUp = true; |
||
723 | break;
|
||
724 | case STATE_NONE:
|
||
725 | default:
|
||
726 | this.state = nextstate;
|
||
727 | this.isSelecctionUp = true; |
||
728 | break;
|
||
729 | } |
||
730 | break;
|
||
731 | case STATE_NONE:
|
||
732 | default:
|
||
733 | this.state = STATE_NONE;
|
||
734 | break;
|
||
735 | } |
||
736 | if( this.state != STATE_NONE ) { |
||
737 | this.start();
|
||
738 | } |
||
739 | } |
||
740 | |||
741 | } |
||
742 | |||
743 | /**
|
||
744 | * Reloads the table data if a feature has been changed, not through the
|
||
745 | * table.
|
||
746 | */
|
||
747 | private void reloadIfFeatureCountChanged(Feature feature) { |
||
748 | // Is any data is changed in the FeatureStore, notify the model
|
||
749 | // listeners. Ignore the case where the updated feature is
|
||
750 | // changed through us.
|
||
751 | if (editableFeature == null || !editableFeature.equals(feature)) { |
||
752 | reloadFeatures(); |
||
753 | //Selection must be locked to avoid losing it when the table is refreshed
|
||
754 | selectionLocked=true;
|
||
755 | //The table is refreshed
|
||
756 | try {
|
||
757 | fireTableDataChanged(); |
||
758 | } catch (Exception e) { |
||
759 | logger.warn("Couldn't reload changed table");
|
||
760 | }finally{
|
||
761 | //The locked selection is unlocked.
|
||
762 | selectionLocked=false;
|
||
763 | } |
||
764 | } |
||
765 | } |
||
766 | |||
767 | private void reloadIfFeatureUpdated(Feature feature) { |
||
768 | // Is any data is changed in the FeatureStore, notify the model
|
||
769 | // listeners. Ignore the case where the updated feature is
|
||
770 | // changed through us.
|
||
771 | if (editableFeature == null || !editableFeature.equals(feature)) { |
||
772 | reloadFeatures(); |
||
773 | fireTableChanged(new TableModelEvent(this, 0, getRowCount())); |
||
774 | } |
||
775 | } |
||
776 | |||
777 | /**
|
||
778 | * Reloads data and structure if the {@link FeatureType} of the features
|
||
779 | * being shown has changed.
|
||
780 | */
|
||
781 | private void reloadIfTypeChanged(FeatureType updatedType) { |
||
782 | // If the updated featured type is the one currently being
|
||
783 | // shown, reload the table.
|
||
784 | if (updatedType != null |
||
785 | && updatedType.getId().equals(getFeatureType().getId())) { |
||
786 | setFeatureType(updatedType); |
||
787 | } |
||
788 | } |
||
789 | |||
790 | private void reloadAll() { |
||
791 | reloadFeatureType(); |
||
792 | } |
||
793 | |||
794 | private void reloadFeatureType() { |
||
795 | try {
|
||
796 | FeatureType featureType = this.getFeaturePager().getFeatureType();
|
||
797 | FeatureStore store = this.getFeaturePager().getFeatureStore();
|
||
798 | this.setFeatureType( store.getFeatureType(featureType.getId()) );
|
||
799 | } catch (DataException e) {
|
||
800 | throw new FeaturesDataReloadException(e); |
||
801 | } |
||
802 | } |
||
803 | |||
804 | @Override
|
||
805 | public void update(final Observable observable, final Object notification) { |
||
806 | if (notification instanceof ComplexNotification) { |
||
807 | // A lot of things might have happened in the store, so don't
|
||
808 | // bother looking into each notification.
|
||
809 | this.delayAction.nextState(DelayAction.STATE_NEED_RELOADALL);
|
||
810 | // reloadAll();
|
||
811 | } else if (observable.equals(getFeatureStore()) |
||
812 | && notification instanceof FeatureStoreNotification) {
|
||
813 | FeatureStoreNotification fsNotification |
||
814 | = (FeatureStoreNotification) notification; |
||
815 | String type = fsNotification.getType();
|
||
816 | |||
817 | // If there are new, updated or deleted features
|
||
818 | // reload the table data
|
||
819 | if (FeatureStoreNotification.AFTER_DELETE.equals(type)
|
||
820 | || FeatureStoreNotification.AFTER_INSERT.equals(type)) { |
||
821 | // reloadIfFeatureCountChanged(fsNotification.getFeature());
|
||
822 | this.delayAction.nextState(DelayAction.STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED, fsNotification.getFeature());
|
||
823 | |||
824 | } else if (FeatureStoreNotification.AFTER_UPDATE.equals(type)) { |
||
825 | // reloadIfFeatureUpdated(fsNotification.getFeature());
|
||
826 | this.delayAction.nextState(DelayAction.STATE_NEED_RELOAD_IF_FEATURE_UPDATED, fsNotification.getFeature());
|
||
827 | |||
828 | } else if (FeatureStoreNotification.AFTER_UPDATE_TYPE.equals(type)) { |
||
829 | // reloadIfTypeChanged(fsNotification.getFeatureType());
|
||
830 | this.delayAction.nextState(DelayAction.STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED, fsNotification.getFeatureType());
|
||
831 | |||
832 | } else if (FeatureStoreNotification.TRANSFORM_CHANGE.equals(type) |
||
833 | || FeatureStoreNotification.AFTER_UNDO.equals(type) |
||
834 | || FeatureStoreNotification.AFTER_REDO.equals(type) |
||
835 | || FeatureStoreNotification.AFTER_REFRESH.equals(type)) { |
||
836 | // reloadAll();
|
||
837 | this.delayAction.nextState(DelayAction.STATE_NEED_RELOADALL);
|
||
838 | |||
839 | } else if (FeatureStoreNotification.AFTER_FINISHEDITING.equals(type) |
||
840 | || FeatureStoreNotification.AFTER_STARTEDITING.equals(type) |
||
841 | || FeatureStoreNotification.AFTER_CANCELEDITING.equals(type)) { |
||
842 | /*
|
||
843 | No tengo nada claro por que es necesario llamar al reloadFeatureType
|
||
844 | pero si no se incluye hay problemas si durante la edicion se a?aden
|
||
845 | campos a la tabla. Sin esto, al cerrar la edicion, los campos a?adidos
|
||
846 | desaparecen de la tabla aunque estan en el fichero.
|
||
847 | Ver ticket #2434 https://devel.gvsig.org/redmine/issues/2434
|
||
848 | */
|
||
849 | // reloadFeatureType();
|
||
850 | // updatePaginHelperWithHiddenColums();
|
||
851 | this.delayAction.nextState(DelayAction.STATE_NEED_RELOAD_FEATURE_TYPE, fsNotification.getFeatureType());
|
||
852 | } else if (FeatureStoreNotification.SELECTION_CHANGE.equals(type)) { |
||
853 | if( this.isSelectionUp() ) { |
||
854 | this.setSelectionUp(true); |
||
855 | this.delayAction.nextState(DelayAction.STATE_NEED_SELECTION_UP);
|
||
856 | } |
||
857 | } |
||
858 | } |
||
859 | } |
||
860 | 42807 | jjdelcerro | |
861 | 42775 | jjdelcerro | @Override
|
862 | 42807 | jjdelcerro | public FeatureSelection getFeatureSelection() {
|
863 | if (selection == null) { |
||
864 | try {
|
||
865 | return getFeatureStore().getFeatureSelection();
|
||
866 | } catch (Exception e) { |
||
867 | logger.warn("Error getting the selection", e);
|
||
868 | } |
||
869 | } |
||
870 | return selection;
|
||
871 | } |
||
872 | |||
873 | @Override
|
||
874 | public void setFeatureSelection(FeatureSelection selection) { |
||
875 | this.selection = selection;
|
||
876 | this.featurePager.setSelection(selection);
|
||
877 | this.fireChangeListeners(new ActionEvent(this, 0,CHANGE_SELECTION)); |
||
878 | } |
||
879 | |||
880 | public void addChangeListener(ActionListener listener) { |
||
881 | if( this.changeListeners==null) { |
||
882 | this.changeListeners = new HashSet<>(); |
||
883 | } |
||
884 | this.changeListeners.add(listener);
|
||
885 | } |
||
886 | |||
887 | public void fireChangeListeners(ActionEvent event) { |
||
888 | if( this.changeListeners == null ) { |
||
889 | return;
|
||
890 | } |
||
891 | for( ActionListener listener : this.changeListeners ) { |
||
892 | try {
|
||
893 | listener.actionPerformed(event); |
||
894 | } catch(Exception ex) { |
||
895 | // Ignore
|
||
896 | } |
||
897 | } |
||
898 | } |
||
899 | |||
900 | @Override
|
||
901 | 42775 | jjdelcerro | public int getSelectionCount() { |
902 | try {
|
||
903 | 42807 | jjdelcerro | FeatureSelection selection = this.getFeatureSelection();
|
904 | 42775 | jjdelcerro | return (int) selection.getSize(); |
905 | } catch (DataException ex) {
|
||
906 | throw new RuntimeException("Can't get selection of the FeatureTableModel",ex); |
||
907 | } |
||
908 | } |
||
909 | 42806 | fdiaz | |
910 | |||
911 | 40435 | jjdelcerro | } |