Changeset 2115 in josm for trunk/src/org


Ignore:
Timestamp:
2009-09-13T19:30:36+02:00 (15 years ago)
Author:
Gubaer
Message:

new: reading open changesets from the server
new: reading user info from the server
new: any open changeset can be used when uploading
new: generic dialog for closing changesets
fixed #3427: JOSM can't keep many changesets open at once
fixed #3408: Allow continuing opened changeset even after restarting JOSM
fixed #3476: Default selection in upload dialog should be different for unclosed changesets. (Upload dialog now looks different)

Location:
trunk/src/org/openstreetmap/josm
Files:
10 added
16 edited
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/CloseChangesetAction.java

    r2113 r2115  
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.actions;
     3
     4import static org.openstreetmap.josm.tools.I18n.tr;
    35
    46import java.awt.event.ActionEvent;
    57import java.awt.event.KeyEvent;
    68import java.io.IOException;
     9import java.util.Collection;
     10import java.util.List;
    711
    812import javax.swing.JOptionPane;
     13import javax.swing.SwingUtilities;
    914
    1015import org.openstreetmap.josm.Main;
     16import org.openstreetmap.josm.data.osm.Changeset;
     17import org.openstreetmap.josm.data.osm.UserInfo;
    1118import org.openstreetmap.josm.gui.ExceptionDialogUtil;
    1219import org.openstreetmap.josm.gui.PleaseWaitRunnable;
    13 import org.openstreetmap.josm.io.ChangesetProcessingType;
    14 import org.openstreetmap.josm.io.OsmApi;
     20import org.openstreetmap.josm.gui.io.CloseChangesetDialog;
     21import org.openstreetmap.josm.gui.io.CloseChangesetTask;
     22import org.openstreetmap.josm.io.ChangesetQuery;
     23import org.openstreetmap.josm.io.OsmServerChangesetReader;
     24import org.openstreetmap.josm.io.OsmServerUserInfoReader;
    1525import org.openstreetmap.josm.io.OsmTransferException;
    1626import org.openstreetmap.josm.tools.Shortcut;
    1727import org.xml.sax.SAXException;
    1828
    19 import static org.openstreetmap.josm.tools.I18n.tr;
     29public class CloseChangesetAction extends JosmAction{
    2030
    21 public class StopChangesetAction extends JosmAction{
    22 
    23     public StopChangesetAction() {
    24         super(tr("Close current changeset"),
     31    public CloseChangesetAction() {
     32        super(tr("Close open changesets"),
    2533                "closechangeset",
    26                 tr("Close the current changeset ..."),
     34                tr("Closes open changesets"),
    2735                Shortcut.registerShortcut(
    2836                        "system:closechangeset",
    29                         tr("File: {0}", tr("Close the current changeset ...")),
     37                        tr("File: {0}", tr("Closes open changesets")),
    3038                        KeyEvent.VK_Q,
    3139                        Shortcut.GROUP_HOTKEY + Shortcut.GROUPS_ALT2
     
    3644    }
    3745    public void actionPerformed(ActionEvent e) {
    38         if (OsmApi.getOsmApi().getCurrentChangeset() == null) {
     46        Main.worker.submit(new DownloadOpenChangesetsTask());
     47    }
     48
     49
     50    protected void onPostDownloadOpenChangesets(DownloadOpenChangesetsTask task) {
     51        if (task.isCancelled() || task.getLastException() != null) return;
     52
     53        List<Changeset> openChangesets = task.getChangesets();
     54        if (openChangesets.isEmpty()) {
    3955            JOptionPane.showMessageDialog(
    4056                    Main.parent,
    41                     tr("There is currently no changeset open."),
    42                     tr("No open changeset"),
     57                    tr("There are no open changesets"),
     58                    tr("No open changesets"),
    4359                    JOptionPane.INFORMATION_MESSAGE
    4460            );
    4561            return;
    4662        }
    47         Main.worker.submit(new StopChangesetActionTask());
     63
     64        CloseChangesetDialog dialog = new CloseChangesetDialog();
     65        dialog.setChangesets(openChangesets);
     66        dialog.setVisible(true);
     67        if (dialog.isCanceled())
     68            return;
     69
     70        Collection<Changeset> changesetsToClose = dialog.getSelectedChangesets();
     71        CloseChangesetTask closeChangesetTask = new CloseChangesetTask(changesetsToClose);
     72        Main.worker.submit(closeChangesetTask);
    4873    }
    4974
    50     @Override
    51     protected void updateEnabledState() {
    52         setEnabled(Main.map != null && OsmApi.getOsmApi().getCurrentChangeset() != null);
    53     }
    5475
    55     static class StopChangesetActionTask extends PleaseWaitRunnable {
     76    private class DownloadOpenChangesetsTask extends PleaseWaitRunnable {
     77
    5678        private boolean cancelled;
     79        private OsmServerChangesetReader reader;
     80        private List<Changeset> changesets;
    5781        private Exception lastException;
     82        private UserInfo userInfo;
    5883
    59         public StopChangesetActionTask() {
    60             super(tr("Closing changeset"), false /* don't ignore exceptions */);
     84        /**
     85         *
     86         * @param model provides the user id of the current user and accepts the changesets
     87         * after download
     88         */
     89        public DownloadOpenChangesetsTask() {
     90            super(tr("Downloading open changesets ...", false /* don't ignore exceptions */));
    6191        }
     92
    6293        @Override
    6394        protected void cancel() {
    6495            this.cancelled = true;
    65             OsmApi.getOsmApi().cancel();
    66 
     96            reader.cancel();
    6797        }
    6898
    6999        @Override
    70100        protected void finish() {
    71             if (cancelled)
    72                 return;
    73             if (lastException != null) {
    74                 ExceptionDialogUtil.explainException(lastException);
    75             }
     101            SwingUtilities.invokeLater(
     102                    new Runnable() {
     103                        public void run() {
     104                            if (lastException != null) {
     105                                ExceptionDialogUtil.explainException(lastException);
     106                            }
     107                            onPostDownloadOpenChangesets(DownloadOpenChangesetsTask.this);
     108                        }
     109                    }
     110            );
     111        }
     112
     113        /**
     114         * Fetch the user info from the server. This is necessary if we don't know
     115         * the users id yet
     116         *
     117         * @return the user info
     118         * @throws OsmTransferException thrown in case of any communication exception
     119         */
     120        protected UserInfo fetchUserInfo() throws OsmTransferException {
     121            OsmServerUserInfoReader reader = new OsmServerUserInfoReader();
     122            return reader.fetchUserInfo(getProgressMonitor().createSubTaskMonitor(1, false));
    76123        }
    77124
     
    79126        protected void realRun() throws SAXException, IOException, OsmTransferException {
    80127            try {
    81                 OsmApi.getOsmApi().stopChangeset(ChangesetProcessingType.USE_EXISTING_AND_CLOSE, getProgressMonitor().createSubTaskMonitor(1, false));
     128                userInfo = fetchUserInfo();
     129                if (cancelled)
     130                    return;
     131                reader = new OsmServerChangesetReader();
     132                ChangesetQuery query = new ChangesetQuery().forUser(userInfo.getId()).beingOpen();
     133                changesets = reader.queryChangesets(
     134                        query,
     135                        getProgressMonitor().createSubTaskMonitor(1, false /* not internal */)
     136                );
    82137            } catch(Exception e) {
    83138                if (cancelled)
     
    86141            }
    87142        }
     143
     144        public boolean isCancelled() {
     145            return cancelled;
     146        }
     147
     148        public List<Changeset> getChangesets() {
     149            return changesets;
     150        }
     151
     152        public Exception getLastException() {
     153            return lastException;
     154        }
    88155    }
    89156}
  • trunk/src/org/openstreetmap/josm/actions/UploadAction.java

    r2096 r2115  
    2828import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    2929import org.openstreetmap.josm.gui.progress.ProgressMonitor;
    30 import org.openstreetmap.josm.io.ChangesetProcessingType;
    3130import org.openstreetmap.josm.io.OsmApi;
    3231import org.openstreetmap.josm.io.OsmApiException;
     
    176175                        Main.map.mapView.getEditLayer(),
    177176                        apiData.getPrimitives(),
    178                         UploadConfirmationHook.getUploadDialog().getChangeset(),
    179                         UploadConfirmationHook.getUploadDialog().getChangesetProcessingType()
     177                        UploadDialog.getUploadDialog().getChangeset(),
     178                        UploadDialog.getUploadDialog().isDoCloseAfterUpload()
    180179                )
    181180        );
     
    244243        );
    245244        switch(ret) {
    246         case JOptionPane.CLOSED_OPTION: return;
    247         case JOptionPane.CANCEL_OPTION: return;
    248         case 0: synchronizePrimitive(primitiveType, id); break;
    249         case 1: synchronizeDataSet(); break;
    250         default:
    251             // should not happen
    252             throw new IllegalStateException(tr("unexpected return value. Got {0}", ret));
     245            case JOptionPane.CLOSED_OPTION: return;
     246            case JOptionPane.CANCEL_OPTION: return;
     247            case 0: synchronizePrimitive(primitiveType, id); break;
     248            case 1: synchronizeDataSet(); break;
     249            default:
     250                // should not happen
     251                throw new IllegalStateException(tr("unexpected return value. Got {0}", ret));
    253252        }
    254253    }
     
    284283        );
    285284        switch(ret) {
    286         case JOptionPane.CLOSED_OPTION: return;
    287         case 1: return;
    288         case 0: synchronizeDataSet(); break;
    289         default:
    290             // should not happen
    291             throw new IllegalStateException(tr("unexpected return value. Got {0}", ret));
     285            case JOptionPane.CLOSED_OPTION: return;
     286            case 1: return;
     287            case 0: synchronizeDataSet(); break;
     288            default:
     289                // should not happen
     290                throw new IllegalStateException(tr("unexpected return value. Got {0}", ret));
    292291        }
    293292    }
     
    457456
    458457    static public class UploadConfirmationHook implements UploadHook {
    459         static private UploadDialog uploadDialog;
    460 
    461         static public UploadDialog getUploadDialog() {
    462             if (uploadDialog == null) {
    463                 uploadDialog = new UploadDialog();
    464             }
    465             return uploadDialog;
    466         }
    467458
    468459        public boolean checkUpload(APIDataSet apiData) {
    469             final UploadDialog dialog = getUploadDialog();
     460            final UploadDialog dialog = UploadDialog.getUploadDialog();
    470461            dialog.setUploadedPrimitives(apiData.getPrimitivesToAdd(),apiData.getPrimitivesToUpdate(), apiData.getPrimitivesToDelete());
    471462            dialog.setVisible(true);
     
    477468    }
    478469
    479     public UploadDiffTask createUploadTask(OsmDataLayer layer, Collection<OsmPrimitive> toUpload, Changeset changeset, ChangesetProcessingType changesetProcessingType) {
    480         return new UploadDiffTask(layer, toUpload, changeset, changesetProcessingType);
    481     }
    482 
     470    public UploadDiffTask createUploadTask(OsmDataLayer layer, Collection<OsmPrimitive> toUpload, Changeset changeset, boolean closeChangesetAfterUpload) {
     471        return new UploadDiffTask(layer, toUpload, changeset, closeChangesetAfterUpload);
     472    }
     473
     474    /**
     475     * The task for uploading a collection of primitives
     476     *
     477     */
    483478    public class UploadDiffTask extends  PleaseWaitRunnable {
    484479        private boolean uploadCancelled = false;
     
    488483        private OsmDataLayer layer;
    489484        private Changeset changeset;
    490         private ChangesetProcessingType changesetProcessingType;
    491 
    492         private UploadDiffTask(OsmDataLayer layer, Collection <OsmPrimitive> toUpload, Changeset changeset, ChangesetProcessingType changesetProcessingType) {
     485        private boolean closeChangesetAfterUpload;
     486
     487        /**
     488         *
     489         * @param layer  the OSM data layer for which data is uploaded
     490         * @param toUpload the collection of primitives to upload
     491         * @param changeset the changeset to use for uploading
     492         * @param closeChangesetAfterUpload true, if the changeset is to be closed after uploading
     493         */
     494        private UploadDiffTask(OsmDataLayer layer, Collection <OsmPrimitive> toUpload, Changeset changeset, boolean closeChangesetAfterUpload) {
    493495            super(tr("Uploading data for layer ''{0}''", layer.getName()),false /* don't ignore exceptions */);
    494496            this.toUpload = toUpload;
    495497            this.layer = layer;
    496498            this.changeset = changeset;
    497             this.changesetProcessingType = changesetProcessingType == null ? ChangesetProcessingType.USE_NEW_AND_CLOSE : changesetProcessingType;
     499            this.closeChangesetAfterUpload = closeChangesetAfterUpload;
    498500        }
    499501
     
    502504            try {
    503505                ProgressMonitor monitor = progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false);
    504                 writer.uploadOsm(layer.data.version, toUpload, changeset,changesetProcessingType, monitor);
     506                writer.uploadOsm(layer.data.version, toUpload, changeset,closeChangesetAfterUpload, monitor);
    505507            } catch (Exception sxe) {
    506508                if (uploadCancelled) {
     
    525527                handleFailedUpload(lastException);
    526528            } else {
     529                // run post upload action on the layer
     530                //
    527531                layer.onPostUploadToServer();
     532                // refresh changeset dialog with the updated changeset
     533                //
     534                UploadDialog.getUploadDialog().setOrUpdateChangeset(changeset);
    528535            }
    529536        }
  • trunk/src/org/openstreetmap/josm/data/osm/Changeset.java

    r2081 r2115  
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
    6 import javax.print.attribute.standard.MediaSize.Other;
    7 
     6import java.util.Collection;
     7import java.util.Date;
     8import java.util.HashMap;
     9import java.util.Map;
     10
     11import org.openstreetmap.josm.data.coor.LatLon;
    812import org.openstreetmap.josm.data.osm.visitor.Visitor;
    913
     
    1317 *
    1418 */
    15 public final class Changeset extends OsmPrimitive {
     19public final class Changeset implements Tagged {
     20    /** the changeset id */
     21    private long id;
     22    /** the user who owns the changeset */
     23    private User user;
     24    /** date this changeset was created at */
     25    private Date createdAt;
     26    /** the date this changeset was closed at*/
     27    private Date closedAt;
     28    /** indicates whether this changeset is still open or not */
     29    private boolean open;
     30    /** the min. coordinates of the bounding box of this changeset */
     31    private LatLon min;
     32    /** the max. coordinates of the bounding box of this changeset */
     33    private LatLon max;
     34    /** the map of tags */
     35    private Map<String,String> tags;
     36    /** indicates whether this changeset is incomplete. For an
     37     * incomplete changeset we only know its id
     38     */
     39    private boolean incomplete;
     40
     41
    1642    /**
    17      * Time of last modification to this object. This is not set by JOSM but
    18      * read from the server and delivered back to the server unmodified.
     43     * Creates a new changeset with id 0.
    1944     */
    20     public String end_timestamp = null;
     45    public Changeset() {
     46        this.id = 0;
     47        this.tags = new HashMap<String, String>();
     48    }
    2149
    2250    /**
    23      * Time of first modification to this object. This is not set by JOSM but
    24      * read from the server and delivered back to the server unmodified.
     51     * Creates a changeset with id <code>id</code>. If id > 0, sets incomplete to true.
     52     *
     53     * @param id the id
    2554     */
    26     public String start_timestamp = null;
    27 
    28     public Changeset() {
    29         super(0);
    30     }
    31 
    3255    public Changeset(long id) {
    33         super(id);
    34     }
    35 
    36     public Changeset(Changeset clone){
    37         super(clone.getId());
    38         cloneFrom(clone);
    39     }
    40 
    41     @Override
     56        this.id = id;
     57        this.incomplete = id > 0;
     58        this.tags = new HashMap<String, String>();
     59    }
     60
     61    /**
     62     * Creates a clone of <code>other</code>
     63     *
     64     * @param other the other changeset. If null, creates a new changeset with id 0.
     65     */
     66    public Changeset(Changeset other) {
     67        if (other == null) {
     68            this.id = 0;
     69            this.tags = new HashMap<String, String>();
     70        } else if (other.isIncomplete()) {
     71            setId(other.getId());
     72            this.incomplete = true;
     73        } else {
     74            cloneFrom(other);
     75            this.incomplete = false;
     76        }
     77    }
     78
     79    public void cloneFrom(Changeset other) {
     80        setId(other.getId());
     81        setUser(other.getUser());
     82        setCreatedAt(other.getCreatedAt());
     83        setClosedAt(other.getClosedAt());
     84        setMin(other.getMin());
     85        setMax(other.getMax());
     86        setKeys(other.getKeys());
     87        setOpen(other.isOpen());
     88    }
     89
    4290    public void visit(Visitor v) {
    4391        v.visit(this);
    4492    }
    4593
    46     public int compareTo(OsmPrimitive other) {
    47         if (other instanceof Changeset) return Long.valueOf(getId()).compareTo(other.getId());
    48         return 1;
    49     }
    50 
    51     @Override
     94    public int compareTo(Changeset other) {
     95        return Long.valueOf(getId()).compareTo(other.getId());
     96    }
     97
    5298    public String getName() {
    5399        // no translation
     
    55101    }
    56102
    57     @Override
    58103    public String getLocalName(){
    59104        return tr("Changeset {0}",getId());
    60105    }
    61106
    62     @Override
    63107    public String getDisplayName(NameFormatter formatter) {
    64108        return formatter.format(this);
    65109    }
    66110
    67 
    68     @Override public void cloneFrom(OsmPrimitive osm) {
    69         super.cloneFrom(osm);
     111    public long getId() {
     112        return id;
     113    }
     114
     115    public void setId(long id) {
     116        this.id = id;
     117    }
     118
     119    public User getUser() {
     120        return user;
     121    }
     122
     123    public void setUser(User user) {
     124        this.user = user;
     125    }
     126
     127    public Date getCreatedAt() {
     128        return createdAt;
     129    }
     130
     131    public void setCreatedAt(Date createdAt) {
     132        this.createdAt = createdAt;
     133    }
     134
     135    public Date getClosedAt() {
     136        return closedAt;
     137    }
     138
     139    public void setClosedAt(Date closedAt) {
     140        this.closedAt = closedAt;
     141    }
     142
     143    public boolean isOpen() {
     144        return open;
     145    }
     146
     147    public void setOpen(boolean open) {
     148        this.open = open;
     149    }
     150
     151    public LatLon getMin() {
     152        return min;
     153    }
     154
     155    public void setMin(LatLon min) {
     156        this.min = min;
     157    }
     158
     159    public LatLon getMax() {
     160        return max;
     161    }
     162
     163    public void setMax(LatLon max) {
     164        this.max = max;
     165    }
     166
     167    public Map<String, String> getKeys() {
     168        return tags;
     169    }
     170
     171    public void setKeys(Map<String, String> keys) {
     172        this.tags = keys;
     173    }
     174
     175    public boolean isIncomplete() {
     176        return incomplete;
     177    }
     178
     179    public void setIncomplete(boolean incomplete) {
     180        this.incomplete = incomplete;
     181    }
     182
     183    public void put(String key, String value) {
     184        this.tags.put(key, value);
     185    }
     186
     187    public String get(String key) {
     188        return this.tags.get(key);
     189    }
     190
     191    public void remove(String key) {
     192        this.tags.remove(key);
     193    }
     194
     195    public boolean hasEqualSemanticAttributes(Changeset other) {
     196        if (other == null)
     197            return false;
     198        if (closedAt == null) {
     199            if (other.closedAt != null)
     200                return false;
     201        } else if (!closedAt.equals(other.closedAt))
     202            return false;
     203        if (createdAt == null) {
     204            if (other.createdAt != null)
     205                return false;
     206        } else if (!createdAt.equals(other.createdAt))
     207            return false;
     208        if (id != other.id)
     209            return false;
     210        if (max == null) {
     211            if (other.max != null)
     212                return false;
     213        } else if (!max.equals(other.max))
     214            return false;
     215        if (min == null) {
     216            if (other.min != null)
     217                return false;
     218        } else if (!min.equals(other.min))
     219            return false;
     220        if (open != other.open)
     221            return false;
     222        if (tags == null) {
     223            if (other.tags != null)
     224                return false;
     225        } else if (!tags.equals(other.tags))
     226            return false;
     227        if (user == null) {
     228            if (other.user != null)
     229                return false;
     230        } else if (!user.equals(other.user))
     231            return false;
     232        return true;
     233    }
     234
     235    @Override
     236    public int hashCode() {
     237        final int prime = 31;
     238        int result = 1;
     239        result = prime * result + (int) (id ^ (id >>> 32));
     240        if (id > 0)
     241            return prime * result + getClass().hashCode();
     242        result = prime * result + ((closedAt == null) ? 0 : closedAt.hashCode());
     243        result = prime * result + ((createdAt == null) ? 0 : createdAt.hashCode());
     244        result = prime * result + ((max == null) ? 0 : max.hashCode());
     245        result = prime * result + ((min == null) ? 0 : min.hashCode());
     246        result = prime * result + (open ? 1231 : 1237);
     247        result = prime * result + ((tags == null) ? 0 : tags.hashCode());
     248        result = prime * result + ((user == null) ? 0 : user.hashCode());
     249        return result;
     250    }
     251
     252    @Override
     253    public boolean equals(Object obj) {
     254        if (this == obj)
     255            return true;
     256        if (obj == null)
     257            return false;
     258        if (getClass() != obj.getClass())
     259            return false;
     260        Changeset other = (Changeset) obj;
     261        if (this.id > 0 && other.id == this.id)
     262            return true;
     263        if (closedAt == null) {
     264            if (other.closedAt != null)
     265                return false;
     266        } else if (!closedAt.equals(other.closedAt))
     267            return false;
     268        if (createdAt == null) {
     269            if (other.createdAt != null)
     270                return false;
     271        } else if (!createdAt.equals(other.createdAt))
     272            return false;
     273        if (id != other.id)
     274            return false;
     275        if (max == null) {
     276            if (other.max != null)
     277                return false;
     278        } else if (!max.equals(other.max))
     279            return false;
     280        if (min == null) {
     281            if (other.min != null)
     282                return false;
     283        } else if (!min.equals(other.min))
     284            return false;
     285        if (open != other.open)
     286            return false;
     287        if (tags == null) {
     288            if (other.tags != null)
     289                return false;
     290        } else if (!tags.equals(other.tags))
     291            return false;
     292        if (user == null) {
     293            if (other.user != null)
     294                return false;
     295        } else if (!user.equals(other.user))
     296            return false;
     297        return true;
     298    }
     299
     300    public boolean hasKeys() {
     301        return !tags.keySet().isEmpty();
     302    }
     303
     304    public Collection<String> keySet() {
     305        return tags.keySet();
    70306    }
    71307}
  • trunk/src/org/openstreetmap/josm/data/osm/DataSet.java

    r2077 r2115  
    326326        Collection<? extends OsmPrimitive> primitives = null;
    327327        switch(type) {
    328         case NODE: primitives = nodes; break;
    329         case WAY: primitives = ways; break;
    330         case RELATION: primitives = relations; break;
    331         case CHANGESET: throw new IllegalArgumentException(tr("unsupported value ''{0}'' or parameter ''{1}''", type, "type"));
     328            case NODE: primitives = nodes; break;
     329            case WAY: primitives = ways; break;
     330            case RELATION: primitives = relations; break;
    332331        }
    333332        for (OsmPrimitive primitive : primitives) {
  • trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java

    r2083 r2115  
    3333 * @author imi
    3434 */
    35 abstract public class OsmPrimitive implements Comparable<OsmPrimitive> {
     35abstract public class OsmPrimitive implements Comparable<OsmPrimitive>, Tagged {
    3636
    3737    static public <T extends OsmPrimitive>  List<T> getFilteredList(Collection<OsmPrimitive> list, Class<T> type) {
  • trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitiveType.java

    r2077 r2115  
    77    NODE ("node"),
    88    WAY  ("way"),
    9     RELATION ("relation"),
    10     CHANGESET ("changeset");
     9    RELATION ("relation");
    1110
    1211    private String apiTypeName;
     
    3534        if (cls.equals(Way.class)) return WAY;
    3635        if (cls.equals(Relation.class)) return RELATION;
    37         if (cls.equals(Changeset.class)) return CHANGESET;
    3836        throw new IllegalArgumentException(tr("parameter ''{0}'' is not an acceptable class, got ''{1}''", "cls", cls.toString()));
    3937    }
  • trunk/src/org/openstreetmap/josm/gui/MainMenu.java

    r2061 r2115  
    5858import org.openstreetmap.josm.actions.ShowStatusReportAction;
    5959import org.openstreetmap.josm.actions.SplitWayAction;
    60 import org.openstreetmap.josm.actions.StopChangesetAction;
     60import org.openstreetmap.josm.actions.CloseChangesetAction;
    6161import org.openstreetmap.josm.actions.ToggleGPXLinesAction;
    6262import org.openstreetmap.josm.actions.UnGlueAction;
     
    100100    public final DownloadAction download = new DownloadAction();
    101101    public final DownloadReferrersAction downloadReferrers = new DownloadReferrersAction();
    102     public final StopChangesetAction stopChangesetAction = new StopChangesetAction();
     102    public final CloseChangesetAction closeChangesetAction = new CloseChangesetAction();
    103103    public final JosmAction update = new UpdateDataAction();
    104104    public final JosmAction updateSelection = new UpdateSelectionAction();
     
    208208        add(fileMenu, update);
    209209        add(fileMenu, updateSelection);
    210         add(fileMenu, stopChangesetAction);
     210        add(fileMenu, closeChangesetAction);
    211211        fileMenu.addSeparator();
    212212        add(fileMenu, exit);
  • trunk/src/org/openstreetmap/josm/gui/conflict/tags/PasteTagsConflictResolverDialog.java

    r2070 r2115  
    8080        resolvers = new HashMap<OsmPrimitiveType, TagConflictResolver>();
    8181        for (OsmPrimitiveType type: OsmPrimitiveType.values()) {
    82             if (type.equals(OsmPrimitiveType.CHANGESET)) {
    83                 continue;
    84             }
    8582            resolvers.put(type, new TagConflictResolver());
    8683            resolvers.get(type).getModel().addPropertyChangeListener(this);
     
    148145        String msg = "";
    149146        switch(type) {
    150         case NODE: msg= trn("{0} node", "{0} nodes", count, count); break;
    151         case WAY: msg= trn("{0} way", "{0} ways", count, count); break;
    152         case RELATION: msg= trn("{0} relation", "{0} relations", count, count); break;
     147            case NODE: msg= trn("{0} node", "{0} nodes", count, count); break;
     148            case WAY: msg= trn("{0} way", "{0} ways", count, count); break;
     149            case RELATION: msg= trn("{0} relation", "{0} relations", count, count); break;
    153150        }
    154151        return msg;
     
    446443                String msg = "";
    447444                switch(type) {
    448                 case NODE: msg = trn("{0} node", "{0} nodes", numPrimitives,numPrimitives); break;
    449                 case WAY: msg = trn("{0} way", "{0} ways", numPrimitives, numPrimitives); break;
    450                 case RELATION: msg = trn("{0} relation", "{0} relations", numPrimitives, numPrimitives); break;
     445                    case NODE: msg = trn("{0} node", "{0} nodes", numPrimitives,numPrimitives); break;
     446                    case WAY: msg = trn("{0} way", "{0} ways", numPrimitives, numPrimitives); break;
     447                    case RELATION: msg = trn("{0} relation", "{0} relations", numPrimitives, numPrimitives); break;
    451448                }
    452449                text = text.equals("") ? msg : text + ", " + msg;
     
    472469                String msg = "";
    473470                switch(type) {
    474                 case NODE: msg = trn("{0} node", "{0} nodes", numPrimitives,numPrimitives); break;
    475                 case WAY: msg = trn("{0} way", "{0} ways", numPrimitives, numPrimitives); break;
    476                 case RELATION: msg = trn("{0} relation", "{0} relations", numPrimitives, numPrimitives); break;
     471                    case NODE: msg = trn("{0} node", "{0} nodes", numPrimitives,numPrimitives); break;
     472                    case WAY: msg = trn("{0} way", "{0} ways", numPrimitives, numPrimitives); break;
     473                    case RELATION: msg = trn("{0} relation", "{0} relations", numPrimitives, numPrimitives); break;
    477474                }
    478475                text = text.equals("") ? msg : text + ", " + msg;
     
    491488
    492489                switch(column) {
    493                 case 0: renderNumTags(info); break;
    494                 case 1: renderFrom(info); break;
    495                 case 2: renderTo(info); break;
     490                    case 0: renderNumTags(info); break;
     491                    case 1: renderFrom(info); break;
     492                    case 2: renderTo(info); break;
    496493                }
    497494            }
  • trunk/src/org/openstreetmap/josm/gui/io/SaveLayersDialog.java

    r2096 r2115  
    3333import org.openstreetmap.josm.Main;
    3434import org.openstreetmap.josm.actions.UploadAction;
    35 import org.openstreetmap.josm.actions.UploadAction.UploadConfirmationHook;
    3635import org.openstreetmap.josm.gui.ExceptionDialogUtil;
    3736import org.openstreetmap.josm.gui.SideButton;
     
    299298        public void cancel() {
    300299            switch(model.getMode()) {
    301             case EDITING_DATA: cancelWhenInEditingModel(); break;
    302             case UPLOADING_AND_SAVING: cancelSafeAndUploadTask(); break;
     300                case EDITING_DATA: cancelWhenInEditingModel(); break;
     301                case UPLOADING_AND_SAVING: cancelSafeAndUploadTask(); break;
    303302            }
    304303        }
     
    334333                Mode mode = (Mode)evt.getNewValue();
    335334                switch(mode) {
    336                 case EDITING_DATA: setEnabled(true); break;
    337                 case UPLOADING_AND_SAVING: setEnabled(false); break;
     335                    case EDITING_DATA: setEnabled(true); break;
     336                    case UPLOADING_AND_SAVING: setEnabled(false); break;
    338337                }
    339338            }
     
    368367                SaveLayersModel.Mode mode = (SaveLayersModel.Mode)evt.getNewValue();
    369368                switch(mode) {
    370                 case EDITING_DATA: setEnabled(true); break;
    371                 case UPLOADING_AND_SAVING: setEnabled(false); break;
     369                    case EDITING_DATA: setEnabled(true); break;
     370                    case UPLOADING_AND_SAVING: setEnabled(false); break;
    372371                }
    373372            }
     
    411410                        layerInfo.getLayer(),
    412411                        monitor,
    413                         UploadAction.UploadConfirmationHook.getUploadDialog().getChangeset(),
    414                         UploadAction.UploadConfirmationHook.getUploadDialog().getChangesetProcessingType()
     412                        UploadDialog.getUploadDialog().getChangeset(),
     413                        UploadDialog.getUploadDialog().isDoCloseAfterUpload()
    415414                );
    416415                currentFuture = worker.submit(currentTask);
  • trunk/src/org/openstreetmap/josm/gui/io/UploadDialog.java

    r2081 r2115  
    66
    77import java.awt.BorderLayout;
     8import java.awt.Component;
    89import java.awt.Dimension;
    910import java.awt.FlowLayout;
     
    1213import java.awt.event.ActionEvent;
    1314import java.awt.event.ActionListener;
     15import java.awt.event.ItemEvent;
     16import java.awt.event.ItemListener;
    1417import java.awt.event.WindowAdapter;
    1518import java.awt.event.WindowEvent;
     19import java.text.SimpleDateFormat;
    1620import java.util.ArrayList;
    17 import java.util.HashMap;
     21import java.util.Collection;
     22import java.util.Collections;
    1823import java.util.LinkedList;
    1924import java.util.List;
    20 import java.util.Map;
    2125
    2226import javax.swing.AbstractAction;
    2327import javax.swing.AbstractListModel;
    2428import javax.swing.BorderFactory;
    25 import javax.swing.BoxLayout;
    2629import javax.swing.ButtonGroup;
     30import javax.swing.DefaultComboBoxModel;
     31import javax.swing.ImageIcon;
     32import javax.swing.JButton;
    2733import javax.swing.JCheckBox;
     34import javax.swing.JComboBox;
    2835import javax.swing.JDialog;
    2936import javax.swing.JLabel;
     
    3441import javax.swing.JScrollPane;
    3542import javax.swing.JTabbedPane;
     43import javax.swing.ListCellRenderer;
     44import javax.swing.UIManager;
    3645import javax.swing.event.ChangeEvent;
    3746import javax.swing.event.ChangeListener;
     47import javax.swing.event.ListDataEvent;
     48import javax.swing.event.ListDataListener;
    3849
    3950import org.openstreetmap.josm.Main;
     
    4657import org.openstreetmap.josm.gui.tagging.TagEditorPanel;
    4758import org.openstreetmap.josm.gui.tagging.TagModel;
    48 import org.openstreetmap.josm.io.ChangesetProcessingType;
    4959import org.openstreetmap.josm.io.OsmApi;
    5060import org.openstreetmap.josm.tools.GBC;
     
    6070public class UploadDialog extends JDialog {
    6171
     72
    6273    public static final String HISTORY_KEY = "upload.comment.history";
     74
     75    /**  the unique instance of the upload dialog */
     76    static private UploadDialog uploadDialog;
     77
     78    /**
     79     * Replies the unique instance of the upload dialog
     80     *
     81     * @return the unique instance of the upload dialog
     82     */
     83    static public UploadDialog getUploadDialog() {
     84        if (uploadDialog == null) {
     85            uploadDialog = new UploadDialog();
     86        }
     87        return uploadDialog;
     88    }
    6389
    6490    /** the list with the added primitives */
     
    77103    private JPanel pnlLists;
    78104    /** checkbox for selecting whether an atomic upload is to be used  */
    79     private JCheckBox cbUseAtomicUpload;
    80     /** input field for changeset comment */
    81     private SuggestingJHistoryComboBox cmt;
    82     /** ui component for editing changeset tags */
    83105    private TagEditorPanel tagEditorPanel;
    84106    /** the tabbed pane used below of the list of primitives  */
    85107    private JTabbedPane southTabbedPane;
    86     /** the button group with the changeset processing types */
    87     private ButtonGroup bgChangesetHandlingOptions;
    88     /** radio buttons for selecting a changeset processing type */
    89     private Map<ChangesetProcessingType, JRadioButton> rbChangesetHandlingOptions;
     108
     109    private ChangesetSelectionPanel pnlChangesetSelection;
    90110
    91111    private boolean canceled = false;
     
    104124    }
    105125
    106     /**
    107      * builds the panel with the ui components for controlling how the changeset
    108      * should be processed (opening/closing a changeset)
    109      *
    110      * @return the panel with the ui components for controlling how the changeset
    111      * should be processed
    112      */
    113     protected JPanel buildChangesetHandlingControlPanel() {
    114         JPanel pnl = new JPanel();
    115         pnl.setLayout(new BoxLayout(pnl, BoxLayout.Y_AXIS));
    116         bgChangesetHandlingOptions = new ButtonGroup();
    117         rbChangesetHandlingOptions = new HashMap<ChangesetProcessingType, JRadioButton>();
    118         ChangesetProcessingTypeChangedAction a = new ChangesetProcessingTypeChangedAction();
    119         for(ChangesetProcessingType type: ChangesetProcessingType.values()) {
    120             rbChangesetHandlingOptions.put(type, new JRadioButton());
    121             rbChangesetHandlingOptions.get(type).addActionListener(a);
    122         }
    123         JRadioButton rb = rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_NEW_AND_CLOSE);
    124         rb.setText(tr("Use a new changeset and close it"));
    125         rb.setToolTipText(tr("Select to upload the data using a new changeset and to close the changeset after the upload"));
    126 
    127         rb = rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_NEW_AND_LEAVE_OPEN);
    128         rb.setText(tr("Use a new changeset and leave it open"));
    129         rb.setToolTipText(tr("Select to upload the data using a new changeset and to leave the changeset open after the upload"));
    130 
    131         pnl.add(new JLabel(tr("Upload to a new or to an existing changeset?")));
    132         pnl.add(rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_NEW_AND_CLOSE));
    133         pnl.add(rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_NEW_AND_LEAVE_OPEN));
    134         pnl.add(rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_EXISTING_AND_CLOSE));
    135         pnl.add(rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_EXISTING_AND_LEAVE_OPEN));
    136 
    137         for(ChangesetProcessingType type: ChangesetProcessingType.values()) {
    138             rbChangesetHandlingOptions.get(type).setVisible(false);
    139             bgChangesetHandlingOptions.add(rbChangesetHandlingOptions.get(type));
    140         }
    141         return pnl;
    142     }
    143 
    144     /**
    145      * build the panel with the widgets for controlling how the changeset should be processed
    146      * (atomic upload or not, comment, opening/closing changeset)
    147      *
    148      * @return
    149      */
    150     protected JPanel buildChangesetControlPanel() {
    151         JPanel pnl = new JPanel();
    152         pnl.setLayout(new BoxLayout(pnl, BoxLayout.Y_AXIS));
    153         pnl.add(cbUseAtomicUpload = new JCheckBox(tr("upload all changes in one request")));
    154         cbUseAtomicUpload.setToolTipText(tr("Enable to upload all changes in one request, disable to use one request per changed primitive"));
    155         boolean useAtomicUpload = Main.pref.getBoolean("osm-server.atomic-upload", true);
    156         cbUseAtomicUpload.setSelected(useAtomicUpload);
    157         cbUseAtomicUpload.setEnabled(OsmApi.getOsmApi().hasSupportForDiffUploads());
    158 
    159         pnl.add(buildChangesetHandlingControlPanel());
    160         return pnl;
    161     }
    162 
    163     /**
    164      * builds the upload control panel
    165      *
    166      * @return
    167      */
    168     protected JPanel buildUploadControlPanel() {
    169         JPanel pnl = new JPanel();
    170         pnl.setLayout(new GridBagLayout());
    171         pnl.add(new JLabel(tr("Provide a brief comment for the changes you are uploading:")), GBC.eol().insets(0, 5, 10, 3));
    172         cmt = new SuggestingJHistoryComboBox();
    173         List<String> cmtHistory = new LinkedList<String>(Main.pref.getCollection(HISTORY_KEY, new LinkedList<String>()));
    174         cmt.setHistory(cmtHistory);
    175         cmt.getEditor().addActionListener(
    176                 new ActionListener() {
    177                     public void actionPerformed(ActionEvent e) {
    178                         TagModel tm = tagEditorPanel.getModel().get("comment");
    179                         if (tm == null) {
    180                             tagEditorPanel.getModel().add(new TagModel("comment", cmt.getText()));
    181                         } else {
    182                             tm.setValue(cmt.getText());
    183                         }
    184                         tagEditorPanel.getModel().fireTableDataChanged();
    185                     }
    186                 }
    187         );
    188         pnl.add(cmt, GBC.eol().fill(GBC.HORIZONTAL));
    189 
    190         // configuration options for atomic upload
    191         //
    192         pnl.add(buildChangesetControlPanel(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
    193         return pnl;
    194     }
    195126
    196127    protected JPanel buildContentPanel() {
     
    211142        //
    212143        southTabbedPane = new JTabbedPane();
    213         southTabbedPane.add(buildUploadControlPanel());
     144        southTabbedPane.add(new JPanel());
    214145        tagEditorPanel = new TagEditorPanel();
    215146        southTabbedPane.add(tagEditorPanel);
     147        southTabbedPane.setComponentAt(0, pnlChangesetSelection = new ChangesetSelectionPanel());
    216148        southTabbedPane.setTitleAt(0, tr("Settings"));
    217149        southTabbedPane.setTitleAt(1, tr("Tags of new changeset"));
     
    340272
    341273    /**
    342      * Replies true if a valid changeset comment has been entered in this dialog
    343      *
    344      * @return true if a valid changeset comment has been entered in this dialog
    345      */
    346     public boolean hasChangesetComment() {
    347         if (!getChangesetProcessingType().isUseNew())
    348             return true;
    349         return cmt.getText().trim().length() >= 3;
    350     }
    351 
    352     /**
    353274     * Remembers the user input in the preference settings
    354275     */
    355276    public void rememberUserInput() {
    356         // store the history of comments
    357         cmt.addCurrentItemToHistory();
    358         Main.pref.putCollection(HISTORY_KEY, cmt.getHistory());
    359         Main.pref.put("osm-server.atomic-upload", cbUseAtomicUpload.isSelected());
     277        pnlChangesetSelection.rememberUserInput();
    360278    }
    361279
     
    365283    public void startUserInput() {
    366284        tagEditorPanel.initAutoCompletion(Main.main.getEditLayer());
    367         initChangesetProcessingType();
    368         cmt.getEditor().selectAll();
    369         cmt.requestFocus();
    370     }
    371 
    372     /**
    373      * Replies the current changeset processing type
    374      *
    375      * @return the current changeset processing type
    376      */
    377     public ChangesetProcessingType getChangesetProcessingType() {
    378         ChangesetProcessingType changesetProcessingType = null;
    379         for (ChangesetProcessingType type: ChangesetProcessingType.values()) {
    380             if (rbChangesetHandlingOptions.get(type).isSelected()) {
    381                 changesetProcessingType = type;
    382                 break;
    383             }
    384         }
    385         return changesetProcessingType == null ?
    386                 ChangesetProcessingType.USE_NEW_AND_CLOSE :
    387                     changesetProcessingType;
     285        pnlChangesetSelection.startUserInput();
    388286    }
    389287
     
    394292     */
    395293    public Changeset getChangeset() {
    396         Changeset changeset = new Changeset();
    397         tagEditorPanel.getModel().applyToPrimitive(changeset);
    398         changeset.put("comment", cmt.getText());
    399         return changeset;
    400     }
    401 
    402     /**
    403      * initializes the panel depending on the possible changeset processing
    404      * types
    405      */
    406     protected void initChangesetProcessingType() {
    407         for (ChangesetProcessingType type: ChangesetProcessingType.values()) {
    408             // show options for new changeset, disable others
    409             //
    410             rbChangesetHandlingOptions.get(type).setVisible(type.isUseNew());
    411         }
    412         if (OsmApi.getOsmApi().getCurrentChangeset() != null) {
    413             Changeset cs = OsmApi.getOsmApi().getCurrentChangeset();
    414             for (ChangesetProcessingType type: ChangesetProcessingType.values()) {
    415                 // show options for using existing changeset
    416                 //
    417                 if (!type.isUseNew()) {
    418                     rbChangesetHandlingOptions.get(type).setVisible(true);
    419                 }
    420             }
    421             JRadioButton rb = rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_EXISTING_AND_CLOSE);
    422             rb.setText(tr("Use the existing changeset {0} and close it after upload",cs.getId()));
    423             rb.setToolTipText(tr("Select to upload to the existing changeset {0} and to close the changeset after this upload",cs.getId()));
    424 
    425             rb = rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_EXISTING_AND_LEAVE_OPEN);
    426             rb.setText(tr("Use the existing changeset {0} and leave it open",cs.getId()));
    427             rb.setToolTipText(tr("Select to upload to the existing changeset {0} and to leave the changeset open for further uploads",cs.getId()));
    428 
    429             rbChangesetHandlingOptions.get(getChangesetProcessingType()).setSelected(true);
    430 
    431         } else {
    432             ChangesetProcessingType type = getChangesetProcessingType();
    433             if (!type.isUseNew()) {
    434                 type = ChangesetProcessingType.USE_NEW_AND_CLOSE;
    435             }
    436             rbChangesetHandlingOptions.get(type).setSelected(true);
    437         }
    438         ChangesetProcessingType type = getChangesetProcessingType();
    439         if (type.isUseNew() || (! type.isUseNew() && OsmApi.getOsmApi().getCurrentChangeset() == null)) {
    440             Changeset cs = new Changeset();
    441             cs.put("created_by", getDefaultCreatedBy());
    442             tagEditorPanel.getModel().initFromPrimitive(cs);
    443         } else {
    444             Changeset cs = OsmApi.getOsmApi().getCurrentChangeset();
    445             tagEditorPanel.getModel().initFromPrimitive(cs);
    446         }
     294        Changeset cs = pnlChangesetSelection.getChangeset();
     295        tagEditorPanel.getModel().applyToPrimitive(cs);
     296        cs.put("comment", getUploadComment());
     297        return cs;
     298    }
     299
     300    /**
     301     * Sets or updates the changeset cs.
     302     * If cs is null, does nothing.
     303     * If cs.getId() == 0 does nothing.
     304     * If cs.getId() > 0 and cs is open, adds it to the list of open
     305     * changesets. If it is closed, removes it from the list of open
     306     * changesets.
     307     *
     308     * @param cs the changeset
     309     */
     310    public void setOrUpdateChangeset(Changeset cs) {
     311        pnlChangesetSelection.setOrUpdateChangeset(cs);
     312    }
     313
     314    public boolean isDoCloseAfterUpload() {
     315        return pnlChangesetSelection.isCloseAfterUpload();
    447316    }
    448317
     
    457326    }
    458327
    459     /**
    460      * refreshes  the panel depending on a changeset processing type
    461      *
    462      * @param type the changeset processing type
    463      */
    464     protected void switchToProcessingType(ChangesetProcessingType type) {
    465         if (type.isUseNew()) {
    466             southTabbedPane.setTitleAt(1, tr("Tags of new changeset"));
    467             // init a new changeset from the currently edited tags
    468             // and the comment field
    469             //
    470             Changeset cs = new Changeset(getChangeset());
    471             if (cs.get("created_by") == null) {
    472                 cs.put("created_by", getDefaultCreatedBy());
    473             }
    474             cs.put("comment", this.cmt.getText());
    475             tagEditorPanel.getModel().initFromPrimitive(cs);
    476         } else {
    477             Changeset cs = OsmApi.getOsmApi().getCurrentChangeset();
    478             if (cs != null) {
    479                 cs.put("comment", this.cmt.getText());
    480                 cs.setKeys(getChangeset().getKeys());
    481                 southTabbedPane.setTitleAt(1, tr("Tags of changeset {0}", cs.getId()));
    482                 tagEditorPanel.getModel().initFromPrimitive(cs);
    483             }
    484         }
    485     }
    486 
    487     public String getUploadComment() {
     328    protected String getUploadComment() {
    488329        switch(southTabbedPane.getSelectedIndex()) {
    489         case 0: return cmt.getText();
    490         case 1:
    491             TagModel tm = tagEditorPanel.getModel().get("comment");
    492             return tm == null? "" : tm.getValue();
     330            case 0:
     331                pnlChangesetSelection.getUploadComment();
     332            case 1:
     333                TagModel tm = tagEditorPanel.getModel().get("comment");
     334                return tm == null? "" : tm.getValue();
    493335        }
    494336        return "";
     
    509351                    getClass().getName() + ".geometry",
    510352                    WindowGeometry.centerInWindow(
    511                             JOptionPane.getFrameForComponent(Main.parent),
     353                            Main.parent,
    512354                            new Dimension(400,600)
    513355                    )
     
    520362    }
    521363
    522     class ChangesetProcessingTypeChangedAction implements ActionListener {
    523         public void actionPerformed(ActionEvent e) {
    524             ChangesetProcessingType type = getChangesetProcessingType();
    525             switchToProcessingType(type);
    526         }
    527     }
    528 
    529 
     364    /**
     365     * This change listener is triggered when current tab in the tabbed pane in
     366     * the lower half of the dialog is changed.
     367     *
     368     * It's main purpose is to keep the content in the text field for the changeset
     369     * comment in sync with the changeset tag "comment".
     370     *
     371     */
    530372    class TabbedPaneChangeLister implements ChangeListener {
    531373
     
    560402            TagModel tm = getOrCreateCommentTag();
    561403            tm.setName("comment");
    562             tm.setValue(cmt.getText().trim());
    563             if (cmt.getText().trim().equals("")) {
     404            tm.setValue(pnlChangesetSelection.getUploadComment().trim());
     405            if (pnlChangesetSelection.getUploadComment().trim().equals("")) {
    564406                removeCommentTag();
    565407            }
    566408            tagEditorPanel.getModel().fireTableDataChanged();
    567409        }
    568 
    569410
    570411        public void stateChanged(ChangeEvent e) {
    571412            if (southTabbedPane.getSelectedIndex() ==0) {
    572413                TagModel tm = tagEditorPanel.getModel().get("comment");
    573                 cmt.setText(tm == null ? "" : tm.getValue());
    574                 cmt.getEditor().selectAll();
    575                 cmt.requestFocus();
     414                pnlChangesetSelection.initEditingOfUploadComment(tm == null ? "" : tm.getValue());
    576415            } else if (southTabbedPane.getSelectedIndex() == 1) {
    577416                refreshCommentTag();
     
    580419    }
    581420
     421    /**
     422     * Handles an upload
     423     *
     424     */
    582425    class UploadAction extends AbstractAction {
    583426        public UploadAction() {
     
    599442            if (getUploadComment().trim().length() < 3) {
    600443                warnIllegalUploadComment();
    601                 cmt.getEditor().selectAll();
    602                 cmt.requestFocus();
     444                southTabbedPane.setSelectedIndex(0);
     445                pnlChangesetSelection.initEditingOfUploadComment(getUploadComment());
    603446                return;
    604447            }
     
    609452    }
    610453
     454    /**
     455     * Action for canceling the dialog
     456     *
     457     */
    611458    class CancelAction extends AbstractAction {
    612459        public CancelAction() {
     
    623470    }
    624471
     472    /**
     473     * A simple list of OSM primitives.
     474     *
     475     */
    625476    class PrimitiveList extends JList {
    626477        public PrimitiveList() {
     
    633484    }
    634485
     486    /**
     487     * A list model for a list of OSM primitives.
     488     *
     489     */
    635490    class PrimitiveListModel extends AbstractListModel{
    636491        private List<OsmPrimitive> primitives;
     
    664519    }
    665520
     521    /**
     522     * Listens to window closing events and processes them as cancel events
     523     *
     524     */
    666525    class WindowClosingAdapter extends WindowAdapter {
    667526        @Override
     
    670529        }
    671530    }
     531
     532    /**
     533     * The panel which provides various UI widgets for controlling how to use
     534     * changesets during upload.
     535     *
     536     */
     537    class ChangesetSelectionPanel extends JPanel implements ListDataListener{
     538
     539        private ButtonGroup bgUseNewOrExisting;
     540        private JRadioButton rbUseNew;
     541        private JRadioButton rbExisting;
     542        private JComboBox cbOpenChangesets;
     543        private JButton btnRefresh;
     544        private JButton btnClose;
     545        private JCheckBox cbCloseAfterUpload;
     546        private OpenChangesetModel model;
     547        private SuggestingJHistoryComboBox cmt;
     548        private JCheckBox cbUseAtomicUpload;
     549
     550        /**
     551         * build the panel with the widgets for controlling whether an atomic upload
     552         * should be used or not
     553         *
     554         * @return the panel
     555         */
     556        protected JPanel buildAtomicUploadControlPanel() {
     557            JPanel pnl = new JPanel();
     558            pnl.setLayout(new GridBagLayout());
     559            GridBagConstraints gc = new GridBagConstraints();
     560            gc.fill = GridBagConstraints.HORIZONTAL;
     561            gc.weightx = 1.0;
     562            gc.anchor = GridBagConstraints.FIRST_LINE_START;
     563            pnl.add(cbUseAtomicUpload = new JCheckBox(tr("Upload all changes in one request")), gc);
     564            cbUseAtomicUpload.setToolTipText(tr("Enable to upload all changes in one request, disable to use one request per changed primitive"));
     565            boolean useAtomicUpload = Main.pref.getBoolean("osm-server.atomic-upload", true);
     566            cbUseAtomicUpload.setSelected(useAtomicUpload);
     567            cbUseAtomicUpload.setEnabled(OsmApi.getOsmApi().hasSupportForDiffUploads());
     568            return pnl;
     569        }
     570
     571        protected JPanel buildUploadCommentPanel() {
     572            JPanel pnl = new JPanel();
     573            pnl.setLayout(new GridBagLayout());
     574            pnl.add(new JLabel(tr("Provide a brief comment for the changes you are uploading:")), GBC.eol().insets(0, 5, 10, 3));
     575            cmt = new SuggestingJHistoryComboBox();
     576            List<String> cmtHistory = new LinkedList<String>(Main.pref.getCollection(HISTORY_KEY, new LinkedList<String>()));
     577            cmt.setHistory(cmtHistory);
     578            cmt.getEditor().addActionListener(
     579                    new ActionListener() {
     580                        public void actionPerformed(ActionEvent e) {
     581                            TagModel tm = tagEditorPanel.getModel().get("comment");
     582                            if (tm == null) {
     583                                tagEditorPanel.getModel().add(new TagModel("comment", cmt.getText()));
     584                            } else {
     585                                tm.setValue(cmt.getText());
     586                            }
     587                            tagEditorPanel.getModel().fireTableDataChanged();
     588                        }
     589                    }
     590            );
     591            pnl.add(cmt, GBC.eol().fill(GBC.HORIZONTAL));
     592            return pnl;
     593        }
     594
     595        protected void build() {
     596            setLayout(new GridBagLayout());
     597            GridBagConstraints gc = new GridBagConstraints();
     598
     599            bgUseNewOrExisting = new ButtonGroup();
     600
     601            // -- atomic upload
     602            gc.gridwidth = 4;
     603            gc.gridy = 0;
     604            gc.fill = GridBagConstraints.HORIZONTAL;
     605            gc.weightx = 1.0;
     606            gc.anchor = GridBagConstraints.FIRST_LINE_START;
     607            add(buildAtomicUploadControlPanel(), gc);
     608
     609            // -- changeset command
     610            gc.gridwidth = 4;
     611            gc.gridy = 1;
     612            gc.fill = GridBagConstraints.HORIZONTAL;
     613            gc.weightx = 1.0;
     614            gc.anchor = GridBagConstraints.FIRST_LINE_START;
     615            add(buildUploadCommentPanel(), gc);
     616
     617            gc.gridwidth = 4;
     618            gc.gridy = 2;
     619            gc.fill = GridBagConstraints.HORIZONTAL;
     620            gc.weightx = 0.0;
     621            gc.anchor = GridBagConstraints.FIRST_LINE_START;
     622            rbUseNew = new JRadioButton(tr("Open a new changeset"));
     623            rbUseNew.setToolTipText(tr("Open a new changeset and use it in the next upload"));
     624            bgUseNewOrExisting.add(rbUseNew);
     625            add(rbUseNew, gc);
     626
     627            gc.gridx = 0;
     628            gc.gridy = 3;
     629            gc.gridwidth = 1;
     630            rbExisting = new JRadioButton(tr("Use an open changeset"));
     631            rbExisting.setToolTipText(tr("Upload data to an already opened changeset"));
     632            bgUseNewOrExisting.add(rbExisting);
     633            add(rbExisting, gc);
     634
     635            gc.gridx = 1;
     636            gc.gridy = 3;
     637            gc.gridwidth = 1;
     638            gc.weightx = 1.0;
     639            model = new OpenChangesetModel();
     640            cbOpenChangesets = new JComboBox(model);
     641            cbOpenChangesets.setToolTipText("Select an open changeset");
     642            cbOpenChangesets.setRenderer(new ChangesetCellRenderer());
     643            cbOpenChangesets.addItemListener(new ChangesetListItemStateListener());
     644            Dimension d = cbOpenChangesets.getPreferredSize();
     645            d.width = 200;
     646            cbOpenChangesets.setPreferredSize(d);
     647            d.width = 100;
     648            cbOpenChangesets.setMinimumSize(d);
     649            model.addListDataListener(this);
     650            add(cbOpenChangesets, gc);
     651
     652            gc.gridx = 3;
     653            gc.gridy = 3;
     654            gc.gridwidth = 1;
     655            gc.weightx = 0.0;
     656            btnRefresh = new JButton(new RefreshAction());
     657            add(btnRefresh, gc);
     658
     659            gc.gridx = 4;
     660            gc.gridy = 3;
     661            gc.gridwidth = 1;
     662            gc.weightx = 0.0;
     663            CloseChangesetAction closeChangesetAction = new CloseChangesetAction();
     664            btnClose = new JButton(closeChangesetAction);
     665            cbOpenChangesets.addItemListener(closeChangesetAction);
     666            add(btnClose, gc);
     667
     668            gc.gridx = 0;
     669            gc.gridy = 4;
     670            gc.gridwidth = 4;
     671            cbCloseAfterUpload = new JCheckBox(tr("Close changeset after upload"));
     672            cbCloseAfterUpload.setToolTipText(tr("Select to close the changeset after the next upload"));
     673            add(cbCloseAfterUpload, gc);
     674            cbCloseAfterUpload.setSelected(true);
     675
     676            rbUseNew.getModel().addItemListener(new RadioButtonHandler());
     677            rbExisting.getModel().addItemListener(new RadioButtonHandler());
     678
     679            refreshGUI();
     680        }
     681
     682        public ChangesetSelectionPanel() {
     683            build();
     684        }
     685
     686        /**
     687         * Remembers the user input in the preference settings
     688         */
     689        public void rememberUserInput() {
     690            // store the history of comments
     691            cmt.addCurrentItemToHistory();
     692            Main.pref.putCollection(HISTORY_KEY, cmt.getHistory());
     693            Main.pref.put("osm-server.atomic-upload", cbUseAtomicUpload.isSelected());
     694        }
     695
     696        /**
     697         * Initializes the panel for user input
     698         */
     699        public void startUserInput() {
     700            cmt.getEditor().selectAll();
     701            cmt.requestFocus();
     702        }
     703
     704        /**
     705         * Replies the current upload comment
     706         *
     707         * @return
     708         */
     709        public String getUploadComment() {
     710            return cmt.getText();
     711        }
     712
     713        /**
     714         * Replies the current upload comment
     715         *
     716         * @return
     717         */
     718        public void setUploadComment(String uploadComment) {
     719            cmt.setText(uploadComment);
     720        }
     721
     722        public void initEditingOfUploadComment(String comment) {
     723            setUploadComment(comment);
     724            cmt.getEditor().selectAll();
     725            cmt.requestFocus();
     726        }
     727
     728        protected void refreshGUI() {
     729            rbExisting.setEnabled(model.getSize() > 0);
     730            if (model.getSize() == 0) {
     731                if (!rbUseNew.isSelected()) {
     732                    rbUseNew.setSelected(true);
     733                }
     734            }
     735            cbOpenChangesets.setEnabled(model.getSize() > 0 && rbExisting.isSelected());
     736        }
     737
     738        public void contentsChanged(ListDataEvent e) {
     739            refreshGUI();
     740        }
     741
     742        public void intervalAdded(ListDataEvent e) {
     743            refreshGUI();
     744        }
     745
     746        public void intervalRemoved(ListDataEvent e) {
     747            refreshGUI();
     748        }
     749
     750        public Changeset getChangeset() {
     751            if (rbUseNew.isSelected() || cbOpenChangesets.getSelectedItem() == null)
     752                return new Changeset();
     753            Changeset cs = (Changeset)cbOpenChangesets.getSelectedItem();
     754            if (cs == null)
     755                return new Changeset();
     756            return cs;
     757        }
     758
     759        public void setOrUpdateChangeset(Changeset cs) {
     760            if (cs == null) {
     761                tagEditorPanel.getModel().clear();
     762                tagEditorPanel.getModel().add("created_by", getDefaultCreatedBy());
     763                tagEditorPanel.getModel().appendNewTag();
     764                rbUseNew.setSelected(true);
     765            } else if (cs.getId() == 0) {
     766                if (cs.get("created_by") == null) {
     767                    cs.put("created_by", getDefaultCreatedBy());
     768                }
     769                tagEditorPanel.getModel().initFromPrimitive(cs);
     770                tagEditorPanel.getModel().appendNewTag();
     771                rbUseNew.setSelected(true);
     772            } else if (cs.getId() > 0 && cs.isOpen()){
     773                if (cs.get("created_by") == null) {
     774                    cs.put("created_by", getDefaultCreatedBy());
     775                }
     776                tagEditorPanel.getModel().initFromPrimitive(cs);
     777                model.addOrUpdate(cs);
     778                cs = model.getChangesetById(cs.getId());
     779                cbOpenChangesets.setSelectedItem(cs);
     780            } else if (cs.getId() > 0 && !cs.isOpen()){
     781                if (cs.get("created_by") == null) {
     782                    cs.put("created_by", getDefaultCreatedBy());
     783                }
     784                tagEditorPanel.getModel().initFromPrimitive(cs);
     785                model.removeChangeset(cs);
     786                if (model.getSize() == 0) {
     787                    rbUseNew.setSelected(true);
     788                    model.setSelectedItem(null);
     789                    southTabbedPane.setTitleAt(1, tr("Tags of new changeset"));
     790                }
     791            }
     792        }
     793
     794        public void setUseNew() {
     795            rbUseNew.setSelected(true);
     796        }
     797
     798        public void setUseExisting() {
     799            rbExisting.setSelected(true);
     800            if (cbOpenChangesets.getSelectedItem() == null && model.getSize() > 0) {
     801                cbOpenChangesets.setSelectedItem(model.getElementAt(0));
     802            }
     803        }
     804
     805        public boolean isCloseAfterUpload() {
     806            return cbCloseAfterUpload.isSelected();
     807        }
     808
     809        class RadioButtonHandler implements ItemListener {
     810            public void itemStateChanged(ItemEvent e) {
     811                if (rbUseNew.isSelected()) {
     812                    southTabbedPane.setTitleAt(1, tr("Tags of new changeset"));
     813                    // init a new changeset from the currently edited tags
     814                    // and the comment field
     815                    //
     816                    Changeset cs = new Changeset();
     817                    tagEditorPanel.getModel().applyToPrimitive(cs);
     818                    if (cs.get("created_by") == null) {
     819                        cs.put("created_by", getDefaultCreatedBy());
     820                    }
     821                    cs.put("comment", cmt.getText());
     822                    tagEditorPanel.getModel().initFromPrimitive(cs);
     823                } else {
     824                    if (cbOpenChangesets.getSelectedItem() == null) {
     825                        model.selectFirstChangeset();
     826                    }
     827                    Changeset cs = (Changeset)cbOpenChangesets.getSelectedItem();
     828                    if (cs != null) {
     829                        cs.put("comment", cmt.getText());
     830                        southTabbedPane.setTitleAt(1, tr("Tags of changeset {0}", cs.getId()));
     831                        tagEditorPanel.getModel().initFromPrimitive(cs);
     832                    }
     833                }
     834                refreshGUI();
     835            }
     836        }
     837
     838        class ChangesetListItemStateListener implements ItemListener {
     839            public void itemStateChanged(ItemEvent e) {
     840
     841                Changeset cs = (Changeset)cbOpenChangesets.getSelectedItem();
     842                if (cs == null) {
     843                    southTabbedPane.setTitleAt(1, tr("Tags of new changeset"));
     844                    // init a new changeset from the currently edited tags
     845                    // and the comment field
     846                    //
     847                    cs = new Changeset();
     848                    tagEditorPanel.getModel().applyToPrimitive(cs);
     849                    if (cs.get("created_by") == null) {
     850                        cs.put("created_by", getDefaultCreatedBy());
     851                    }
     852                    cs.put("comment", cmt.getText());
     853                    tagEditorPanel.getModel().initFromPrimitive(cs);
     854                } else {
     855                    southTabbedPane.setTitleAt(1, tr("Tags of changeset {0}", cs.getId()));
     856                    cs.put("comment", cmt.getText());
     857                    southTabbedPane.setTitleAt(1, tr("Tags of changeset {0}", cs.getId()));
     858                    if (cs.get("created_by") == null) {
     859                        cs.put("created_by", getDefaultCreatedBy());
     860                    }
     861                    tagEditorPanel.getModel().initFromPrimitive(cs);
     862                }
     863            }
     864        }
     865
     866        class RefreshAction extends AbstractAction {
     867            public RefreshAction() {
     868                //putValue(NAME, tr("Reload"));
     869                putValue(SHORT_DESCRIPTION, tr("Load the list of your open changesets from the server"));
     870                putValue(SMALL_ICON, ImageProvider.get("dialogs", "refresh"));
     871            }
     872
     873            public void actionPerformed(ActionEvent e) {
     874                DownloadOpenChangesetsTask task = new DownloadOpenChangesetsTask(model);
     875                Main.worker.submit(task);
     876            }
     877        }
     878
     879        class CloseChangesetAction extends AbstractAction implements ItemListener{
     880            public CloseChangesetAction() {
     881                putValue(NAME, tr("Close"));
     882                putValue(SHORT_DESCRIPTION, tr("Close the currently selected open changeset"));
     883                refreshEnabledState();
     884            }
     885
     886            public void actionPerformed(ActionEvent e) {
     887                Changeset cs = (Changeset)cbOpenChangesets.getSelectedItem();
     888                if (cs == null) return;
     889                CloseChangesetTask task = new CloseChangesetTask(Collections.singletonList(cs));
     890                Main.worker.submit(task);
     891            }
     892
     893            protected void refreshEnabledState() {
     894                setEnabled(cbOpenChangesets.getModel().getSize() > 0 && cbOpenChangesets.getSelectedItem() != null);
     895            }
     896
     897            public void itemStateChanged(ItemEvent e) {
     898                refreshEnabledState();
     899            }
     900        }
     901    }
     902
     903    public class OpenChangesetModel extends DefaultComboBoxModel {
     904        private List<Changeset> changesets;
     905        private long uid;
     906        private Changeset selectedChangeset = null;
     907
     908        protected Changeset getChangesetById(long id) {
     909            for (Changeset cs : changesets) {
     910                if (cs.getId() == id) return cs;
     911            }
     912            return null;
     913        }
     914
     915        public OpenChangesetModel() {
     916            this.changesets = new ArrayList<Changeset>();
     917        }
     918
     919        protected void internalAddOrUpdate(Changeset cs) {
     920            Changeset other = getChangesetById(cs.getId());
     921            if (other != null) {
     922                cs.cloneFrom(other);
     923            } else {
     924                changesets.add(cs);
     925            }
     926        }
     927
     928        public void addOrUpdate(Changeset cs) {
     929            if (cs.getId() <= 0 )
     930                throw new IllegalArgumentException(tr("changeset id > 0 expected. Got {1}", "id", cs.getId()));
     931            internalAddOrUpdate(cs);
     932            fireContentsChanged(this, 0, getSize());
     933        }
     934
     935        public void remove(long id) {
     936            Changeset cs = getChangesetById(id);
     937            if (cs != null) {
     938                changesets.remove(cs);
     939            }
     940            fireContentsChanged(this, 0, getSize());
     941        }
     942
     943        public void addOrUpdate(Collection<Changeset> changesets) {
     944            for (Changeset cs: changesets) {
     945                internalAddOrUpdate(cs);
     946            }
     947            fireContentsChanged(this, 0, getSize());
     948            if (getSelectedItem() == null && !this.changesets.isEmpty()) {
     949                setSelectedItem(this.changesets.get(0));
     950            } else {
     951                setSelectedItem(null);
     952            }
     953        }
     954
     955        public void setUserId(long uid) {
     956            this.uid = uid;
     957        }
     958
     959        public long getUserId() {
     960            return uid;
     961        }
     962
     963        public void selectFirstChangeset() {
     964            if (changesets == null || changesets.isEmpty()) return;
     965            setSelectedItem(changesets.get(0));
     966        }
     967
     968        public void removeChangeset(Changeset cs) {
     969            if (cs == null) return;
     970            changesets.remove(cs);
     971            if (selectedChangeset == cs) {
     972                selectFirstChangeset();
     973            }
     974            fireContentsChanged(this, 0, getSize());
     975        }
     976        /* ------------------------------------------------------------------------------------ */
     977        /* ComboBoxModel                                                                        */
     978        /* ------------------------------------------------------------------------------------ */
     979        @Override
     980        public Object getElementAt(int index) {
     981            return changesets.get(index);
     982        }
     983
     984        @Override
     985        public int getIndexOf(Object anObject) {
     986            return changesets.indexOf(anObject);
     987        }
     988
     989        @Override
     990        public int getSize() {
     991            return changesets.size();
     992        }
     993
     994        @Override
     995        public Object getSelectedItem() {
     996            return selectedChangeset;
     997        }
     998
     999        @Override
     1000        public void setSelectedItem(Object anObject) {
     1001            if (anObject == null) {
     1002                this.selectedChangeset = null;
     1003                super.setSelectedItem(null);
     1004                return;
     1005            }
     1006            if (! (anObject instanceof Changeset)) return;
     1007            Changeset cs = (Changeset)anObject;
     1008            if (cs.getId() == 0 || ! cs.isOpen()) return;
     1009            Changeset candidate = getChangesetById(cs.getId());
     1010            if (candidate == null) return;
     1011            this.selectedChangeset = candidate;
     1012            super.setSelectedItem(selectedChangeset);
     1013        }
     1014    }
    6721015}
  • trunk/src/org/openstreetmap/josm/gui/io/UploadLayerTask.java

    r2040 r2115  
    3636    private ProgressMonitor monitor;
    3737    private Changeset changeset;
    38     private ChangesetProcessingType changesetProcessingType;
     38    private boolean closeChangesetAfterUpload;
    3939
    4040    /**
     
    4444     * @param changeset the changeset to be used if <code>changesetProcessingType</code> indicates that a new
    4545     *   changeset is to be used
    46      * @param changesetProcessingType how we handle changesets
     46     * @param closeChangesetAfterUpload true, if the changeset should be closed after the upload
    4747     * @throws IllegalArgumentException thrown, if layer is null
    4848     */
    49     public UploadLayerTask(OsmDataLayer layer, ProgressMonitor monitor, Changeset changeset, ChangesetProcessingType changesetProcessingType) {
     49    public UploadLayerTask(OsmDataLayer layer, ProgressMonitor monitor, Changeset changeset, boolean closeChangesetAfterUpload) {
    5050        if (layer == null)
    5151            throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", layer));
     
    5656        this.monitor = monitor;
    5757        this.changeset = changeset;
    58         this.changesetProcessingType = changesetProcessingType == null ? ChangesetProcessingType.USE_NEW_AND_CLOSE : changesetProcessingType;
     58        this.closeChangesetAfterUpload = closeChangesetAfterUpload;
    5959    }
    6060
     
    6969            ProgressMonitor m = monitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false);
    7070            if (isCancelled()) return;
    71             writer.uploadOsm(layer.data.version, toUpload, changeset, changesetProcessingType, m);
     71            writer.uploadOsm(layer.data.version, toUpload, changeset, closeChangesetAfterUpload, m);
    7272        } catch (Exception sxe) {
    7373            if (isCancelled()) {
  • trunk/src/org/openstreetmap/josm/gui/tagging/TagEditorModel.java

    r2081 r2115  
    99import java.util.Collection;
    1010import java.util.Comparator;
     11import java.util.HashMap;
    1112import java.util.Iterator;
    1213import java.util.List;
     14import java.util.Map;
    1315import java.util.logging.Logger;
    1416
     
    1921import org.openstreetmap.josm.command.SequenceCommand;
    2022import org.openstreetmap.josm.data.osm.OsmPrimitive;
     23import org.openstreetmap.josm.data.osm.Tagged;
    2124
    2225
     
    8386        TagModel tag = tags.get(rowIndex);
    8487        switch(columnIndex) {
    85         case 0:
    86         case 1: return tag;
    87 
    88         default:
    89             throw new IndexOutOfBoundsException("unexpected columnIndex: columnIndex=" + columnIndex);
     88            case 0:
     89            case 1: return tag;
     90
     91            default:
     92                throw new IndexOutOfBoundsException("unexpected columnIndex: columnIndex=" + columnIndex);
    9093        }
    9194    }
     
    280283     * @param primitive the OSM primitive
    281284     */
    282     public void initFromPrimitive(OsmPrimitive primitive) {
     285    public void initFromPrimitive(Tagged primitive) {
    283286        clear();
    284287        for (String key : primitive.keySet()) {
     
    293296
    294297    /**
     298     * initializes the model with the tags of an OSM primitive
     299     *
     300     * @param primitive the OSM primitive
     301     */
     302    public void initFromTags(Map<String,String> tags) {
     303        clear();
     304        for (String key : tags.keySet()) {
     305            String value = tags.get(key);
     306            add(key,value);
     307        }
     308        TagModel tag = new TagModel();
     309        sort();
     310        this.tags.add(tag);
     311        setDirty(false);
     312    }
     313
     314    /**
    295315     * applies the current state of the tag editor model to a primitive
    296316     *
     
    298318     *
    299319     */
    300     public void applyToPrimitive(OsmPrimitive primitive) {
    301         primitive.removeAll();
    302         for (TagModel tag: tags) {
     320    public void applyToPrimitive(Tagged primitive) {
     321        Map<String,String> tags = primitive.getKeys();
     322        applyToTags(tags);
     323        primitive.setKeys(tags);
     324    }
     325
     326    /**
     327     * applies the current state of the tag editor model to a map of tags
     328     *
     329     * @param tags the map of key/value pairs
     330     *
     331     */
     332    public void applyToTags(Map<String, String> tags) {
     333        tags.clear();
     334        for (TagModel tag: this.tags) {
    303335            // tag still holds an unchanged list of different values for the same key.
    304336            // no property change command required
     
    312344                continue;
    313345            }
    314             primitive.put(tag.getName(), tag.getValue());
    315         }
     346            tags.put(tag.getName(), tag.getValue());
     347        }
     348    }
     349
     350    public Map<String,String> getTags() {
     351        Map<String,String> tags = new HashMap<String, String>();
     352        applyToTags(tags);
     353        return tags;
    316354    }
    317355
  • trunk/src/org/openstreetmap/josm/io/OsmApi.java

    r2074 r2115  
    2323import java.util.Collections;
    2424import java.util.HashMap;
    25 import java.util.Properties;
    2625
    2726import javax.xml.parsers.SAXParserFactory;
     
    3231import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
    3332import org.openstreetmap.josm.data.osm.visitor.CreateOsmChangeVisitor;
     33import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
    3434import org.openstreetmap.josm.gui.progress.ProgressMonitor;
    3535import org.xml.sax.Attributes;
     
    205205
    206206    /**
     207     * Makes an XML string from an OSM primitive. Uses the OsmWriter class.
     208     * @param o the OSM primitive
     209     * @param addBody true to generate the full XML, false to only generate the encapsulating tag
     210     * @return XML string
     211     */
     212    private String toXml(Changeset s) {
     213        swriter.getBuffer().setLength(0);
     214        osmWriter.header();
     215        s.visit(osmWriter);
     216        osmWriter.footer();
     217        osmWriter.out.flush();
     218        return swriter.toString();
     219    }
     220
     221    /**
    207222     * Returns the base URL for API requests, including the negotiated version number.
    208223     * @return base URL string
     
    229244     */
    230245    public void createPrimitive(OsmPrimitive osm, ProgressMonitor monitor) throws OsmTransferException {
    231         initialize(monitor);
    232246        String ret = "";
    233247        try {
     248            ensureValidChangeset();
     249            initialize(monitor);
    234250            ret = sendRequest("PUT", OsmPrimitiveType.from(osm).getAPIName()+"/create", toXml(osm, true),monitor);
    235251            osm.setOsmId(Long.parseLong(ret.trim()), 1);
     
    244260     * version.
    245261     *
    246      * @param osm the primitive
     262     * @param osm the primitive. Must not be null
    247263     * @throws OsmTransferException if something goes wrong
    248264     */
    249265    public void modifyPrimitive(OsmPrimitive osm, ProgressMonitor monitor) throws OsmTransferException {
    250         initialize(monitor);
    251         if (version.equals("0.5")) {
    252             // legacy mode does not return the new object version.
    253             sendRequest("PUT", OsmPrimitiveType.from(osm).getAPIName()+"/" + osm.getId(), toXml(osm, true),monitor);
    254         } else {
    255             String ret = null;
    256             // normal mode (0.6 and up) returns new object version.
    257             try {
     266        String ret = null;
     267        try {
     268            ensureValidChangeset();
     269            initialize(monitor);
     270            if (version.equals("0.5")) {
     271                // legacy mode does not return the new object version.
     272                sendRequest("PUT", OsmPrimitiveType.from(osm).getAPIName()+"/" + osm.getId(), toXml(osm, true),monitor);
     273            } else {
     274                // normal mode (0.6 and up) returns new object version.
    258275                ret = sendRequest("PUT", OsmPrimitiveType.from(osm).getAPIName()+"/" + osm.getId(), toXml(osm, true), monitor);
    259276                osm.setOsmId(osm.getId(), Integer.parseInt(ret.trim()));
    260             } catch(NumberFormatException e) {
    261                 throw new OsmTransferException(tr("unexpected format of new version of modified primitive ''{0}'', got ''{1}''", osm.getId(), ret));
    262277            }
     278        } catch(NumberFormatException e) {
     279            throw new OsmTransferException(tr("unexpected format of new version of modified primitive ''{0}'', got ''{1}''", osm.getId(), ret));
    263280        }
    264281    }
     
    270287     */
    271288    public void deletePrimitive(OsmPrimitive osm, ProgressMonitor monitor) throws OsmTransferException {
     289        ensureValidChangeset();
    272290        initialize(monitor);
    273291        // can't use a the individual DELETE method in the 0.6 API. Java doesn't allow
     
    280298
    281299    /**
    282      * Creates a new changeset based on the keys in <code>changeset</code>
    283      *
    284      * @param changeset the changeset to be used for uploading
     300     * Creates a new changeset based on the keys in <code>changeset</code>. If this
     301     * method succeeds, changeset.getId() replies the id the server assigned to the new
     302     * changeset
     303     *
     304     * The changeset must not be null, but its key/value-pairs may be empty.
     305     *
     306     * @param changeset the changeset toe be created. Must not be null.
    285307     * @param progressMonitor the progress monitor
    286308     * @throws OsmTransferException signifying a non-200 return code, or connection errors
    287      */
    288     public void createChangeset(Changeset changeset, ProgressMonitor progressMonitor) throws OsmTransferException {
     309     * @throws IllegalArgumentException thrown if changeset is null
     310     */
     311    public void openChangeset(Changeset changeset, ProgressMonitor progressMonitor) throws OsmTransferException {
     312        if (changeset == null)
     313            throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "changeset"));
    289314        try {
    290315            progressMonitor.beginTask((tr("Creating changeset...")));
    291             createPrimitive(changeset, progressMonitor);
    292             this.changeset = changeset;
    293             progressMonitor.setCustomText((tr("Successfully opened changeset {0}",this.changeset.getId())));
     316            initialize(progressMonitor);
     317            String ret = "";
     318            try {
     319                ret = sendRequest("PUT", "changeset/create", toXml(changeset),progressMonitor);
     320                changeset.setId(Long.parseLong(ret.trim()));
     321                changeset.setOpen(true);
     322            } catch(NumberFormatException e){
     323                throw new OsmTransferException(tr("unexpected format of id replied by the server, got ''{0}''", ret));
     324            }
     325            progressMonitor.setCustomText((tr("Successfully opened changeset {0}",changeset.getId())));
    294326        } finally {
    295327            progressMonitor.finishTask();
     
    298330
    299331    /**
    300      * Updates the current changeset with the keys in  <code>changesetUpdate</code>.
    301      *
    302      * @param changesetUpdate the changeset to update
    303      * @param progressMonitor the progress monitor
     332     * Updates a changeset with the keys in  <code>changesetUpdate</code>. The changeset must not
     333     * be null and id > 0 must be true.
     334     *
     335     * @param changeset the changeset to update. Must not be null.
     336     * @param monitor the progress monitor. If null, uses the {@see NullProgressMonitor#INSTANCE}.
    304337     *
    305338     * @throws OsmTransferException if something goes wrong.
    306      */
    307     public void updateChangeset(Changeset changesetUpdate, ProgressMonitor progressMonitor) throws OsmTransferException {
     339     * @throws IllegalArgumentException if changeset is null
     340     * @throws IllegalArgumentException if changeset.getId() == 0
     341     *
     342     */
     343    public void updateChangeset(Changeset changeset, ProgressMonitor monitor) throws OsmTransferException {
     344        if (changeset == null)
     345            throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "changeset"));
     346        if (monitor == null) {
     347            monitor = NullProgressMonitor.INSTANCE;
     348        }
     349        if (changeset.getId() <= 0)
     350            throw new IllegalArgumentException(tr("id of changeset > 0 required. Got {0}", changeset.getId()));
    308351        try {
    309             progressMonitor.beginTask(tr("Updating changeset..."));
    310             initialize(progressMonitor);
    311             if (this.changeset != null && this.changeset.getId() > 0) {
    312                 if (this.changeset.hasEqualSemanticAttributes(changesetUpdate)) {
    313                     progressMonitor.setCustomText(tr("Changeset {0} is unchanged. Skipping update.", changesetUpdate.getId()));
    314                     return;
    315                 }
    316                 this.changeset.setKeys(changesetUpdate.getKeys());
    317                 progressMonitor.setCustomText(tr("Updating changeset {0}...", this.changeset.getId()));
    318                 sendRequest(
    319                         "PUT",
    320                         OsmPrimitiveType.from(changesetUpdate).getAPIName() + "/" + this.changeset.getId(),
    321                         toXml(this.changeset, true),
    322                         progressMonitor
    323                 );
    324             } else
    325                 throw new OsmTransferException(tr("Failed to update changeset. Either there is no current changeset or the id of the current changeset is 0"));
     352            monitor.beginTask(tr("Updating changeset..."));
     353            initialize(monitor);
     354            monitor.setCustomText(tr("Updating changeset {0}...", changeset.getId()));
     355            sendRequest(
     356                    "PUT",
     357                    "changeset/" + this.changeset.getId(),
     358                    toXml(this.changeset),
     359                    monitor
     360            );
    326361        } finally {
    327             progressMonitor.finishTask();
    328         }
    329     }
    330 
    331     /**
    332      * Closes a changeset on the server.
    333      *
    334      * @param changesetProcessingType how changesets are currently handled
    335      * @param progressMonitor the progress monitor
     362            monitor.finishTask();
     363        }
     364    }
     365
     366
     367    /**
     368     * Closes a changeset on the server. Sets changeset.setOpen(false) if this operation
     369     * succeeds.
     370     *
     371     * @param changeset the changeset to be closed. Must not be null. changeset.getId() > 0 required.
     372     * @param monitor the progress monitor. If null, uses {@see NullProgressMonitor#INSTANCE}
    336373     *
    337374     * @throws OsmTransferException if something goes wrong.
    338      */
    339     public void stopChangeset(ChangesetProcessingType changesetProcessingType, ProgressMonitor progressMonitor) throws OsmTransferException {
    340         if (changesetProcessingType == null) {
    341             changesetProcessingType = ChangesetProcessingType.USE_NEW_AND_CLOSE;
    342         }
     375     * @throws IllegalArgumentException thrown if changeset is null
     376     * @throws IllegalArgumentException thrown if changeset.getId() <= 0
     377     */
     378    public void closeChangeset(Changeset changeset, ProgressMonitor monitor) throws OsmTransferException {
     379        if (changeset == null)
     380            throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "changeset"));
     381        if (monitor == null) {
     382            monitor = NullProgressMonitor.INSTANCE;
     383        }
     384        if (changeset.getId() <= 0)
     385            throw new IllegalArgumentException(tr("id of changeset > 0 required. Got {0}", changeset.getId()));
    343386        try {
    344             progressMonitor.beginTask(tr("Closing changeset..."));
    345             initialize(progressMonitor);
    346             if (changesetProcessingType.isCloseAfterUpload()) {
    347                 progressMonitor.setCustomText(tr("Closing changeset {0}...", changeset.getId()));
    348                 if (this.changeset != null && this.changeset.getId() > 0) {
    349                     sendRequest("PUT", "changeset" + "/" + changeset.getId() + "/close", null, progressMonitor);
    350                     changeset = null;
    351                 }
    352             } else {
    353                 progressMonitor.setCustomText(tr("Leaving changeset {0} open...", changeset.getId()));
    354             }
     387            monitor.beginTask(tr("Closing changeset..."));
     388            initialize(monitor);
     389            sendRequest("PUT", "changeset" + "/" + changeset.getId() + "/close", null, monitor);
     390            changeset.setOpen(false);
    355391        } finally {
    356             progressMonitor.finishTask();
     392            monitor.finishTask();
    357393        }
    358394    }
     
    365401     * @throws OsmTransferException if something is wrong
    366402     */
    367     public Collection<OsmPrimitive> uploadDiff(final Collection<OsmPrimitive> list, ProgressMonitor progressMonitor) throws OsmTransferException {
    368 
    369         progressMonitor.beginTask("", list.size() * 2);
     403    public Collection<OsmPrimitive> uploadDiff(Collection<OsmPrimitive> list, ProgressMonitor progressMonitor) throws OsmTransferException {
    370404        try {
     405            progressMonitor.beginTask("", list.size() * 2);
    371406            if (changeset == null)
    372407                throw new OsmTransferException(tr("No changeset present for diff upload"));
     
    385420
    386421            String diff = duv.getDocument();
    387             try {
    388                 String diffresult = sendRequest("POST", "changeset/" + changeset.getId() + "/upload", diff,progressMonitor);
    389                 DiffResultReader.parseDiffResult(diffresult, list, processed, duv.getNewIdMap(),
    390                         progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
    391             } catch(OsmTransferException e) {
    392                 throw e;
    393             } catch(Exception e) {
    394                 throw new OsmTransferException(e);
    395             }
    396 
     422            String diffresult = sendRequest("POST", "changeset/" + changeset.getId() + "/upload", diff,progressMonitor);
     423            DiffResultReader.parseDiffResult(diffresult, list, processed, duv.getNewIdMap(),
     424                    progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
    397425            return processed;
     426        } catch(OsmTransferException e) {
     427            throw e;
     428        } catch(Exception e) {
     429            throw new OsmTransferException(e);
    398430        } finally {
    399431            progressMonitor.finishTask();
     
    536568                }
    537569                throw new OsmTransferException(e);
     570            } catch(OsmTransferException e) {
     571                throw e;
    538572            } catch (Exception e) {
    539                 if (e instanceof OsmTransferException) throw (OsmTransferException) e;
    540573                throw new OsmTransferException(e);
    541574            }
     
    552585    }
    553586
    554     /**
    555      * Replies the current changeset
    556      *
    557      * @return the current changeset
    558      */
    559     public Changeset getCurrentChangeset() {
     587
     588    /**
     589     * Ensures that the current changeset can be used for uploading data
     590     *
     591     * @throws OsmTransferException thrown if the current changeset can't be used for
     592     * uploading data
     593     */
     594    protected void ensureValidChangeset() throws OsmTransferException {
     595        if (changeset == null)
     596            throw new OsmTransferException(tr("current changeset is null. Can't upload data."));
     597        if (changeset.getId() <= 0)
     598            throw new OsmTransferException(tr("id of current changeset > required. Current id is {0}", changeset.getId()));
     599    }
     600    /**
     601     * Replies the changeset data uploads are currently directed to
     602     *
     603     * @return the changeset data uploads are currently directed to
     604     */
     605    public Changeset getChangeset() {
    560606        return changeset;
    561607    }
     608
     609    /**
     610     * Sets the changesets to which further data uploads are directed. The changeset
     611     * can be null. If it isn't null it must have been created, i.e. id > 0 is required. Furthermore,
     612     * it must be open.
     613     *
     614     * @param changeset the changeset
     615     * @throws IllegalArgumentException thrown if changeset.getId() <= 0
     616     * @throws IllegalArgumentException thrown if !changeset.isOpen()
     617     */
     618    public void setChangeset(Changeset changeset) {
     619        if (changeset == null) {
     620            this.changeset = null;
     621            return;
     622        }
     623        if (changeset.getId() <= 0)
     624            throw new IllegalArgumentException(tr("Changeset id > 0 expected. Got {0}", changeset.getId()));
     625        if (!changeset.isOpen())
     626            throw new IllegalArgumentException(tr("Open changeset expected. Got closed changeset with id {0}", changeset.getId()));
     627        this.changeset = changeset;
     628    }
     629
    562630}
  • trunk/src/org/openstreetmap/josm/io/OsmDataParsingException.java

    r2094 r2115  
    77import org.xml.sax.SAXException;
    88
    9 /**
    10  * Represents a parsing error in an OSM data file.
    11  *
    12  * Use {@see #getColumnNumber()} and {@see #getLineNumber()} to locate
    13  * the position in the file where the parsing error occured.
    14  *
    15  */
    169public class OsmDataParsingException extends SAXException {
    1710    private int columnNumber;
  • trunk/src/org/openstreetmap/josm/io/OsmReader.java

    r2094 r2115  
    3636
    3737/**
    38  * Parser for the Osm Api. Read from an input stream and constructs a dataset out of it.
     38 * Parser for the Osm Api. Read from an input stream and construct a dataset out of it.
    3939 *
    4040 */
     
    8080    }
    8181
     82    private static class OsmPrimitiveData {
     83        public long id = 0;
     84        public boolean modified = false;
     85        public boolean deleted = false;
     86        public Date timestamp = new Date();
     87        public User user = null;
     88        public boolean visible = true;
     89        public int version = 0;
     90        public LatLon latlon = new LatLon(0,0);
     91        private OsmPrimitive primitive;
     92
     93        public void copyTo(OsmPrimitive osm) {
     94            osm.setModified(modified);
     95            osm.setDeleted(deleted);
     96            //  id < 0 possible if read from a file
     97            if (id <= 0) {
     98                osm.clearOsmId();
     99            } else {
     100                osm.setOsmId(id, version);
     101            }
     102            osm.setTimestamp(timestamp);
     103            osm.user = user;
     104            osm.setVisible(visible);
     105            osm.mappaintStyle = null;
     106        }
     107
     108        public Node createNode() {
     109            Node node = new Node();
     110            node.setCoor(latlon);
     111            copyTo(node);
     112            primitive = node;
     113            return node;
     114        }
     115
     116        public Way createWay() {
     117            Way way = new Way();
     118            copyTo(way);
     119            primitive = way;
     120            return way;
     121        }
     122        public Relation createRelation() {
     123            Relation relation= new Relation();
     124            copyTo(relation);
     125            primitive = relation;
     126            return relation;
     127        }
     128
     129        public void rememberTag(String key, String value) {
     130            primitive.put(key, value);
     131        }
     132    }
    82133
    83134    /**
     
    100151     */
    101152    private Map<Long, Collection<RelationMemberData>> relations = new HashMap<Long, Collection<RelationMemberData>>();
    102 
    103153
    104154    private class Parser extends DefaultHandler {
     
    241291                current.rememberTag(key, value);
    242292            } else {
    243                 System.out.println(tr("Warning: Undefined element ''{0}'' found in input stream. Skipping.", qName));
     293                throwException(tr("Undefined element ''{0}'' found in input stream. Aborting.", qName));
    244294            }
    245295        }
     
    503553        }
    504554    }
    505 
    506     /**
    507      * Temporarily holds data for a parsed {@see OsmPrimitive} and provides
    508      * methods for creating an {@see OsmPrimitive} based on this data.
    509      */
    510     private static class OsmPrimitiveData {
    511         public long id = 0;
    512         public boolean modified = false;
    513         public boolean deleted = false;
    514         public Date timestamp = new Date();
    515         public User user = null;
    516         public boolean visible = true;
    517         public int version = 0;
    518         public LatLon latlon = new LatLon(0,0);
    519         private OsmPrimitive primitive;
    520 
    521         public void copyTo(OsmPrimitive osm) {
    522             //  id < 0 possible if read from a file
    523             if (id <= 0) {
    524                 osm.clearOsmId();
    525             } else {
    526                 osm.setOsmId(id, version);
    527             }
    528             osm.setDeleted(deleted);
    529             osm.setModified(modified);
    530             osm.setTimestamp(timestamp);
    531             osm.user = user;
    532             osm.setVisible(visible);
    533             osm.mappaintStyle = null;
    534         }
    535 
    536         public Node createNode() {
    537             Node node = new Node();
    538             node.setCoor(latlon);
    539             copyTo(node);
    540             primitive = node;
    541             return node;
    542         }
    543 
    544         public Way createWay() {
    545             Way way = new Way();
    546             copyTo(way);
    547             primitive = way;
    548             return way;
    549         }
    550         public Relation createRelation() {
    551             Relation relation= new Relation();
    552             copyTo(relation);
    553             primitive = relation;
    554             return relation;
    555         }
    556 
    557         public void rememberTag(String key, String value) {
    558             primitive.put(key, value);
    559         }
    560     }
    561555}
  • trunk/src/org/openstreetmap/josm/io/OsmServerWriter.java

    r2081 r2115  
    6565     *
    6666     * @param primitives the collection of primitives to upload
    67      * @param changeset the changeset to be used if <code>changesetProcessingType</code> indicates that
    68      *   a new changeset should be opened
    69      * @param changesetProcessingType how we handle changesets
    7067     * @param progressMonitor the progress monitor
    7168     * @throws OsmTransferException thrown if an exception occurs
    7269     */
    73     protected void uploadChangesIndividually(Collection<OsmPrimitive> primitives, Changeset changeset, ChangesetProcessingType changesetProcessingType, ProgressMonitor progressMonitor) throws OsmTransferException {
     70    protected void uploadChangesIndividually(Collection<OsmPrimitive> primitives, ProgressMonitor progressMonitor) throws OsmTransferException {
    7471        try {
    7572            progressMonitor.beginTask(tr("Starting to upload with one request per primitive ..."));
    7673            progressMonitor.setTicksCount(primitives.size());
    77             if (changesetProcessingType.isUseNew()) {
    78                 api.createChangeset(changeset,progressMonitor.createSubTaskMonitor(0, false));
    79             } else {
    80                 api.updateChangeset(changeset,progressMonitor.createSubTaskMonitor(0, false));
    81             }
    8274            uploadStartTime = System.currentTimeMillis();
    8375            for (OsmPrimitive osm : primitives) {
     
    8678                String msg = "";
    8779                switch(OsmPrimitiveType.from(osm)) {
    88                 case NODE: msg = marktr("{0}% ({1}/{2}), {3} left. Uploading node ''{4}'' (id: {5})"); break;
    89                 case WAY: msg = marktr("{0}% ({1}/{2}), {3} left. Uploading way ''{4}'' (id: {5})"); break;
    90                 case RELATION: msg = marktr("{0}% ({1}/{2}), {3} left. Uploading relation ''{4}'' (id: {5})"); break;
     80                    case NODE: msg = marktr("{0}% ({1}/{2}), {3} left. Uploading node ''{4}'' (id: {5})"); break;
     81                    case WAY: msg = marktr("{0}% ({1}/{2}), {3} left. Uploading way ''{4}'' (id: {5})"); break;
     82                    case RELATION: msg = marktr("{0}% ({1}/{2}), {3} left. Uploading relation ''{4}'' (id: {5})"); break;
    9183                }
    9284                progressMonitor.subTask(
     
    10799            throw new OsmTransferException(e);
    108100        } finally {
    109             try {
    110                 // starting the changeset may have failed, for instance because the user
    111                 // cancelled the upload task. Only close the changeset if we currently have
    112                 // an open changeset
    113 
    114                 if (api.getCurrentChangeset() != null && api.getCurrentChangeset().getId() > 0) {
    115                     api.stopChangeset(changesetProcessingType, progressMonitor.createSubTaskMonitor(0, false));
    116                 }
    117             } catch(Exception e) {
    118                 OsmChangesetCloseException closeException = new OsmChangesetCloseException(e);
    119                 closeException.setChangeset(api.getCurrentChangeset());
    120                 throw closeException;
    121             } finally {
    122                 progressMonitor.finishTask();
    123             }
     101            progressMonitor.finishTask();
    124102        }
    125103    }
     
    132110     * @throws OsmTransferException thrown if an exception occurs
    133111     */
    134     protected void uploadChangesAsDiffUpload(Collection<OsmPrimitive> primitives, Changeset changeset, ChangesetProcessingType changesetProcessingType, ProgressMonitor progressMonitor) throws OsmTransferException {
     112    protected void uploadChangesAsDiffUpload(Collection<OsmPrimitive> primitives, ProgressMonitor progressMonitor) throws OsmTransferException {
    135113        // upload everything in one changeset
    136114        //
    137115        try {
    138116            progressMonitor.beginTask(tr("Starting to upload in one request ..."));
    139             if (changesetProcessingType.isUseNew()) {
    140                 api.createChangeset(changeset,progressMonitor.createSubTaskMonitor(0, false));
    141             } else {
    142                 api.updateChangeset(changeset,progressMonitor.createSubTaskMonitor(0, false));
    143             }
    144117            processed.addAll(api.uploadDiff(primitives, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false)));
    145118        } catch(OsmTransferException e) {
     
    148121            throw new OsmTransferException(e);
    149122        } finally {
    150             try {
    151                 api.stopChangeset(changesetProcessingType, progressMonitor.createSubTaskMonitor(0, false));
    152             } catch (Exception ee) {
    153                 OsmChangesetCloseException closeException = new OsmChangesetCloseException(ee);
    154                 closeException.setChangeset(api.getCurrentChangeset());
    155                 throw closeException;
    156             } finally {
    157                 progressMonitor.finishTask();
    158             }
    159 
     123            progressMonitor.finishTask();
    160124        }
    161125    }
     
    167131     * @param primitives list of objects to send
    168132     */
    169     public void uploadOsm(String apiVersion, Collection<OsmPrimitive> primitives, Changeset changeset, ChangesetProcessingType changesetProcessingType, ProgressMonitor progressMonitor) throws OsmTransferException {
     133    public void uploadOsm(String apiVersion, Collection<OsmPrimitive> primitives, Changeset changeset, boolean closeChangesetAfterUpload, ProgressMonitor progressMonitor) throws OsmTransferException {
    170134        processed = new LinkedList<OsmPrimitive>();
    171135        progressMonitor.beginTask(tr("Uploading data ..."));
     
    184148                useDiffUpload = false;
    185149            }
    186 
     150            if (changeset == null) {
     151                changeset = new Changeset();
     152            }
     153            if (changeset.getId() == 0) {
     154                api.openChangeset(changeset,progressMonitor.createSubTaskMonitor(0, false));
     155            } else {
     156                api.updateChangeset(changeset,progressMonitor.createSubTaskMonitor(0, false));
     157            }
     158            api.setChangeset(changeset);
    187159            if (useDiffUpload) {
    188                 uploadChangesAsDiffUpload(primitives,changeset, changesetProcessingType, progressMonitor.createSubTaskMonitor(0,false));
     160                uploadChangesAsDiffUpload(primitives,progressMonitor.createSubTaskMonitor(0,false));
    189161            } else {
    190                 uploadChangesIndividually(primitives,changeset,changesetProcessingType,  progressMonitor.createSubTaskMonitor(0,false));
    191             }
     162                uploadChangesIndividually(primitives,progressMonitor.createSubTaskMonitor(0,false));
     163            }
     164        } catch(OsmTransferException e) {
     165            throw e;
     166        } catch(Exception e) {
     167            throw new OsmTransferException(e);
    192168        } finally {
    193             progressMonitor.finishTask();
     169            try {
     170                if (closeChangesetAfterUpload && api.getChangeset() != null && api.getChangeset().getId() > 0) {
     171                    api.closeChangeset(changeset,progressMonitor.createSubTaskMonitor(0, false));
     172                    api.setChangeset(null);
     173                }
     174            } catch (Exception ee) {
     175                OsmChangesetCloseException closeException = new OsmChangesetCloseException(ee);
     176                closeException.setChangeset(api.getChangeset());
     177                throw closeException;
     178            } finally {
     179                progressMonitor.finishTask();
     180            }
    194181        }
    195182    }
  • trunk/src/org/openstreetmap/josm/io/OsmWriter.java

    r2070 r2115  
    66import java.util.Map.Entry;
    77
     8import org.openstreetmap.josm.data.coor.CoordinateFormat;
    89import org.openstreetmap.josm.data.osm.Changeset;
    910import org.openstreetmap.josm.data.osm.DataSet;
     
    1415import org.openstreetmap.josm.data.osm.Relation;
    1516import org.openstreetmap.josm.data.osm.RelationMember;
    16 import org.openstreetmap.josm.data.osm.User;
     17import org.openstreetmap.josm.data.osm.Tagged;
    1718import org.openstreetmap.josm.data.osm.Way;
    1819import org.openstreetmap.josm.data.osm.visitor.Visitor;
     
    143144
    144145    public void visit(Changeset cs) {
    145         addCommon(cs, "changeset");
    146         out.println(">\n");
    147         addTags(cs, "changeset", false);
    148     }
    149 
    150     public final void footer(PrintWriter out) {
    151         out.println("</osm>");
     146        out.print("  <changeset ");
     147        out.print(" id='"+cs.getId()+"'");
     148        if (cs.getUser() != null) {
     149            out.print(" user='"+cs.getUser().getName() +"'");
     150            out.print(" uid='"+cs.getUser().getId() +"'");
     151        }
     152        if (cs.getCreatedAt() != null) {
     153            out.print(" created_at='"+DateUtils.fromDate(cs.getCreatedAt()) +"'");
     154        }
     155        if (cs.getClosedAt() != null) {
     156            out.print(" closed_at='"+DateUtils.fromDate(cs.getClosedAt()) +"'");
     157        }
     158        out.print(" open='"+ (cs.isOpen() ? "true" : "false") +"'");
     159        if (cs.getMin() != null) {
     160            out.print(" min_lon='"+ cs.getMin().lonToString(CoordinateFormat.DECIMAL_DEGREES) +"'");
     161            out.print(" min_lat='"+ cs.getMin().latToString(CoordinateFormat.DECIMAL_DEGREES) +"'");
     162        }
     163        if (cs.getMax() != null) {
     164            out.print(" max_lon='"+ cs.getMin().lonToString(CoordinateFormat.DECIMAL_DEGREES) +"'");
     165            out.print(" max_lat='"+ cs.getMin().latToString(CoordinateFormat.DECIMAL_DEGREES) +"'");
     166        }
     167        out.println(">");
     168        addTags(cs, "changeset", false); // also writes closing </changeset>
    152169    }
    153170
     
    164181    }
    165182
    166     private void addTags(OsmPrimitive osm, String tagname, boolean tagOpen) {
     183    private void addTags(Tagged osm, String tagname, boolean tagOpen) {
    167184        if (osm.hasKeys()) {
    168185            if (tagOpen) {
    169186                out.println(">");
    170187            }
    171             for (Entry<String, String> e : osm.entrySet()) {
     188            for (Entry<String, String> e : osm.getKeys().entrySet()) {
    172189                if ((osm instanceof Changeset) || !("created_by".equals(e.getKey()))) {
    173190                    out.println("    <tag k='"+ XmlWriter.encode(e.getKey()) +
Note: See TracChangeset for help on using the changeset viewer.