001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.dialogs.relation;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005import static org.openstreetmap.josm.tools.I18n.trn;
006
007import java.awt.Dialog;
008import java.io.IOException;
009import java.util.Collection;
010import java.util.HashSet;
011import java.util.Set;
012
013import javax.swing.SwingUtilities;
014
015import org.openstreetmap.josm.Main;
016import org.openstreetmap.josm.data.osm.DataSet;
017import org.openstreetmap.josm.data.osm.OsmPrimitive;
018import org.openstreetmap.josm.data.osm.Relation;
019import org.openstreetmap.josm.gui.DefaultNameFormatter;
020import org.openstreetmap.josm.gui.ExceptionDialogUtil;
021import org.openstreetmap.josm.gui.PleaseWaitRunnable;
022import org.openstreetmap.josm.gui.layer.OsmDataLayer;
023import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
024import org.openstreetmap.josm.gui.progress.ProgressMonitor;
025import org.openstreetmap.josm.io.MultiFetchServerObjectReader;
026import org.openstreetmap.josm.io.OsmTransferException;
027import org.xml.sax.SAXException;
028
029/**
030 * The asynchronous task for downloading relation members.
031 *
032 */
033public class DownloadRelationMemberTask extends PleaseWaitRunnable {
034    private boolean canceled;
035    private Exception lastException;
036    private final Set<Relation> parents = new HashSet<>();
037    private Collection<OsmPrimitive> children;
038    private OsmDataLayer curLayer;
039    private MultiFetchServerObjectReader objectReader;
040
041    public DownloadRelationMemberTask(Relation parent, Collection<OsmPrimitive> children, OsmDataLayer curLayer, Dialog dialog) {
042        super(tr("Download relation members"), new PleaseWaitProgressMonitor(dialog), false /* don't ignore exception */);
043        if (parent != null)
044            this.parents.add(parent);
045        this.children = children;
046        this.curLayer = curLayer;
047    }
048
049    public DownloadRelationMemberTask(Relation parent, Collection<OsmPrimitive> children, OsmDataLayer curLayer) {
050        super(tr("Download relation members"), false /* don't ignore exception */);
051        if (parent != null)
052            this.parents.add(parent);
053        this.children = children;
054        this.curLayer = curLayer;
055    }
056
057    /**
058     * Creates a download task for downloading the child primitives {@code children} for all parent
059     * relations in {@code parents}.
060     *
061     * @param parents the collection of parent relations
062     * @param children the collection of child primitives to download
063     * @param curLayer the current OSM layer
064     */
065    public DownloadRelationMemberTask(Collection<Relation> parents, Collection<OsmPrimitive> children, OsmDataLayer curLayer) {
066        super(tr("Download relation members"), false /* don't ignore exception */);
067        this.parents.addAll(parents);
068        this.children = children;
069        this.curLayer = curLayer;
070    }
071
072    @Override
073    protected void cancel() {
074        canceled = true;
075        synchronized (this) {
076            if (objectReader != null) {
077                objectReader.cancel();
078            }
079        }
080    }
081
082    @Override
083    protected void finish() {
084        Main.map.repaint();
085        if (canceled)
086            return;
087        if (lastException != null) {
088            ExceptionDialogUtil.explainException(lastException);
089        }
090    }
091
092    protected String buildDownloadFeedbackMessage() {
093        if (parents.isEmpty()) {
094            return trn("Downloading {0} incomplete object",
095                    "Downloading {0} incomplete objects",
096                    children.size(),
097                    children.size());
098        } else if (parents.size() == 1) {
099            Relation parent = parents.iterator().next();
100            return trn("Downloading {0} incomplete child of relation ''{1}''",
101                    "Downloading {0} incomplete children of relation ''{1}''",
102                    children.size(),
103                    children.size(),
104                    parent.getDisplayName(DefaultNameFormatter.getInstance()));
105        } else {
106            return trn("Downloading {0} incomplete child of {1} parent relations",
107                    "Downloading {0} incomplete children of {1} parent relations",
108                    children.size(),
109                    children.size(),
110                    parents.size());
111        }
112    }
113
114    @Override
115    protected void realRun() throws SAXException, IOException, OsmTransferException {
116        try {
117            synchronized (this) {
118                if (canceled) return;
119                objectReader = new MultiFetchServerObjectReader();
120            }
121            objectReader.append(children);
122            progressMonitor.indeterminateSubTask(
123                    buildDownloadFeedbackMessage()
124            );
125            final DataSet dataSet = objectReader.parseOsm(progressMonitor
126                    .createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
127            if (dataSet == null)
128                return;
129            dataSet.deleteInvisible();
130            synchronized (this) {
131                if (canceled) return;
132                objectReader = null;
133            }
134
135            SwingUtilities.invokeLater(
136                    new Runnable() {
137                        @Override
138                        public void run() {
139                            curLayer.mergeFrom(dataSet);
140                            curLayer.onPostDownloadFromServer();
141                        }
142                    }
143            );
144
145        } catch (Exception e) {
146            if (canceled) {
147                Main.warn(tr("Ignoring exception because task was canceled. Exception: {0}", e.toString()));
148                return;
149            }
150            lastException = e;
151        }
152    }
153}