source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTable.java@ 8285

Last change on this file since 8285 was 8285, checked in by Don-vip, 9 years ago

fix sonar squid:S2039 - Member variable visibility should be specified

  • Property svn:eol-style set to native
File size: 11.9 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.dialogs.relation;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Container;
7import java.awt.Dimension;
8import java.awt.KeyboardFocusManager;
9import java.awt.event.ActionEvent;
10import java.awt.event.KeyEvent;
11import java.util.ArrayList;
12import java.util.Arrays;
13import java.util.Collection;
14import java.util.List;
15
16import javax.swing.AbstractAction;
17import javax.swing.JComponent;
18import javax.swing.JPopupMenu;
19import javax.swing.JTable;
20import javax.swing.JViewport;
21import javax.swing.KeyStroke;
22import javax.swing.ListSelectionModel;
23import javax.swing.SwingUtilities;
24import javax.swing.event.ListSelectionEvent;
25import javax.swing.event.ListSelectionListener;
26
27import org.openstreetmap.josm.Main;
28import org.openstreetmap.josm.actions.AutoScaleAction;
29import org.openstreetmap.josm.actions.ZoomToAction;
30import org.openstreetmap.josm.data.osm.OsmPrimitive;
31import org.openstreetmap.josm.data.osm.Relation;
32import org.openstreetmap.josm.data.osm.RelationMember;
33import org.openstreetmap.josm.data.osm.Way;
34import org.openstreetmap.josm.gui.MapView;
35import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
36import org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType;
37import org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType.Direction;
38import org.openstreetmap.josm.gui.layer.Layer;
39import org.openstreetmap.josm.gui.layer.OsmDataLayer;
40import org.openstreetmap.josm.gui.util.HighlightHelper;
41import org.openstreetmap.josm.gui.widgets.OsmPrimitivesTable;
42
43public class MemberTable extends OsmPrimitivesTable implements IMemberModelListener {
44
45 /** the additional actions in popup menu */
46 private ZoomToGapAction zoomToGap;
47 private HighlightHelper highlightHelper = new HighlightHelper();
48 private boolean highlightEnabled;
49
50 /**
51 * constructor for relation member table
52 *
53 * @param layer the data layer of the relation. Must not be null
54 * @param relation the relation. Can be null
55 * @param model the table model
56 */
57 public MemberTable(OsmDataLayer layer, Relation relation, MemberTableModel model) {
58 super(model, new MemberTableColumnModel(layer.data, relation), model.getSelectionModel());
59 setLayer(layer);
60 model.addMemberModelListener(this);
61 init();
62 }
63
64 /**
65 * initialize the table
66 */
67 protected void init() {
68 MemberRoleCellEditor ce = (MemberRoleCellEditor)getColumnModel().getColumn(0).getCellEditor();
69 setRowHeight(ce.getEditor().getPreferredSize().height);
70 setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
71 setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
72 putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
73
74 // make ENTER behave like TAB
75 //
76 getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
77 KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false), "selectNextColumnCell");
78
79 initHighlighting();
80
81 // install custom navigation actions
82 //
83 getActionMap().put("selectNextColumnCell", new SelectNextColumnCellAction());
84 getActionMap().put("selectPreviousColumnCell", new SelectPreviousColumnCellAction());
85 }
86
87 @Override
88 protected ZoomToAction buildZoomToAction() {
89 return new ZoomToAction(this);
90 }
91
92 @Override
93 protected JPopupMenu buildPopupMenu() {
94 JPopupMenu menu = super.buildPopupMenu();
95 zoomToGap = new ZoomToGapAction();
96 MapView.addLayerChangeListener(zoomToGap);
97 getSelectionModel().addListSelectionListener(zoomToGap);
98 menu.add(zoomToGap);
99 menu.addSeparator();
100 menu.add(new SelectPreviousGapAction());
101 menu.add(new SelectNextGapAction());
102 return menu;
103 }
104
105 @Override
106 public Dimension getPreferredSize(){
107 Container c = getParent();
108 while(c != null && ! (c instanceof JViewport)) {
109 c = c.getParent();
110 }
111 if (c != null) {
112 Dimension d = super.getPreferredSize();
113 d.width = c.getSize().width;
114 return d;
115 }
116 return super.getPreferredSize();
117 }
118
119 @Override
120 public void makeMemberVisible(int index) {
121 scrollRectToVisible(getCellRect(index, 0, true));
122 }
123
124 private ListSelectionListener highlighterListener = new ListSelectionListener() {
125 @Override
126 public void valueChanged(ListSelectionEvent lse) {
127 if (Main.isDisplayingMapView()) {
128 Collection<RelationMember> sel = getMemberTableModel().getSelectedMembers();
129 final List<OsmPrimitive> toHighlight = new ArrayList<>();
130 for (RelationMember r: sel) {
131 if (r.getMember().isUsable()) {
132 toHighlight.add(r.getMember());
133 }
134 }
135 SwingUtilities.invokeLater(new Runnable() {
136 @Override
137 public void run() {
138 if (highlightHelper.highlightOnly(toHighlight)) {
139 Main.map.mapView.repaint();
140 }
141 }
142 });
143 }
144 }};
145
146 private void initHighlighting() {
147 highlightEnabled = Main.pref.getBoolean("draw.target-highlight", true);
148 if (!highlightEnabled) return;
149 getMemberTableModel().getSelectionModel().addListSelectionListener(highlighterListener);
150 if (Main.isDisplayingMapView()) {
151 HighlightHelper.clearAllHighlighted();
152 Main.map.mapView.repaint();
153 }
154 }
155
156 /**
157 * Action to be run when the user navigates to the next cell in the table, for instance by
158 * pressing TAB or ENTER. The action alters the standard navigation path from cell to cell: <ul>
159 * <li>it jumps over cells in the first column</li> <li>it automatically add a new empty row
160 * when the user leaves the last cell in the table</li></ul>
161 */
162 class SelectNextColumnCellAction extends AbstractAction {
163 @Override
164 public void actionPerformed(ActionEvent e) {
165 run();
166 }
167
168 public void run() {
169 int col = getSelectedColumn();
170 int row = getSelectedRow();
171 if (getCellEditor() != null) {
172 getCellEditor().stopCellEditing();
173 }
174
175 if (col == 0 && row < getRowCount() - 1) {
176 row++;
177 } else if (row < getRowCount() - 1) {
178 col = 0;
179 row++;
180 } else {
181 // go to next component, no more rows in this table
182 KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
183 manager.focusNextComponent();
184 return;
185 }
186 changeSelection(row, col, false, false);
187 }
188 }
189
190 /**
191 * Action to be run when the user navigates to the previous cell in the table, for instance by
192 * pressing Shift-TAB
193 */
194 private class SelectPreviousColumnCellAction extends AbstractAction {
195
196 @Override
197 public void actionPerformed(ActionEvent e) {
198 int col = getSelectedColumn();
199 int row = getSelectedRow();
200 if (getCellEditor() != null) {
201 getCellEditor().stopCellEditing();
202 }
203
204 if (col <= 0 && row <= 0) {
205 // change nothing
206 } else if (row > 0) {
207 col = 0;
208 row--;
209 }
210 changeSelection(row, col, false, false);
211 }
212 }
213
214 @Override
215 public void unlinkAsListener() {
216 super.unlinkAsListener();
217 MapView.removeLayerChangeListener(zoomToGap);
218 }
219
220 public void stopHighlighting() {
221 if (highlighterListener == null) return;
222 if (!highlightEnabled) return;
223 getMemberTableModel().getSelectionModel().removeListSelectionListener(highlighterListener);
224 highlighterListener = null;
225 if (Main.isDisplayingMapView()) {
226 HighlightHelper.clearAllHighlighted();
227 Main.map.mapView.repaint();
228 }
229 }
230
231 private class SelectPreviousGapAction extends AbstractAction {
232
233 public SelectPreviousGapAction() {
234 putValue(NAME, tr("Select previous Gap"));
235 putValue(SHORT_DESCRIPTION, tr("Select the previous relation member which gives rise to a gap"));
236 }
237
238 @Override
239 public void actionPerformed(ActionEvent e) {
240 int i = getSelectedRow() - 1;
241 while (i >= 0 && getMemberTableModel().getWayConnection(i).linkPrev) {
242 i--;
243 }
244 if (i >= 0) {
245 getSelectionModel().setSelectionInterval(i, i);
246 }
247 }
248 }
249
250 private class SelectNextGapAction extends AbstractAction {
251
252 public SelectNextGapAction() {
253 putValue(NAME, tr("Select next Gap"));
254 putValue(SHORT_DESCRIPTION, tr("Select the next relation member which gives rise to a gap"));
255 }
256
257 @Override
258 public void actionPerformed(ActionEvent e) {
259 int i = getSelectedRow() + 1;
260 while (i < getRowCount() && getMemberTableModel().getWayConnection(i).linkNext) {
261 i++;
262 }
263 if (i < getRowCount()) {
264 getSelectionModel().setSelectionInterval(i, i);
265 }
266 }
267 }
268
269 private class ZoomToGapAction extends AbstractAction implements LayerChangeListener, ListSelectionListener {
270
271 public ZoomToGapAction() {
272 putValue(NAME, tr("Zoom to Gap"));
273 putValue(SHORT_DESCRIPTION, tr("Zoom to the gap in the way sequence"));
274 updateEnabledState();
275 }
276
277 private WayConnectionType getConnectionType() {
278 return getMemberTableModel().getWayConnection(getSelectedRows()[0]);
279 }
280
281 private final Collection<Direction> connectionTypesOfInterest = Arrays.asList(WayConnectionType.Direction.FORWARD, WayConnectionType.Direction.BACKWARD);
282
283 private boolean hasGap() {
284 WayConnectionType connectionType = getConnectionType();
285 return connectionTypesOfInterest.contains(connectionType.direction)
286 && !(connectionType.linkNext && connectionType.linkPrev);
287 }
288
289 @Override
290 public void actionPerformed(ActionEvent e) {
291 WayConnectionType connectionType = getConnectionType();
292 Way way = (Way) getMemberTableModel().getReferredPrimitive(getSelectedRows()[0]);
293 if (!connectionType.linkPrev) {
294 getLayer().data.setSelected(WayConnectionType.Direction.FORWARD.equals(connectionType.direction)
295 ? way.firstNode() : way.lastNode());
296 AutoScaleAction.autoScale("selection");
297 } else if (!connectionType.linkNext) {
298 getLayer().data.setSelected(WayConnectionType.Direction.FORWARD.equals(connectionType.direction)
299 ? way.lastNode() : way.firstNode());
300 AutoScaleAction.autoScale("selection");
301 }
302 }
303
304 private void updateEnabledState() {
305 setEnabled(Main.main != null
306 && Main.main.getEditLayer() == getLayer()
307 && getSelectedRowCount() == 1
308 && hasGap());
309 }
310
311 @Override
312 public void valueChanged(ListSelectionEvent e) {
313 updateEnabledState();
314 }
315
316 @Override
317 public void activeLayerChange(Layer oldLayer, Layer newLayer) {
318 updateEnabledState();
319 }
320
321 @Override
322 public void layerAdded(Layer newLayer) {
323 updateEnabledState();
324 }
325
326 @Override
327 public void layerRemoved(Layer oldLayer) {
328 updateEnabledState();
329 }
330 }
331
332 protected MemberTableModel getMemberTableModel() {
333 return (MemberTableModel) getModel();
334 }
335}
Note: See TracBrowser for help on using the repository browser.