001    // License: GPL. For details, see LICENSE file.
002    package org.openstreetmap.josm.gui.dialogs.relation;
003    
004    import static org.openstreetmap.josm.tools.I18n.tr;
005    import static org.openstreetmap.josm.tools.I18n.trn;
006    
007    import java.awt.Dialog;
008    import java.io.IOException;
009    import java.util.Collection;
010    import java.util.HashSet;
011    import java.util.Set;
012    
013    import javax.swing.SwingUtilities;
014    
015    import org.openstreetmap.josm.Main;
016    import org.openstreetmap.josm.data.osm.DataSet;
017    import org.openstreetmap.josm.data.osm.OsmPrimitive;
018    import org.openstreetmap.josm.data.osm.Relation;
019    import org.openstreetmap.josm.gui.DefaultNameFormatter;
020    import org.openstreetmap.josm.gui.ExceptionDialogUtil;
021    import org.openstreetmap.josm.gui.PleaseWaitRunnable;
022    import org.openstreetmap.josm.gui.layer.OsmDataLayer;
023    import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
024    import org.openstreetmap.josm.gui.progress.ProgressMonitor;
025    import org.openstreetmap.josm.io.MultiFetchServerObjectReader;
026    import org.openstreetmap.josm.io.OsmTransferException;
027    import org.xml.sax.SAXException;
028    
029    /**
030     * The asynchronous task for downloading relation members.
031     *
032     */
033    public class DownloadRelationMemberTask extends PleaseWaitRunnable {
034        private boolean canceled;
035        private Exception lastException;
036        private final Set<Relation> parents = new HashSet<Relation>();
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.size() == 0) {
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                            public void run() {
138                                curLayer.mergeFrom(dataSet);
139                                curLayer.onPostDownloadFromServer();
140                            }
141                        }
142                );
143    
144            } catch (Exception e) {
145                if (canceled) {
146                    System.out.println(tr("Warning: Ignoring exception because task was canceled. Exception: {0}", e
147                            .toString()));
148                    return;
149                }
150                lastException = e;
151            }
152        }
153    }