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 / FeatureSelectionModel.java @ 44644
History | View | Annotate | Download (13.3 KB)
1 | 40559 | jjdelcerro | /**
|
---|---|---|---|
2 | * gvSIG. Desktop Geographic Information System.
|
||
3 | 40435 | jjdelcerro | *
|
4 | 40559 | jjdelcerro | * Copyright (C) 2007-2013 gvSIG Association.
|
5 | *
|
||
6 | 40435 | jjdelcerro | * 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 | 40559 | jjdelcerro | *
|
11 | 40435 | jjdelcerro | * 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 | 40559 | jjdelcerro | *
|
16 | 40435 | jjdelcerro | * 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 | 40559 | jjdelcerro | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
19 | 40435 | jjdelcerro | * MA 02110-1301, USA.
|
20 | 40559 | jjdelcerro | *
|
21 | * 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 | * AUTHORS (In addition to CIT):
|
||
26 | * 2010 {} {{Task}}
|
||
27 | */
|
||
28 | 42775 | jjdelcerro | package org.gvsig.fmap.dal.swing.impl.featuretable; |
29 | 40435 | jjdelcerro | |
30 | 42807 | jjdelcerro | import java.awt.event.ActionEvent; |
31 | import java.awt.event.ActionListener; |
||
32 | 43358 | jjdelcerro | import java.util.logging.Level; |
33 | 40435 | jjdelcerro | import javax.swing.ListSelectionModel; |
34 | import javax.swing.event.EventListenerList; |
||
35 | import javax.swing.event.ListSelectionEvent; |
||
36 | import javax.swing.event.ListSelectionListener; |
||
37 | |||
38 | import org.gvsig.fmap.dal.exception.DataException; |
||
39 | import org.gvsig.fmap.dal.feature.Feature; |
||
40 | 42804 | jbadia | import org.gvsig.fmap.dal.feature.FeatureQuery; |
41 | 40435 | jjdelcerro | import org.gvsig.fmap.dal.feature.FeatureSelection; |
42 | import org.gvsig.fmap.dal.feature.FeatureSet; |
||
43 | import org.gvsig.fmap.dal.feature.FeatureStore; |
||
44 | import org.gvsig.fmap.dal.feature.FeatureStoreNotification; |
||
45 | import org.gvsig.fmap.dal.feature.exception.ConcurrentDataModificationException; |
||
46 | 42775 | jjdelcerro | import org.gvsig.fmap.dal.swing.FeatureTableModel; |
47 | 40435 | jjdelcerro | import org.gvsig.tools.dispose.DisposableIterator; |
48 | import org.gvsig.tools.observer.Observable; |
||
49 | import org.gvsig.tools.observer.Observer; |
||
50 | import org.slf4j.Logger; |
||
51 | import org.slf4j.LoggerFactory; |
||
52 | |||
53 | /**
|
||
54 | * @author 2010- C?sar Ordi?ana - gvSIG team
|
||
55 | */
|
||
56 | public class FeatureSelectionModel implements ListSelectionModel, Observer { |
||
57 | 42775 | jjdelcerro | private static final Logger LOG = LoggerFactory.getLogger(FeatureSelectionModel.class); |
58 | 42639 | dmartinezizquierdo | |
59 | 40435 | jjdelcerro | protected EventListenerList listenerList = new EventListenerList(); |
60 | |||
61 | private final FeatureTableModel featureTableModel; |
||
62 | |||
63 | private int selectionMode = SINGLE_INTERVAL_SELECTION; |
||
64 | |||
65 | private boolean isAdjusting = false; |
||
66 | |||
67 | private int anchor = -1; |
||
68 | |||
69 | private int lead = -1; |
||
70 | 42639 | dmartinezizquierdo | |
71 | 40435 | jjdelcerro | private int currentFirst = -1; |
72 | private int currentLast = -1; |
||
73 | |||
74 | /**
|
||
75 | * Creates a new {@link FeatureSelectionModel} with a
|
||
76 | * {@link FeatureTableModel} used to get the {@link Feature}s by position in
|
||
77 | * the table.
|
||
78 | 42639 | dmartinezizquierdo | *
|
79 | 40435 | jjdelcerro | * @param featureTableModel
|
80 | * to get Features from
|
||
81 | * @throws DataException
|
||
82 | * if there is an error getting the store selection
|
||
83 | */
|
||
84 | 42775 | jjdelcerro | public FeatureSelectionModel(FeatureTableModel featureTableModel) {
|
85 | 40435 | jjdelcerro | this.featureTableModel = featureTableModel;
|
86 | 42807 | jjdelcerro | this.featureTableModel.getFeatureSelection().addObserver(this); |
87 | this.featureTableModel.addChangeListener(new ActionListener() { |
||
88 | |||
89 | @Override
|
||
90 | public void actionPerformed(ActionEvent e) { |
||
91 | if( FeatureTableModel.CHANGE_SELECTION.equals(e.getActionCommand()) ) {
|
||
92 | featureSelectionChanged(); |
||
93 | } |
||
94 | } |
||
95 | }); |
||
96 | 40435 | jjdelcerro | } |
97 | 42807 | jjdelcerro | |
98 | private void featureSelectionChanged() { |
||
99 | this.featureTableModel.getFeatureSelection().addObserver(this); |
||
100 | } |
||
101 | |||
102 | 42775 | jjdelcerro | @Override
|
103 | 40435 | jjdelcerro | public int getAnchorSelectionIndex() { |
104 | return anchor;
|
||
105 | } |
||
106 | |||
107 | 42775 | jjdelcerro | @Override
|
108 | 40435 | jjdelcerro | public int getLeadSelectionIndex() { |
109 | return lead;
|
||
110 | } |
||
111 | |||
112 | 42775 | jjdelcerro | @Override
|
113 | 40435 | jjdelcerro | public int getMaxSelectionIndex() { |
114 | 42639 | dmartinezizquierdo | |
115 | 40435 | jjdelcerro | int resp = this.getSelectionIndex(true); |
116 | return resp;
|
||
117 | /*
|
||
118 | 42639 | dmartinezizquierdo | *
|
119 | 40435 | jjdelcerro | * The call to "featureTableModel.getFeatureAt(i)"
|
120 | * causes a lot of reloadPage all over
|
||
121 | 42639 | dmartinezizquierdo | *
|
122 | 40435 | jjdelcerro | FeatureSelection selection = getFeatureSelection();
|
123 | try {
|
||
124 | if (!selection.isEmpty()) {
|
||
125 | for (int i = featureTableModel.getRowCount() - 1; i >= 0; i--) {
|
||
126 | if (selection.isSelected(featureTableModel.getFeatureAt(i))) {
|
||
127 | return i;
|
||
128 | }
|
||
129 | }
|
||
130 | }
|
||
131 | } catch (DataException e) {
|
||
132 | throw new SelectionChangeException(e);
|
||
133 | }
|
||
134 | return -1;
|
||
135 | */
|
||
136 | } |
||
137 | |||
138 | 42775 | jjdelcerro | @Override
|
139 | 40435 | jjdelcerro | public int getMinSelectionIndex() { |
140 | |||
141 | int resp = this.getSelectionIndex(false); |
||
142 | return resp;
|
||
143 | 42639 | dmartinezizquierdo | |
144 | 40435 | jjdelcerro | /*
|
145 | 42639 | dmartinezizquierdo | *
|
146 | 40435 | jjdelcerro | * The call to "featureTableModel.getFeatureAt(i)"
|
147 | * causes a lot of reloadPage all over
|
||
148 | 42639 | dmartinezizquierdo | *
|
149 | 40435 | jjdelcerro | try {
|
150 | |||
151 | int ii = 0;
|
||
152 | |||
153 | FeatureSelection selection = this.getFeatureSelection();
|
||
154 | for (int i = 0; i < featureTableModel.getRowCount(); i++) {
|
||
155 | if (selection.isSelected(featureTableModel.getFeatureAt(i))) {
|
||
156 | ii = i;
|
||
157 | }
|
||
158 | }
|
||
159 | } catch (Exception e) {
|
||
160 | throw new SelectionChangeException(e);
|
||
161 | }
|
||
162 | */
|
||
163 | 42639 | dmartinezizquierdo | |
164 | 40435 | jjdelcerro | } |
165 | |||
166 | 42775 | jjdelcerro | @Override
|
167 | 40435 | jjdelcerro | public void insertIndexInterval(int index, int length, boolean before) { |
168 | // Nothing to do
|
||
169 | } |
||
170 | |||
171 | 42775 | jjdelcerro | @Override
|
172 | 40435 | jjdelcerro | public void removeIndexInterval(int index0, int index1) { |
173 | // Nothing to do
|
||
174 | } |
||
175 | |||
176 | 42775 | jjdelcerro | @Override
|
177 | 40435 | jjdelcerro | public void setAnchorSelectionIndex(int index) { |
178 | this.anchor = index;
|
||
179 | } |
||
180 | |||
181 | 42775 | jjdelcerro | @Override
|
182 | 40435 | jjdelcerro | public void setLeadSelectionIndex(int index) { |
183 | this.lead = index;
|
||
184 | } |
||
185 | |||
186 | 42775 | jjdelcerro | @Override
|
187 | 40435 | jjdelcerro | public void addSelectionInterval(int index0, int index1) { |
188 | 42639 | dmartinezizquierdo | if (!featureTableModel.isSelectionLocked()){
|
189 | doWithSelection(new FeatureSelectionOperation() {
|
||
190 | 40435 | jjdelcerro | |
191 | 42775 | jjdelcerro | @Override
|
192 | 42639 | dmartinezizquierdo | public void doWithSelection(FeatureSelection selection, int first, |
193 | int last) throws DataException { |
||
194 | for (int i = first; i <= last; i++) { |
||
195 | Feature feature = getFeature(i); |
||
196 | if (!selection.isSelected(feature)) {
|
||
197 | selection.select(feature); |
||
198 | } |
||
199 | } |
||
200 | } |
||
201 | 40435 | jjdelcerro | |
202 | 42639 | dmartinezizquierdo | }, index0, index1, true);
|
203 | } |
||
204 | 40435 | jjdelcerro | } |
205 | |||
206 | 42775 | jjdelcerro | @Override
|
207 | 40435 | jjdelcerro | public void setSelectionInterval(int index0, int index1) { |
208 | 42639 | dmartinezizquierdo | if (!featureTableModel.isSelectionLocked()){
|
209 | doWithSelection(new FeatureSelectionOperation() {
|
||
210 | 40435 | jjdelcerro | |
211 | 42775 | jjdelcerro | @Override
|
212 | 42639 | dmartinezizquierdo | public void doWithSelection(FeatureSelection selection, int first, |
213 | int last) throws DataException { |
||
214 | selection.deselectAll(); |
||
215 | for (int i = first; i <= last; i++) { |
||
216 | Feature feature = getFeature(i); |
||
217 | selection.select(feature); |
||
218 | } |
||
219 | } |
||
220 | 40435 | jjdelcerro | |
221 | 42639 | dmartinezizquierdo | }, index0, index1, true);
|
222 | } |
||
223 | 40435 | jjdelcerro | } |
224 | |||
225 | 42775 | jjdelcerro | @Override
|
226 | 40435 | jjdelcerro | public void removeSelectionInterval(int index0, int index1) { |
227 | 42639 | dmartinezizquierdo | if (!featureTableModel.isSelectionLocked()){
|
228 | doWithSelection(new FeatureSelectionOperation() {
|
||
229 | 40435 | jjdelcerro | |
230 | 42775 | jjdelcerro | @Override
|
231 | 42639 | dmartinezizquierdo | public void doWithSelection(FeatureSelection selection, int first, |
232 | int last) throws DataException { |
||
233 | for (int i = first; i <= last; i++) { |
||
234 | Feature feature = getFeature(i); |
||
235 | if (selection.isSelected(feature)) {
|
||
236 | selection.deselect(feature); |
||
237 | } |
||
238 | } |
||
239 | } |
||
240 | 40435 | jjdelcerro | |
241 | 42639 | dmartinezizquierdo | }, index0, index1, false);
|
242 | } |
||
243 | 40435 | jjdelcerro | } |
244 | |||
245 | 42775 | jjdelcerro | @Override
|
246 | 40435 | jjdelcerro | public void clearSelection() { |
247 | 42639 | dmartinezizquierdo | if (!featureTableModel.isSelectionLocked()){
|
248 | try {
|
||
249 | getFeatureSelection().deselectAll(); |
||
250 | } catch (DataException e) {
|
||
251 | throw new SelectionChangeException(e); |
||
252 | } |
||
253 | } |
||
254 | 40435 | jjdelcerro | } |
255 | |||
256 | 42775 | jjdelcerro | @Override
|
257 | 40435 | jjdelcerro | public boolean isSelectedIndex(int index) { |
258 | if (index == -1) { |
||
259 | return false; |
||
260 | } |
||
261 | Feature feature = featureTableModel.getFeatureAt(index); |
||
262 | return getFeatureSelection().isSelected(feature);
|
||
263 | } |
||
264 | |||
265 | 42775 | jjdelcerro | @Override
|
266 | 40435 | jjdelcerro | public boolean isSelectionEmpty() { |
267 | try {
|
||
268 | return getFeatureSelection().isEmpty();
|
||
269 | } catch (DataException ex) {
|
||
270 | throw new SelectionChangeException(ex); |
||
271 | } |
||
272 | } |
||
273 | |||
274 | 42775 | jjdelcerro | /**
|
275 | *
|
||
276 | * @return
|
||
277 | */
|
||
278 | @Override
|
||
279 | 40435 | jjdelcerro | public boolean getValueIsAdjusting() { |
280 | return isAdjusting;
|
||
281 | } |
||
282 | |||
283 | 42775 | jjdelcerro | @Override
|
284 | 40435 | jjdelcerro | public void setValueIsAdjusting(boolean valueIsAdjusting) { |
285 | if (this.isAdjusting != valueIsAdjusting) { |
||
286 | this.isAdjusting = valueIsAdjusting;
|
||
287 | if (this.isAdjusting) { |
||
288 | getFeatureSelection().beginComplexNotification(); |
||
289 | } else {
|
||
290 | getFeatureSelection().endComplexNotification(); |
||
291 | } |
||
292 | } |
||
293 | } |
||
294 | |||
295 | 42775 | jjdelcerro | @Override
|
296 | 40435 | jjdelcerro | public int getSelectionMode() { |
297 | return selectionMode;
|
||
298 | } |
||
299 | |||
300 | 42775 | jjdelcerro | @Override
|
301 | 40435 | jjdelcerro | public void setSelectionMode(int selectionMode) { |
302 | this.selectionMode = selectionMode;
|
||
303 | } |
||
304 | |||
305 | 42775 | jjdelcerro | @Override
|
306 | 40435 | jjdelcerro | public void addListSelectionListener(ListSelectionListener listener) { |
307 | listenerList.add(ListSelectionListener.class, listener);
|
||
308 | } |
||
309 | |||
310 | 42775 | jjdelcerro | @Override
|
311 | 40435 | jjdelcerro | public void removeListSelectionListener(ListSelectionListener listener) { |
312 | listenerList.remove(ListSelectionListener.class, listener);
|
||
313 | } |
||
314 | |||
315 | 42775 | jjdelcerro | @Override
|
316 | 40435 | jjdelcerro | public void update(Observable observable, Object notification) { |
317 | 42807 | jjdelcerro | if( observable instanceof FeatureSelection ) { |
318 | try{
|
||
319 | fireValueChanged(-1, -1, false); |
||
320 | }catch(ConcurrentDataModificationException e){
|
||
321 | LOG.warn("The store has been updated and the selection can not be refreshed", e);
|
||
322 | } |
||
323 | } |
||
324 | 40435 | jjdelcerro | } |
325 | |||
326 | private FeatureSelection getFeatureSelection() {
|
||
327 | 42807 | jjdelcerro | return this.featureTableModel.getFeatureSelection(); |
328 | 40435 | jjdelcerro | } |
329 | |||
330 | /**
|
||
331 | * @param operation
|
||
332 | * @param index0
|
||
333 | * @param index1
|
||
334 | */
|
||
335 | private void doWithSelection(FeatureSelectionOperation operation, |
||
336 | int index0, int index1, boolean select) { |
||
337 | // Set the anchor and lead
|
||
338 | anchor = index0; |
||
339 | lead = index1; |
||
340 | |||
341 | // As index0 <= index1 is no guaranteed, calculate the first and second
|
||
342 | // values
|
||
343 | int first = (index0 <= index1) ? index0 : index1;
|
||
344 | int last = (index0 <= index1) ? index1 : index0;
|
||
345 | 42639 | dmartinezizquierdo | |
346 | 40435 | jjdelcerro | //If the new selection is not updated don't continue
|
347 | if ((currentFirst == first) && (currentLast == last)){
|
||
348 | return;
|
||
349 | } |
||
350 | currentFirst = first; |
||
351 | currentLast = last; |
||
352 | |||
353 | FeatureSelection selection = getFeatureSelection(); |
||
354 | |||
355 | // Perform the selection operation into a complex notification
|
||
356 | selection.beginComplexNotification(); |
||
357 | try {
|
||
358 | // Is a full select or deselect
|
||
359 | if (first == 00 && last == featureTableModel.getRowCount() - 1) { |
||
360 | if (select) {
|
||
361 | selection.selectAll(); |
||
362 | } else {
|
||
363 | selection.deselectAll(); |
||
364 | } |
||
365 | } else {
|
||
366 | operation.doWithSelection(selection, first, last); |
||
367 | } |
||
368 | } catch (DataException e) {
|
||
369 | throw new SelectionChangeException(e); |
||
370 | } finally {
|
||
371 | selection.endComplexNotification(); |
||
372 | } |
||
373 | |||
374 | fireValueChanged(first, last, isAdjusting); |
||
375 | } |
||
376 | |||
377 | /**
|
||
378 | * Returns a Feature by table row position.
|
||
379 | */
|
||
380 | private Feature getFeature(int index) { |
||
381 | return featureTableModel.getFeatureAt(index);
|
||
382 | } |
||
383 | |||
384 | /**
|
||
385 | * Returns the FeatureStore.
|
||
386 | */
|
||
387 | private FeatureStore getFeatureStore() {
|
||
388 | return featureTableModel.getFeatureStore();
|
||
389 | } |
||
390 | |||
391 | /**
|
||
392 | * @param firstIndex
|
||
393 | * the first index in the interval
|
||
394 | * @param lastIndex
|
||
395 | * the last index in the interval
|
||
396 | * @param isAdjusting
|
||
397 | * true if this is the final change in a series of adjustments
|
||
398 | * @see EventListenerList
|
||
399 | */
|
||
400 | protected void fireValueChanged(int firstIndex, int lastIndex, |
||
401 | boolean isAdjusting) {
|
||
402 | Object[] listeners = listenerList.getListenerList(); |
||
403 | ListSelectionEvent e = null; |
||
404 | |||
405 | for (int i = listeners.length - 2; i >= 0; i -= 2) { |
||
406 | if (listeners[i] == ListSelectionListener.class) { |
||
407 | if (e == null) { |
||
408 | e = |
||
409 | new ListSelectionEvent(this, firstIndex, lastIndex, |
||
410 | isAdjusting); |
||
411 | } |
||
412 | ((ListSelectionListener) listeners[i + 1]).valueChanged(e); |
||
413 | } |
||
414 | } |
||
415 | } |
||
416 | |||
417 | private interface FeatureSelectionOperation { |
||
418 | void doWithSelection(FeatureSelection selection, int first, int last) |
||
419 | throws DataException;
|
||
420 | } |
||
421 | 42639 | dmartinezizquierdo | |
422 | 40435 | jjdelcerro | /**
|
423 | 42639 | dmartinezizquierdo | *
|
424 | * Return the index of the the first (last) selected feature
|
||
425 | *
|
||
426 | * @param last whether to return the index of the last selected feature
|
||
427 | 40435 | jjdelcerro | * @return
|
428 | */
|
||
429 | private int getSelectionIndex(boolean last) { |
||
430 | 42639 | dmartinezizquierdo | |
431 | 40435 | jjdelcerro | int ind = -1; |
432 | int resp = -1; |
||
433 | |||
434 | FeatureSet fs = null;
|
||
435 | DisposableIterator diter = null;
|
||
436 | |||
437 | try {
|
||
438 | FeatureSelection selection = getFeatureSelection(); |
||
439 | if (!selection.isEmpty()) {
|
||
440 | 43358 | jjdelcerro | FeatureStore store = getFeatureStore(); |
441 | 42804 | jbadia | FeatureQuery query = this.featureTableModel.getFeatureQuery();
|
442 | 43358 | jjdelcerro | if(query== null){ |
443 | query = store.createFeatureQuery(); |
||
444 | 42804 | jbadia | }else{
|
445 | 43358 | jjdelcerro | try {
|
446 | query = (FeatureQuery) query.clone(); |
||
447 | } catch (CloneNotSupportedException ex) { |
||
448 | } |
||
449 | 42804 | jbadia | } |
450 | 43358 | jjdelcerro | query.addEssentialAttributeNames(store); |
451 | fs = store.getFeatureSet(query); |
||
452 | 40435 | jjdelcerro | diter = fs.fastIterator(); |
453 | 43358 | jjdelcerro | Feature feat; |
454 | 40435 | jjdelcerro | while (diter.hasNext()) {
|
455 | ind++; |
||
456 | feat = (Feature) diter.next(); |
||
457 | if (selection.isSelected(feat)) {
|
||
458 | resp = ind; |
||
459 | if (!last) {
|
||
460 | break;
|
||
461 | } |
||
462 | } |
||
463 | } |
||
464 | 42639 | dmartinezizquierdo | |
465 | 40435 | jjdelcerro | } |
466 | } catch (DataException e) {
|
||
467 | throw new SelectionChangeException(e); |
||
468 | } finally {
|
||
469 | if (diter != null) { |
||
470 | diter.dispose(); |
||
471 | } |
||
472 | |||
473 | if (fs != null) { |
||
474 | fs.dispose(); |
||
475 | } |
||
476 | } |
||
477 | 42639 | dmartinezizquierdo | return resp;
|
478 | 40435 | jjdelcerro | } |
479 | 42639 | dmartinezizquierdo | |
480 | 40435 | jjdelcerro | } |