Ticket #8390: conflict-save-draft01.patch

File conflict-save-draft01.patch, 16.2 KB (added by bastiK, 11 years ago)
  • src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java

     
    804804            dialog.showDialog();
    805805            if (dialog.getValue() != 1) return false;
    806806        }
    807 
    808         ConflictCollection conflicts = getConflicts();
    809         if (conflicts != null && !conflicts.isEmpty()) {
    810             ExtendedDialog dialog = new ExtendedDialog(
    811                     Main.parent,
    812                     /* I18N: Display title of the window showing conflicts */
    813                     tr("Conflicts"),
    814                     new String[] {tr("Reject Conflicts and Save"), tr("Cancel")}
    815             );
    816             dialog.setContent(tr("There are unresolved conflicts. Conflicts will not be saved and handled as if you rejected all. Continue?"));
    817             dialog.setButtonIcons(new String[] {"save.png", "cancel.png"});
    818             dialog.showDialog();
    819             if (dialog.getValue() != 1) return false;
    820         }
    821807        return true;
    822808    }
    823809   
  • src/org/openstreetmap/josm/io/OsmReader.java

     
    1818import javax.xml.stream.XMLStreamReader;
    1919
    2020import org.openstreetmap.josm.data.Bounds;
     21import org.openstreetmap.josm.data.conflict.Conflict;
     22import org.openstreetmap.josm.data.conflict.ConflictCollection;
    2123import org.openstreetmap.josm.data.coor.LatLon;
    2224import org.openstreetmap.josm.data.osm.Changeset;
    2325import org.openstreetmap.josm.data.osm.DataSet;
    2426import org.openstreetmap.josm.data.osm.DataSource;
    2527import org.openstreetmap.josm.data.osm.Node;
    2628import org.openstreetmap.josm.data.osm.NodeData;
     29import org.openstreetmap.josm.data.osm.OsmPrimitive;
    2730import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
    2831import org.openstreetmap.josm.data.osm.PrimitiveData;
    2932import org.openstreetmap.josm.data.osm.Relation;
     
    131134                if (parser.getLocalName().equals("bounds")) {
    132135                    parseBounds(generator);
    133136                } else if (parser.getLocalName().equals("node")) {
    134                     parseNode();
     137                    Node n = parseNode(false);
     138                    externalIdMap.put(n.getPrimitiveId(), n);
    135139                } else if (parser.getLocalName().equals("way")) {
    136140                    parseWay();
    137141                } else if (parser.getLocalName().equals("relation")) {
     
    175179        jumpToEnd();
    176180    }
    177181
    178     protected Node parseNode() throws XMLStreamException {
     182    /**
     183     * Parse a node.
     184     *
     185     * @param isConflict True, if the node participates in a conflict with
     186     * role "their". False, if it is a regular node, that will be included
     187     * in the DataSet.
     188     * @return the parsed node
     189     * @throws XMLStreamException
     190     */
     191    protected Node parseNode(boolean isConflict) throws XMLStreamException {
    179192        NodeData nd = new NodeData();
    180193        String lat = parser.getAttributeValue(null, "lat");
    181194        String lon = parser.getAttributeValue(null, "lon");
     
    186199        Node n = new Node(nd.getId(), nd.getVersion());
    187200        n.setVisible(nd.isVisible());
    188201        n.load(nd);
    189         externalIdMap.put(nd.getPrimitiveId(), n);
    190202        while (true) {
    191203            int event = parser.next();
    192204            if (event == XMLStreamConstants.START_ELEMENT) {
    193205                if (parser.getLocalName().equals("tag")) {
    194206                    parseTag(n);
     207                } else if (!isConflict && parser.getLocalName().equals("conflict")) {
     208                    parseNodeConflict(n);
    195209                } else {
    196210                    parseUnknown();
    197211                }
     
    200214        }
    201215    }
    202216
     217    protected void parseNodeConflict(Node my) throws XMLStreamException {
     218        Node their = null;
     219        while (true) {
     220            int event = parser.next();
     221            if (event == XMLStreamConstants.START_ELEMENT) {
     222                if (parser.getLocalName().equals("node")) {
     223                    their = parseNode(true);
     224                    conflicts.add(new Conflict(my, their));
     225                } else {
     226                    parseUnknown();
     227                }
     228            } else if (event == XMLStreamConstants.END_ELEMENT)
     229                return;
     230        }
     231    }
     232
    203233    protected Way parseWay() throws XMLStreamException {
    204234        WayData wd = new WayData();
    205235        readCommon(wd);
     
    348378        while (true) {
    349379            int event = parser.next();
    350380            if (event == XMLStreamConstants.START_ELEMENT) {
    351                 parseUnknown(false); /* no more warning for inner elements */
     381                parseUnknown(false); /* no more warnings for inner elements */
    352382            } else if (event == XMLStreamConstants.END_ELEMENT)
    353383                return;
    354384        }
     
    556586        }
    557587    }
    558588
    559     protected DataSet doParseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
     589    public DataSet parse(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
    560590        if (progressMonitor == null) {
    561591            progressMonitor = NullProgressMonitor.INSTANCE;
    562592        }
     
    616646     * @throws IllegalArgumentException thrown if source is null
    617647     */
    618648    public static DataSet parseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
    619         return new OsmReader().doParseDataSet(source, progressMonitor);
     649        return new OsmReader().parse(source, progressMonitor);
    620650    }
     651
     652    public ConflictCollection getConflicts() {
     653        return conflicts;
     654    }
     655
    621656}
  • src/org/openstreetmap/josm/io/OsmWriter.java

     
    1111import java.util.List;
    1212import java.util.Map.Entry;
    1313
     14import org.openstreetmap.josm.data.conflict.Conflict;
     15import org.openstreetmap.josm.data.conflict.ConflictCollection;
    1416import org.openstreetmap.josm.data.coor.CoordinateFormat;
    1517import org.openstreetmap.josm.data.osm.Changeset;
    1618import org.openstreetmap.josm.data.osm.DataSet;
     
    4244    private boolean isOsmChange;
    4345    private String version;
    4446    private Changeset changeset;
     47    private ConflictCollection conflicts;
    4548
    4649    /**
    4750     * Do not call this directly. Use OsmWriterFactory instead.
     
    5255        this.version = (version == null ? DEFAULT_API_VERSION : version);
    5356    }
    5457
    55     public void setWithBody(boolean wb) {
    56         this.withBody = wb;
     58    /**
     59     * Set to false, if you want to skip the element body.
     60     *
     61     * If set to false, node coordinates, way nodes and relation members are
     62     * omitted in the output.
     63     *
     64     * @param withBody false, if body should be skipped
     65     */
     66    public void setWithBody(boolean withBody) {
     67        this.withBody = withBody;
    5768    }
    5869
     70    /**
     71     * Set to true, if a .osmChange file is written.
     72     *
     73     * For upload of changes to the server, not all attributes that are
     74     * normally written to a .osm file are needed.
     75     *
     76     * @param isOsmChange true, if a .osmChange file is written
     77     */
    5978    public void setIsOsmChange(boolean isOsmChange) {
    6079        this.isOsmChange = isOsmChange;
    6180    }
     
    100119    public void writeLayer(OsmDataLayer layer) {
    101120        header(!layer.isUploadDiscouraged());
    102121        writeDataSources(layer.data);
     122        conflicts = layer.getConflicts();
    103123        writeContent(layer.data);
    104124        footer();
    105125    }
     
    123143    }
    124144
    125145    protected boolean shouldWrite(OsmPrimitive osm) {
     146        // FIXME: the following condition should be equivalent:
     147        // !osm.isNew() || !osm.isDeleted();
    126148        return !osm.isNewOrUndeleted() || !osm.isDeleted();
    127149    }
    128150
     
    133155                    + s.bounds.getMin().lon()+"' maxlat='"
    134156                    + s.bounds.getMax().lat()+"' maxlon='"
    135157                    + s.bounds.getMax().lon()
    136                     +"' origin='"+XmlWriter.encode(s.origin)+"' />");
     158                    +"' origin='"+XmlWriter.encode(s.origin)+"'/>");
    137159        }
    138160    }
    139161
     
    144166        if (!withBody) {
    145167            out.println("/>");
    146168        } else {
     169            boolean hasInnerElements = false;
    147170            if (n.getCoor() != null) {
    148171                out.print(" lat='"+n.getCoor().lat()+"' lon='"+n.getCoor().lon()+"'");
    149172            }
    150             addTags(n, "node", true);
     173            if (n.hasKeys()) {
     174                out.println(">");
     175                hasInnerElements = true;
     176                addTags(n, "    ");
     177            }
     178            Conflict c = conflicts.getConflictForMy(n);
     179            if (c != null) {
     180                IPrimitive th = c.getTheir();
     181                if (th instanceof INode) {
     182                    INode nConflict = (INode) th;
     183                    if (!hasInnerElements) {
     184                        out.println(">");
     185                    }
     186                    out.println("    <conflict>");
     187                    // FIXME: add c.isMyDeleted and c.mergedMap
     188                    out.print("    ");
     189                    addCommon(th, "node");
     190                    if (nConflict.getCoor() != null) {
     191                        out.print(" lat='"+nConflict.getCoor().lat()+"' lon='"+nConflict.getCoor().lon()+"'");
     192                    }
     193                    if (nConflict.hasKeys()) {
     194                        out.println(">");
     195                        addTags(nConflict, "        ");
     196                        out.println("      </node>");
     197                    } else {
     198                        out.println("/>");
     199                    }
     200                    out.println("    </conflict>");
     201                    hasInnerElements = true;
     202                }
     203            }
     204            if (hasInnerElements) {
     205                out.println("  </node>");
     206            } else {
     207                out.println("/>");
     208            }
    151209        }
    152210    }
    153211
     
    216274        }
    217275    };
    218276
     277    protected void addTags(Tagged osm, String inset) {
     278        List<Entry<String, String>> entries = new ArrayList<Entry<String,String>>(osm.getKeys().entrySet());
     279        Collections.sort(entries, byKeyComparator);
     280        for (Entry<String, String> e : entries) {
     281            out.println(inset + "<tag k='"+ XmlWriter.encode(e.getKey()) +
     282                    "' v='"+XmlWriter.encode(e.getValue())+ "'/>");
     283        }
     284    }
     285
    219286    protected void addTags(Tagged osm, String tagname, boolean tagOpen) {
    220287        if (osm.hasKeys()) {
    221288            if (tagOpen) {
  • src/org/openstreetmap/josm/io/OsmImporter.java

     
    8787     * associatedFile can be null if the stream does not come from a file.
    8888     */
    8989    public OsmImporterData loadLayer(InputStream in, final File associatedFile, final String layerName, ProgressMonitor progressMonitor) throws IllegalDataException {
    90         final DataSet dataSet = parseDataSet(in, progressMonitor);
     90        OsmReader reader = new OsmReader();
     91        DataSet dataSet = reader.parse(in, progressMonitor);
    9192        if (dataSet == null) {
    9293            throw new IllegalDataException(tr("Invalid dataset"));
    9394        }
    9495        OsmDataLayer layer = createLayer(dataSet, associatedFile, layerName);
     96        layer.getConflicts().add(reader.getConflicts());
    9597        Runnable postLayerTask = createPostLayerTask(dataSet, associatedFile, layerName, layer);
    9698        return new OsmImporterData(layer, postLayerTask);
    9799    }
    98100
    99     protected DataSet parseDataSet(InputStream in, ProgressMonitor progressMonitor) throws IllegalDataException {
    100         return OsmReader.parseDataSet(in, progressMonitor);
    101     }
    102 
    103101    protected OsmDataLayer createLayer(final DataSet dataSet, final File associatedFile, final String layerName) {
    104102        return new OsmDataLayer(dataSet, layerName, associatedFile);
    105103    }
  • src/org/openstreetmap/josm/io/OsmChangeReader.java

     
    6565            if (event == XMLStreamConstants.START_ELEMENT) {
    6666                OsmPrimitive p = null;
    6767                if (parser.getLocalName().equals("node")) {
    68                     p = parseNode();
     68                    p = parseNode(false);
    6969                } else if (parser.getLocalName().equals("way")) {
    7070                    p = parseWay();
    7171                } else if (parser.getLocalName().equals("relation")) {
     
    9797     * @throws IllegalArgumentException thrown if source is null
    9898     */
    9999    public static DataSet parseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
    100         return new OsmChangeReader().doParseDataSet(source, progressMonitor);
     100        return new OsmChangeReader().parse(source, progressMonitor);
    101101    }
    102102}
  • src/org/openstreetmap/josm/io/AbstractReader.java

     
    99import java.util.List;
    1010import java.util.Map;
    1111
     12import org.openstreetmap.josm.data.conflict.ConflictCollection;
    1213import org.openstreetmap.josm.data.osm.Changeset;
    1314import org.openstreetmap.josm.data.osm.DataSet;
    1415import org.openstreetmap.josm.data.osm.Node;
     
    3334     */
    3435    protected DataSet ds = new DataSet();
    3536
     37    protected ConflictCollection conflicts = new ConflictCollection();
     38
    3639    protected Changeset uploadChangeset;
    3740
    3841    /** the map from external ids to read OsmPrimitives. External ids are
     
    189192            }
    190193        }
    191194    }
     195
     196    protected void processConflictsAfterParsing() {
     197        // add conflict primitives with role "their" to a dummy dataset,
     198        // because each primitive needs a parent dataset.
     199        DataSet theirDataSet = new DataSet();
     200        for (OsmPrimitive their : conflicts.getTheirConflictParties()) {
     201            theirDataSet.addPrimitive(their);
     202        }
     203    }
    192204   
    193205    protected final void prepareDataSet() throws IllegalDataException {
    194206        try {
  • src/org/openstreetmap/josm/data/conflict/Conflict.java

     
    33
    44import java.util.Map;
    55
     6import org.openstreetmap.josm.data.osm.IPrimitive;
    67import org.openstreetmap.josm.data.osm.OsmPrimitive;
    78import org.openstreetmap.josm.data.osm.PrimitiveId;
    89
     
    4546        return their;
    4647    }
    4748
    48     public boolean isMatchingMy(OsmPrimitive my) {
     49    public boolean isMatchingMy(IPrimitive my) {
    4950        return this.my == my;
    5051    }
    5152
  • src/org/openstreetmap/josm/data/conflict/ConflictCollection.java

     
    1111import java.util.Set;
    1212import java.util.concurrent.CopyOnWriteArrayList;
    1313
     14import org.openstreetmap.josm.data.osm.IPrimitive;
    1415import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1516import org.openstreetmap.josm.tools.CheckParameterUtil;
    1617
     
    151152     * @return the conflict for the {@link OsmPrimitive} <code>my</code>, null
    152153     * if no such conflict exists.
    153154     */
    154     public Conflict<?> getConflictForMy(OsmPrimitive my) {
     155    public Conflict<?> getConflictForMy(IPrimitive my) {
    155156        for(Conflict<?> c : conflicts) {
    156157            if (c.isMatchingMy(my))
    157158                return c;