source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/relation/ParentRelationLoadingTask.java @ 13486

Last change on this file since 13486 was 13486, checked in by Don-vip, 5 months ago

fix #8039, see #10456 - fix bugs with non-downloadable layers

  • Property svn:eol-style set to native
File size: 6.7 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.io.IOException;
7import java.util.ArrayList;
8import java.util.List;
9import java.util.Optional;
10
11import javax.swing.JOptionPane;
12import javax.swing.SwingUtilities;
13
14import org.openstreetmap.josm.Main;
15import org.openstreetmap.josm.data.osm.DataSet;
16import org.openstreetmap.josm.data.osm.DataSetMerger;
17import org.openstreetmap.josm.data.osm.Relation;
18import org.openstreetmap.josm.gui.PleaseWaitRunnable;
19import org.openstreetmap.josm.gui.layer.OsmDataLayer;
20import org.openstreetmap.josm.gui.progress.swing.PleaseWaitProgressMonitor;
21import org.openstreetmap.josm.io.OsmApi;
22import org.openstreetmap.josm.io.OsmServerBackreferenceReader;
23import org.openstreetmap.josm.io.OsmTransferException;
24import org.openstreetmap.josm.tools.CheckParameterUtil;
25import org.openstreetmap.josm.tools.Logging;
26import org.xml.sax.SAXException;
27
28/**
29 * This is an asynchronous task for loading the parents of a given relation.
30 *
31 * Typical usage:
32 * <pre>
33 *  final ParentRelationLoadingTask task = new ParentRelationLoadingTask(
34 *                   child,   // the child relation
35 *                   MainApplication.getLayerManager().getEditLayer(), // the edit layer
36 *                   true,  // load fully
37 *                   new PleaseWaitProgressMonitor()  // a progress monitor
38 *   );
39 *   task.setContinuation(
40 *       new Runnable() {
41 *          public void run() {
42 *              if (task.isCanceled() || task.hasError())
43 *                  return;
44 *              List&lt;Relation&gt; parents = task.getParents();
45 *              // do something with the parent relations
46 *       }
47 *   );
48 *
49 *   // start the task
50 *   MainApplication.worker.submit(task);
51 * </pre>
52 *
53 */
54public class ParentRelationLoadingTask extends PleaseWaitRunnable {
55    private boolean canceled;
56    private Exception lastException;
57    private DataSet referrers;
58    private final boolean full;
59    private final OsmDataLayer layer;
60    private final Relation child;
61    private final List<Relation> parents;
62    private Runnable continuation;
63
64    /**
65     * Creates a new task for asynchronously downloading the parents of a child relation.
66     *
67     * @param child the child relation. Must not be null. Must have an id &gt; 0.
68     * @param layer  the OSM data layer. Must not be null.
69     * @param full if true, parent relations are fully downloaded (i.e. with their members)
70     * @param monitor the progress monitor to be used
71     *
72     * @throws IllegalArgumentException if child is null
73     * @throws IllegalArgumentException if layer is null
74     * @throws IllegalArgumentException if child.getId() == 0
75     */
76    public ParentRelationLoadingTask(Relation child, OsmDataLayer layer, boolean full, PleaseWaitProgressMonitor monitor) {
77        super(tr("Download referring relations"), monitor, false /* don't ignore exception */);
78        CheckParameterUtil.ensure(child, "child", "id > 0", ch -> ch.getUniqueId() > 0);
79        CheckParameterUtil.ensureParameterNotNull(layer, "layer");
80        if (!layer.isDownloadable()) {
81            throw new IllegalArgumentException("Non-downloadable layer: " + layer);
82        }
83        referrers = null;
84        this.layer = layer;
85        parents = new ArrayList<>();
86        this.child = child;
87        this.full = full;
88    }
89
90    /**
91     * Set a continuation which is called upon the job finished.
92     *
93     * @param continuation the continuation
94     */
95    public void setContinuation(Runnable continuation) {
96        this.continuation = continuation;
97    }
98
99    /**
100     * Replies true if this has been canceled by the user.
101     *
102     * @return true if this has been canceled by the user.
103     */
104    public boolean isCanceled() {
105        return canceled;
106    }
107
108    /**
109     * Replies true if an exception has been caught during the execution of this task.
110     *
111     * @return true if an exception has been caught during the execution of this task.
112     */
113    public boolean hasError() {
114        return lastException != null;
115    }
116
117    protected OsmDataLayer getLayer() {
118        return layer;
119    }
120
121    public List<Relation> getParents() {
122        return parents;
123    }
124
125    @Override
126    protected void cancel() {
127        canceled = true;
128        OsmApi.getOsmApi().cancel();
129    }
130
131    protected void showLastException() {
132        JOptionPane.showMessageDialog(
133                Main.parent,
134                Optional.ofNullable(lastException.getMessage()).orElseGet(lastException::toString),
135                tr("Error"),
136                JOptionPane.ERROR_MESSAGE
137        );
138    }
139
140    @Override
141    protected void finish() {
142        if (canceled) return;
143        if (lastException != null) {
144            showLastException();
145            return;
146        }
147        parents.clear();
148        for (Relation parent : referrers.getRelations()) {
149            parents.add((Relation) getLayer().data.getPrimitiveById(parent));
150        }
151        if (continuation != null) {
152            continuation.run();
153        }
154    }
155
156    @Override
157    protected void realRun() throws SAXException, IOException, OsmTransferException {
158        try {
159            progressMonitor.indeterminateSubTask(null);
160            OsmServerBackreferenceReader reader = new OsmServerBackreferenceReader(child, full);
161            referrers = reader.parseOsm(progressMonitor.createSubTaskMonitor(1, false));
162            if (referrers != null) {
163                final DataSetMerger visitor = new DataSetMerger(getLayer().data, referrers);
164                visitor.merge();
165
166                // copy the merged layer's data source info
167                getLayer().data.addDataSources(referrers.getDataSources());
168                // FIXME: this is necessary because there are dialogs listening
169                // for DataChangeEvents which manipulate Swing components on this thread.
170                SwingUtilities.invokeLater(getLayer()::onPostDownloadFromServer);
171
172                if (visitor.getConflicts().isEmpty())
173                    return;
174                getLayer().getConflicts().add(visitor.getConflicts());
175                JOptionPane.showMessageDialog(
176                        Main.parent,
177                        tr("There were {0} conflicts during import.",
178                                visitor.getConflicts().size()),
179                                tr("Warning"),
180                                JOptionPane.WARNING_MESSAGE
181                );
182            }
183        } catch (OsmTransferException e) {
184            if (canceled) {
185                Logging.warn(tr("Ignoring exception because task was canceled. Exception: {0}", e.toString()));
186                return;
187            }
188            lastException = e;
189        }
190    }
191}
Note: See TracBrowser for help on using the repository browser.