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

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

File:
1 edited

Legend:

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

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