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