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

Last change on this file since 14027 was 13675, checked in by Don-vip, 6 years ago

rework constructors of MemberRoleCellEditor / MemberTableColumnModel

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