21 |
import javax.swing.ListSelectionModel; |
import javax.swing.ListSelectionModel; |
22 |
import javax.swing.event.ListSelectionEvent; |
import javax.swing.event.ListSelectionEvent; |
23 |
import javax.swing.event.ListSelectionListener; |
import javax.swing.event.ListSelectionListener; |
24 |
|
import javax.swing.table.TableModel; |
25 |
|
|
26 |
import org.geotools.feature.Feature; |
import org.geotools.feature.Feature; |
27 |
|
|
28 |
import schmitzm.geotools.gui.FeatureCollectionTableModel; |
import schmitzm.geotools.gui.FeatureCollectionTableModel; |
29 |
|
import schmitzm.swing.table.PipedTableModel; |
30 |
|
import schmitzm.swing.table.SelectionTableModel; |
31 |
import skrueger.geotools.selection.StyledFeatureLayerSelectionModel; |
import skrueger.geotools.selection.StyledFeatureLayerSelectionModel; |
32 |
import skrueger.geotools.selection.StyledLayerSelectionEvent; |
import skrueger.geotools.selection.StyledLayerSelectionEvent; |
33 |
import skrueger.geotools.selection.StyledLayerSelectionModel; |
import skrueger.geotools.selection.StyledLayerSelectionModel; |
34 |
|
|
35 |
/** |
/** |
36 |
* This class keeps the selection of a (feature) {@link JTable} synchronized |
* This class keeps the selection of a (feature) {@link JTable} synchronized |
37 |
* with the {@link StyledLayerSelectionModel} of a layer. |
* with the {@link StyledLayerSelectionModel} of a layer. This is done by |
38 |
* This is done by implementing: |
* implementing: |
39 |
* <ul> |
* <ul> |
40 |
* <li>a {@link PropertyChangeListener} which listens to the |
* <li>a {@link PropertyChangeListener} which listens to the |
41 |
* {@link StyledLayerSelectionModel} and accordingly changes the {@link JTable} |
* {@link StyledLayerSelectionModel} and accordingly changes the {@link JTable} |
42 |
* selection</li> |
* selection</li> |
43 |
* <li>a {@link ListSelectionListener} which listens to the {@link JTable} |
* <li>a {@link ListSelectionListener} which listens to the {@link JTable} and |
44 |
* and accordingly changes the {@link StyledLayerSelectionModel} selection</li> |
* accordingly changes the {@link StyledLayerSelectionModel} selection</li> |
45 |
* </ul> |
* </ul> |
46 |
* After creating, the instance of this synchronizer must be added as listener to |
* After creating, the instance of this synchronizer must be added as listener |
47 |
* both, the {@link StyledLayerSelectionModel} and the table's {@link ListSelectionModel}. |
* to both, the {@link StyledLayerSelectionModel} and the table's |
48 |
* @author <a href="mailto:[email protected]">Martin Schmitz</a> (University of Bonn/Germany) |
* {@link ListSelectionModel}. |
49 |
|
* |
50 |
|
* @author <a href="mailto:[email protected]">Martin Schmitz</a> |
51 |
|
* (University of Bonn/Germany) |
52 |
*/ |
*/ |
53 |
public class TableSelectionSynchronizer extends StyledLayerSelectionModelSynchronizer<Feature> implements ListSelectionListener { |
public class TableSelectionSynchronizer extends |
54 |
/** Holds the table to keep synchronized with the layer selection |
StyledLayerSelectionModelSynchronizer<StyledFeatureLayerSelectionModel> |
55 |
* model. */ |
implements ListSelectionListener { |
56 |
protected JTable featureTable = null; |
/** |
57 |
/** Holds the table's data. */ |
* Holds the table to keep synchronized with the layer selection model. |
58 |
protected FeatureCollectionTableModel featureTableModel = null; |
*/ |
59 |
|
protected JTable featureTable = null; |
60 |
/** |
/** Holds the table's data. */ |
61 |
|
protected FeatureCollectionTableModel featureTableModel = null; |
62 |
|
|
63 |
|
/** |
64 |
* Creates a new synchronizer |
* Creates a new synchronizer |
65 |
* |
* |
66 |
* @param layerSelModel |
* @param layerSelModel |
71 |
*/ |
*/ |
72 |
public TableSelectionSynchronizer( |
public TableSelectionSynchronizer( |
73 |
StyledFeatureLayerSelectionModel layerSelModel, JTable table) { |
StyledFeatureLayerSelectionModel layerSelModel, JTable table) { |
|
|
|
74 |
super(layerSelModel); |
super(layerSelModel); |
75 |
|
|
76 |
if (!(table.getModel() instanceof FeatureCollectionTableModel)) { |
TableModel model = table.getModel(); |
77 |
|
if (model instanceof PipedTableModel) |
78 |
|
model = ((PipedTableModel) table.getModel()).getPipedModel(); |
79 |
|
|
80 |
|
if (!(model instanceof FeatureCollectionTableModel)) |
81 |
throw new IllegalArgumentException( |
throw new IllegalArgumentException( |
82 |
"Table must have a model instance of FeatureCollectionTableModel"); |
"Table must have a model instance of FeatureCollectionTableModel"); |
|
} |
|
83 |
|
|
84 |
|
this.featureTableModel = (FeatureCollectionTableModel) model; |
85 |
this.featureTable = table; |
this.featureTable = table; |
|
this.featureTableModel = (FeatureCollectionTableModel) table.getModel(); |
|
86 |
} |
} |
87 |
|
|
88 |
/** |
/** |
89 |
* Called by {@link StyledLayerSelectionModel} when a the selection on other |
* Called by {@link StyledLayerSelectionModel} when a the selection on other |
90 |
* selection components (map, chart, ...) has changed. When calling |
* selection components (map, chart, ...) has changed. When calling this |
91 |
* this method changes the table selection according to the |
* method changes the table selection according to the |
92 |
* {@link StyledLayerSelectionModel} selection. |
* {@link StyledLayerSelectionModel} selection. |
93 |
* @param evt an event |
* |
94 |
*/ |
* @param evt |
95 |
@Override |
* an event |
96 |
public void propertyChange(PropertyChangeEvent evt) { |
*/ |
97 |
if ( !(evt instanceof StyledLayerSelectionEvent) ) |
@Override |
98 |
return; |
public void propertyChange(PropertyChangeEvent evt) { |
99 |
StyledLayerSelectionEvent selEvt = (StyledLayerSelectionEvent)evt; |
if (!(evt instanceof StyledLayerSelectionEvent)) |
100 |
// Only react on own layer and ignore events invoked by |
return; |
101 |
// this component itself |
StyledLayerSelectionEvent selEvt = (StyledLayerSelectionEvent) evt; |
102 |
if ( selEvt.getEmitter() != layerSelModel || |
// Only react on own layer and ignore events invoked by |
103 |
selectionChangeCausedByMe ) |
// this component itself |
104 |
return; |
if (selEvt.getEmitter() != layerSelModel || selectionChangeCausedByMe) |
105 |
// Apply new selection on table (except this event is one of |
return; |
106 |
// some more events) |
// Apply new selection on table (except this event is one of |
107 |
Vector<Feature> newSelection = layerSelModel.getSelection(); |
// some more events) |
108 |
if ( newSelection == null ) |
Vector<String> newSelection = layerSelModel.getSelection(); |
109 |
return; |
if (newSelection == null) |
110 |
|
return; |
111 |
// Avoid event circles in valueChanged(..) |
|
112 |
selectionChangeCausedByMe = true; |
// LOGGER.debug("Table pop changed "+selEvt); |
113 |
|
// LOGGER.debug("Table pop changed to "+newSelection); |
114 |
ListSelectionModel tableSelModel = featureTable.getSelectionModel(); |
|
115 |
tableSelModel.setValueIsAdjusting(true); |
// Avoid event circles in valueChanged(..) |
116 |
tableSelModel.clearSelection(); |
selectionChangeCausedByMe = true; |
117 |
for (Feature f : newSelection) { |
|
118 |
int modelIdx = featureTableModel.findFeature(f); |
ListSelectionModel tableSelModel = featureTable.getSelectionModel(); |
119 |
if ( modelIdx >= 0 ) { |
tableSelModel.setValueIsAdjusting(true); |
120 |
int tableIdx = featureTable.convertRowIndexToView(modelIdx); |
tableSelModel.clearSelection(); |
121 |
tableSelModel.addSelectionInterval(tableIdx, tableIdx); |
for (String fid : newSelection) { |
122 |
} |
int modelIdx = featureTableModel.findFeature(fid); |
123 |
} |
if (modelIdx >= 0) { |
124 |
tableSelModel.setValueIsAdjusting(false); // event is fired autmatically! |
int tableIdx = featureTable.convertRowIndexToView(modelIdx); |
125 |
|
tableSelModel.addSelectionInterval(tableIdx, tableIdx); |
126 |
// Danger of event circles in valueChanged(..) banned |
} else { |
127 |
selectionChangeCausedByMe = false; |
LOGGER |
128 |
} |
.warn("Something that is not visible in the Table should be selected"); |
129 |
|
} |
130 |
/** |
} |
131 |
* Called when the table selection is changed by the user. |
tableSelModel.setValueIsAdjusting(false); // event is fired |
132 |
* When calling this method changes the selection of the |
// autmatically! |
133 |
* {@link StyledLayerSelectionModel}. |
|
134 |
* @param evt an event |
// Danger of event circles in valueChanged(..) banned |
135 |
*/ |
selectionChangeCausedByMe = false; |
136 |
@Override |
} |
137 |
public void valueChanged(ListSelectionEvent evt) { |
|
138 |
// ignore event if it is part of multiple events |
/** |
139 |
if ( evt != null && evt.getValueIsAdjusting() ) |
* Called when the table selection is changed by the user. When calling this |
140 |
return; |
* method changes the selection of the {@link StyledLayerSelectionModel}. |
141 |
// ignore event if it is caused by the DpLayerVectorSelectionModel |
* |
142 |
if ( selectionChangeCausedByMe ) |
* @param evt |
143 |
return; |
* an event |
144 |
|
*/ |
145 |
// Avoid event circles in propertyChange(..) |
@Override |
146 |
selectionChangeCausedByMe = true; |
public void valueChanged(ListSelectionEvent evt) { |
147 |
|
// ignore event if it is part of multiple events |
148 |
// reset the selection of the DpLayerSelectionModel |
if (evt != null && evt.getValueIsAdjusting()) |
149 |
layerSelModel.setValueIsAdjusting(true); |
return; |
150 |
for (int i=evt.getFirstIndex(); i<=evt.getLastIndex(); i++) { |
// ignore event if it is caused by the DpLayerVectorSelectionModel |
151 |
Feature changedFeature = featureTableModel.getFeature( featureTable.convertRowIndexToModel(i) ); |
if (selectionChangeCausedByMe) |
152 |
if ( featureTable.isRowSelected(i) ) |
return; |
153 |
layerSelModel.addSelection(changedFeature); |
|
154 |
else |
// Avoid event circles in propertyChange(..) |
155 |
layerSelModel.removeSelection(changedFeature); |
selectionChangeCausedByMe = true; |
156 |
} |
|
157 |
layerSelModel.setValueIsAdjusting(false); |
// reset the selection of the DpLayerSelectionModel |
158 |
|
layerSelModel.setValueIsAdjusting(true); |
159 |
// Danger of event circles in propertyChange(..) banned |
LOGGER.debug("valueCahnged in TableSyncronizer vom Index " |
160 |
selectionChangeCausedByMe = false; |
+ evt.getFirstIndex() + " to " + evt.getLastIndex()); |
161 |
} |
|
162 |
|
if (evt == null || (evt != null && evt.getFirstIndex() == -1)){ |
163 |
|
// If the value is changing because the filter has been changed (e.g. |
164 |
|
// table structure change) the evt.getFirstIndex() is -1, but evt.getLastIndex is > -1 |
165 |
|
layerSelModel.clearSelection(); |
166 |
|
} else{ |
167 |
|
|
168 |
|
for (int i = evt.getFirstIndex(); i <= evt.getLastIndex(); i++) { |
169 |
|
int featureIndex = featureTable.convertRowIndexToModel(i); |
170 |
|
Feature changedFeature = featureTableModel.getFeature(featureIndex); |
171 |
|
if (featureTable.isRowSelected(i)) |
172 |
|
layerSelModel.addSelection(changedFeature.getID()); |
173 |
|
else |
174 |
|
layerSelModel.removeSelection(changedFeature.getID()); |
175 |
|
} |
176 |
|
} |
177 |
|
layerSelModel.setValueIsAdjusting(false); |
178 |
|
|
179 |
|
// Danger of event circles in propertyChange(..) banned |
180 |
|
selectionChangeCausedByMe = false; |
181 |
|
} |
182 |
} |
} |