Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.library / org.gvsig.fmap.control / src / main / java / org / gvsig / fmap / mapcontrol / dal / feature / swing / FeatureSelectionModel.java @ 43358

History | View | Annotate | Download (13.6 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
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
 * as published by the Free Software Foundation; either version 3
9
 * 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
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
/*
25
 * AUTHORS (In addition to CIT):
26
 * 2010 {}  {{Task}}
27
 */
28
package org.gvsig.fmap.mapcontrol.dal.feature.swing;
29

    
30
import javax.swing.ListSelectionModel;
31
import javax.swing.event.EventListenerList;
32
import javax.swing.event.ListSelectionEvent;
33
import javax.swing.event.ListSelectionListener;
34

    
35
import org.gvsig.fmap.dal.exception.DataException;
36
import org.gvsig.fmap.dal.feature.Feature;
37
import org.gvsig.fmap.dal.feature.FeatureQuery;
38
import org.gvsig.fmap.dal.feature.FeatureSelection;
39
import org.gvsig.fmap.dal.feature.FeatureSet;
40
import org.gvsig.fmap.dal.feature.FeatureStore;
41
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
42
import org.gvsig.fmap.dal.feature.exception.ConcurrentDataModificationException;
43
import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.FeatureTableModel;
44
import org.gvsig.tools.dispose.DisposableIterator;
45
import org.gvsig.tools.observer.Observable;
46
import org.gvsig.tools.observer.Observer;
47
import org.slf4j.Logger;
48
import org.slf4j.LoggerFactory;
49

    
50
/**
51
 * @author 2010- C?sar Ordi?ana - gvSIG team
52
 */
53
public class FeatureSelectionModel implements ListSelectionModel, Observer {
54
    private static Logger LOG =
55
        LoggerFactory.getLogger(FeatureSelectionModel.class);
56

    
57
        protected EventListenerList listenerList = new EventListenerList();
58

    
59
        private final FeatureTableModel featureTableModel;
60

    
61
        private int selectionMode = SINGLE_INTERVAL_SELECTION;
62

    
63
        private boolean isAdjusting = false;
64

    
65
        private int anchor = -1;
66

    
67
        private int lead = -1;
68

    
69
        private int currentFirst = -1;
70
        private int currentLast = -1;
71

    
72
        /**
73
         * Creates a new {@link FeatureSelectionModel} with a
74
         * {@link FeatureTableModel} used to get the {@link Feature}s by position in
75
         * the table.
76
         *
77
         * @param featureTableModel
78
         *            to get Features from
79
         * @throws DataException
80
         *             if there is an error getting the store selection
81
         */
82
        public FeatureSelectionModel(FeatureTableModel featureTableModel)
83
                        throws DataException {
84
                this.featureTableModel = featureTableModel;
85
                this.featureTableModel.getFeatureStore().addObserver(this);
86
        }
87

    
88
        public int getAnchorSelectionIndex() {
89
                return anchor;
90
        }
91

    
92
        public int getLeadSelectionIndex() {
93
                return lead;
94
        }
95

    
96
        public int getMaxSelectionIndex() {
97

    
98
            int resp = this.getSelectionIndex(true);
99
            return resp;
100
            /*
101
             *
102
             * The call to "featureTableModel.getFeatureAt(i)"
103
             * causes a lot of reloadPage all over
104
             *
105
                FeatureSelection selection = getFeatureSelection();
106
                try {
107
                        if (!selection.isEmpty()) {
108
                                for (int i = featureTableModel.getRowCount() - 1; i >= 0; i--) {
109
                                        if (selection.isSelected(featureTableModel.getFeatureAt(i))) {
110
                                                return i;
111
                                        }
112
                                }
113
                        }
114
                } catch (DataException e) {
115
                        throw new SelectionChangeException(e);
116
                }
117
                return -1;
118
                */
119
        }
120

    
121
        public int getMinSelectionIndex() {
122

    
123
            int resp = this.getSelectionIndex(false);
124
            return resp;
125

    
126
            /*
127
             *
128
         * The call to "featureTableModel.getFeatureAt(i)"
129
         * causes a lot of reloadPage all over
130
             *
131
                try {
132

133
                    int ii = 0;
134

135
                    FeatureSelection selection = this.getFeatureSelection();
136
            for (int i = 0; i < featureTableModel.getRowCount(); i++) {
137
                if (selection.isSelected(featureTableModel.getFeatureAt(i))) {
138
                    ii = i;
139
                }
140
            }
141
                } catch (Exception e) {
142
                        throw new SelectionChangeException(e);
143
                }
144
                */
145

    
146
        }
147

    
148
        public void insertIndexInterval(int index, int length, boolean before) {
149
                // Nothing to do
150
        }
151

    
152
        public void removeIndexInterval(int index0, int index1) {
153
                // Nothing to do
154
        }
155

    
156
        public void setAnchorSelectionIndex(int index) {
157
                this.anchor = index;
158
        }
159

    
160
        public void setLeadSelectionIndex(int index) {
161
                this.lead = index;
162
        }
163

    
164
        public void addSelectionInterval(int index0, int index1) {
165
            if (!featureTableModel.isSelectionLocked()){
166
                doWithSelection(new FeatureSelectionOperation() {
167

    
168
                    public void doWithSelection(FeatureSelection selection, int first,
169
                        int last) throws DataException {
170
                        for (int i = first; i <= last; i++) {
171
                            Feature feature = getFeature(i);
172
                            if (!selection.isSelected(feature)) {
173
                                selection.select(feature);
174
                            }
175
                        }
176
                    }
177

    
178
                }, index0, index1, true);
179
            }
180
        }
181

    
182
        public void setSelectionInterval(int index0, int index1) {
183
            if (!featureTableModel.isSelectionLocked()){
184
                doWithSelection(new FeatureSelectionOperation() {
185

    
186
                    public void doWithSelection(FeatureSelection selection, int first,
187
                        int last) throws DataException {
188
                        selection.deselectAll();
189
                        for (int i = first; i <= last; i++) {
190
                            Feature feature = getFeature(i);
191
                            selection.select(feature);
192
                        }
193
                    }
194

    
195
                }, index0, index1, true);
196
            }
197
        }
198

    
199
        public void removeSelectionInterval(int index0, int index1) {
200
            if (!featureTableModel.isSelectionLocked()){
201
                doWithSelection(new FeatureSelectionOperation() {
202

    
203
                    public void doWithSelection(FeatureSelection selection, int first,
204
                        int last) throws DataException {
205
                        for (int i = first; i <= last; i++) {
206
                            Feature feature = getFeature(i);
207
                            if (selection.isSelected(feature)) {
208
                                selection.deselect(feature);
209
                            }
210
                        }
211
                    }
212

    
213
                }, index0, index1, false);
214
            }
215
        }
216

    
217
        public void clearSelection() {
218
            if (!featureTableModel.isSelectionLocked()){
219
                try {
220
                    getFeatureSelection().deselectAll();
221
                } catch (DataException e) {
222
                    throw new SelectionChangeException(e);
223
                }
224
            }
225
        }
226

    
227
        public boolean isSelectedIndex(int index) {
228
                if (index == -1) {
229
                        return false;
230
                }
231
                Feature feature = featureTableModel.getFeatureAt(index);
232
                return getFeatureSelection().isSelected(feature);
233
        }
234

    
235
        public boolean isSelectionEmpty() {
236
                try {
237
                        return getFeatureSelection().isEmpty();
238
                } catch (DataException ex) {
239
                        throw new SelectionChangeException(ex);
240
                }
241
        }
242

    
243
        public boolean getValueIsAdjusting() {
244
                return isAdjusting;
245
        }
246

    
247
        public void setValueIsAdjusting(boolean valueIsAdjusting) {
248
                if (this.isAdjusting != valueIsAdjusting) {
249
                        this.isAdjusting = valueIsAdjusting;
250
                        if (this.isAdjusting) {
251
                                getFeatureSelection().beginComplexNotification();
252
                        } else {
253
                                getFeatureSelection().endComplexNotification();
254
                        }
255
                }
256
        }
257

    
258
        public int getSelectionMode() {
259
                return selectionMode;
260
        }
261

    
262
        public void setSelectionMode(int selectionMode) {
263
                this.selectionMode = selectionMode;
264
        }
265

    
266
        public void addListSelectionListener(ListSelectionListener listener) {
267
                listenerList.add(ListSelectionListener.class, listener);
268
        }
269

    
270
        public void removeListSelectionListener(ListSelectionListener listener) {
271
                listenerList.remove(ListSelectionListener.class, listener);
272
        }
273

    
274
        public void update(Observable observable, Object notification) {
275
                if (notification instanceof FeatureStoreNotification) {
276
                        FeatureStoreNotification fnotification =
277
                                        (FeatureStoreNotification) notification;
278
                        if (!fnotification.getSource().equals(getFeatureStore())) {
279
                                return;
280
                        }
281
                        if (FeatureStoreNotification.SELECTION_CHANGE.equals(fnotification.getType())) {
282
                                try{
283
                                    fireValueChanged(-1, -1, false);
284
                                }catch(ConcurrentDataModificationException e){
285
                                    LOG.warn("The store has been updated and the selection can not be refreshed", e);
286
                                }
287
                        }
288
                }
289
        }
290

    
291
        private FeatureSelection getFeatureSelection() {
292
                try {
293
                        return (FeatureSelection) getFeatureStore().getSelection();
294
                } catch (DataException ex) {
295
                        throw new SelectionChangeException(ex);
296
                }
297
        }
298

    
299
        /**
300
         * @param operation
301
         * @param index0
302
         * @param index1
303
         */
304
        private void doWithSelection(FeatureSelectionOperation operation,
305
                        int index0, int index1, boolean select) {
306
                // Set the anchor and lead
307
                anchor = index0;
308
                lead = index1;
309

    
310
                // As index0 <= index1 is no guaranteed, calculate the first and second
311
                // values
312
                int first = (index0 <= index1) ? index0 : index1;
313
                int last = (index0 <= index1) ? index1 : index0;
314

    
315
                //If the new selection is not updated don't continue
316
                if ((currentFirst == first) && (currentLast == last)){
317
                    return;
318
                }
319

    
320
                int oldFirst = currentFirst;
321
                int oldLast = currentLast;
322
                currentFirst = first;
323
                currentLast = last;
324

    
325
                FeatureSelection selection = getFeatureSelection();
326

    
327
                // Perform the selection operation into a complex notification
328
                selection.beginComplexNotification();
329
                try {
330
                        // Is a full select or deselect
331
                        if (first == 00 && last == featureTableModel.getRowCount() - 1) {
332
                                if (select) {
333
                                        selection.selectAll();
334
                                } else {
335
                                        selection.deselectAll();
336
                                }
337
                        } else {
338
                                operation.doWithSelection(selection, first, last);
339
                        }
340
                } catch (DataException e) {
341
                        throw new SelectionChangeException(e);
342
                } finally {
343
                        selection.endComplexNotification();
344
                }
345

    
346
                // Para no lanzar dos veces el fireValueChanged sobre las mismas filas de la selecci?n
347
                if(oldFirst<=first){
348
                    if(oldLast<first){ //No intersectan los rangos
349
                        fireValueChanged(oldFirst, oldLast, isAdjusting);
350
                        fireValueChanged(first, last, isAdjusting);
351
                    } else { // Intersectan los rangos oldFirst - first - ...
352
                if (last > oldLast) { // Intersectan los rangos oldFirst - first - oldLast - last
353
                    fireValueChanged(oldFirst, last, isAdjusting);
354
                } else { // Intersectan los rangos oldFirst - first - last - oldLast
355
                    fireValueChanged(oldFirst, oldLast, isAdjusting);
356
                }
357
                    }
358
                }
359
        if(first<=oldFirst){
360
            if(last<oldFirst){ //No intersectan los rangos
361
                fireValueChanged(oldFirst, oldLast, isAdjusting);
362
                fireValueChanged(first, last, isAdjusting);
363
            } else { // Intersectan los rangos first - oldFirst - ...
364
                if (last > oldLast) { // Intersectan los rangos first - oldFirst - oldLast - last
365
                    fireValueChanged(first, last, isAdjusting);
366
                } else { // Intersectan los rangos first - oldFirst - last - oldLast
367
                    fireValueChanged(first, oldLast, isAdjusting);
368
                }
369
            }
370
        }
371
        }
372

    
373
        /**
374
         * Returns a Feature by table row position.
375
         */
376
        private Feature getFeature(int index) {
377
                return featureTableModel.getFeatureAt(index);
378
        }
379

    
380
        /**
381
         * Returns the FeatureStore.
382
         */
383
        private FeatureStore getFeatureStore() {
384
                return featureTableModel.getFeatureStore();
385
        }
386

    
387
        /**
388
         * @param firstIndex
389
         *            the first index in the interval
390
         * @param lastIndex
391
         *            the last index in the interval
392
         * @param isAdjusting
393
         *            true if this is the final change in a series of adjustments
394
         * @see EventListenerList
395
         */
396
        protected void fireValueChanged(int firstIndex, int lastIndex,
397
                        boolean isAdjusting) {
398
                Object[] listeners = listenerList.getListenerList();
399
                ListSelectionEvent e = null;
400

    
401
                for (int i = listeners.length - 2; i >= 0; i -= 2) {
402
                        if (listeners[i] == ListSelectionListener.class) {
403
                                if (e == null) {
404
                                        e =
405
                                                        new ListSelectionEvent(this, firstIndex, lastIndex,
406
                                                                        isAdjusting);
407
                                }
408
                                ((ListSelectionListener) listeners[i + 1]).valueChanged(e);
409
                        }
410
                }
411
        }
412

    
413
        private interface FeatureSelectionOperation {
414
                void doWithSelection(FeatureSelection selection, int first, int last)
415
                                throws DataException;
416
        }
417

    
418
        /**
419
         *
420
         * Return the index of the the first (last) selected feature
421
         *
422
         * @param last whether to return the index of the last selected feature
423
         * @return
424
         */
425
        private int getSelectionIndex(boolean last) {
426

    
427
        int ind = -1;
428
        int resp = -1;
429

    
430
        FeatureSet fs = null;
431
        DisposableIterator diter = null;
432

    
433
        try {
434
            FeatureSelection selection = getFeatureSelection();
435
            if (!selection.isEmpty()) {
436
                FeatureStore store = getFeatureStore();
437
                FeatureQuery query = store.createFeatureQuery();
438
                query.addEssentialAttributeNames(store);
439
                fs = store.getFeatureSet(query);
440
                diter = fs.fastIterator();
441
                Feature feat = null;
442
                while (diter.hasNext()) {
443
                    ind++;
444
                    feat = (Feature) diter.next();
445
                    if (selection.isSelected(feat)) {
446
                        resp = ind;
447
                        if (!last) {
448
                            break;
449
                        }
450
                    }
451
                }
452

    
453
            }
454
        } catch (DataException e) {
455
            throw new SelectionChangeException(e);
456
        } finally {
457
            if (diter != null) {
458
                diter.dispose();
459
            }
460

    
461
            if (fs != null) {
462
                fs.dispose();
463
            }
464
        }
465
        return resp;
466
        }
467

    
468
}