Changeset 2599 in josm for trunk/src/org/openstreetmap


Ignore:
Timestamp:
2009-12-09T21:25:40+01:00 (14 years ago)
Author:
Gubaer
Message:

fixed #4130: Chunked upload mode counter is wrong
fixed #4118: Upload dialog too complicated
fixed #4129: Hide the new "Upload data in one request/chunks/individually" behind an expanding "Upload method" box
fixed #2075: API 0.6: don't upload more than 50K edits at once
fixed #4044: Huge uploads never end [should be solved with chunked upload mode]
fixed #4110: Upload dialog spacing wrong
fixed #3386: Upload dialog has empty areas when the changeset doesn't include all of add/modify/delete operations
see #3369: bulk import helper [JOSM now supports multi changesets uploads]

See online help for more details.

Completes r2598

Location:
trunk/src/org/openstreetmap/josm
Files:
12 added
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/io/CloseChangesetTask.java

    r2512 r2599  
    6060                    public void run() {
    6161                        for (Changeset cs: closedChangesets) {
    62                             UploadDialog.getUploadDialog().setOrUpdateChangeset(cs);
     62                            UploadDialog.getUploadDialog().updateListOfChangesetsAfterUploadOperation(cs);
    6363                        }
    6464                    }
  • trunk/src/org/openstreetmap/josm/gui/io/DownloadOpenChangesetsTask.java

    r2512 r2599  
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.gui.io;
     3
     4import static org.openstreetmap.josm.tools.I18n.tr;
    35
    46import java.io.IOException;
     
    1315import org.openstreetmap.josm.gui.ExceptionDialogUtil;
    1416import org.openstreetmap.josm.gui.PleaseWaitRunnable;
    15 import org.openstreetmap.josm.gui.io.UploadDialog.OpenChangesetModel;
    1617import org.openstreetmap.josm.io.ChangesetQuery;
    1718import org.openstreetmap.josm.io.OsmServerChangesetReader;
     
    1920import org.openstreetmap.josm.io.OsmTransferException;
    2021import org.xml.sax.SAXException;
    21 import static org.openstreetmap.josm.tools.I18n.tr;
    2222
    2323/**
     
    3131    private OsmServerChangesetReader reader;
    3232    private List<Changeset> changesets;
    33     private OpenChangesetModel model;
     33    private OpenChangesetComboBoxModel model;
    3434    private Exception lastException;
    3535    private UserInfo userInfo;
     
    4040     * after download
    4141     */
    42     public DownloadOpenChangesetsTask(OpenChangesetModel model) {
     42    public DownloadOpenChangesetsTask(OpenChangesetComboBoxModel model) {
    4343        super(tr("Downloading open changesets ...", false /* don't ignore exceptions */));
    4444        this.model = model;
  • trunk/src/org/openstreetmap/josm/gui/io/SaveLayersDialog.java

    r2569 r2599  
    3333import org.openstreetmap.josm.Main;
    3434import org.openstreetmap.josm.actions.UploadAction;
     35import org.openstreetmap.josm.data.APIDataSet;
    3536import org.openstreetmap.josm.gui.ExceptionDialogUtil;
    3637import org.openstreetmap.josm.gui.SideButton;
     
    406407                    continue;
    407408                }
     409                final UploadDialog dialog = UploadDialog.getUploadDialog();
     410                dialog.setUploadedPrimitives(new APIDataSet(layerInfo.getLayer().data));
     411                dialog.setVisible(true);
     412                if (dialog.isCanceled()) {
     413                    model.setUploadState(layerInfo.getLayer(), UploadOrSaveState.CANCELLED);
     414                    continue;
     415                }
     416                dialog.rememberUserInput();
    408417
    409418                currentTask = new UploadLayerTask(
     
    411420                        layerInfo.getLayer(),
    412421                        monitor,
    413                         UploadDialog.getUploadDialog().getChangeset(),
    414                         UploadDialog.getUploadDialog().isDoCloseAfterUpload()
     422                        UploadDialog.getUploadDialog().getChangeset()
    415423                );
    416424                currentFuture = worker.submit(currentTask);
  • trunk/src/org/openstreetmap/josm/gui/io/UploadDialog.java

    r2569 r2599  
    1 // License: GPL. For details, see LICENSE file.
    21package org.openstreetmap.josm.gui.io;
    32
    43import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
    54import static org.openstreetmap.josm.tools.I18n.tr;
    6 import static org.openstreetmap.josm.tools.I18n.trn;
    75
    86import java.awt.BorderLayout;
    97import java.awt.Dimension;
    108import java.awt.FlowLayout;
    11 import java.awt.GridBagConstraints;
    12 import java.awt.GridBagLayout;
    139import java.awt.event.ActionEvent;
    14 import java.awt.event.ActionListener;
    15 import java.awt.event.ItemEvent;
    16 import java.awt.event.ItemListener;
    1710import java.awt.event.KeyEvent;
    1811import java.awt.event.WindowAdapter;
    1912import java.awt.event.WindowEvent;
    20 import java.util.ArrayList;
    21 import java.util.Collection;
     13import java.beans.PropertyChangeEvent;
     14import java.beans.PropertyChangeListener;
    2215import java.util.Collections;
    23 import java.util.LinkedList;
    2416import java.util.List;
     17import java.util.logging.Logger;
    2518
    2619import javax.swing.AbstractAction;
    27 import javax.swing.AbstractListModel;
    2820import javax.swing.BorderFactory;
    29 import javax.swing.ButtonGroup;
    30 import javax.swing.DefaultComboBoxModel;
    3121import javax.swing.InputMap;
    3222import javax.swing.JButton;
    33 import javax.swing.JCheckBox;
    34 import javax.swing.JComboBox;
    3523import javax.swing.JComponent;
    3624import javax.swing.JDialog;
    37 import javax.swing.JLabel;
    38 import javax.swing.JList;
    3925import javax.swing.JOptionPane;
    4026import javax.swing.JPanel;
    41 import javax.swing.JRadioButton;
    42 import javax.swing.JScrollPane;
    4327import javax.swing.JTabbedPane;
    4428import javax.swing.KeyStroke;
    45 import javax.swing.event.ChangeEvent;
    46 import javax.swing.event.ChangeListener;
    47 import javax.swing.event.ListDataEvent;
    48 import javax.swing.event.ListDataListener;
    4929
    5030import org.openstreetmap.josm.Main;
     31import org.openstreetmap.josm.data.APIDataSet;
    5132import org.openstreetmap.josm.data.osm.Changeset;
    5233import org.openstreetmap.josm.data.osm.OsmPrimitive;
    5334import org.openstreetmap.josm.gui.HelpAwareOptionPane;
    54 import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
    5535import org.openstreetmap.josm.gui.SideButton;
    5636import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
    5737import org.openstreetmap.josm.gui.help.HelpUtil;
    58 import org.openstreetmap.josm.gui.tagging.TagEditorModel;
    59 import org.openstreetmap.josm.gui.tagging.TagEditorPanel;
    60 import org.openstreetmap.josm.gui.tagging.TagModel;
    61 import org.openstreetmap.josm.gui.widgets.HistoryComboBox;
    62 import org.openstreetmap.josm.tools.GBC;
     38import org.openstreetmap.josm.io.OsmApi;
    6339import org.openstreetmap.josm.tools.ImageProvider;
    6440import org.openstreetmap.josm.tools.WindowGeometry;
     
    6945 *
    7046 */
    71 public class UploadDialog extends JDialog {
    72 
    73     public static final String HISTORY_KEY = "upload.comment.history";
     47public class UploadDialog extends JDialog implements PropertyChangeListener{
     48    protected static final Logger logger = Logger.getLogger(UploadDialog.class.getName());
    7449
    7550    /**  the unique instance of the upload dialog */
     
    8863    }
    8964
    90     /** the list with the added primitives */
    91     private PrimitiveList lstAdd;
    92     private JLabel lblAdd;
    93     private JScrollPane spAdd;
    94     /** the list with the updated primitives */
    95     private PrimitiveList lstUpdate;
    96     private JLabel lblUpdate;
    97     private JScrollPane spUpdate;
    98     /** the list with the deleted primitives */
    99     private PrimitiveList lstDelete;
    100     private JLabel lblDelete;
    101     private JScrollPane spDelete;
    102     /** the panel containing the widgets for the lists of primitives */
    103     private JPanel pnlLists;
     65    /** the panel with the objects to upload */
     66    private UploadedObjectsSummaryPanel pnlUploadedObjects;
     67    /** the panel to select the changeset used */
     68    private ChangesetManagementPanel pnlChangesetManagement;
     69
     70    private BasicUploadSettingsPanel pnlBasicUploadSettings;
     71
     72    private UploadStrategySelectionPanel pnlUploadStrategySelectionPanel;
     73
    10474    /** checkbox for selecting whether an atomic upload is to be used  */
    105     private TagEditorPanel tagEditorPanel;
     75    private TagSettingsPanel pnlTagSettings;
    10676    /** the tabbed pane used below of the list of primitives  */
    107     private JTabbedPane southTabbedPane;
     77    private JTabbedPane tpConfigPanels;
    10878    /** the upload button */
    10979    private JButton btnUpload;
    11080
    111     private ChangesetSelectionPanel pnlChangesetSelection;
    11281    private boolean canceled = false;
    11382
    114     /**
    115      * builds the panel with the lists of primitives
    116      *
    117      * @return the panel with the lists of primitives
    118      */
    119     protected JPanel buildListsPanel() {
    120         pnlLists = new JPanel();
    121         pnlLists.setLayout(new GridBagLayout());
    122         // we don't add the lists yet, see setUploadPrimitives()
    123         //
    124         return pnlLists;
    125     }
    12683
    12784    /**
     
    13390        JPanel pnl = new JPanel();
    13491        pnl.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    135         pnl.setLayout(new GridBagLayout());
    136         GridBagConstraints gc = new GridBagConstraints();
    137 
    138         // first the panel with the list in the upper half
     92        pnl.setLayout(new BorderLayout());
     93
     94        // the panel with the list of uploaded objects
    13995        //
    140         gc.fill = GridBagConstraints.BOTH;
    141         gc.weightx = 1.0;
    142         gc.weighty = 1.0;
    143         pnl.add(buildListsPanel(), gc);
     96        pnl.add(pnlUploadedObjects = new UploadedObjectsSummaryPanel(), BorderLayout.CENTER);
    14497
    14598        // a tabbed pane with two configuration panels in the
    14699        // lower half
    147100        //
    148         southTabbedPane = new JTabbedPane();
    149         southTabbedPane.add(new JPanel());
    150         tagEditorPanel = new TagEditorPanel();
    151         southTabbedPane.add(tagEditorPanel);
    152         southTabbedPane.setComponentAt(0, pnlChangesetSelection = new ChangesetSelectionPanel());
    153         southTabbedPane.setTitleAt(0, tr("Settings"));
    154         southTabbedPane.setToolTipTextAt(0, tr("Decide how to upload the data and which changeset to use"));
    155         southTabbedPane.setTitleAt(1, tr("Tags of new changeset"));
    156         southTabbedPane.setToolTipTextAt(1, tr("Apply tags to the changeset data is uploaded to"));
    157         southTabbedPane.addChangeListener(new TabbedPaneChangeLister());
    158         JPanel pnl1 = new JPanel();
    159         pnl1.setLayout(new BorderLayout());
    160         pnl1.add(southTabbedPane,BorderLayout.CENTER);
    161         gc.fill = GridBagConstraints.HORIZONTAL;
    162         gc.gridy = 1;
    163         gc.weightx = 1.0;
    164         gc.weighty = 0.0;
    165         pnl.add(pnl1, gc);
     101        tpConfigPanels = new JTabbedPane() {
     102            @Override
     103            public Dimension getPreferredSize() {
     104                // make sure the tabbed pane never grabs more space than necessary
     105                //
     106                return super.getMinimumSize();
     107            }
     108        };
     109        tpConfigPanels.add(new JPanel());
     110        tpConfigPanels.add(new JPanel());
     111        tpConfigPanels.add(new JPanel());
     112        tpConfigPanels.add(new JPanel());
     113
     114        tpConfigPanels.setComponentAt(0, pnlBasicUploadSettings = new BasicUploadSettingsPanel());
     115        tpConfigPanels.setTitleAt(0, tr("Settings"));
     116        tpConfigPanels.setToolTipTextAt(0, tr("Decide how to upload the data and which changeset to use"));
     117
     118        tpConfigPanels.setComponentAt(1,pnlTagSettings = new TagSettingsPanel());
     119        tpConfigPanels.setTitleAt(1, tr("Tags of new changeset"));
     120        tpConfigPanels.setToolTipTextAt(1, tr("Apply tags to the changeset data is uploaded to"));
     121
     122        tpConfigPanels.setComponentAt(2,pnlChangesetManagement = new ChangesetManagementPanel());
     123        tpConfigPanels.setTitleAt(2, tr("Changesets"));
     124        tpConfigPanels.setToolTipTextAt(2, tr("Manage open changesets and select a changeset to upload to"));
     125
     126        tpConfigPanels.setComponentAt(3, pnlUploadStrategySelectionPanel = new UploadStrategySelectionPanel());
     127        tpConfigPanels.setTitleAt(3, tr("Advanced"));
     128        tpConfigPanels.setToolTipTextAt(3, tr("Configure advanced settings"));
     129
     130        pnl.add(tpConfigPanels, BorderLayout.SOUTH);
    166131        return pnl;
    167132    }
     
    193158                JComponent.WHEN_IN_FOCUSED_WINDOW
    194159        );
    195         pnl.add(new SideButton(new ContextSensitiveHelpAction(ht("/Dialogs/UploadDialog"))));
    196         HelpUtil.setHelpContext(getRootPane(),ht("/Dialogs/UploadDialog"));
     160        pnl.add(new SideButton(new ContextSensitiveHelpAction(ht("/Dialog/UploadDialog"))));
     161        HelpUtil.setHelpContext(getRootPane(),ht("/Dialog/UploadDialog"));
    197162        return pnl;
    198163    }
     
    202167     */
    203168    protected void build() {
    204         setTitle(tr("Upload"));
     169        setTitle(tr("Upload to ''{0}''", OsmApi.getOsmApi().getBaseUrl()));
    205170        getContentPane().setLayout(new BorderLayout());
    206171        getContentPane().add(buildContentPanel(), BorderLayout.CENTER);
     
    208173
    209174        addWindowListener(new WindowEventHandler());
     175
     176        // synchronized input of upload comments
     177        //
     178        //UploadCommentSynchronizer synchronizer = new UploadCommentSynchronizer();
     179        //pnlTagSettings.getModeaddTableModelListener(synchronizer);
     180        pnlTagSettings.addPropertyChangeListener(pnlBasicUploadSettings);
     181        pnlBasicUploadSettings.addPropertyChangeListener(pnlTagSettings);
     182
     183
     184        // make sure the the configuration panels listen to each other
     185        // changes
     186        //
     187        pnlChangesetManagement.addPropertyChangeListener(
     188                pnlBasicUploadSettings.getUploadParameterSummaryPanel()
     189        );
     190        pnlChangesetManagement.addPropertyChangeListener(pnlTagSettings);
     191        pnlChangesetManagement.addPropertyChangeListener(this);
     192        pnlUploadedObjects.addPropertyChangeListener(
     193                pnlBasicUploadSettings.getUploadParameterSummaryPanel()
     194        );
     195        pnlUploadedObjects.addPropertyChangeListener(pnlUploadStrategySelectionPanel);
     196        pnlUploadStrategySelectionPanel.addPropertyChangeListener(
     197                pnlBasicUploadSettings.getUploadParameterSummaryPanel()
     198        );
     199
     200        // users can click on either of two links in the upload parameter
     201        // summary handler. This installs the handler for these two events.
     202        // We simply select the appropriate tab in the tabbed pane with the
     203        // configuration dialogs.
     204        //
     205        pnlBasicUploadSettings.getUploadParameterSummaryPanel().setConfigurationParameterRequestListener(
     206                new ConfigurationParameterRequestHandler() {
     207                    public void handleUploadStrategyConfigurationRequest() {
     208                        tpConfigPanels.setSelectedIndex(3);
     209                    }
     210                    public void handleChangesetConfigurationRequest() {
     211                        tpConfigPanels.setSelectedIndex(2);
     212                    }
     213                }
     214        );
     215
     216        pnlBasicUploadSettings.setUploadCommentDownFocusTraversalHandler(
     217                new AbstractAction() {
     218                    public void actionPerformed(ActionEvent e) {
     219                        btnUpload.requestFocusInWindow();
     220                    }
     221                }
     222        );
    210223    }
    211224
     
    215228    public UploadDialog() {
    216229        super(JOptionPane.getFrameForComponent(Main.parent), true /* modal */);
    217         OsmPrimitivRenderer renderer = new OsmPrimitivRenderer();
    218 
    219         // initialize the three lists for primitives
    220         //
    221         lstAdd = new PrimitiveList();
    222         lstAdd.setCellRenderer(renderer);
    223         lstAdd.setVisibleRowCount(Math.min(lstAdd.getModel().getSize(), 10));
    224         spAdd = new JScrollPane(lstAdd);
    225         lblAdd = new JLabel(tr("Objects to add:"));
    226 
    227         lstUpdate = new PrimitiveList();
    228         lstUpdate.setCellRenderer(renderer);
    229         lstUpdate.setVisibleRowCount(Math.min(lstUpdate.getModel().getSize(), 10));
    230         spUpdate = new JScrollPane(lstUpdate);
    231         lblUpdate = new JLabel(tr("Objects to modify:"));
    232 
    233         lstDelete = new PrimitiveList();
    234         lstDelete.setCellRenderer(renderer);
    235         lstDelete.setVisibleRowCount(Math.min(lstDelete.getModel().getSize(), 10));
    236         spDelete = new JScrollPane(lstDelete);
    237         lblDelete = new JLabel(tr("Objects to delete:"));
    238 
    239         // build the GUI
    240         //
    241230        build();
    242231    }
    243232
    244233    /**
    245      * sets the collection of primitives which will be uploaded
    246      *
    247      * @param add  the collection of primitives to add
    248      * @param update the collection of primitives to update
    249      * @param delete the collection of primitives to delete
    250      */
    251     public void setUploadedPrimitives(List<OsmPrimitive> add, List<OsmPrimitive> update, List<OsmPrimitive> delete) {
    252         lstAdd.getPrimitiveListModel().setPrimitives(add);
    253         lstUpdate.getPrimitiveListModel().setPrimitives(update);
    254         lstDelete.getPrimitiveListModel().setPrimitives(delete);
    255 
    256         GridBagConstraints gcLabel = new GridBagConstraints();
    257         gcLabel.fill = GridBagConstraints.HORIZONTAL;
    258         gcLabel.weightx = 1.0;
    259         gcLabel.weighty = 0.0;
    260         gcLabel.anchor = GridBagConstraints.FIRST_LINE_START;
    261 
    262         GridBagConstraints gcList = new GridBagConstraints();
    263         gcList.fill = GridBagConstraints.BOTH;
    264         gcList.weightx = 1.0;
    265         gcList.weighty = 1.0;
    266         gcList.anchor = GridBagConstraints.CENTER;
    267         pnlLists.removeAll();
    268         int y = -1;
    269         if (!add.isEmpty()) {
    270             y++;
    271             gcLabel.gridy = y;
    272             lblAdd.setText(trn("{0} object to add:", "{0} objects to add:", add.size(),add.size()));
    273             pnlLists.add(lblAdd, gcLabel);
    274             y++;
    275             gcList.gridy = y;
    276             pnlLists.add(spAdd, gcList);
    277         }
    278         if (!update.isEmpty()) {
    279             y++;
    280             gcLabel.gridy = y;
    281             lblUpdate.setText(trn("{0} object to modify:", "{0} objects to modify:", update.size(),update.size()));
    282             pnlLists.add(lblUpdate, gcLabel);
    283             y++;
    284             gcList.gridy = y;
    285             pnlLists.add(spUpdate, gcList);
    286         }
    287         if (!delete.isEmpty()) {
    288             y++;
    289             gcLabel.gridy = y;
    290             lblDelete.setText(trn("{0} object to delete:", "{0} objects to delete:", delete.size(),delete.size()));
    291             pnlLists.add(lblDelete, gcLabel);
    292             y++;
    293             gcList.gridy = y;
    294             pnlLists.add(spDelete, gcList);
    295         }
    296         pnlChangesetSelection.setNumUploadedObjects(add.size() + update.size() + delete.size());
     234     * Sets the collection of primitives to upload
     235     *
     236     * @param toUpload the dataset with the objects to upload. If null, assumes the empty
     237     * set of objects to upload
     238     *
     239     */
     240    public void setUploadedPrimitives(APIDataSet toUpload) {
     241        if (toUpload == null) {
     242            List<OsmPrimitive> emptyList = Collections.emptyList();
     243            pnlUploadedObjects.setUploadedPrimitives(emptyList, emptyList, emptyList);
     244            return;
     245        }
     246        pnlUploadedObjects.setUploadedPrimitives(
     247                toUpload.getPrimitivesToAdd(),
     248                toUpload.getPrimitivesToUpdate(),
     249                toUpload.getPrimitivesToDelete()
     250        );
    297251    }
    298252
     
    301255     */
    302256    public void rememberUserInput() {
    303         pnlChangesetSelection.rememberUserInput();
     257        pnlBasicUploadSettings.rememberUserInput();
     258        pnlUploadStrategySelectionPanel.rememberUserInput();
    304259    }
    305260
     
    308263     */
    309264    public void startUserInput() {
    310         tagEditorPanel.initAutoCompletion(Main.main.getEditLayer());
    311         pnlChangesetSelection.startUserInput();
     265        tpConfigPanels.setSelectedIndex(0);
     266        pnlBasicUploadSettings.startUserInput();
     267        pnlTagSettings.startUserInput();
     268        pnlTagSettings.setUploadComment(getUploadComment());
     269        pnlTagSettings.initFromChangeset(pnlChangesetManagement.getSelectedChangeset());
     270        pnlUploadStrategySelectionPanel.initFromPreferences();
     271        UploadParameterSummaryPanel pnl = pnlBasicUploadSettings.getUploadParameterSummaryPanel();
     272        pnl.setUploadStrategySpecification(pnlUploadStrategySelectionPanel.getUploadStrategySpecification());
     273        pnl.setCloseChangesetAfterNextUpload(pnlChangesetManagement.isCloseChangesetAfterUpload());
     274        pnl.setNumObjects(pnlUploadedObjects.getNumObjectsToUpload());
    312275    }
    313276
     
    318281     */
    319282    public Changeset getChangeset() {
    320         Changeset cs = pnlChangesetSelection.getChangeset();
    321         tagEditorPanel.getModel().applyToPrimitive(cs);
    322         cs.put("comment", getUploadComment());
     283        Changeset cs = pnlChangesetManagement.getSelectedChangeset();
     284        if (cs == null) {
     285            cs = new Changeset();
     286        }
     287        cs.setKeys(pnlTagSettings.getTags());
    323288        return cs;
    324289    }
     
    330295     */
    331296    public UploadStrategySpecification getUploadStrategySpecification() {
    332         return pnlChangesetSelection.getUploadStrategySpecification();
     297        UploadStrategySpecification spec = pnlUploadStrategySelectionPanel.getUploadStrategySpecification();
     298        spec.setCloseChangesetAfterUpload(pnlChangesetManagement.isCloseChangesetAfterUpload());
     299        return spec;
    333300    }
    334301
     
    343310     * @param cs the changeset
    344311     */
    345     public void setOrUpdateChangeset(Changeset cs) {
    346         pnlChangesetSelection.setOrUpdateChangeset(cs);
     312    public void updateListOfChangesetsAfterUploadOperation(Changeset cs) {
     313        pnlChangesetManagement.updateListOfChangesetsAfterUploadOperation(cs);
    347314    }
    348315
     
    355322    public void removeChangeset(Changeset cs) {
    356323        if (cs == null) return;
    357         pnlChangesetSelection.removeChangeset(cs);
    358     }
    359 
    360     /**
    361      * Replies true if the changeset is to be closed after the
    362      * next upload
    363      *
    364      * @return true if the changeset is to be closed after the
    365      * next upload; false, otherwise
    366      */
    367     public boolean isDoCloseAfterUpload() {
    368         return pnlChangesetSelection.isCloseAfterUpload();
    369     }
    370 
    371     /**
    372      * Replies the default value for "created_by"
    373      *
    374      * @return the default value for "created_by"
    375      */
    376     protected String getDefaultCreatedBy() {
    377         Object ua = System.getProperties().get("http.agent");
    378         return(ua == null) ? "JOSM" : ua.toString();
     324        pnlChangesetManagement.removeChangeset(cs);
    379325    }
    380326
     
    385331     */
    386332    protected String getUploadComment() {
    387         switch(southTabbedPane.getSelectedIndex()) {
    388         case 0:
    389             return pnlChangesetSelection.getUploadComment();
    390         case 1:
    391             TagModel tm = tagEditorPanel.getModel().get("comment");
    392             return tm == null? "" : tm.getValue();
    393         }
    394         return "";
     333        return pnlBasicUploadSettings.getUploadComment();
    395334    }
    396335
     
    405344
    406345    /**
    407      * Sets whether the dialog was canceld
     346     * Sets whether the dialog was canceled
    408347     *
    409348     * @param canceled true, if the dialog is canceled
     
    423362                    )
    424363            ).apply(this);
     364            startUserInput();
    425365        } else if (!visible && isShowing()){
    426366            new WindowGeometry(this).remember(getClass().getName() + ".geometry");
    427367        }
    428368        super.setVisible(visible);
    429     }
    430 
    431     /**
    432      * This change listener is triggered when current tab in the tabbed pane in
    433      * the lower half of the dialog is changed.
    434      *
    435      * It's main purpose is to keep the content in the text field for the changeset
    436      * comment in sync with the changeset tag "comment".
    437      *
    438      */
    439     class TabbedPaneChangeLister implements ChangeListener {
    440 
    441         protected boolean hasCommentTag() {
    442             TagEditorModel model = tagEditorPanel.getModel();
    443             return model.get("comment") != null;
    444         }
    445 
    446         protected TagModel getEmptyTag() {
    447             TagEditorModel model = tagEditorPanel.getModel();
    448             TagModel tm = model.get("");
    449             if (tm != null) return tm;
    450             tm = new TagModel("", "");
    451             model.add(tm);
    452             return tm;
    453         }
    454         protected TagModel getOrCreateCommentTag() {
    455             TagEditorModel model = tagEditorPanel.getModel();
    456             if (hasCommentTag())
    457                 return model.get("comment");
    458             TagModel tm = getEmptyTag();
    459             tm.setName("comment");
    460             return tm;
    461         }
    462 
    463         protected void removeCommentTag() {
    464             TagEditorModel model = tagEditorPanel.getModel();
    465             model.delete("comment");
    466         }
    467 
    468         protected void refreshCommentTag() {
    469             TagModel tm = getOrCreateCommentTag();
    470             tm.setName("comment");
    471             tm.setValue(pnlChangesetSelection.getUploadComment().trim());
    472             if (pnlChangesetSelection.getUploadComment().trim().equals("")) {
    473                 removeCommentTag();
    474             }
    475             tagEditorPanel.getModel().fireTableDataChanged();
    476         }
    477 
    478         public void stateChanged(ChangeEvent e) {
    479             if (southTabbedPane.getSelectedIndex() ==0) {
    480                 TagModel tm = tagEditorPanel.getModel().get("comment");
    481                 pnlChangesetSelection.initEditingOfUploadComment(tm == null ? "" : tm.getValue());
    482             } else if (southTabbedPane.getSelectedIndex() == 1) {
    483                 refreshCommentTag();
    484             }
    485         }
    486369    }
    487370
     
    504387                    JOptionPane.ERROR_MESSAGE,
    505388                    ht("/Dialog/UploadDialog#IllegalUploadComment")
    506 
    507389            );
    508390        }
     
    518400        }
    519401
    520 
    521402        public void actionPerformed(ActionEvent e) {
    522403            if (getUploadComment().trim().length() < 3) {
    523404                warnIllegalUploadComment();
    524                 southTabbedPane.setSelectedIndex(0);
    525                 pnlChangesetSelection.initEditingOfUploadComment(getUploadComment());
     405                tpConfigPanels.setSelectedIndex(0);
     406                pnlBasicUploadSettings.initEditingOfUploadComment(getUploadComment());
    526407                return;
    527408            }
     
    530411                if (strategy.getChunkSize() == UploadStrategySpecification.UNSPECIFIED_CHUNK_SIZE) {
    531412                    warnIllegalChunkSize();
    532                     southTabbedPane.setSelectedIndex(0);
    533                     pnlChangesetSelection.initEditingOfChunkSize();
     413                    tpConfigPanels.setSelectedIndex(0);
    534414                    return;
    535415                }
     
    558438
    559439    /**
    560      * A simple list of OSM primitives.
    561      *
    562      */
    563     class PrimitiveList extends JList {
    564         public PrimitiveList() {
    565             super(new PrimitiveListModel());
    566         }
    567 
    568         public PrimitiveListModel getPrimitiveListModel() {
    569             return (PrimitiveListModel)getModel();
    570         }
    571     }
    572 
    573     /**
    574      * A list model for a list of OSM primitives.
    575      *
    576      */
    577     class PrimitiveListModel extends AbstractListModel{
    578         private List<OsmPrimitive> primitives;
    579 
    580         public PrimitiveListModel() {
    581             primitives = new ArrayList<OsmPrimitive>();
    582         }
    583 
    584         public PrimitiveListModel(List<OsmPrimitive> primitives) {
    585             setPrimitives(primitives);
    586         }
    587 
    588         public void setPrimitives(List<OsmPrimitive> primitives) {
    589             if (primitives == null) {
    590                 this.primitives = new ArrayList<OsmPrimitive>();
    591             } else {
    592                 this.primitives = primitives;
    593             }
    594             fireContentsChanged(this,0,getSize());
    595         }
    596 
    597         public Object getElementAt(int index) {
    598             if (primitives == null) return null;
    599             return primitives.get(index);
    600         }
    601 
    602         public int getSize() {
    603             if (primitives == null) return 0;
    604             return primitives.size();
    605         }
    606     }
    607 
    608     /**
    609440     * Listens to window closing events and processes them as cancel events.
    610441     * Listens to window open events and initializes user input
     
    619450        @Override
    620451        public void windowOpened(WindowEvent e) {
    621             startUserInput();
    622         }
    623     }
    624 
    625     /**
    626      * The panel which provides various UI widgets for controlling how to use
    627      * changesets during upload.
    628      *
    629      */
    630     class ChangesetSelectionPanel extends JPanel implements ListDataListener{
    631 
    632         private ButtonGroup bgUseNewOrExisting;
    633         private JRadioButton rbUseNew;
    634         private JRadioButton rbExisting;
    635         private JComboBox cbOpenChangesets;
    636         private JButton btnRefresh;
    637         private JButton btnClose;
    638         private JCheckBox cbCloseAfterUpload;
    639         private OpenChangesetModel model;
    640         private HistoryComboBox cmt;
    641         private UploadStrategySelectionPanel pnlUploadStrategy;
    642 
    643         /**
    644          * build the panel with the widgets for controlling whether an atomic upload
    645          * should be used or not
    646          *
    647          * @return the panel
    648          */
    649         protected JPanel buildUploadStrategySelectionPanel() {
    650             pnlUploadStrategy = new UploadStrategySelectionPanel();
    651             pnlUploadStrategy.initFromPreferences();
    652             return pnlUploadStrategy;
    653         }
    654 
    655         protected JPanel buildUploadCommentPanel() {
    656             JPanel pnl = new JPanel();
    657             pnl.setLayout(new GridBagLayout());
    658             pnl.add(new JLabel(tr("Provide a brief comment for the changes you are uploading:")), GBC.eol().insets(0, 5, 10, 3));
    659             cmt = new HistoryComboBox();
    660             cmt.setToolTipText(tr("Enter an upload comment (min. 3 characters)"));
    661             List<String> cmtHistory = new LinkedList<String>(Main.pref.getCollection(HISTORY_KEY, new LinkedList<String>()));
    662             // we have to reverse the history, because ComboBoxHistory will reverse it again
    663             // in addElement()
    664             //
    665             Collections.reverse(cmtHistory);
    666             cmt.setPossibleItems(cmtHistory);
    667             cmt.getEditor().addActionListener(
    668                     new ActionListener() {
    669                         public void actionPerformed(ActionEvent e) {
    670                             TagModel tm = tagEditorPanel.getModel().get("comment");
    671                             if (tm == null) {
    672                                 tagEditorPanel.getModel().add(new TagModel("comment", cmt.getText()));
    673                             } else {
    674                                 tm.setValue(cmt.getText());
    675                             }
    676                             tagEditorPanel.getModel().fireTableDataChanged();
    677                         }
    678                     }
    679             );
    680             cmt.getEditor().addActionListener(
    681                     new ActionListener() {
    682                         public void actionPerformed(ActionEvent e) {
    683                             btnUpload.requestFocusInWindow();
    684                         }
    685                     }
    686             );
    687             pnl.add(cmt, GBC.eol().fill(GBC.HORIZONTAL));
    688             return pnl;
    689         }
    690 
    691         protected void build() {
    692             setLayout(new GridBagLayout());
    693             GridBagConstraints gc = new GridBagConstraints();
    694 
    695             bgUseNewOrExisting = new ButtonGroup();
    696 
    697             // -- atomic upload
    698             gc.gridwidth = 4;
    699             gc.gridy = 0;
    700             gc.fill = GridBagConstraints.HORIZONTAL;
    701             gc.weightx = 1.0;
    702             gc.anchor = GridBagConstraints.FIRST_LINE_START;
    703             add(buildUploadStrategySelectionPanel(), gc);
    704 
    705             // -- changeset command
    706             gc.gridwidth = 4;
    707             gc.gridy = 1;
    708             gc.fill = GridBagConstraints.HORIZONTAL;
    709             gc.weightx = 1.0;
    710             gc.anchor = GridBagConstraints.FIRST_LINE_START;
    711             add(buildUploadCommentPanel(), gc);
    712 
    713             gc.gridwidth = 4;
    714             gc.gridy = 2;
    715             gc.fill = GridBagConstraints.HORIZONTAL;
    716             gc.weightx = 0.0;
    717             gc.anchor = GridBagConstraints.FIRST_LINE_START;
    718             rbUseNew = new JRadioButton(tr("Open a new changeset"));
    719             rbUseNew.setToolTipText(tr("Open a new changeset and use it in the next upload"));
    720             bgUseNewOrExisting.add(rbUseNew);
    721             add(rbUseNew, gc);
    722 
    723             gc.gridx = 0;
    724             gc.gridy = 3;
    725             gc.gridwidth = 1;
    726             rbExisting = new JRadioButton(tr("Use an open changeset"));
    727             rbExisting.setToolTipText(tr("Upload data to an already opened changeset"));
    728             bgUseNewOrExisting.add(rbExisting);
    729             add(rbExisting, gc);
    730 
    731             gc.gridx = 1;
    732             gc.gridy = 3;
    733             gc.gridwidth = 1;
    734             gc.weightx = 1.0;
    735             model = new OpenChangesetModel();
    736             cbOpenChangesets = new JComboBox(model);
    737             cbOpenChangesets.setToolTipText("Select an open changeset");
    738             cbOpenChangesets.setRenderer(new ChangesetCellRenderer());
    739             cbOpenChangesets.addItemListener(new ChangesetListItemStateListener());
    740             Dimension d = cbOpenChangesets.getPreferredSize();
    741             d.width = 200;
    742             cbOpenChangesets.setPreferredSize(d);
    743             d.width = 100;
    744             cbOpenChangesets.setMinimumSize(d);
    745             model.addListDataListener(this);
    746             add(cbOpenChangesets, gc);
    747 
    748             gc.gridx = 2;
    749             gc.gridy = 3;
    750             gc.gridwidth = 1;
    751             gc.weightx = 0.0;
    752             btnRefresh = new JButton(new RefreshAction());
    753             add(btnRefresh, gc);
    754 
    755             gc.gridx = 3;
    756             gc.gridy = 3;
    757             gc.gridwidth = 1;
    758             gc.weightx = 0.0;
    759             CloseChangesetAction closeChangesetAction = new CloseChangesetAction();
    760             btnClose = new JButton(closeChangesetAction);
    761             cbOpenChangesets.addItemListener(closeChangesetAction);
    762             add(btnClose, gc);
    763 
    764             gc.gridx = 0;
    765             gc.gridy = 4;
    766             gc.gridwidth = 4;
    767             cbCloseAfterUpload = new JCheckBox(tr("Close changeset after upload"));
    768             cbCloseAfterUpload.setToolTipText(tr("Select to close the changeset after the next upload"));
    769             add(cbCloseAfterUpload, gc);
    770             cbCloseAfterUpload.setSelected(true);
    771 
    772             rbUseNew.getModel().addItemListener(new RadioButtonHandler());
    773             rbExisting.getModel().addItemListener(new RadioButtonHandler());
    774 
    775             refreshGUI();
    776         }
    777 
    778         public ChangesetSelectionPanel() {
    779             build();
    780         }
    781 
    782         /**
    783          * Remembers the user input in the preference settings
    784          */
    785         public void rememberUserInput() {
    786             // store the history of comments
    787             cmt.addCurrentItemToHistory();
    788             Main.pref.putCollection(HISTORY_KEY, cmt.getHistory());
    789             pnlUploadStrategy.saveToPreferences();
    790         }
    791 
    792         /**
    793          * Initializes the panel for user input
    794          */
    795         public void startUserInput() {
    796             List<String> history = cmt.getHistory();
    797             if (history != null && !history.isEmpty()) {
    798                 cmt.setText(history.get(0));
     452            //startUserInput();
     453        }
     454
     455        @Override
     456        public void windowActivated(WindowEvent arg0) {
     457            if (tpConfigPanels.getSelectedIndex() == 0) {
     458                pnlBasicUploadSettings.initEditingOfUploadComment(getUploadComment());
    799459            }
    800             cmt.requestFocusInWindow();
    801             cmt.getEditor().getEditorComponent().requestFocusInWindow();
    802         }
    803 
    804         public void prepareDialogForNextUpload(Changeset cs) {
    805             if (cs == null || cs.getId() == 0) {
    806                 rbUseNew.setSelected(true);
    807                 cbCloseAfterUpload.setSelected(true);
    808             } if (cs.getId() == 0) {
    809                 rbUseNew.setSelected(true);
    810                 cbCloseAfterUpload.setSelected(true);
    811             } else if (cs.isOpen()) {
    812                 rbExisting.setSelected(true);
    813                 cbCloseAfterUpload.setSelected(false);
     460        }
     461    }
     462
     463    /* -------------------------------------------------------------------------- */
     464    /* Interface PropertyChangeListener                                           */
     465    /* -------------------------------------------------------------------------- */
     466    public void propertyChange(PropertyChangeEvent evt) {
     467        if (evt.getPropertyName().equals(ChangesetManagementPanel.SELECTED_CHANGESET_PROP)) {
     468            Changeset cs = (Changeset)evt.getNewValue();
     469            if (cs == null) {
     470                tpConfigPanels.setTitleAt(1, tr("Tags of new changeset"));
    814471            } else {
    815                 rbUseNew.setSelected(true);
    816                 cbCloseAfterUpload.setSelected(true);
     472                tpConfigPanels.setTitleAt(1, tr("Tags of changeset {0}", cs.getId()));
    817473            }
    818474        }
    819 
    820         /**
    821          * Replies the current upload comment
    822          *
    823          * @return
    824          */
    825         public String getUploadComment() {
    826             return cmt.getText();
    827         }
    828 
    829         /**
    830          * Replies the current upload comment
    831          *
    832          * @return
    833          */
    834         public void setUploadComment(String uploadComment) {
    835             cmt.setText(uploadComment);
    836         }
    837 
    838         public void initEditingOfUploadComment(String comment) {
    839             setUploadComment(comment);
    840             cmt.getEditor().selectAll();
    841             cmt.requestFocusInWindow();
    842         }
    843 
    844         public void initEditingOfChunkSize() {
    845             pnlUploadStrategy.initEditingOfChunkSize();
    846         }
    847 
    848         protected void refreshGUI() {
    849             rbExisting.setEnabled(model.getSize() > 0);
    850             if (model.getSize() == 0) {
    851                 if (!rbUseNew.isSelected()) {
    852                     rbUseNew.setSelected(true);
    853                 }
    854             }
    855             cbOpenChangesets.setEnabled(model.getSize() > 0 && rbExisting.isSelected());
    856         }
    857 
    858         public void contentsChanged(ListDataEvent e) {
    859             refreshGUI();
    860         }
    861 
    862         public void intervalAdded(ListDataEvent e) {
    863             refreshGUI();
    864         }
    865 
    866         public void intervalRemoved(ListDataEvent e) {
    867             refreshGUI();
    868         }
    869 
    870         public Changeset getChangeset() {
    871             if (rbUseNew.isSelected() || cbOpenChangesets.getSelectedItem() == null)
    872                 return new Changeset();
    873             Changeset cs = (Changeset)cbOpenChangesets.getSelectedItem();
    874             if (cs == null)
    875                 return new Changeset();
    876             return cs;
    877         }
    878 
    879         /**
    880          * Replies the {@see UploadStrategySpecification} the user entered in the dialog.
    881          *
    882          * @return the {@see UploadStrategySpecification} the user entered in the dialog.
    883          */
    884         public UploadStrategySpecification getUploadStrategySpecification() {
    885             return pnlUploadStrategy.getUploadStrategySpecification();
    886         }
    887 
    888         public void setOrUpdateChangeset(Changeset cs) {
    889             if (cs == null) {
    890                 cs = new Changeset();
    891                 cs.put("created_by", getDefaultCreatedBy());
    892                 tagEditorPanel.getModel().initFromPrimitive(cs);
    893                 tagEditorPanel.getModel().appendNewTag();
    894                 prepareDialogForNextUpload(cs);
    895             } else if (cs.getId() == 0) {
    896                 if (cs.get("created_by") == null) {
    897                     cs.put("created_by", getDefaultCreatedBy());
    898                 }
    899                 tagEditorPanel.getModel().initFromPrimitive(cs);
    900                 tagEditorPanel.getModel().appendNewTag();
    901                 prepareDialogForNextUpload(cs);
    902             } else if (cs.getId() > 0 && cs.isOpen()){
    903                 if (cs.get("created_by") == null) {
    904                     cs.put("created_by", getDefaultCreatedBy());
    905                 }
    906                 tagEditorPanel.getModel().initFromPrimitive(cs);
    907                 model.addOrUpdate(cs);
    908                 cs = model.getChangesetById(cs.getId());
    909                 cbOpenChangesets.setSelectedItem(cs);
    910                 prepareDialogForNextUpload(cs);
    911             } else if (cs.getId() > 0 && !cs.isOpen()){
    912                 removeChangeset(cs);
    913             }
    914         }
    915 
    916         /**
    917          * Remove a changeset from the list of open changeset
    918          *
    919          * @param cs the changeset to be removed. Ignored if null.
    920          */
    921         public void removeChangeset(Changeset cs) {
    922             if (cs ==  null) return;
    923             Changeset selected = (Changeset)model.getSelectedItem();
    924             model.removeChangeset(cs);
    925             if (model.getSize() == 0 || selected == cs) {
    926                 // no more changesets or removed changeset is the currently selected
    927                 // changeset? Switch to using a new changeset.
    928                 //
    929                 rbUseNew.setSelected(true);
    930                 model.setSelectedItem(null);
    931                 southTabbedPane.setTitleAt(1, tr("Tags of new changeset"));
    932 
    933                 cs = new Changeset();
    934                 if (cs.get("created_by") == null) {
    935                     cs.put("created_by", getDefaultCreatedBy());
    936                     cs.put("comment", getUploadComment());
    937                 }
    938                 tagEditorPanel.getModel().initFromPrimitive(cs);
    939             }
    940             prepareDialogForNextUpload(cs);
    941         }
    942 
    943         /**
    944          * Sets whether a new changeset is to be used
    945          *
    946          */
    947         public void setUseNewChangeset() {
    948             rbUseNew.setSelected(true);
    949         }
    950 
    951         /**
    952          * Sets whether an existing changeset is to be used
    953          */
    954         public void setUseExistingChangeset() {
    955             rbExisting.setSelected(true);
    956             if (cbOpenChangesets.getSelectedItem() == null && model.getSize() > 0) {
    957                 cbOpenChangesets.setSelectedItem(model.getElementAt(0));
    958             }
    959         }
    960 
    961         /**
    962          * Replies true if the selected changeset should be closed after the
    963          * next upload
    964          *
    965          * @return true if the selected changeset should be closed after the
    966          * next upload
    967          */
    968         public boolean isCloseAfterUpload() {
    969             return cbCloseAfterUpload.isSelected();
    970         }
    971 
    972         public void setNumUploadedObjects(int numUploadedObjects) {
    973             pnlUploadStrategy.setNumUploadedObjects(numUploadedObjects);
    974         }
    975 
    976         class RadioButtonHandler implements ItemListener {
    977             public void itemStateChanged(ItemEvent e) {
    978                 if (rbUseNew.isSelected()) {
    979                     southTabbedPane.setTitleAt(1, tr("Tags of new changeset"));
    980                     // init a new changeset from the currently edited tags
    981                     // and the comment field
    982                     //
    983                     Changeset cs = new Changeset();
    984                     tagEditorPanel.getModel().applyToPrimitive(cs);
    985                     if (cs.get("created_by") == null) {
    986                         cs.put("created_by", getDefaultCreatedBy());
    987                     }
    988                     cs.put("comment", cmt.getText());
    989                     tagEditorPanel.getModel().initFromPrimitive(cs);
    990                 } else {
    991                     if (cbOpenChangesets.getSelectedItem() == null) {
    992                         model.selectFirstChangeset();
    993                     }
    994                     Changeset cs = (Changeset)cbOpenChangesets.getSelectedItem();
    995                     if (cs != null) {
    996                         cs.put("comment", cmt.getText());
    997                         southTabbedPane.setTitleAt(1, tr("Tags of changeset {0}", cs.getId()));
    998                         tagEditorPanel.getModel().initFromPrimitive(cs);
    999                     }
    1000                 }
    1001                 refreshGUI();
    1002             }
    1003         }
    1004 
    1005         class ChangesetListItemStateListener implements ItemListener {
    1006             public void itemStateChanged(ItemEvent e) {
    1007                 Changeset cs = (Changeset)cbOpenChangesets.getSelectedItem();
    1008                 if (cs == null) {
    1009                     southTabbedPane.setTitleAt(1, tr("Tags of new changeset"));
    1010                     // init a new changeset from the currently edited tags
    1011                     // and the comment field
    1012                     //
    1013                     cs = new Changeset();
    1014                     tagEditorPanel.getModel().applyToPrimitive(cs);
    1015                     if (cs.get("created_by") == null) {
    1016                         cs.put("created_by", getDefaultCreatedBy());
    1017                     }
    1018                     cs.put("comment", cmt.getText());
    1019                     tagEditorPanel.getModel().initFromPrimitive(cs);
    1020                 } else {
    1021                     southTabbedPane.setTitleAt(1, tr("Tags of changeset {0}", cs.getId()));
    1022                     if (cs.get("created_by") == null) {
    1023                         cs.put("created_by", getDefaultCreatedBy());
    1024                     }
    1025                     tagEditorPanel.getModel().initFromPrimitive(cs);
    1026                     if (cs.get("comment") != null) {
    1027                         cmt.setText(cs.get("comment"));
    1028                     }
    1029                 }
    1030             }
    1031         }
    1032 
    1033         /**
    1034          * Refreshes the list of open changesets
    1035          *
    1036          */
    1037         class RefreshAction extends AbstractAction {
    1038             public RefreshAction() {
    1039                 //putValue(NAME, tr("Reload"));
    1040                 putValue(SHORT_DESCRIPTION, tr("Load the list of your open changesets from the server"));
    1041                 putValue(SMALL_ICON, ImageProvider.get("dialogs", "refresh"));
    1042             }
    1043 
    1044             public void actionPerformed(ActionEvent e) {
    1045                 DownloadOpenChangesetsTask task = new DownloadOpenChangesetsTask(model);
    1046                 Main.worker.submit(task);
    1047             }
    1048         }
    1049 
    1050         class CloseChangesetAction extends AbstractAction implements ItemListener{
    1051             public CloseChangesetAction() {
    1052                 putValue(NAME, tr("Close"));
    1053                 putValue(SMALL_ICON, ImageProvider.get("closechangeset"));
    1054                 putValue(SHORT_DESCRIPTION, tr("Close the currently selected open changeset"));
    1055                 refreshEnabledState();
    1056             }
    1057 
    1058             public void actionPerformed(ActionEvent e) {
    1059                 Changeset cs = (Changeset)cbOpenChangesets.getSelectedItem();
    1060                 if (cs == null) return;
    1061                 CloseChangesetTask task = new CloseChangesetTask(Collections.singletonList(cs));
    1062                 Main.worker.submit(task);
    1063             }
    1064 
    1065             protected void refreshEnabledState() {
    1066                 setEnabled(cbOpenChangesets.getModel().getSize() > 0 && cbOpenChangesets.getSelectedItem() != null);
    1067             }
    1068 
    1069             public void itemStateChanged(ItemEvent e) {
    1070                 refreshEnabledState();
    1071             }
    1072         }
    1073     }
    1074 
    1075     /**
    1076      * A combobox model for the list of open changesets
    1077      *
    1078      */
    1079     public class OpenChangesetModel extends DefaultComboBoxModel {
    1080         private List<Changeset> changesets;
    1081         private long uid;
    1082         private Changeset selectedChangeset = null;
    1083 
    1084         protected Changeset getChangesetById(long id) {
    1085             for (Changeset cs : changesets) {
    1086                 if (cs.getId() == id) return cs;
    1087             }
    1088             return null;
    1089         }
    1090 
    1091         public OpenChangesetModel() {
    1092             this.changesets = new ArrayList<Changeset>();
    1093         }
    1094 
    1095         protected void internalAddOrUpdate(Changeset cs) {
    1096             Changeset other = getChangesetById(cs.getId());
    1097             if (other != null) {
    1098                 cs.cloneFrom(other);
    1099             } else {
    1100                 changesets.add(cs);
    1101             }
    1102         }
    1103 
    1104         public void addOrUpdate(Changeset cs) {
    1105             if (cs.getId() <= 0 )
    1106                 throw new IllegalArgumentException(tr("Changeset ID > 0 expected. Got {0}.", cs.getId()));
    1107             internalAddOrUpdate(cs);
    1108             fireContentsChanged(this, 0, getSize());
    1109         }
    1110 
    1111         public void remove(long id) {
    1112             Changeset cs = getChangesetById(id);
    1113             if (cs != null) {
    1114                 changesets.remove(cs);
    1115             }
    1116             fireContentsChanged(this, 0, getSize());
    1117         }
    1118 
    1119         public void setChangesets(Collection<Changeset> changesets) {
    1120             this.changesets.clear();
    1121             if (changesets != null) {
    1122                 for (Changeset cs: changesets) {
    1123                     internalAddOrUpdate(cs);
    1124                 }
    1125             }
    1126             fireContentsChanged(this, 0, getSize());
    1127             if (getSelectedItem() == null && !this.changesets.isEmpty()) {
    1128                 setSelectedItem(this.changesets.get(0));
    1129             } else if (getSelectedItem() != null) {
    1130                 if (changesets.contains(getSelectedItem())) {
    1131                     setSelectedItem(getSelectedItem());
    1132                 } else if (!this.changesets.isEmpty()){
    1133                     setSelectedItem(this.changesets.get(0));
    1134                 } else {
    1135                     setSelectedItem(null);
    1136                 }
    1137             } else {
    1138                 setSelectedItem(null);
    1139             }
    1140         }
    1141 
    1142         public void setUserId(long uid) {
    1143             this.uid = uid;
    1144         }
    1145 
    1146         public long getUserId() {
    1147             return uid;
    1148         }
    1149 
    1150         public void selectFirstChangeset() {
    1151             if (changesets == null || changesets.isEmpty()) return;
    1152             setSelectedItem(changesets.get(0));
    1153         }
    1154 
    1155         public void removeChangeset(Changeset cs) {
    1156             if (cs == null) return;
    1157             changesets.remove(cs);
    1158             if (selectedChangeset == cs) {
    1159                 selectFirstChangeset();
    1160             }
    1161             fireContentsChanged(this, 0, getSize());
    1162         }
    1163         /* ------------------------------------------------------------------------------------ */
    1164         /* ComboBoxModel                                                                        */
    1165         /* ------------------------------------------------------------------------------------ */
    1166         @Override
    1167         public Object getElementAt(int index) {
    1168             return changesets.get(index);
    1169         }
    1170 
    1171         @Override
    1172         public int getIndexOf(Object anObject) {
    1173             return changesets.indexOf(anObject);
    1174         }
    1175 
    1176         @Override
    1177         public int getSize() {
    1178             return changesets.size();
    1179         }
    1180 
    1181         @Override
    1182         public Object getSelectedItem() {
    1183             return selectedChangeset;
    1184         }
    1185 
    1186         @Override
    1187         public void setSelectedItem(Object anObject) {
    1188             if (anObject == null) {
    1189                 this.selectedChangeset = null;
    1190                 super.setSelectedItem(null);
    1191                 return;
    1192             }
    1193             if (! (anObject instanceof Changeset)) return;
    1194             Changeset cs = (Changeset)anObject;
    1195             if (cs.getId() == 0 || ! cs.isOpen()) return;
    1196             Changeset candidate = getChangesetById(cs.getId());
    1197             if (candidate == null) return;
    1198             this.selectedChangeset = candidate;
    1199             super.setSelectedItem(selectedChangeset);
    1200         }
    1201475    }
    1202476}
  • trunk/src/org/openstreetmap/josm/gui/io/UploadLayerTask.java

    r2569 r2599  
    4141    private ProgressMonitor monitor;
    4242    private Changeset changeset;
    43     private boolean closeChangesetAfterUpload;
    4443    private Collection<OsmPrimitive> toUpload;
    4544    private HashSet<OsmPrimitive> processedPrimitives;
     
    5352     * @param monitor  a progress monitor. If monitor is null, uses {@see NullProgressMonitor#INSTANCE}
    5453     * @param changeset the changeset to be used
    55      * @param closeChangesetAfterUpload true, if the changeset should be closed after the upload
    5654     * @throws IllegalArgumentException thrown, if layer is null
    5755     * @throws IllegalArgumentException thrown if strategy is null
    5856     */
    59     public UploadLayerTask(UploadStrategySpecification strategy, OsmDataLayer layer, ProgressMonitor monitor, Changeset changeset, boolean closeChangesetAfterUpload) {
     57    public UploadLayerTask(UploadStrategySpecification strategy, OsmDataLayer layer, ProgressMonitor monitor, Changeset changeset) {
    6058        if (layer == null)
    6159            throw new IllegalArgumentException(tr("Parameter ''{0}'' must not be null.", "layer"));
     
    6967        this.changeset = changeset;
    7068        this.strategy = strategy;
    71         this.closeChangesetAfterUpload = closeChangesetAfterUpload;
    7269        processedPrimitives = new HashSet<OsmPrimitive>();
    7370    }
     
    134131                }
    135132            }
    136             if (closeChangesetAfterUpload) {
     133            if (strategy.isCloseChangesetAfterUpload()) {
    137134                if (changeset != null && changeset.getId() > 0) {
    138135                    OsmApi.getOsmApi().closeChangeset(changeset, monitor.createSubTaskMonitor(0, false));
  • trunk/src/org/openstreetmap/josm/gui/io/UploadStrategySelectionPanel.java

    r2569 r2599  
    99import java.awt.GridBagLayout;
    1010import java.awt.Insets;
     11import java.awt.event.ActionEvent;
     12import java.awt.event.ActionListener;
    1113import java.awt.event.FocusEvent;
    1214import java.awt.event.FocusListener;
     15import java.awt.event.ItemEvent;
     16import java.awt.event.ItemListener;
    1317import java.beans.PropertyChangeEvent;
    1418import java.beans.PropertyChangeListener;
     
    2327import javax.swing.JTextField;
    2428import javax.swing.UIManager;
    25 import javax.swing.event.ChangeEvent;
    26 import javax.swing.event.ChangeListener;
    2729import javax.swing.event.DocumentEvent;
    2830import javax.swing.event.DocumentListener;
    2931
    3032import org.openstreetmap.josm.Main;
    31 
    32 public class UploadStrategySelectionPanel extends JPanel {
     33import org.openstreetmap.josm.gui.JMultilineLabel;
     34import org.openstreetmap.josm.io.OsmApi;
     35import org.openstreetmap.josm.tools.ImageProvider;
     36
     37/**
     38 * UploadStrategySelectionPanel is a panel for selecting an upload strategy.
     39 *
     40 * Clients can listen for property change events for the property
     41 * {@see #UPLOAD_STRATEGY_SPECIFICATION_PROP}.
     42 */
     43public class UploadStrategySelectionPanel extends JPanel implements PropertyChangeListener {
     44
     45    /**
     46     * The property for the upload strategy
     47     */
     48    public final static String UPLOAD_STRATEGY_SPECIFICATION_PROP =
     49        UploadStrategySelectionPanel.class.getName() + ".uploadStrategySpecification";
     50
    3351    private static final Color BG_COLOR_ERROR = new Color(255,224,224);
    3452
    3553    private ButtonGroup bgStrategies;
     54    private ButtonGroup bgMultiChangesetPolicies;
    3655    private Map<UploadStrategy, JRadioButton> rbStrategy;
    3756    private Map<UploadStrategy, JLabel> lblNumRequests;
     57    private Map<UploadStrategy, JMultilineLabel> lblStrategies;
    3858    private JTextField tfChunkSize;
     59    private JPanel pnlMultiChangesetPolicyPanel;
     60    private JRadioButton rbFillOneChangeset;
     61    private JRadioButton rbUseMultipleChangesets;
     62    private JMultilineLabel lblMultiChangesetPoliciesHeader;
    3963
    4064    private long numUploadedObjects = 0;
     
    4468    }
    4569
    46     protected void build() {
    47         setLayout(new GridBagLayout());
     70    protected JPanel buildUploadStrategyPanel() {
     71        JPanel pnl = new JPanel();
     72        pnl.setLayout(new GridBagLayout());
    4873        bgStrategies = new ButtonGroup();
    4974        rbStrategy = new HashMap<UploadStrategy, JRadioButton>();
     75        lblStrategies = new HashMap<UploadStrategy, JMultilineLabel>();
    5076        lblNumRequests = new HashMap<UploadStrategy, JLabel>();
    5177        for (UploadStrategy strategy: UploadStrategy.values()) {
    5278            rbStrategy.put(strategy, new JRadioButton());
    5379            lblNumRequests.put(strategy, new JLabel());
     80            lblStrategies.put(strategy, new JMultilineLabel(""));
    5481            bgStrategies.add(rbStrategy.get(strategy));
    5582        }
     
    5986        gc.gridx = 0;
    6087        gc.gridy = 0;
    61         gc.weightx = 0.0;
    62         gc.weighty = 0.0;
    63         gc.insets = new Insets(0,5,0,5);
     88        gc.weightx = 1.0;
     89        gc.weighty = 0.0;
     90        gc.gridwidth = 4;
     91        gc.insets = new Insets(0,0,3,0);
    6492        gc.anchor = GridBagConstraints.FIRST_LINE_START;
    65         add(rbStrategy.get(UploadStrategy.SINGLE_REQUEST_STRATEGY), gc);
    66         gc.gridx = 1;
    67         gc.gridy = 0;
    68         gc.weightx = 0.0;
    69         gc.weighty = 0.0;
    70         gc.gridwidth = 2;
    71         add(new JLabel(tr("Upload data in one request")), gc);
    72         gc.gridx = 3;
    73         gc.gridy = 0;
    74         gc.weightx = 1.0;
    75         gc.weighty = 0.0;
    76         gc.gridwidth = 1;
    77         add(lblNumRequests.get(UploadStrategy.SINGLE_REQUEST_STRATEGY), gc);
    78 
    79         // -- chunked dataset strategy
     93        pnl.add(new JMultilineLabel(tr("Please select the upload strategy:")), gc);
     94
     95        // -- single request strategy
    8096        gc.gridx = 0;
    8197        gc.gridy = 1;
    8298        gc.weightx = 0.0;
    8399        gc.weighty = 0.0;
    84         add(rbStrategy.get(UploadStrategy.CHUNKED_DATASET_STRATEGY), gc);
     100        gc.gridwidth = 1;
     101        gc.anchor = GridBagConstraints.FIRST_LINE_START;
     102        pnl.add(rbStrategy.get(UploadStrategy.SINGLE_REQUEST_STRATEGY), gc);
    85103        gc.gridx = 1;
    86104        gc.gridy = 1;
    87105        gc.weightx = 0.0;
    88106        gc.weighty = 0.0;
    89         gc.gridwidth = 1;
    90         add(new JLabel(tr("Upload data in chunks of objects. Chunk size: ")), gc);
    91         gc.gridx = 2;
    92         gc.gridy = 1;
    93         gc.weightx = 0.0;
    94         gc.weighty = 0.0;
    95         gc.gridwidth = 1;
    96         add(tfChunkSize = new JTextField(4), gc);
     107        gc.gridwidth = 2;
     108        JLabel lbl = lblStrategies.get(UploadStrategy.SINGLE_REQUEST_STRATEGY);
     109        lbl.setText(tr("Upload data in one request"));
     110        pnl.add(lbl, gc);
    97111        gc.gridx = 3;
    98112        gc.gridy = 1;
     
    100114        gc.weighty = 0.0;
    101115        gc.gridwidth = 1;
    102         add(lblNumRequests.get(UploadStrategy.CHUNKED_DATASET_STRATEGY), gc);
     116        pnl.add(lblNumRequests.get(UploadStrategy.SINGLE_REQUEST_STRATEGY), gc);
     117
     118        // -- chunked dataset strategy
     119        gc.gridx = 0;
     120        gc.gridy = 2;
     121        gc.weightx = 0.0;
     122        gc.weighty = 0.0;
     123        pnl.add(rbStrategy.get(UploadStrategy.CHUNKED_DATASET_STRATEGY), gc);
     124        gc.gridx = 1;
     125        gc.gridy = 2;
     126        gc.weightx = 0.0;
     127        gc.weighty = 0.0;
     128        gc.gridwidth = 1;
     129        lbl = lblStrategies.get(UploadStrategy.CHUNKED_DATASET_STRATEGY);
     130        lbl.setText(tr("Upload data in chunks of objects. Chunk size: "));
     131        pnl.add(lbl, gc);
     132        gc.gridx = 2;
     133        gc.gridy = 2;
     134        gc.weightx = 0.0;
     135        gc.weighty = 0.0;
     136        gc.gridwidth = 1;
     137        pnl.add(tfChunkSize = new JTextField(4), gc);
     138        gc.gridx = 3;
     139        gc.gridy = 2;
     140        gc.weightx = 1.0;
     141        gc.weighty = 0.0;
     142        gc.gridwidth = 1;
     143        pnl.add(lblNumRequests.get(UploadStrategy.CHUNKED_DATASET_STRATEGY), gc);
    103144
    104145        // -- single request strategy
    105146        gc.gridx = 0;
    106         gc.gridy = 2;
    107         gc.weightx = 0.0;
    108         gc.weighty = 0.0;
    109         add(rbStrategy.get(UploadStrategy.INDIVIDUAL_OBJECTS_STRATEGY), gc);
     147        gc.gridy = 3;
     148        gc.weightx = 0.0;
     149        gc.weighty = 0.0;
     150        pnl.add(rbStrategy.get(UploadStrategy.INDIVIDUAL_OBJECTS_STRATEGY), gc);
    110151        gc.gridx = 1;
    111         gc.gridy = 2;
     152        gc.gridy = 3;
    112153        gc.weightx = 0.0;
    113154        gc.weighty = 0.0;
    114155        gc.gridwidth = 2;
    115         add(new JLabel(tr("Upload each object individually")), gc);
     156        lbl = lblStrategies.get(UploadStrategy.INDIVIDUAL_OBJECTS_STRATEGY);
     157        lbl.setText(tr("Upload each object individually"));
     158        pnl.add(lbl, gc);
    116159        gc.gridx = 3;
    117         gc.gridy = 2;
    118         gc.weightx = 1.0;
    119         gc.weighty = 0.0;
    120         gc.gridwidth = 1;
    121         add(lblNumRequests.get(UploadStrategy.INDIVIDUAL_OBJECTS_STRATEGY), gc);
    122 
     160        gc.gridy = 3;
     161        gc.weightx = 1.0;
     162        gc.weighty = 0.0;
     163        gc.gridwidth = 1;
     164        pnl.add(lblNumRequests.get(UploadStrategy.INDIVIDUAL_OBJECTS_STRATEGY), gc);
    123165
    124166        tfChunkSize.addFocusListener(new TextFieldFocusHandler());
    125167        tfChunkSize.getDocument().addDocumentListener(new ChunkSizeInputVerifier());
     168
    126169        StrategyChangeListener strategyChangeListener = new StrategyChangeListener();
     170        tfChunkSize.addFocusListener(strategyChangeListener);
     171        tfChunkSize.addActionListener(strategyChangeListener);
    127172        for(UploadStrategy strategy: UploadStrategy.values()) {
    128             rbStrategy.get(strategy).addChangeListener(strategyChangeListener);
    129         }
    130 
     173            rbStrategy.get(strategy).addItemListener(strategyChangeListener);
     174        }
     175
     176        return pnl;
     177    }
     178
     179    protected JPanel buildMultiChangesetPolicyPanel() {
     180        pnlMultiChangesetPolicyPanel = new JPanel();
     181        pnlMultiChangesetPolicyPanel.setLayout(new GridBagLayout());
     182        GridBagConstraints gc = new GridBagConstraints();
     183        gc.gridx = 0;
     184        gc.gridy = 0;
     185        gc.fill = GridBagConstraints.HORIZONTAL;
     186        gc.anchor = GridBagConstraints.FIRST_LINE_START;
     187        gc.weightx = 1.0;
     188        pnlMultiChangesetPolicyPanel.add(lblMultiChangesetPoliciesHeader = new JMultilineLabel(tr("<html>There are <strong>multiple changesets</strong> necessary in order to upload {0} objects. What policy shall be used?</html>", numUploadedObjects)), gc);
     189        gc.gridy = 1;
     190        pnlMultiChangesetPolicyPanel.add(rbFillOneChangeset = new JRadioButton(tr("Fill up one changeset and return to the Upload Dialog")),gc);
     191        gc.gridy = 2;
     192        pnlMultiChangesetPolicyPanel.add(rbUseMultipleChangesets = new JRadioButton(tr("Open and use as many new changesets as necessary")),gc);
     193
     194        bgMultiChangesetPolicies = new ButtonGroup();
     195        bgMultiChangesetPolicies.add(rbFillOneChangeset);
     196        bgMultiChangesetPolicies.add(rbUseMultipleChangesets);
     197        return pnlMultiChangesetPolicyPanel;
     198    }
     199
     200    protected void build() {
     201        setLayout(new GridBagLayout());
     202        GridBagConstraints gc = new GridBagConstraints();
     203        gc.gridx = 0;
     204        gc.gridy = 0;
     205        gc.fill = GridBagConstraints.HORIZONTAL;
     206        gc.weightx = 1.0;
     207        gc.weighty = 0.0;
     208        gc.anchor = GridBagConstraints.NORTHWEST;
     209        gc.insets = new Insets(3,3,3,3);
     210
     211        add(buildUploadStrategyPanel(), gc);
     212        gc.gridy = 1;
     213        add(buildMultiChangesetPolicyPanel(), gc);
     214
     215        // consume remaining space
     216        gc.gridy = 2;
     217        gc.fill = GridBagConstraints.BOTH;
     218        gc.weightx = 1.0;
     219        gc.weighty = 1.0;
     220        add(new JPanel(), gc);
     221
     222        int maxChunkSize = OsmApi.getOsmApi().getCapabilities().getMaxChangsetSize();
     223        pnlMultiChangesetPolicyPanel.setVisible(
     224                maxChunkSize > 0 && numUploadedObjects > maxChunkSize
     225        );
    131226    }
    132227
     
    139234        if (strategy == null) return;
    140235        rbStrategy.get(strategy.getStrategy()).setSelected(true);
     236        tfChunkSize.setEnabled(strategy.equals(UploadStrategy.CHUNKED_DATASET_STRATEGY));
    141237        if (strategy.getStrategy().equals(UploadStrategy.CHUNKED_DATASET_STRATEGY)) {
    142             tfChunkSize.setEnabled(strategy.equals(UploadStrategy.CHUNKED_DATASET_STRATEGY));
    143238            if (strategy.getChunkSize() != UploadStrategySpecification.UNSPECIFIED_CHUNK_SIZE) {
    144239                tfChunkSize.setText(Integer.toString(strategy.getChunkSize()));
     
    152247        UploadStrategy strategy = getUploadStrategy();
    153248        int chunkSize = getChunkSize();
     249        UploadStrategySpecification spec = new UploadStrategySpecification();
    154250        switch(strategy) {
    155         case INDIVIDUAL_OBJECTS_STRATEGY: return UploadStrategySpecification.createIndividualObjectStrategy();
    156         case SINGLE_REQUEST_STRATEGY: return UploadStrategySpecification.createSingleRequestUploadStrategy();
    157         case CHUNKED_DATASET_STRATEGY: return UploadStrategySpecification.createChunkedUploadStrategy(chunkSize);
    158         }
    159         // should not happen
    160         return null;
     251        case INDIVIDUAL_OBJECTS_STRATEGY:
     252            spec.setStrategy(strategy);
     253            break;
     254        case SINGLE_REQUEST_STRATEGY:
     255            spec.setStrategy(strategy);
     256            break;
     257        case CHUNKED_DATASET_STRATEGY:
     258            spec.setStrategy(strategy).setChunkSize(chunkSize);
     259            break;
     260        }
     261        if(pnlMultiChangesetPolicyPanel.isVisible()) {
     262            if (rbFillOneChangeset.isSelected()) {
     263                spec.setPolicy(MaxChangesetSizeExceededPolicy.FILL_ONE_CHANGESET_AND_RETURN_TO_UPLOAD_DIALOG);
     264            } else if (rbUseMultipleChangesets.isSelected()) {
     265                spec.setPolicy(MaxChangesetSizeExceededPolicy.AUTOMATICALLY_OPEN_NEW_CHANGESETS);
     266            } else {
     267                spec.setPolicy(null); // unknown policy
     268            }
     269        } else {
     270            spec.setPolicy(null);
     271        }
     272        return spec;
    161273    }
    162274
     
    171283        return strategy;
    172284    }
    173 
    174285
    175286    protected int getChunkSize() {
     
    191302    }
    192303
    193     public void saveToPreferences() {
     304    public void rememberUserInput() {
    194305        UploadStrategy strategy = getUploadStrategy();
    195306        UploadStrategy.saveToPreferences(strategy);
     
    204315
    205316    protected void updateNumRequestsLabels() {
     317        int maxChunkSize = OsmApi.getOsmApi().getCapabilities().getMaxChangsetSize();
     318        if (maxChunkSize > 0 && numUploadedObjects > maxChunkSize) {
     319            rbStrategy.get(UploadStrategy.SINGLE_REQUEST_STRATEGY).setEnabled(false);
     320            JLabel lbl = lblStrategies.get(UploadStrategy.SINGLE_REQUEST_STRATEGY);
     321            lbl.setIcon(ImageProvider.get("warning-small.png"));
     322            lbl.setText(tr("Upload in one request not possible (too many objects to upload)"));
     323            lbl.setToolTipText(tr("<html>Can''t upload {0} objects in one request because the<br>"
     324                    + "max. changeset size {1} on server ''{2}'' is exceeded.</html>",
     325                    numUploadedObjects,
     326                    maxChunkSize,
     327                    OsmApi.getOsmApi().getBaseUrl()
     328            )
     329            );
     330            rbStrategy.get(UploadStrategy.CHUNKED_DATASET_STRATEGY).setSelected(true);
     331            lblNumRequests.get(UploadStrategy.SINGLE_REQUEST_STRATEGY).setVisible(false);
     332
     333            lblMultiChangesetPoliciesHeader.setText(tr("<html>There are <strong>multiple changesets</strong> necessary in order to upload {0} objects. What policy shall be used?</html>", numUploadedObjects));
     334            if (!rbFillOneChangeset.isSelected() && ! rbUseMultipleChangesets.isSelected()) {
     335                rbUseMultipleChangesets.setSelected(true);
     336            }
     337            pnlMultiChangesetPolicyPanel.setVisible(true);
     338
     339        } else {
     340            rbStrategy.get(UploadStrategy.SINGLE_REQUEST_STRATEGY).setEnabled(true);
     341            JLabel lbl = lblStrategies.get(UploadStrategy.SINGLE_REQUEST_STRATEGY);
     342            lbl.setText(tr("Upload data in one request"));
     343            lbl.setIcon(null);
     344            lbl.setToolTipText("");
     345            lblNumRequests.get(UploadStrategy.SINGLE_REQUEST_STRATEGY).setVisible(true);
     346
     347            pnlMultiChangesetPolicyPanel.setVisible(false);
     348        }
     349
    206350        lblNumRequests.get(UploadStrategy.SINGLE_REQUEST_STRATEGY).setText(tr("(1 request)"));
    207351        if (numUploadedObjects == 0) {
     
    229373    }
    230374
     375    public void propertyChange(PropertyChangeEvent evt) {
     376        if (evt.getPropertyName().equals(UploadedObjectsSummaryPanel.NUM_OBJECTS_TO_UPLOAD_PROP)) {
     377            setNumUploadedObjects((Integer)evt.getNewValue());
     378        }
     379    }
     380
    231381    class TextFieldFocusHandler implements FocusListener {
    232382        public void focusGained(FocusEvent e) {
     
    241391
    242392    class ChunkSizeInputVerifier implements DocumentListener, PropertyChangeListener {
    243 
    244393        protected void setErrorFeedback(JTextField tf, String message) {
    245394            tf.setBorder(BorderFactory.createLineBorder(Color.RED, 1));
     
    257406            try {
    258407                int chunkSize = Integer.parseInt(tfChunkSize.getText().trim());
     408                int maxChunkSize = OsmApi.getOsmApi().getCapabilities().getMaxChangsetSize();
    259409                if (chunkSize <= 0) {
    260410                    setErrorFeedback(tfChunkSize, tr("Illegal chunk size <= 0. Please enter an integer > 1"));
     411                } else if (maxChunkSize > 0 && chunkSize > maxChunkSize) {
     412                    setErrorFeedback(tfChunkSize, tr("Chunk size {0} exceeds max. changeset size {1} for server ''{2}''", chunkSize, maxChunkSize, OsmApi.getOsmApi().getBaseUrl()));
    261413                } else {
    262414                    clearErrorFeedback(tfChunkSize, tr("Please enter an integer > 1"));
     415                }
     416
     417                if (maxChunkSize > 0 && chunkSize > maxChunkSize) {
     418                    setErrorFeedback(tfChunkSize, tr("Chunk size {0} exceeds max. changeset size {1} for server ''{2}''", chunkSize, maxChunkSize, OsmApi.getOsmApi().getBaseUrl()));
    263419                }
    264420            } catch(NumberFormatException e) {
     
    291447    }
    292448
    293     class StrategyChangeListener implements ChangeListener {
    294         public void stateChanged(ChangeEvent e) {
     449    class StrategyChangeListener implements ItemListener, FocusListener, ActionListener {
     450
     451        protected void notifyStrategy() {
     452            firePropertyChange(UPLOAD_STRATEGY_SPECIFICATION_PROP, null, getUploadStrategySpecification());
     453        }
     454
     455        public void itemStateChanged(ItemEvent e) {
    295456            UploadStrategy strategy = getUploadStrategy();
    296457            if (strategy == null) return;
     
    303464                tfChunkSize.setEnabled(false);
    304465            }
     466            notifyStrategy();
     467        }
     468
     469        public void focusGained(FocusEvent arg0) {}
     470
     471        public void focusLost(FocusEvent arg0) {
     472            notifyStrategy();
     473        }
     474
     475        public void actionPerformed(ActionEvent arg0) {
     476            notifyStrategy();
    305477        }
    306478    }
  • trunk/src/org/openstreetmap/josm/gui/io/UploadStrategySpecification.java

    r2569 r2599  
    22package org.openstreetmap.josm.gui.io;
    33
    4 public class UploadStrategySpecification {
     4
     5
     6/**
     7 * An UploadStrategySpecification consists of the parameter describing the strategy
     8 * for uploading a collection of {@see OsmPrimitive}.
     9 *
     10 * This includes:
     11 * <ul>
     12 * <li>a decision on which {@see UploadStrategy} to use</li>
     13 * <li>the upload chunk size</li>
     14 * <li>whether to close the changeset used after the upload</li>
     15 * </ul>
     16 *
     17 *
     18 */
     19public class UploadStrategySpecification  {
     20    /** indicates that the chunk size isn't specified */
    521    static public final int UNSPECIFIED_CHUNK_SIZE = -1;
    6     static public UploadStrategySpecification createIndividualObjectStrategy() {
    7         return new UploadStrategySpecification(UploadStrategy.INDIVIDUAL_OBJECTS_STRATEGY, 1);
    8     }
    9 
    10     static public UploadStrategySpecification createChunkedUploadStrategy(int chunkSize) {
    11         return new UploadStrategySpecification(UploadStrategy.CHUNKED_DATASET_STRATEGY, chunkSize);
    12     }
    13 
    14     static public UploadStrategySpecification createSingleRequestUploadStrategy() {
    15         return new UploadStrategySpecification(UploadStrategy.SINGLE_REQUEST_STRATEGY, UNSPECIFIED_CHUNK_SIZE);
    16     }
    1722
    1823    private UploadStrategy strategy;
    1924    private int chunkSize;
     25    private MaxChangesetSizeExceededPolicy policy;
     26    private boolean closeChangesetAfterUpload;
    2027
    21     private UploadStrategySpecification(UploadStrategy strategy, int chunkSize) {
    22         this.strategy = strategy;
    23         this.chunkSize = chunkSize;
     28    /**
     29     * Creates a new upload strategy with default values.
     30     */
     31    public UploadStrategySpecification() {
     32        this.strategy = UploadStrategy.DEFAULT_UPLOAD_STRATEGY;
     33        this.chunkSize = UNSPECIFIED_CHUNK_SIZE;
     34        this.policy = null;
     35        this.closeChangesetAfterUpload = true;
    2436    }
    2537
     38    /**
     39     * Clones another upload strategy. If other is null,assumes default
     40     * values.
     41     *
     42     * @param other the other upload strategy
     43     */
     44    public UploadStrategySpecification(UploadStrategySpecification other) {
     45        if (other == null) return;
     46        this.strategy = other.strategy;
     47        this.chunkSize = other.chunkSize;
     48        this.policy = other.policy;
     49        this.closeChangesetAfterUpload = other.closeChangesetAfterUpload;
     50    }
     51
     52    /**
     53     * Replies the upload strategy
     54     * @return
     55     */
    2656    public UploadStrategy getStrategy() {
    2757        return strategy;
    2858    }
     59
    2960    public int getChunkSize() {
    3061        return chunkSize;
    3162    }
     63
     64    public static int getUnspecifiedChunkSize() {
     65        return UNSPECIFIED_CHUNK_SIZE;
     66    }
     67
     68    public MaxChangesetSizeExceededPolicy getPolicy() {
     69        return policy;
     70    }
     71
     72    public UploadStrategySpecification setStrategy(UploadStrategy strategy) {
     73        this.strategy = strategy;
     74        return this;
     75    }
     76
     77    public UploadStrategySpecification setChunkSize(int chunkSize) {
     78        this.chunkSize = chunkSize;
     79        return this;
     80    }
     81
     82    public UploadStrategySpecification setPolicy(MaxChangesetSizeExceededPolicy policy) {
     83        this.policy = policy;
     84        return this;
     85    }
     86
     87    public UploadStrategySpecification setCloseChangesetAfterUpload(boolean closeChangesetAfterUpload) {
     88        this.closeChangesetAfterUpload = closeChangesetAfterUpload;
     89        return this;
     90    }
     91
     92    public boolean isCloseChangesetAfterUpload() {
     93        return closeChangesetAfterUpload;
     94    }
     95
     96    public int getNumRequests(int numObjects) {
     97        if (numObjects <=0) return 0;
     98        switch(strategy) {
     99        case INDIVIDUAL_OBJECTS_STRATEGY: return numObjects;
     100        case SINGLE_REQUEST_STRATEGY: return 1;
     101        case CHUNKED_DATASET_STRATEGY:
     102            if (chunkSize == UNSPECIFIED_CHUNK_SIZE)
     103                return 0;
     104            else
     105                return (int)Math.ceil((double)numObjects / (double)chunkSize);
     106        }
     107        // should not happen
     108        return 0;
     109    }
     110
     111    @Override
     112    public int hashCode() {
     113        final int prime = 31;
     114        int result = 1;
     115        result = prime * result + chunkSize;
     116        result = prime * result + (closeChangesetAfterUpload ? 1231 : 1237);
     117        result = prime * result + ((policy == null) ? 0 : policy.hashCode());
     118        result = prime * result + ((strategy == null) ? 0 : strategy.hashCode());
     119        return result;
     120    }
     121
     122    @Override
     123    public boolean equals(Object obj) {
     124        if (this == obj)
     125            return true;
     126        if (obj == null)
     127            return false;
     128        if (getClass() != obj.getClass())
     129            return false;
     130        UploadStrategySpecification other = (UploadStrategySpecification) obj;
     131        if (chunkSize != other.chunkSize)
     132            return false;
     133        if (closeChangesetAfterUpload != other.closeChangesetAfterUpload)
     134            return false;
     135        if (policy == null) {
     136            if (other.policy != null)
     137                return false;
     138        } else if (!policy.equals(other.policy))
     139            return false;
     140        if (strategy == null) {
     141            if (other.strategy != null)
     142                return false;
     143        } else if (!strategy.equals(other.strategy))
     144            return false;
     145        return true;
     146    }
    32147}
  • trunk/src/org/openstreetmap/josm/gui/tagging/TagCellEditor.java

    r2512 r2599  
    155155            }
    156156        }
    157 
    158157        return super.stopCellEditing();
    159158    }
  • trunk/src/org/openstreetmap/josm/gui/tagging/TagEditorModel.java

    r2512 r2599  
    219219        if (name == null) return;
    220220        Iterator<TagModel> it = tags.iterator();
     221        boolean changed = false;
    221222        while(it.hasNext()) {
    222223            TagModel tm = it.next();
    223224            if (tm.getName().equals(name)) {
     225                changed = true;
    224226                it.remove();
    225227            }
    226228        }
    227         fireTableDataChanged();
    228         setDirty(true);
     229        if (changed) {
     230            fireTableDataChanged();
     231            setDirty(true);
     232        }
    229233    }
    230234    /**
     
    449453            setDirty(true);
    450454        }
     455        fireTableDataChanged();
    451456    }
    452457
     
    464469            setDirty(true);
    465470        }
     471        fireTableDataChanged();
    466472    }
    467473
  • trunk/src/org/openstreetmap/josm/gui/tagging/TagEditorPanel.java

    r2512 r2599  
    77import java.awt.GridBagConstraints;
    88import java.awt.GridBagLayout;
     9import java.awt.Insets;
    910import java.awt.event.ActionEvent;
    1011import java.beans.PropertyChangeEvent;
     
    6970        //
    7071        AddAction addAction = new AddAction();
    71         pnl.add(new JButton(addAction));
     72        JButton btn;
     73        pnl.add(btn = new JButton(addAction));
     74        btn.setMargin(new Insets(0,0,0,0));
    7275        tagTable.addPropertyChangeListener(addAction);
    7376
     
    7780        tagTable.getSelectionModel().addListSelectionListener(deleteAction);
    7881        tagTable.addPropertyChangeListener(deleteAction);
    79         pnl.add(new JButton(deleteAction));
     82        pnl.add(btn = new JButton(deleteAction));
     83        btn.setMargin(new Insets(0,0,0,0));
    8084        return pnl;
    8185    }
  • trunk/src/org/openstreetmap/josm/io/Capabilities.java

    r2512 r2599  
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.io;
     3
     4import static org.openstreetmap.josm.tools.I18n.tr;
    35
    46import java.util.HashMap;
     
    7173    }
    7274
     75    /**
     76     * Replies the max number of objects in a changeset. -1 if either the capabilities
     77     * don't include this parameter or if the parameter value is illegal (not a number,
     78     * a negative number)
     79     *
     80     * @return the max number of objects in a changeset
     81     */
     82    public int getMaxChangsetSize() {
     83        String v = get("changesets", "maximum_elements");
     84        if (v == null) return -1;
     85        try {
     86            int n = Integer.parseInt(v);
     87            if (n <= 0) {
     88                System.err.println(tr("Warning: illegal value of attribute '{0}'' of element ''{1}'' in server capabilities. Got ''{2}", "changesets", "maximum_elements", n ));
     89                return -1;
     90            }
     91            return n;
     92        } catch(NumberFormatException e) {
     93            System.err.println(tr("Warning: illegal value of attribute '{0}'' of element ''{1}'' in server capabilities. Got ''{2}", "changesets", "maximum_elements", v ));
     94            return -1;
     95        }
     96    }
    7397}
  • trunk/src/org/openstreetmap/josm/io/ChangesetClosedException.java

    r2569 r2599  
    3131    final static public String ERROR_HEADER_PATTERN = "The changeset (\\d+) was closed at (.*)";
    3232
    33     static enum Source {
     33    public static enum Source {
    3434        /**
    3535         * The exception was thrown when a changeset was updated. This most likely means
     
    114114
    115115    /**
     116     * Creates the exception
     117     *
     118     * @param changesetId the id if the closed changeset
     119     * @param closedOn the date the changeset was closed on
     120     * @param source the source for the exception
     121     */
     122    public ChangesetClosedException(long changesetId, Date closedOn, Source source) {
     123        super("");
     124        this.source = source == null ? Source.UNSPECIFIED : source;
     125        this.changesetId = changesetId;
     126        this.closedOn = closedOn;
     127    }
     128
     129    /**
    116130     * Replies the id of the changeset which was closed
    117131     *
     
    139153        return source;
    140154    }
     155
     156    public void setSource(Source source) {
     157        this.source = source == null ? Source.UNSPECIFIED : source;
     158    }
    141159}
  • trunk/src/org/openstreetmap/josm/io/MultiFetchServerObjectReader.java

    r2578 r2599  
    1919import org.openstreetmap.josm.data.osm.OsmPrimitive;
    2020import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
     21import org.openstreetmap.josm.data.osm.PrimitiveId;
    2122import org.openstreetmap.josm.data.osm.Relation;
    2223import org.openstreetmap.josm.data.osm.RelationMember;
     
    7677
    7778    /**
    78      * remembers an {@see OsmPrimitive}'s id and its type. The id will
     79     * Remembers an {@see OsmPrimitive}'s id. The id will
    7980     * later be fetched as part of a Multi Get request.
    8081     *
    81      * Ignore the id if it id <= 0.
     82     * Ignore the id if it represents a new primitives.
    8283     *
    8384     * @param id  the id
    84      * @param type  the type
    85      */
    86     protected void remember(long id, OsmPrimitiveType type) {
    87         if (id <= 0) return;
    88         if (type.equals(OsmPrimitiveType.NODE)) {
    89             nodes.add(id);
    90         } else if (type.equals(OsmPrimitiveType.WAY)) {
    91             ways.add(id);
    92         } if (type.equals(OsmPrimitiveType.RELATION)) {
    93             relations.add(id);
     85     */
     86    protected void remember(PrimitiveId id) {
     87        if (id.isNew()) return;
     88        switch(id.getType()) {
     89        case NODE: nodes.add(id.getUniqueId()); break;
     90        case WAY: ways.add(id.getUniqueId()); break;
     91        case RELATION: relations.add(id.getUniqueId()); break;
    9492        }
    9593    }
     
    115113        if (primitive == null)
    116114            throw new NoSuchElementException(tr("No primitive with id {0} in local dataset. Can't infer primitive type.", id));
    117         remember(id, OsmPrimitiveType.from(primitive));
     115        remember(primitive.getPrimitiveId());
    118116        return;
    119117    }
     
    153151    public MultiFetchServerObjectReader append(Node node) {
    154152        if (node == null) return this;
    155         if (node.isNew()) return this;
    156         remember(node.getId(), OsmPrimitiveType.NODE);
     153        remember(node.getPrimitiveId());
    157154        return this;
    158155    }
     
    170167        for (Node node: way.getNodes()) {
    171168            if (!node.isNew()) {
    172                 remember(node.getId(), OsmPrimitiveType.NODE);
    173             }
    174         }
    175         remember(way.getId(), OsmPrimitiveType.WAY);
     169                remember(node.getPrimitiveId());
     170            }
     171        }
     172        remember(way.getPrimitiveId());
    176173        return this;
    177174    }
     
    187184        if (relation == null) return this;
    188185        if (relation.isNew()) return this;
    189         remember(relation.getId(), OsmPrimitiveType.RELATION);
     186        remember(relation.getPrimitiveId());
    190187        for (RelationMember member : relation.getMembers()) {
    191188            if (OsmPrimitiveType.from(member.getMember()).equals(OsmPrimitiveType.RELATION)) {
  • trunk/src/org/openstreetmap/josm/io/OsmApi.java

    r2569 r2599  
    8080        String serverUrl = Main.pref.get("osm-server.url", "http://api.openstreetmap.org/api");
    8181        if (serverUrl == null)
    82             throw new IllegalStateException(tr("Preference ''{0}'' missing. Can't initialize OsmApi.", "osm-server.url"));
     82            throw new IllegalStateException(tr("Preference ''{0}'' missing. Can''t initialize OsmApi.", "osm-server.url"));
    8383        return getOsmApi(serverUrl);
    8484    }
     
    342342                    monitor
    343343            );
     344        } catch(ChangesetClosedException e) {
     345            e.setSource(ChangesetClosedException.Source.UPDATE_CHANGESET);
     346            throw e;
    344347        } catch(OsmApiException e) {
    345348            if (e.getResponseCode() == HttpURLConnection.HTTP_CONFLICT && ChangesetClosedException.errorHeaderMatchesPattern(e.getErrorHeader()))
  • trunk/src/org/openstreetmap/josm/io/OsmServerWriter.java

    r2569 r2599  
    149149            while(it.hasNext()) {
    150150                i++;
    151                 progressMonitor.setCustomText(tr("({0}/{1}) Uploading {2} objects...", i,numChunks,chunkSize));
    152151                if (canceled) return;
    153152                int j = 0;
     
    158157                    chunk.add(it.next());
    159158                }
     159                progressMonitor.setCustomText(tr("({0}/{1}) Uploading {2} objects...", i,numChunks,chunk.size()));
    160160                processed.addAll(api.uploadDiff(chunk, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false)));
    161161            }
Note: See TracChangeset for help on using the changeset viewer.