Statistics
| Revision:

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

History | View | Annotate | Download (12.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.dal.swing.impl.featuretable;
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.dal.swing.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 final Logger LOG = LoggerFactory.getLogger(FeatureSelectionModel.class);
54

    
55
        protected EventListenerList listenerList = new EventListenerList();
56

    
57
        private final FeatureTableModel featureTableModel;
58

    
59
        private int selectionMode = SINGLE_INTERVAL_SELECTION;
60

    
61
        private boolean isAdjusting = false;
62

    
63
        private int anchor = -1;
64

    
65
        private int lead = -1;
66

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

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

    
85
    @Override
86
        public int getAnchorSelectionIndex() {
87
                return anchor;
88
        }
89

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

    
95
    @Override
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
    @Override
122
        public int getMinSelectionIndex() {
123

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

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

134
                    int ii = 0;
135

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

    
147
        }
148

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

    
154
    @Override
155
        public void removeIndexInterval(int index0, int index1) {
156
                // Nothing to do
157
        }
158

    
159
    @Override
160
        public void setAnchorSelectionIndex(int index) {
161
                this.anchor = index;
162
        }
163

    
164
    @Override
165
        public void setLeadSelectionIndex(int index) {
166
                this.lead = index;
167
        }
168

    
169
    @Override
170
        public void addSelectionInterval(int index0, int index1) {
171
            if (!featureTableModel.isSelectionLocked()){
172
                doWithSelection(new FeatureSelectionOperation() {
173

    
174
                    @Override
175
                    public void doWithSelection(FeatureSelection selection, int first,
176
                        int last) throws DataException {
177
                        for (int i = first; i <= last; i++) {
178
                            Feature feature = getFeature(i);
179
                            if (!selection.isSelected(feature)) {
180
                                selection.select(feature);
181
                            }
182
                        }
183
                    }
184

    
185
                }, index0, index1, true);
186
            }
187
        }
188

    
189
    @Override
190
        public void setSelectionInterval(int index0, int index1) {
191
            if (!featureTableModel.isSelectionLocked()){
192
                doWithSelection(new FeatureSelectionOperation() {
193

    
194
                    @Override
195
                    public void doWithSelection(FeatureSelection selection, int first,
196
                        int last) throws DataException {
197
                        selection.deselectAll();
198
                        for (int i = first; i <= last; i++) {
199
                            Feature feature = getFeature(i);
200
                            selection.select(feature);
201
                        }
202
                    }
203

    
204
                }, index0, index1, true);
205
            }
206
        }
207

    
208
    @Override
209
        public void removeSelectionInterval(int index0, int index1) {
210
            if (!featureTableModel.isSelectionLocked()){
211
                doWithSelection(new FeatureSelectionOperation() {
212

    
213
                    @Override
214
                    public void doWithSelection(FeatureSelection selection, int first,
215
                        int last) throws DataException {
216
                        for (int i = first; i <= last; i++) {
217
                            Feature feature = getFeature(i);
218
                            if (selection.isSelected(feature)) {
219
                                selection.deselect(feature);
220
                            }
221
                        }
222
                    }
223

    
224
                }, index0, index1, false);
225
            }
226
        }
227

    
228
    @Override
229
        public void clearSelection() {
230
            if (!featureTableModel.isSelectionLocked()){
231
                try {
232
                    getFeatureSelection().deselectAll();
233
                } catch (DataException e) {
234
                    throw new SelectionChangeException(e);
235
                }
236
            }
237
        }
238

    
239
    @Override
240
        public boolean isSelectedIndex(int index) {
241
                if (index == -1) {
242
                        return false;
243
                }
244
                Feature feature = featureTableModel.getFeatureAt(index);
245
                return getFeatureSelection().isSelected(feature);
246
        }
247

    
248
    @Override
249
        public boolean isSelectionEmpty() {
250
                try {
251
                        return getFeatureSelection().isEmpty();
252
                } catch (DataException ex) {
253
                        throw new SelectionChangeException(ex);
254
                }
255
        }
256

    
257
    /**
258
     *
259
     * @return
260
     */
261
    @Override
262
        public boolean getValueIsAdjusting() {
263
                return isAdjusting;
264
        }
265

    
266
    @Override
267
        public void setValueIsAdjusting(boolean valueIsAdjusting) {
268
                if (this.isAdjusting != valueIsAdjusting) {
269
                        this.isAdjusting = valueIsAdjusting;
270
                        if (this.isAdjusting) {
271
                                getFeatureSelection().beginComplexNotification();
272
                        } else {
273
                                getFeatureSelection().endComplexNotification();
274
                        }
275
                }
276
        }
277

    
278
    @Override
279
        public int getSelectionMode() {
280
                return selectionMode;
281
        }
282

    
283
    @Override
284
        public void setSelectionMode(int selectionMode) {
285
                this.selectionMode = selectionMode;
286
        }
287

    
288
    @Override
289
        public void addListSelectionListener(ListSelectionListener listener) {
290
                listenerList.add(ListSelectionListener.class, listener);
291
        }
292

    
293
    @Override
294
        public void removeListSelectionListener(ListSelectionListener listener) {
295
                listenerList.remove(ListSelectionListener.class, listener);
296
        }
297

    
298
    @Override
299
        public void update(Observable observable, Object notification) {
300
                if (notification instanceof FeatureStoreNotification) {
301
                        FeatureStoreNotification fnotification =
302
                                        (FeatureStoreNotification) notification;
303
                        if (!fnotification.getSource().equals(getFeatureStore())) {
304
                                return;
305
                        }
306
                        if (FeatureStoreNotification.SELECTION_CHANGE.equals(fnotification.getType())) {
307
                                try{
308
                                    fireValueChanged(-1, -1, false);
309
                                }catch(ConcurrentDataModificationException e){
310
                                    LOG.warn("The store has been updated and the selection can not be refreshed", e);
311
                                }
312
                        }
313
                }
314
        }
315

    
316
        private FeatureSelection getFeatureSelection() {
317
                try {
318
                        return (FeatureSelection) getFeatureStore().getSelection();
319
                } catch (DataException ex) {
320
                        throw new SelectionChangeException(ex);
321
                }
322
        }
323

    
324
        /**
325
         * @param operation
326
         * @param index0
327
         * @param index1
328
         */
329
        private void doWithSelection(FeatureSelectionOperation operation,
330
                        int index0, int index1, boolean select) {
331
                // Set the anchor and lead
332
                anchor = index0;
333
                lead = index1;
334

    
335
                // As index0 <= index1 is no guaranteed, calculate the first and second
336
                // values
337
                int first = (index0 <= index1) ? index0 : index1;
338
                int last = (index0 <= index1) ? index1 : index0;
339

    
340
                //If the new selection is not updated don't continue
341
                if ((currentFirst == first) && (currentLast == last)){
342
                    return;
343
                }
344
                currentFirst = first;
345
                currentLast = last;
346

    
347
                FeatureSelection selection = getFeatureSelection();
348

    
349
                // Perform the selection operation into a complex notification
350
                selection.beginComplexNotification();
351
                try {
352
                        // Is a full select or deselect
353
                        if (first == 00 && last == featureTableModel.getRowCount() - 1) {
354
                                if (select) {
355
                                        selection.selectAll();
356
                                } else {
357
                                        selection.deselectAll();
358
                                }
359
                        } else {
360
                                operation.doWithSelection(selection, first, last);
361
                        }
362
                } catch (DataException e) {
363
                        throw new SelectionChangeException(e);
364
                } finally {
365
                        selection.endComplexNotification();
366
                }
367

    
368
                fireValueChanged(first, last, isAdjusting);
369
        }
370

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

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

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

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

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

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

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

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

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

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

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

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

    
464
}