Changeset 2115 in josm


Ignore:
Timestamp:
Sep 13, 2009 7:30:36 PM (4 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.