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

Last change on this file since 10478 was 10478, checked in by stoecker, 8 years ago

fix #13040 - patch by Michael Zangl - gsoc-core - fix exception

  • Property svn:eol-style set to native
File size: 10.1 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.Dimension;
7import java.awt.GraphicsEnvironment;
8import java.awt.event.ActionEvent;
9import java.util.ArrayList;
10import java.util.Arrays;
11import java.util.Collection;
12import java.util.List;
13
14import javax.swing.AbstractAction;
15import javax.swing.DropMode;
16import javax.swing.JPopupMenu;
17import javax.swing.JTable;
18import javax.swing.ListSelectionModel;
19import javax.swing.SwingUtilities;
20import javax.swing.event.ListSelectionEvent;
21import javax.swing.event.ListSelectionListener;
22
23import org.openstreetmap.josm.Main;
24import org.openstreetmap.josm.actions.AutoScaleAction;
25import org.openstreetmap.josm.actions.ZoomToAction;
26import org.openstreetmap.josm.data.osm.OsmPrimitive;
27import org.openstreetmap.josm.data.osm.Relation;
28import org.openstreetmap.josm.data.osm.RelationMember;
29import org.openstreetmap.josm.data.osm.Way;
30import org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType;
31import org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType.Direction;
32import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;
33import org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener;
34import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent;
35import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;
36import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeEvent;
37import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener;
38import org.openstreetmap.josm.gui.layer.OsmDataLayer;
39import org.openstreetmap.josm.gui.util.HighlightHelper;
40import org.openstreetmap.josm.gui.widgets.OsmPrimitivesTable;
41
42public class MemberTable extends OsmPrimitivesTable implements IMemberModelListener {
43
44 /** the additional actions in popup menu */
45 private ZoomToGapAction zoomToGap;
46 private final transient HighlightHelper highlightHelper = new HighlightHelper();
47 private boolean highlightEnabled;
48
49 /**
50 * constructor for relation member table
51 *
52 * @param layer the data layer of the relation. Must not be null
53 * @param relation the relation. Can be null
54 * @param model the table model
55 */
56 public MemberTable(OsmDataLayer layer, Relation relation, MemberTableModel model) {
57 super(model, new MemberTableColumnModel(layer.data, relation), model.getSelectionModel());
58 setLayer(layer);
59 model.addMemberModelListener(this);
60
61 MemberRoleCellEditor ce = (MemberRoleCellEditor) getColumnModel().getColumn(0).getCellEditor();
62 setRowHeight(ce.getEditor().getPreferredSize().height);
63 setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
64 setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
65 putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
66
67 installCustomNavigation(0);
68 initHighlighting();
69
70 if (!GraphicsEnvironment.isHeadless()) {
71 setTransferHandler(new MemberTransferHandler());
72 setFillsViewportHeight(true); // allow drop on empty table
73 setDragEnabled(true);
74 setDropMode(DropMode.INSERT_ROWS);
75 }
76 }
77
78 @Override
79 protected ZoomToAction buildZoomToAction() {
80 return new ZoomToAction(this);
81 }
82
83 @Override
84 protected JPopupMenu buildPopupMenu() {
85 JPopupMenu menu = super.buildPopupMenu();
86 zoomToGap = new ZoomToGapAction();
87 registerListeners();
88 getSelectionModel().addListSelectionListener(zoomToGap);
89 menu.add(zoomToGap);
90 menu.addSeparator();
91 menu.add(new SelectPreviousGapAction());
92 menu.add(new SelectNextGapAction());
93 return menu;
94 }
95
96 @Override
97 public Dimension getPreferredSize() {
98 return getPreferredFullWidthSize();
99 }
100
101 @Override
102 public void makeMemberVisible(int index) {
103 scrollRectToVisible(getCellRect(index, 0, true));
104 }
105
106 private transient ListSelectionListener highlighterListener = new ListSelectionListener() {
107 @Override
108 public void valueChanged(ListSelectionEvent lse) {
109 if (Main.isDisplayingMapView()) {
110 Collection<RelationMember> sel = getMemberTableModel().getSelectedMembers();
111 final List<OsmPrimitive> toHighlight = new ArrayList<>();
112 for (RelationMember r: sel) {
113 if (r.getMember().isUsable()) {
114 toHighlight.add(r.getMember());
115 }
116 }
117 SwingUtilities.invokeLater(new Runnable() {
118 @Override
119 public void run() {
120 if (Main.isDisplayingMapView() && highlightHelper.highlightOnly(toHighlight)) {
121 Main.map.mapView.repaint();
122 }
123 }
124 });
125 }
126 }
127 };
128
129 private void initHighlighting() {
130 highlightEnabled = Main.pref.getBoolean("draw.target-highlight", true);
131 if (!highlightEnabled) return;
132 getMemberTableModel().getSelectionModel().addListSelectionListener(highlighterListener);
133 if (Main.isDisplayingMapView()) {
134 HighlightHelper.clearAllHighlighted();
135 Main.map.mapView.repaint();
136 }
137 }
138
139 @Override
140 public void registerListeners() {
141 Main.getLayerManager().addLayerChangeListener(zoomToGap);
142 Main.getLayerManager().addActiveLayerChangeListener(zoomToGap);
143 super.registerListeners();
144 }
145
146 @Override
147 public void unregisterListeners() {
148 super.unregisterListeners();
149 Main.getLayerManager().removeLayerChangeListener(zoomToGap);
150 Main.getLayerManager().removeActiveLayerChangeListener(zoomToGap);
151 }
152
153 public void stopHighlighting() {
154 if (highlighterListener == null) return;
155 if (!highlightEnabled) return;
156 getMemberTableModel().getSelectionModel().removeListSelectionListener(highlighterListener);
157 highlighterListener = null;
158 if (Main.isDisplayingMapView()) {
159 HighlightHelper.clearAllHighlighted();
160 Main.map.mapView.repaint();
161 }
162 }
163
164 private class SelectPreviousGapAction extends AbstractAction {
165
166 SelectPreviousGapAction() {
167 putValue(NAME, tr("Select previous Gap"));
168 putValue(SHORT_DESCRIPTION, tr("Select the previous relation member which gives rise to a gap"));
169 }
170
171 @Override
172 public void actionPerformed(ActionEvent e) {
173 int i = getSelectedRow() - 1;
174 while (i >= 0 && getMemberTableModel().getWayConnection(i).linkPrev) {
175 i--;
176 }
177 if (i >= 0) {
178 getSelectionModel().setSelectionInterval(i, i);
179 }
180 }
181 }
182
183 private class SelectNextGapAction extends AbstractAction {
184
185 SelectNextGapAction() {
186 putValue(NAME, tr("Select next Gap"));
187 putValue(SHORT_DESCRIPTION, tr("Select the next relation member which gives rise to a gap"));
188 }
189
190 @Override
191 public void actionPerformed(ActionEvent e) {
192 int i = getSelectedRow() + 1;
193 while (i < getRowCount() && getMemberTableModel().getWayConnection(i).linkNext) {
194 i++;
195 }
196 if (i < getRowCount()) {
197 getSelectionModel().setSelectionInterval(i, i);
198 }
199 }
200 }
201
202 private class ZoomToGapAction extends AbstractAction implements LayerChangeListener, ActiveLayerChangeListener, ListSelectionListener {
203
204 /**
205 * Constructs a new {@code ZoomToGapAction}.
206 */
207 ZoomToGapAction() {
208 putValue(NAME, tr("Zoom to Gap"));
209 putValue(SHORT_DESCRIPTION, tr("Zoom to the gap in the way sequence"));
210 updateEnabledState();
211 }
212
213 private WayConnectionType getConnectionType() {
214 return getMemberTableModel().getWayConnection(getSelectedRows()[0]);
215 }
216
217 private final Collection<Direction> connectionTypesOfInterest = Arrays.asList(
218 WayConnectionType.Direction.FORWARD, WayConnectionType.Direction.BACKWARD);
219
220 private boolean hasGap() {
221 WayConnectionType connectionType = getConnectionType();
222 return connectionTypesOfInterest.contains(connectionType.direction)
223 && !(connectionType.linkNext && connectionType.linkPrev);
224 }
225
226 @Override
227 public void actionPerformed(ActionEvent e) {
228 WayConnectionType connectionType = getConnectionType();
229 Way way = (Way) getMemberTableModel().getReferredPrimitive(getSelectedRows()[0]);
230 if (!connectionType.linkPrev) {
231 getLayer().data.setSelected(WayConnectionType.Direction.FORWARD.equals(connectionType.direction)
232 ? way.firstNode() : way.lastNode());
233 AutoScaleAction.autoScale("selection");
234 } else if (!connectionType.linkNext) {
235 getLayer().data.setSelected(WayConnectionType.Direction.FORWARD.equals(connectionType.direction)
236 ? way.lastNode() : way.firstNode());
237 AutoScaleAction.autoScale("selection");
238 }
239 }
240
241 private void updateEnabledState() {
242 setEnabled(Main.main != null
243 && Main.getLayerManager().getEditLayer() == getLayer()
244 && getSelectedRowCount() == 1
245 && hasGap());
246 }
247
248 @Override
249 public void valueChanged(ListSelectionEvent e) {
250 updateEnabledState();
251 }
252
253 @Override
254 public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) {
255 updateEnabledState();
256 }
257
258 @Override
259 public void layerAdded(LayerAddEvent e) {
260 updateEnabledState();
261 }
262
263 @Override
264 public void layerRemoving(LayerRemoveEvent e) {
265 updateEnabledState();
266 }
267
268 @Override
269 public void layerOrderChanged(LayerOrderChangeEvent e) {
270 // Do nothing
271 }
272 }
273
274 protected MemberTableModel getMemberTableModel() {
275 return (MemberTableModel) getModel();
276 }
277}
Note: See TracBrowser for help on using the repository browser.