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

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

sonar - Immutable Field

  • Property svn:eol-style set to native
File size: 12.0 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 final transient 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 transient 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 (Main.isDisplayingMapView() && highlightHelper.highlightOnly(toHighlight)) {
139 Main.map.mapView.repaint();
140 }
141 }
142 });
143 }
144 }
145 };
146
147 private void initHighlighting() {
148 highlightEnabled = Main.pref.getBoolean("draw.target-highlight", true);
149 if (!highlightEnabled) return;
150 getMemberTableModel().getSelectionModel().addListSelectionListener(highlighterListener);
151 if (Main.isDisplayingMapView()) {
152 HighlightHelper.clearAllHighlighted();
153 Main.map.mapView.repaint();
154 }
155 }
156
157 /**
158 * Action to be run when the user navigates to the next cell in the table, for instance by
159 * pressing TAB or ENTER. The action alters the standard navigation path from cell to cell: <ul>
160 * <li>it jumps over cells in the first column</li> <li>it automatically add a new empty row
161 * when the user leaves the last cell in the table</li></ul>
162 */
163 class SelectNextColumnCellAction extends AbstractAction {
164 @Override
165 public void actionPerformed(ActionEvent e) {
166 run();
167 }
168
169 public void run() {
170 int col = getSelectedColumn();
171 int row = getSelectedRow();
172 if (getCellEditor() != null) {
173 getCellEditor().stopCellEditing();
174 }
175
176 if (col == 0 && row < getRowCount() - 1) {
177 row++;
178 } else if (row < getRowCount() - 1) {
179 col = 0;
180 row++;
181 } else {
182 // go to next component, no more rows in this table
183 KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
184 manager.focusNextComponent();
185 return;
186 }
187 changeSelection(row, col, false, false);
188 }
189 }
190
191 /**
192 * Action to be run when the user navigates to the previous cell in the table, for instance by
193 * pressing Shift-TAB
194 */
195 private class SelectPreviousColumnCellAction extends AbstractAction {
196
197 @Override
198 public void actionPerformed(ActionEvent e) {
199 int col = getSelectedColumn();
200 int row = getSelectedRow();
201 if (getCellEditor() != null) {
202 getCellEditor().stopCellEditing();
203 }
204
205 if (col <= 0 && row <= 0) {
206 // change nothing
207 } else if (row > 0) {
208 col = 0;
209 row--;
210 }
211 changeSelection(row, col, false, false);
212 }
213 }
214
215 @Override
216 public void unlinkAsListener() {
217 super.unlinkAsListener();
218 MapView.removeLayerChangeListener(zoomToGap);
219 }
220
221 public void stopHighlighting() {
222 if (highlighterListener == null) return;
223 if (!highlightEnabled) return;
224 getMemberTableModel().getSelectionModel().removeListSelectionListener(highlighterListener);
225 highlighterListener = null;
226 if (Main.isDisplayingMapView()) {
227 HighlightHelper.clearAllHighlighted();
228 Main.map.mapView.repaint();
229 }
230 }
231
232 private class SelectPreviousGapAction extends AbstractAction {
233
234 SelectPreviousGapAction() {
235 putValue(NAME, tr("Select previous Gap"));
236 putValue(SHORT_DESCRIPTION, tr("Select the previous relation member which gives rise to a gap"));
237 }
238
239 @Override
240 public void actionPerformed(ActionEvent e) {
241 int i = getSelectedRow() - 1;
242 while (i >= 0 && getMemberTableModel().getWayConnection(i).linkPrev) {
243 i--;
244 }
245 if (i >= 0) {
246 getSelectionModel().setSelectionInterval(i, i);
247 }
248 }
249 }
250
251 private class SelectNextGapAction extends AbstractAction {
252
253 SelectNextGapAction() {
254 putValue(NAME, tr("Select next Gap"));
255 putValue(SHORT_DESCRIPTION, tr("Select the next relation member which gives rise to a gap"));
256 }
257
258 @Override
259 public void actionPerformed(ActionEvent e) {
260 int i = getSelectedRow() + 1;
261 while (i < getRowCount() && getMemberTableModel().getWayConnection(i).linkNext) {
262 i++;
263 }
264 if (i < getRowCount()) {
265 getSelectionModel().setSelectionInterval(i, i);
266 }
267 }
268 }
269
270 private class ZoomToGapAction extends AbstractAction implements LayerChangeListener, ListSelectionListener {
271
272 /**
273 * Constructs a new {@code ZoomToGapAction}.
274 */
275 ZoomToGapAction() {
276 putValue(NAME, tr("Zoom to Gap"));
277 putValue(SHORT_DESCRIPTION, tr("Zoom to the gap in the way sequence"));
278 updateEnabledState();
279 }
280
281 private WayConnectionType getConnectionType() {
282 return getMemberTableModel().getWayConnection(getSelectedRows()[0]);
283 }
284
285 private final Collection<Direction> connectionTypesOfInterest = Arrays.asList(
286 WayConnectionType.Direction.FORWARD, WayConnectionType.Direction.BACKWARD);
287
288 private boolean hasGap() {
289 WayConnectionType connectionType = getConnectionType();
290 return connectionTypesOfInterest.contains(connectionType.direction)
291 && !(connectionType.linkNext && connectionType.linkPrev);
292 }
293
294 @Override
295 public void actionPerformed(ActionEvent e) {
296 WayConnectionType connectionType = getConnectionType();
297 Way way = (Way) getMemberTableModel().getReferredPrimitive(getSelectedRows()[0]);
298 if (!connectionType.linkPrev) {
299 getLayer().data.setSelected(WayConnectionType.Direction.FORWARD.equals(connectionType.direction)
300 ? way.firstNode() : way.lastNode());
301 AutoScaleAction.autoScale("selection");
302 } else if (!connectionType.linkNext) {
303 getLayer().data.setSelected(WayConnectionType.Direction.FORWARD.equals(connectionType.direction)
304 ? way.lastNode() : way.firstNode());
305 AutoScaleAction.autoScale("selection");
306 }
307 }
308
309 private void updateEnabledState() {
310 setEnabled(Main.main != null
311 && Main.main.getEditLayer() == getLayer()
312 && getSelectedRowCount() == 1
313 && hasGap());
314 }
315
316 @Override
317 public void valueChanged(ListSelectionEvent e) {
318 updateEnabledState();
319 }
320
321 @Override
322 public void activeLayerChange(Layer oldLayer, Layer newLayer) {
323 updateEnabledState();
324 }
325
326 @Override
327 public void layerAdded(Layer newLayer) {
328 updateEnabledState();
329 }
330
331 @Override
332 public void layerRemoved(Layer oldLayer) {
333 updateEnabledState();
334 }
335 }
336
337 protected MemberTableModel getMemberTableModel() {
338 return (MemberTableModel) getModel();
339 }
340}
Note: See TracBrowser for help on using the repository browser.