source: josm/branch/0.5/src/org/openstreetmap/josm/actions/mapmode/AddSegmentAction.java@ 329

Last change on this file since 329 was 329, checked in by framm, 17 years ago

This commit is a manual merge of all changes that have been made to
the intermediate "core_0.5" branch on the main OSM repository,
bevore JOSM was moved to openstreetmap.de.

Changes incorporated here:

r4464@svn.openstreetmap.org
r4466@svn.openstreetmap.org
r4468@svn.openstreetmap.org
r4469@svn.openstreetmap.org
r4479@svn.openstreetmap.org

File size: 5.5 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.actions.mapmode;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Color;
7import java.awt.Graphics;
8import java.awt.Point;
9import java.awt.event.ActionEvent;
10import java.awt.event.KeyEvent;
11import java.awt.event.MouseEvent;
12import java.awt.event.MouseListener;
13import java.util.Collection;
14
15import org.openstreetmap.josm.Main;
16import org.openstreetmap.josm.command.AddCommand;
17import org.openstreetmap.josm.command.ChangeCommand;
18import org.openstreetmap.josm.data.osm.Node;
19import org.openstreetmap.josm.data.osm.OsmPrimitive;
20import org.openstreetmap.josm.data.osm.Way;
21import org.openstreetmap.josm.gui.MapFrame;
22import org.openstreetmap.josm.tools.ImageProvider;
23
24/**
25 * The user can add a new segment between two nodes by pressing on the
26 * starting node and dragging to the ending node.
27 *
28 * No segment can be created if there is already a segment containing
29 * both nodes.
30 *
31 * @author imi
32 */
33public class AddSegmentAction extends MapMode implements MouseListener {
34
35 /**
36 * The first node the user pressed the button onto.
37 */
38 private Node first;
39 /**
40 * The second node used if the user releases the button.
41 */
42 private Node second;
43
44 /**
45 * Whether the hint is currently drawn on screen.
46 */
47 private boolean hintDrawn = false;
48
49 /**
50 * Create a new AddSegmentAction.
51 * @param mapFrame The MapFrame this action belongs to.
52 */
53 public AddSegmentAction(MapFrame mapFrame) {
54 super(tr("Connect two nodes"),
55 "addsegment",
56 tr("Connect two nodes using ways."),
57 KeyEvent.VK_G,
58 mapFrame,
59 ImageProvider.getCursor("normal", "segment"));
60 }
61
62 @Override public void enterMode() {
63 super.enterMode();
64 Main.map.mapView.addMouseListener(this);
65 Main.map.mapView.addMouseMotionListener(this);
66 }
67
68 @Override public void exitMode() {
69 super.exitMode();
70 Main.map.mapView.removeMouseListener(this);
71 Main.map.mapView.removeMouseMotionListener(this);
72 drawHint(false);
73 }
74
75 /**
76 * Called when user hits space bar while dragging.
77 */
78 @Override public void actionPerformed(ActionEvent e) {
79 super.actionPerformed(e);
80 makeSegment();
81 }
82
83 /**
84 * If user clicked on a node, from the dragging with that node.
85 */
86 @Override public void mousePressed(MouseEvent e) {
87 if (e.getButton() != MouseEvent.BUTTON1)
88 return;
89
90 Node clicked = Main.map.mapView.getNearestNode(e.getPoint());
91 if (clicked == null) return;
92
93 drawHint(false);
94 first = second = clicked;
95 }
96
97 /**
98 * Draw a hint which nodes will get connected if the user release
99 * the mouse button now.
100 */
101 @Override public void mouseDragged(MouseEvent e) {
102 if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == 0)
103 return;
104
105 Node hovered = Main.map.mapView.getNearestNode(e.getPoint());
106 if (hovered == second) return;
107
108 drawHint(false);
109 second = hovered;
110 drawHint(true);
111 }
112
113 /**
114 * If left button was released, try to create the segment.
115 */
116 @Override public void mouseReleased(MouseEvent e) {
117 if (e.getButton() == MouseEvent.BUTTON1) {
118 drawHint(false);
119 makeSegment();
120 first = null;
121 }
122 }
123
124 /**
125 * @return If the node is the end of exactly one way, return this.
126 * <code>null</code> otherwise.
127 */
128 private Way getWayForNode(Node n) {
129 Way way = null;
130 for (Way w : Main.ds.ways) {
131 int i = w.nodes.indexOf(n);
132 if (i == -1) continue;
133 if (i == 0 || i == w.nodes.size() - 1) {
134 if (way != null)
135 return null;
136 way = w;
137 }
138 }
139 return way;
140 }
141
142 /**
143 * Create the segment if first and second are different and there is
144 * not already a segment.
145 */
146 private void makeSegment() {
147 Node n1 = first;
148 Node n2 = second;
149
150 // this is to allow continued segment drawing by hitting the space bar
151 // at every intermediate node
152 first = second;
153 second = null;
154
155 if (n1 == null || n2 == null || n1 == n2) return;
156
157 Way w = getWayForNode(n1);
158 Way wnew;
159 Collection<OsmPrimitive> sel = Main.ds.getSelected();
160
161 if (w == null) {
162 // create a new way and add it to the current selection.
163 wnew = new Way();
164 wnew.nodes.add(n1);
165 wnew.nodes.add(n2);
166 Main.main.undoRedo.add(new AddCommand(wnew));
167 sel.add(wnew);
168 Main.ds.setSelected(sel);
169 } else {
170 // extend an existing way; only add to current selection if
171 // it is not already in there.
172 wnew = new Way(w);
173 if (wnew.nodes.get(wnew.nodes.size() - 1) == n1) {
174 wnew.nodes.add(n2);
175 } else {
176 wnew.nodes.add(0, n2);
177 }
178 Main.main.undoRedo.add(new ChangeCommand(w, wnew));
179 // do not use wnew below; ChangeCommand only uses wnew as a
180 // message about changes to be done to w but will not replace w!
181 if (!sel.contains(w)) {
182 sel.add(w);
183 }
184 // do not move this into the if block above since it also
185 // fires the selection change event which is desired.
186 Main.ds.setSelected(sel);
187 }
188
189 Main.map.mapView.repaint();
190 }
191
192 /**
193 * Draw or remove the hint line, depending on the parameter.
194 */
195 private void drawHint(boolean draw) {
196 if (draw == hintDrawn)
197 return;
198 if (first == null || second == null)
199 return;
200 if (second == first)
201 return;
202
203 Graphics g = Main.map.mapView.getGraphics();
204 g.setColor(Color.BLACK);
205 g.setXORMode(Color.WHITE);
206 Point firstDrawn = Main.map.mapView.getPoint(first.eastNorth);
207 Point secondDrawn = Main.map.mapView.getPoint(second.eastNorth);
208 g.drawLine(firstDrawn.x, firstDrawn.y, secondDrawn.x, secondDrawn.y);
209 hintDrawn = !hintDrawn;
210 }
211}
Note: See TracBrowser for help on using the repository browser.