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 @ 43269

History | View | Annotate | Download (13.4 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.FeatureSelection;
38
import org.gvsig.fmap.dal.feature.FeatureSet;
39
import org.gvsig.fmap.dal.feature.FeatureStore;
40
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
41
import org.gvsig.fmap.dal.feature.exception.ConcurrentDataModificationException;
42
import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.FeatureTableModel;
43
import org.gvsig.tools.dispose.DisposableIterator;
44
import org.gvsig.tools.observer.Observable;
45
import org.gvsig.tools.observer.Observer;
46
import org.slf4j.Logger;
47
import org.slf4j.LoggerFactory;
48

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

    
56
        protected EventListenerList listenerList = new EventListenerList();
57

    
58
        private final FeatureTableModel featureTableModel;
59

    
60
        private int selectionMode = SINGLE_INTERVAL_SELECTION;
61

    
62
        private boolean isAdjusting = false;
63

    
64
        private int anchor = -1;
65

    
66
        private int lead = -1;
67

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

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

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

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

    
95
        public int getMaxSelectionIndex() {
96

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

    
120
        public int getMinSelectionIndex() {
121

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

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

132
                    int ii = 0;
133

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

    
145
        }
146

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
324
                FeatureSelection selection = getFeatureSelection();
325

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

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

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

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

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

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

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

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

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

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

    
432
        try {
433
            FeatureSelection selection = getFeatureSelection();
434
            if (!selection.isEmpty()) {
435

    
436
                fs = getFeatureStore().getFeatureSet();
437
                diter = fs.fastIterator();
438
                Feature feat = null;
439
                while (diter.hasNext()) {
440
                    ind++;
441
                    feat = (Feature) diter.next();
442
                    if (selection.isSelected(feat)) {
443
                        resp = ind;
444
                        if (!last) {
445
                            break;
446
                        }
447
                    }
448
                }
449

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

    
458
            if (fs != null) {
459
                fs.dispose();
460
            }
461
        }
462
        return resp;
463
        }
464

    
465
}