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

Last change on this file since 6070 was 6070, checked in by stoecker, 11 years ago

see #8853 remove tabs, trailing spaces, windows line ends, strange characters

  • Property svn:eol-style set to native
File size: 11.8 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;
14
15import javax.swing.AbstractAction;
16import javax.swing.JComponent;
17import javax.swing.JPopupMenu;
18import javax.swing.JTable;
19import javax.swing.JViewport;
20import javax.swing.KeyStroke;
21import javax.swing.ListSelectionModel;
22import javax.swing.SwingUtilities;
23import javax.swing.event.ListSelectionEvent;
24import javax.swing.event.ListSelectionListener;
25
26import org.openstreetmap.josm.Main;
27import org.openstreetmap.josm.actions.AutoScaleAction;
28import org.openstreetmap.josm.actions.ZoomToAction;
29import org.openstreetmap.josm.data.osm.OsmPrimitive;
30import org.openstreetmap.josm.data.osm.RelationMember;
31import org.openstreetmap.josm.data.osm.Way;
32import org.openstreetmap.josm.gui.MapView;
33import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
34import org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType;
35import org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType.Direction;
36import org.openstreetmap.josm.gui.layer.Layer;
37import org.openstreetmap.josm.gui.layer.OsmDataLayer;
38import org.openstreetmap.josm.gui.util.HighlightHelper;
39import org.openstreetmap.josm.gui.widgets.OsmPrimitivesTable;
40
41public class MemberTable extends OsmPrimitivesTable implements IMemberModelListener {
42
43 /** the additional actions in popup menu */
44 private ZoomToGapAction zoomToGap;
45 private HighlightHelper highlightHelper = new HighlightHelper();
46 private boolean highlightEnabled;
47
48 /**
49 * constructor for relation member table
50 *
51 * @param layer the data layer of the relation
52 * @param model the table model
53 */
54 public MemberTable(OsmDataLayer layer, MemberTableModel model) {
55 super(model, new MemberTableColumnModel(layer.data), model.getSelectionModel());
56 setLayer(layer);
57 model.addMemberModelListener(this);
58 init();
59 }
60
61 /**
62 * initialize the table
63 */
64 protected void init() {
65 MemberRoleCellEditor ce = (MemberRoleCellEditor)getColumnModel().getColumn(0).getCellEditor();
66 setRowHeight(ce.getEditor().getPreferredSize().height);
67 setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
68 setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
69 putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
70
71 // make ENTER behave like TAB
72 //
73 getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
74 KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false), "selectNextColumnCell");
75
76 initHighlighting();
77
78 // install custom navigation actions
79 //
80 getActionMap().put("selectNextColumnCell", new SelectNextColumnCellAction());
81 getActionMap().put("selectPreviousColumnCell", new SelectPreviousColumnCellAction());
82 }
83
84 @Override
85 protected ZoomToAction buildZoomToAction() {
86 return new ZoomToAction(this);
87 }
88
89 @Override
90 protected JPopupMenu buildPopupMenu() {
91 JPopupMenu menu = super.buildPopupMenu();
92 zoomToGap = new ZoomToGapAction();
93 MapView.addLayerChangeListener(zoomToGap);
94 getSelectionModel().addListSelectionListener(zoomToGap);
95 menu.add(zoomToGap);
96 menu.addSeparator();
97 menu.add(new SelectPreviousGapAction());
98 menu.add(new SelectNextGapAction());
99 return menu;
100 }
101
102 @Override
103 public Dimension getPreferredSize(){
104 Container c = getParent();
105 while(c != null && ! (c instanceof JViewport)) {
106 c = c.getParent();
107 }
108 if (c != null) {
109 Dimension d = super.getPreferredSize();
110 d.width = c.getSize().width;
111 return d;
112 }
113 return super.getPreferredSize();
114 }
115
116 @Override
117 public void makeMemberVisible(int index) {
118 scrollRectToVisible(getCellRect(index, 0, true));
119 }
120
121 ListSelectionListener highlighterListener = new ListSelectionListener() {
122 @Override
123 public void valueChanged(ListSelectionEvent lse) {
124 if (Main.isDisplayingMapView()) {
125 Collection<RelationMember> sel = getMemberTableModel().getSelectedMembers();
126 final ArrayList<OsmPrimitive> toHighlight = new ArrayList<OsmPrimitive>();
127 for (RelationMember r: sel) {
128 if (r.getMember().isUsable()) {
129 toHighlight.add(r.getMember());
130 }
131 }
132 SwingUtilities.invokeLater(new Runnable() {
133 @Override
134 public void run() {
135 if (highlightHelper.highlightOnly(toHighlight)) {
136 Main.map.mapView.repaint();
137 }
138 }
139 });
140 }
141 }};
142
143 private void initHighlighting() {
144 highlightEnabled = Main.pref.getBoolean("draw.target-highlight", true);
145 if (!highlightEnabled) return;
146 getMemberTableModel().getSelectionModel().addListSelectionListener(highlighterListener);
147 if (Main.isDisplayingMapView()) {
148 HighlightHelper.clearAllHighlighted();
149 Main.map.mapView.repaint();
150 }
151 }
152
153 /**
154 * Action to be run when the user navigates to the next cell in the table, for instance by
155 * pressing TAB or ENTER. The action alters the standard navigation path from cell to cell: <ul>
156 * <li>it jumps over cells in the first column</li> <li>it automatically add a new empty row
157 * when the user leaves the last cell in the table</li> <ul>
158 *
159 *
160 */
161 class SelectNextColumnCellAction extends AbstractAction {
162 @Override
163 public void actionPerformed(ActionEvent e) {
164 run();
165 }
166
167 public void run() {
168 int col = getSelectedColumn();
169 int row = getSelectedRow();
170 if (getCellEditor() != null) {
171 getCellEditor().stopCellEditing();
172 }
173
174 if (col == 0 && row < getRowCount() - 1) {
175 row++;
176 } else if (row < getRowCount() - 1) {
177 col = 0;
178 row++;
179 } else {
180 // go to next component, no more rows in this table
181 KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
182 manager.focusNextComponent();
183 return;
184 }
185 changeSelection(row, col, false, false);
186 }
187 }
188
189 /**
190 * Action to be run when the user navigates to the previous cell in the table, for instance by
191 * pressing Shift-TAB
192 *
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.