source: josm/src/org/openstreetmap/josm/actions/mapmode/AddWayAction.java@ 235

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

Properly sort newly added ways; bug had been introduced with 222.
Fixes (sorta) #137.

File size: 7.7 KB
Line 
1package org.openstreetmap.josm.actions.mapmode;
2
3import static org.openstreetmap.josm.tools.I18n.tr;
4import static org.openstreetmap.josm.tools.I18n.trn;
5
6import java.awt.event.KeyEvent;
7import java.awt.event.MouseEvent;
8import java.util.Arrays;
9import java.util.Collection;
10import java.util.HashSet;
11import java.util.LinkedList;
12
13import javax.swing.JOptionPane;
14
15import org.openstreetmap.josm.Main;
16import org.openstreetmap.josm.actions.ReorderAction;
17import org.openstreetmap.josm.command.AddCommand;
18import org.openstreetmap.josm.command.ChangeCommand;
19import org.openstreetmap.josm.command.DeleteCommand;
20import org.openstreetmap.josm.data.SelectionChangedListener;
21import org.openstreetmap.josm.data.osm.OsmPrimitive;
22import org.openstreetmap.josm.data.osm.Segment;
23import org.openstreetmap.josm.data.osm.Way;
24import org.openstreetmap.josm.gui.MapFrame;
25import org.openstreetmap.josm.tools.ImageProvider;
26
27/**
28 * Add a new way. The action is split into the first phase, where a new way get
29 * created or selected and the second, where this way is modified.
30 *
31 * Way creation mode:
32 * If there is a selection when the mode is entered, all segments in this
33 * selection form a new way. All non-segment objects are deselected. If there
34 * were ways selected, the user is asked whether to select all segments of these
35 * ways or not, except there is exactly one way selected, which enter the
36 * edit ways mode for this way immediatly.
37 *
38 * If there is no selection on entering, and the user clicks on an segment,
39 * the way editing starts the with a new way and this segment. If the user click
40 * on a way (not holding Alt down), then this way is edited in the way edit mode.
41 *
42 * Way editing mode:
43 * The user can click on subsequent segments. If the segment belonged to the way
44 * it get removed from the way. Elsewhere it get added to the way. JOSM try to add
45 * the segment in the correct position. This is done by searching for connections
46 * to the segment at its 'to' node which are also in the way. The segemnt is
47 * inserted in the way as predecessor of the found segment (or at last segment, if
48 * nothing found).
49 *
50 * @author imi
51 */
52public class AddWayAction extends MapMode implements SelectionChangedListener {
53 private Way way;
54
55 /**
56 * Create a new AddWayAction.
57 * @param mapFrame The MapFrame this action belongs to.
58 * @param followMode The mode to go into when finished creating a way.
59 */
60 public AddWayAction(MapFrame mapFrame) {
61 super(tr("Add Way"), "addway", tr("Add a new way to the data."), KeyEvent.VK_W, mapFrame, ImageProvider.getCursor("normal", "way"));
62 Main.ds.listeners.add(this);
63 }
64
65 @Override public void enterMode() {
66 super.enterMode();
67 way = makeWay();
68 Main.ds.setSelected(way);
69 Main.map.mapView.addMouseListener(this);
70 }
71
72 @Override public void exitMode() {
73 super.exitMode();
74 way = null;
75 Main.map.mapView.removeMouseListener(this);
76 }
77
78 @Override public void mouseClicked(MouseEvent e) {
79 if (e.getButton() != MouseEvent.BUTTON1)
80 return;
81
82 Segment s = Main.map.mapView.getNearestSegment(e.getPoint());
83 if (s == null)
84 return;
85
86 // special case for initial selecting one way
87 if (way == null && (e.getModifiers() & MouseEvent.ALT_DOWN_MASK) == 0) {
88 Way w = Main.map.mapView.getNearestWay(e.getPoint());
89 if (w != null) {
90 way = w;
91 Main.ds.setSelected(way);
92 for (Segment seg : way.segments) {
93 if (seg.incomplete) {
94 JOptionPane.showMessageDialog(Main.parent,tr("Warning: This way is incomplete. Try to download it before adding segments."));
95 return;
96 }
97 }
98 return;
99 }
100 }
101
102 if (way != null && way.segments.contains(s)) {
103 Way copy = new Way(way);
104
105 copy.segments.remove(s);
106 if (copy.segments.isEmpty()) {
107 Main.main.editLayer().add(new DeleteCommand(Arrays.asList(new OsmPrimitive[]{way})));
108 way = null;
109 } else
110 Main.main.editLayer().add(new ChangeCommand(way, copy));
111 } else {
112 if (way == null) {
113 way = new Way();
114 way.segments.add(s);
115 Main.main.editLayer().add(new AddCommand(way));
116 } else {
117 Way copy = new Way(way);
118 int i;
119 for (i = 0; i < way.segments.size(); ++i)
120 if (way.segments.get(i).from == s.to)
121 break;
122 copy.segments.add(i, s);
123 Main.main.editLayer().add(new ChangeCommand(way, copy));
124 }
125 }
126 Main.ds.setSelected(way);
127 }
128
129 /**
130 * Form a way, either out of the (one) selected way or by creating a way over the selected
131 * line segments.
132 */
133 private Way makeWay() {
134 Collection<OsmPrimitive> selection = Main.ds.getSelected();
135 if (selection.isEmpty())
136 return null;
137
138 if (selection.size() == 1 && selection.iterator().next() instanceof Way) {
139 Way way = (Way)selection.iterator().next();
140 for (Segment seg : way.segments) {
141 if (seg.incomplete) {
142 JOptionPane.showMessageDialog(Main.parent, tr("Warning: This way is incomplete. Try to download it before adding segments."));
143 break;
144 }
145 }
146 return way;
147 }
148
149 HashSet<Segment> segmentSet = new HashSet<Segment>();
150 int numberOfSelectedWays = 0;
151 for (OsmPrimitive osm : selection) {
152 if (osm instanceof Way)
153 numberOfSelectedWays++;
154 else if (osm instanceof Segment)
155 segmentSet.add((Segment)osm);
156 }
157
158 Way wayToAdd = null;
159 boolean reordered = false;
160 if (numberOfSelectedWays > 0) {
161 int answer = JOptionPane.showConfirmDialog(Main.parent,trn("{0} way has been selected.\nDo you wish to select all segments belonging to the way instead?","{0} ways have been selected.\nDo you wish to select all segments belonging to the ways instead?",numberOfSelectedWays,numberOfSelectedWays),tr("Add segments from ways"), JOptionPane.YES_NO_OPTION);
162 if (answer == JOptionPane.YES_OPTION) {
163 for (OsmPrimitive osm : selection)
164 if (osm instanceof Way)
165 segmentSet.addAll(((Way)osm).segments);
166 } else if (numberOfSelectedWays == 1) {
167 answer = JOptionPane.showConfirmDialog(Main.parent,tr("Do you want to add all other selected segments to the one selected way?"),tr("Add segments to way?"), JOptionPane.YES_NO_OPTION);
168 if (answer == JOptionPane.YES_OPTION) {
169 for (OsmPrimitive osm : selection) {
170 if (osm instanceof Way) {
171 wayToAdd = (Way)osm;
172 answer = JOptionPane.showConfirmDialog(Main.parent,tr("Reorder all line segments?"), tr("Reorder?"), JOptionPane.YES_NO_CANCEL_OPTION);
173 if (answer == JOptionPane.CANCEL_OPTION)
174 return wayToAdd;
175 if (answer == JOptionPane.YES_OPTION) {
176 segmentSet.addAll(wayToAdd.segments);
177 reordered = true;
178 } else
179 segmentSet.removeAll(wayToAdd.segments);
180 break;
181 }
182 }
183 }
184 }
185 }
186
187 if (segmentSet.isEmpty())
188 return null;
189
190 LinkedList<Segment> rawSegments = new LinkedList<Segment>(segmentSet);
191 LinkedList<Segment> sortedSegments = ReorderAction.sortSegments(rawSegments, true);
192
193 if (wayToAdd != null) {
194 Way w = new Way(wayToAdd);
195 if (reordered)
196 w.segments.clear();
197 w.segments.addAll(sortedSegments);
198 Main.main.editLayer().add(new ChangeCommand(wayToAdd, w));
199 return wayToAdd;
200 }
201
202 if (JOptionPane.YES_OPTION != JOptionPane.showConfirmDialog(Main.parent,trn("Create a new way out of {0} segment?","Create a new way out of {0} segments?",sortedSegments.size(),sortedSegments.size()), tr("Create new way"), JOptionPane.YES_NO_OPTION))
203 return null;
204
205 Way w = new Way();
206 w.segments.addAll(sortedSegments);
207 Main.main.editLayer().add(new AddCommand(w));
208 return w;
209 }
210
211 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
212 if (newSelection.size() == 1) {
213 OsmPrimitive osm = newSelection.iterator().next();
214 way = osm instanceof Way ? (Way)osm : null;
215 } else
216 way = null;
217 }
218}
Note: See TracBrowser for help on using the repository browser.