source: josm/src/org/openstreetmap/josm/io/IncompleteDownloader.java@ 219

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

Give users the chance to delete segments from a way if they fail to download.
Patch submitted by Martijn van Oosterhout <kleptog@…>.

File size: 5.4 KB
Line 
1package org.openstreetmap.josm.io;
2
3import static org.openstreetmap.josm.tools.I18n.tr;
4
5import java.io.BufferedReader;
6import java.io.ByteArrayInputStream;
7import java.io.FileNotFoundException;
8import java.io.IOException;
9import java.io.InputStreamReader;
10import java.io.StringReader;
11import java.util.Collection;
12import java.util.ArrayList;
13
14import org.openstreetmap.josm.Main;
15import org.openstreetmap.josm.data.osm.DataSet;
16import org.openstreetmap.josm.data.osm.Node;
17import org.openstreetmap.josm.data.osm.Segment;
18import org.openstreetmap.josm.data.osm.Way;
19import org.openstreetmap.josm.data.osm.visitor.MergeVisitor;
20import org.xml.sax.Attributes;
21import org.xml.sax.SAXException;
22
23import javax.swing.JOptionPane;
24import org.openstreetmap.josm.command.ChangeCommand;
25import org.openstreetmap.josm.command.Command;
26import org.openstreetmap.josm.command.SequenceCommand;
27
28import uk.co.wilson.xml.MinML2;
29
30/**
31 * Capable of downloading ways without having to fully parse their segments.
32 *
33 * @author Imi
34 */
35public class IncompleteDownloader extends OsmServerReader {
36
37 /**
38 * The new downloaded data will be inserted here.
39 */
40 public final DataSet data = new DataSet();
41
42 /**
43 * The list of incomplete Ways to download. The ways will be filled and are complete after download.
44 */
45 private final Collection<Way> toDownload;
46 private MergeVisitor merger = new MergeVisitor(data);
47
48 public IncompleteDownloader(Collection<Way> toDownload) {
49 this.toDownload = toDownload;
50 }
51
52 public void parse() throws SAXException, IOException {
53 Main.pleaseWaitDlg.currentAction.setText(tr("Downloading incomplete ways..."));
54 Main.pleaseWaitDlg.progress.setMaximum(toDownload.size());
55 Main.pleaseWaitDlg.progress.setValue(0);
56 ArrayList<Command> cmds = new ArrayList<Command>();
57 int i = 0;
58 try {
59 for (Way w : toDownload) {
60 // if some of the way's segments fail to download and the user
61 // decides to delete them, the download method will return an
62 // "edit way" command.
63 Command cmd = download(w);
64 if (cmd != null)
65 cmds.add(cmd);
66 Main.pleaseWaitDlg.progress.setValue(++i);
67 }
68 } catch (IOException e) {
69 if (!cancel)
70 throw e;
71 } catch (SAXException e) {
72 throw e;
73 } catch (Exception e) {
74 if (!cancel)
75 throw (e instanceof RuntimeException) ? (RuntimeException)e : new RuntimeException(e);
76 }
77 if (cmds.size() > 0)
78 Main.main.editLayer().add(new SequenceCommand(tr("Fix data errors"), cmds));
79 }
80
81 private static class SegmentParser extends MinML2 {
82 public long from, to;
83 @Override public void startElement(String ns, String lname, String qname, Attributes a) {
84 if (qname.equals("segment")) {
85 from = Long.parseLong(a.getValue("from"));
86 to = Long.parseLong(a.getValue("to"));
87 }
88 }
89 }
90
91 /**
92 * Downloads all missing segments from the given way. If segments fail do download,
93 * offers the user a chance to delete those segments from the way.
94 *
95 * @param w way to complete
96 * @return an "edit way" command if the user decided to delete segments
97 * @throws IOException
98 * @throws SAXException
99 */
100 private Command download(Way w) throws IOException, SAXException {
101 // get all the segments
102 Way newway = null;
103 for (Segment s : w.segments) {
104 if (!s.incomplete)
105 continue;
106 BufferedReader segReader;
107 try {
108 segReader = new BufferedReader(new InputStreamReader(getInputStream("segment/"+s.id, null), "UTF-8"));
109 } catch (FileNotFoundException e) {
110 Object[] options = {"Delete", "Ignore", "Abort"};
111 int n = JOptionPane.showOptionDialog(Main.parent,
112 tr("Segment {0} is deleted but part of Way {1}",s.id, w.id),
113 tr("Data error"),
114 JOptionPane.YES_NO_CANCEL_OPTION,
115 JOptionPane.ERROR_MESSAGE,
116 null, options, options[2]);
117 if (n == 0)
118 {
119 if( newway == null )
120 newway = new Way(w);
121 newway.segments.remove(s);
122 }
123 else if (n == 2)
124 {
125 e.printStackTrace();
126 throw new IOException(tr("Data error: Segment {0} is deleted but part of Way {1}", s.id, w.id));
127 }
128 continue;
129 }
130 StringBuilder segBuilder = new StringBuilder();
131 for (String line = segReader.readLine(); line != null; line = segReader.readLine())
132 segBuilder.append(line+"\n");
133 SegmentParser segmentParser = new SegmentParser();
134 segmentParser.parse(new StringReader(segBuilder.toString()));
135 if (segmentParser.from == 0 || segmentParser.to == 0)
136 throw new SAXException("Invalid segment response.");
137 if (!hasNode(segmentParser.from))
138 readNode(segmentParser.from, s.id).visit(merger);
139 if (!hasNode(segmentParser.to))
140 readNode(segmentParser.to, s.id).visit(merger);
141 readSegment(segBuilder.toString()).visit(merger);
142 }
143 if( newway != null )
144 return new ChangeCommand(w, newway);
145 return null;
146 }
147
148 private boolean hasNode(long id) {
149 for (Node n : Main.ds.nodes)
150 if (n.id == id)
151 return true;
152 return false;
153 }
154
155 private Segment readSegment(String seg) throws SAXException, IOException {
156 return OsmReader.parseDataSet(new ByteArrayInputStream(seg.getBytes("UTF-8")), data, null).segments.iterator().next();
157 }
158
159 private Node readNode(long id, long segId) throws SAXException, IOException {
160 try {
161 return OsmReader.parseDataSet(getInputStream("node/"+id, null), data, null).nodes.iterator().next();
162 } catch (FileNotFoundException e) {
163 e.printStackTrace();
164 throw new IOException(tr("Data error: Node {0} is deleted but part of Segment {1}", id, segId));
165 }
166 }
167}
Note: See TracBrowser for help on using the repository browser.