source: josm/trunk/src/org/openstreetmap/josm/gui/io/UploadDialog.java

Last change on this file was 14355, checked in by Don-vip, 5 months ago

fix #16865 - UploadDialogTest: fix for non-headless mode (patch by ris, modified). Probably IUploadDialog should die

  • Property svn:eol-style set to native
File size: 27.9 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.io;
3
4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
5import static org.openstreetmap.josm.tools.I18n.tr;
6import static org.openstreetmap.josm.tools.I18n.trn;
7
8import java.awt.Component;
9import java.awt.Dimension;
10import java.awt.FlowLayout;
11import java.awt.GridBagLayout;
12import java.awt.event.ActionEvent;
13import java.awt.event.WindowAdapter;
14import java.awt.event.WindowEvent;
15import java.beans.PropertyChangeEvent;
16import java.beans.PropertyChangeListener;
17import java.lang.Character.UnicodeBlock;
18import java.util.ArrayList;
19import java.util.Collection;
20import java.util.Collections;
21import java.util.HashMap;
22import java.util.Iterator;
23import java.util.List;
24import java.util.Map;
25import java.util.Map.Entry;
26import java.util.Optional;
27import java.util.concurrent.TimeUnit;
28
29import javax.swing.AbstractAction;
30import javax.swing.BorderFactory;
31import javax.swing.Icon;
32import javax.swing.JButton;
33import javax.swing.JOptionPane;
34import javax.swing.JPanel;
35import javax.swing.JTabbedPane;
36
37import org.openstreetmap.josm.data.APIDataSet;
38import org.openstreetmap.josm.data.Version;
39import org.openstreetmap.josm.data.osm.Changeset;
40import org.openstreetmap.josm.data.osm.DataSet;
41import org.openstreetmap.josm.data.osm.OsmPrimitive;
42import org.openstreetmap.josm.gui.ExtendedDialog;
43import org.openstreetmap.josm.gui.HelpAwareOptionPane;
44import org.openstreetmap.josm.gui.MainApplication;
45import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
46import org.openstreetmap.josm.gui.help.HelpUtil;
47import org.openstreetmap.josm.gui.util.GuiHelper;
48import org.openstreetmap.josm.gui.util.MultiLineFlowLayout;
49import org.openstreetmap.josm.gui.util.WindowGeometry;
50import org.openstreetmap.josm.io.OsmApi;
51import org.openstreetmap.josm.io.UploadStrategy;
52import org.openstreetmap.josm.io.UploadStrategySpecification;
53import org.openstreetmap.josm.spi.preferences.Config;
54import org.openstreetmap.josm.spi.preferences.PreferenceChangeEvent;
55import org.openstreetmap.josm.spi.preferences.PreferenceChangedListener;
56import org.openstreetmap.josm.spi.preferences.Setting;
57import org.openstreetmap.josm.tools.GBC;
58import org.openstreetmap.josm.tools.ImageOverlay;
59import org.openstreetmap.josm.tools.ImageProvider;
60import org.openstreetmap.josm.tools.ImageProvider.ImageSizes;
61import org.openstreetmap.josm.tools.InputMapUtils;
62import org.openstreetmap.josm.tools.Utils;
63
64/**
65 * This is a dialog for entering upload options like the parameters for
66 * the upload changeset and the strategy for opening/closing a changeset.
67 * @since 2025
68 */
69public class UploadDialog extends AbstractUploadDialog implements PropertyChangeListener, PreferenceChangedListener {
70    /** the unique instance of the upload dialog */
71    private static UploadDialog uploadDialog;
72
73    /** list of custom components that can be added by plugins at JOSM startup */
74    private static final Collection<Component> customComponents = new ArrayList<>();
75
76    /** the "created_by" changeset OSM key */
77    private static final String CREATED_BY = "created_by";
78
79    /** the panel with the objects to upload */
80    private UploadedObjectsSummaryPanel pnlUploadedObjects;
81    /** the panel to select the changeset used */
82    private ChangesetManagementPanel pnlChangesetManagement;
83
84    private BasicUploadSettingsPanel pnlBasicUploadSettings;
85
86    private UploadStrategySelectionPanel pnlUploadStrategySelectionPanel;
87
88    /** checkbox for selecting whether an atomic upload is to be used  */
89    private TagSettingsPanel pnlTagSettings;
90    /** the tabbed pane used below of the list of primitives  */
91    private JTabbedPane tpConfigPanels;
92    /** the upload button */
93    private JButton btnUpload;
94
95    /** the changeset comment model keeping the state of the changeset comment */
96    private final transient ChangesetCommentModel changesetCommentModel = new ChangesetCommentModel();
97    private final transient ChangesetCommentModel changesetSourceModel = new ChangesetCommentModel();
98    private final transient ChangesetReviewModel changesetReviewModel = new ChangesetReviewModel();
99
100    private transient DataSet dataSet;
101
102    /**
103     * Constructs a new {@code UploadDialog}.
104     */
105    public UploadDialog() {
106        super(GuiHelper.getFrameForComponent(MainApplication.getMainFrame()), ModalityType.DOCUMENT_MODAL);
107        build();
108        pack();
109    }
110
111    /**
112     * Replies the unique instance of the upload dialog
113     *
114     * @return the unique instance of the upload dialog
115     */
116    public static synchronized UploadDialog getUploadDialog() {
117        if (uploadDialog == null) {
118            uploadDialog = new UploadDialog();
119        }
120        return uploadDialog;
121    }
122
123    /**
124     * builds the content panel for the upload dialog
125     *
126     * @return the content panel
127     */
128    protected JPanel buildContentPanel() {
129        JPanel pnl = new JPanel(new GridBagLayout());
130        pnl.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
131
132        // the panel with the list of uploaded objects
133        pnlUploadedObjects = new UploadedObjectsSummaryPanel();
134        pnl.add(pnlUploadedObjects, GBC.eol().fill(GBC.BOTH));
135
136        // Custom components
137        for (Component c : customComponents) {
138            pnl.add(c, GBC.eol().fill(GBC.HORIZONTAL));
139        }
140
141        // a tabbed pane with configuration panels in the lower half
142        tpConfigPanels = new CompactTabbedPane();
143
144        pnlBasicUploadSettings = new BasicUploadSettingsPanel(changesetCommentModel, changesetSourceModel, changesetReviewModel);
145        tpConfigPanels.add(pnlBasicUploadSettings);
146        tpConfigPanels.setTitleAt(0, tr("Settings"));
147        tpConfigPanels.setToolTipTextAt(0, tr("Decide how to upload the data and which changeset to use"));
148
149        pnlTagSettings = new TagSettingsPanel(changesetCommentModel, changesetSourceModel, changesetReviewModel);
150        tpConfigPanels.add(pnlTagSettings);
151        tpConfigPanels.setTitleAt(1, tr("Tags of new changeset"));
152        tpConfigPanels.setToolTipTextAt(1, tr("Apply tags to the changeset data is uploaded to"));
153
154        pnlChangesetManagement = new ChangesetManagementPanel(changesetCommentModel);
155        tpConfigPanels.add(pnlChangesetManagement);
156        tpConfigPanels.setTitleAt(2, tr("Changesets"));
157        tpConfigPanels.setToolTipTextAt(2, tr("Manage open changesets and select a changeset to upload to"));
158
159        pnlUploadStrategySelectionPanel = new UploadStrategySelectionPanel();
160        tpConfigPanels.add(pnlUploadStrategySelectionPanel);
161        tpConfigPanels.setTitleAt(3, tr("Advanced"));
162        tpConfigPanels.setToolTipTextAt(3, tr("Configure advanced settings"));
163
164        pnl.add(tpConfigPanels, GBC.eol().fill(GBC.HORIZONTAL));
165
166        pnl.add(buildActionPanel(), GBC.eol().fill(GBC.HORIZONTAL));
167        return pnl;
168    }
169
170    /**
171     * builds the panel with the OK and CANCEL buttons
172     *
173     * @return The panel with the OK and CANCEL buttons
174     */
175    protected JPanel buildActionPanel() {
176        JPanel pnl = new JPanel(new MultiLineFlowLayout(FlowLayout.CENTER));
177        pnl.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
178
179        // -- upload button
180        btnUpload = new JButton(new UploadAction(this));
181        pnl.add(btnUpload);
182        btnUpload.setFocusable(true);
183        InputMapUtils.enableEnter(btnUpload);
184        InputMapUtils.addCtrlEnterAction(getRootPane(), btnUpload.getAction());
185
186        // -- cancel button
187        CancelAction cancelAction = new CancelAction(this);
188        pnl.add(new JButton(cancelAction));
189        InputMapUtils.addEscapeAction(getRootPane(), cancelAction);
190        pnl.add(new JButton(new ContextSensitiveHelpAction(ht("/Dialog/Upload"))));
191        HelpUtil.setHelpContext(getRootPane(), ht("/Dialog/Upload"));
192        return pnl;
193    }
194
195    /**
196     * builds the gui
197     */
198    protected void build() {
199        setTitle(tr("Upload to ''{0}''", OsmApi.getOsmApi().getBaseUrl()));
200        setContentPane(buildContentPanel());
201
202        addWindowListener(new WindowEventHandler());
203
204        // make sure the configuration panels listen to each other changes
205        //
206        pnlChangesetManagement.addPropertyChangeListener(this);
207        pnlChangesetManagement.addPropertyChangeListener(
208                pnlBasicUploadSettings.getUploadParameterSummaryPanel()
209        );
210        pnlChangesetManagement.addPropertyChangeListener(this);
211        pnlUploadedObjects.addPropertyChangeListener(
212                pnlBasicUploadSettings.getUploadParameterSummaryPanel()
213        );
214        pnlUploadedObjects.addPropertyChangeListener(pnlUploadStrategySelectionPanel);
215        pnlUploadStrategySelectionPanel.addPropertyChangeListener(
216                pnlBasicUploadSettings.getUploadParameterSummaryPanel()
217        );
218
219        // users can click on either of two links in the upload parameter
220        // summary handler. This installs the handler for these two events.
221        // We simply select the appropriate tab in the tabbed pane with the configuration dialogs.
222        //
223        pnlBasicUploadSettings.getUploadParameterSummaryPanel().setConfigurationParameterRequestListener(
224                new ConfigurationParameterRequestHandler() {
225                    @Override
226                    public void handleUploadStrategyConfigurationRequest() {
227                        tpConfigPanels.setSelectedIndex(3);
228                    }
229
230                    @Override
231                    public void handleChangesetConfigurationRequest() {
232                        tpConfigPanels.setSelectedIndex(2);
233                    }
234                }
235        );
236
237        pnlBasicUploadSettings.setUploadTagDownFocusTraversalHandlers(
238                new AbstractAction() {
239                    @Override
240                    public void actionPerformed(ActionEvent e) {
241                        btnUpload.requestFocusInWindow();
242                    }
243                }
244        );
245
246        setMinimumSize(new Dimension(600, 350));
247
248        Config.getPref().addPreferenceChangeListener(this);
249    }
250
251    /**
252     * Sets the collection of primitives to upload
253     *
254     * @param toUpload the dataset with the objects to upload. If null, assumes the empty
255     * set of objects to upload
256     *
257     */
258    public void setUploadedPrimitives(APIDataSet toUpload) {
259        if (toUpload == null) {
260            if (pnlUploadedObjects != null) {
261                List<OsmPrimitive> emptyList = Collections.emptyList();
262                pnlUploadedObjects.setUploadedPrimitives(emptyList, emptyList, emptyList);
263            }
264            return;
265        }
266        pnlUploadedObjects.setUploadedPrimitives(
267                toUpload.getPrimitivesToAdd(),
268                toUpload.getPrimitivesToUpdate(),
269                toUpload.getPrimitivesToDelete()
270        );
271    }
272
273    /**
274     * Sets the tags for this upload based on (later items overwrite earlier ones):
275     * <ul>
276     * <li>previous "source" and "comment" input</li>
277     * <li>the tags set in the dataset (see {@link DataSet#getChangeSetTags()})</li>
278     * <li>the tags from the selected open changeset</li>
279     * <li>the JOSM user agent (see {@link Version#getAgentString(boolean)})</li>
280     * </ul>
281     *
282     * @param dataSet to obtain the tags set in the dataset
283     */
284    public void setChangesetTags(DataSet dataSet) {
285        final Map<String, String> tags = new HashMap<>();
286
287        // obtain from previous input
288        tags.put("source", getLastChangesetSourceFromHistory());
289        tags.put("comment", getLastChangesetCommentFromHistory());
290
291        // obtain from dataset
292        if (dataSet != null) {
293            tags.putAll(dataSet.getChangeSetTags());
294        }
295        this.dataSet = dataSet;
296
297        // obtain from selected open changeset
298        if (pnlChangesetManagement.getSelectedChangeset() != null) {
299            tags.putAll(pnlChangesetManagement.getSelectedChangeset().getKeys());
300        }
301
302        // set/adapt created_by
303        final String agent = Version.getInstance().getAgentString(false);
304        final String createdBy = tags.get(CREATED_BY);
305        if (createdBy == null || createdBy.isEmpty()) {
306            tags.put(CREATED_BY, agent);
307        } else if (!createdBy.contains(agent)) {
308            tags.put(CREATED_BY, createdBy + ';' + agent);
309        }
310
311        // remove empty values
312        final Iterator<String> it = tags.keySet().iterator();
313        while (it.hasNext()) {
314            final String v = tags.get(it.next());
315            if (v == null || v.isEmpty()) {
316                it.remove();
317            }
318        }
319
320        pnlTagSettings.initFromTags(tags);
321        pnlTagSettings.tableChanged(null);
322    }
323
324    @Override
325    public void rememberUserInput() {
326        pnlBasicUploadSettings.rememberUserInput();
327        pnlUploadStrategySelectionPanel.rememberUserInput();
328    }
329
330    /**
331     * Initializes the panel for user input
332     */
333    public void startUserInput() {
334        tpConfigPanels.setSelectedIndex(0);
335        pnlBasicUploadSettings.startUserInput();
336        pnlTagSettings.startUserInput();
337        pnlUploadStrategySelectionPanel.initFromPreferences();
338        UploadParameterSummaryPanel pnl = pnlBasicUploadSettings.getUploadParameterSummaryPanel();
339        pnl.setUploadStrategySpecification(pnlUploadStrategySelectionPanel.getUploadStrategySpecification());
340        pnl.setCloseChangesetAfterNextUpload(pnlChangesetManagement.isCloseChangesetAfterUpload());
341        pnl.setNumObjects(pnlUploadedObjects.getNumObjectsToUpload());
342    }
343
344    /**
345     * Replies the current changeset
346     *
347     * @return the current changeset
348     */
349    public Changeset getChangeset() {
350        Changeset cs = Optional.ofNullable(pnlChangesetManagement.getSelectedChangeset()).orElseGet(Changeset::new);
351        cs.setKeys(pnlTagSettings.getTags(false));
352        return cs;
353    }
354
355    /**
356     * Sets the changeset to be used in the next upload
357     *
358     * @param cs the changeset
359     */
360    public void setSelectedChangesetForNextUpload(Changeset cs) {
361        pnlChangesetManagement.setSelectedChangesetForNextUpload(cs);
362    }
363
364    @Override
365    public UploadStrategySpecification getUploadStrategySpecification() {
366        UploadStrategySpecification spec = pnlUploadStrategySelectionPanel.getUploadStrategySpecification();
367        spec.setCloseChangesetAfterUpload(pnlChangesetManagement.isCloseChangesetAfterUpload());
368        return spec;
369    }
370
371    @Override
372    public String getUploadComment() {
373        return changesetCommentModel.getComment();
374    }
375
376    @Override
377    public String getUploadSource() {
378        return changesetSourceModel.getComment();
379    }
380
381    @Override
382    public void setVisible(boolean visible) {
383        if (visible) {
384            new WindowGeometry(
385                    getClass().getName() + ".geometry",
386                    WindowGeometry.centerInWindow(
387                            MainApplication.getMainFrame(),
388                            new Dimension(400, 600)
389                    )
390            ).applySafe(this);
391            startUserInput();
392        } else if (isShowing()) { // Avoid IllegalComponentStateException like in #8775
393            new WindowGeometry(this).remember(getClass().getName() + ".geometry");
394        }
395        super.setVisible(visible);
396    }
397
398    /**
399     * Adds a custom component to this dialog.
400     * Custom components added at JOSM startup are displayed between the objects list and the properties tab pane.
401     * @param c The custom component to add. If {@code null}, this method does nothing.
402     * @return {@code true} if the collection of custom components changed as a result of the call
403     * @since 5842
404     */
405    public static boolean addCustomComponent(Component c) {
406        if (c != null) {
407            return customComponents.add(c);
408        }
409        return false;
410    }
411
412    static final class CompactTabbedPane extends JTabbedPane {
413        @Override
414        public Dimension getPreferredSize() {
415            // make sure the tabbed pane never grabs more space than necessary
416            return super.getMinimumSize();
417        }
418    }
419
420    /**
421     * Handles an upload.
422     */
423    static class UploadAction extends AbstractAction {
424
425        private final transient IUploadDialog dialog;
426
427        UploadAction(IUploadDialog dialog) {
428            this.dialog = dialog;
429            putValue(NAME, tr("Upload Changes"));
430            new ImageProvider("upload").getResource().attachImageIcon(this, true);
431            putValue(SHORT_DESCRIPTION, tr("Upload the changed primitives"));
432        }
433
434        /**
435         * Displays a warning message indicating that the upload comment is empty/short.
436         * @return true if the user wants to revisit, false if they want to continue
437         */
438        protected boolean warnUploadComment() {
439            return warnUploadTag(
440                    tr("Please revise upload comment"),
441                    tr("Your upload comment is <i>empty</i>, or <i>very short</i>.<br /><br />" +
442                            "This is technically allowed, but please consider that many users who are<br />" +
443                            "watching changes in their area depend on meaningful changeset comments<br />" +
444                            "to understand what is going on!<br /><br />" +
445                            "If you spend a minute now to explain your change, you will make life<br />" +
446                            "easier for many other mappers."),
447                    "upload_comment_is_empty_or_very_short"
448            );
449        }
450
451        /**
452         * Displays a warning message indicating that no changeset source is given.
453         * @return true if the user wants to revisit, false if they want to continue
454         */
455        protected boolean warnUploadSource() {
456            return warnUploadTag(
457                    tr("Please specify a changeset source"),
458                    tr("You did not specify a source for your changes.<br />" +
459                            "It is technically allowed, but this information helps<br />" +
460                            "other users to understand the origins of the data.<br /><br />" +
461                            "If you spend a minute now to explain your change, you will make life<br />" +
462                            "easier for many other mappers."),
463                    "upload_source_is_empty"
464            );
465        }
466
467        protected boolean warnUploadTag(final String title, final String message, final String togglePref) {
468            String[] buttonTexts = new String[] {tr("Revise"), tr("Cancel"), tr("Continue as is")};
469            Icon[] buttonIcons = new Icon[] {
470                    new ImageProvider("ok").setMaxSize(ImageSizes.LARGEICON).get(),
471                    new ImageProvider("cancel").setMaxSize(ImageSizes.LARGEICON).get(),
472                    new ImageProvider("upload").setMaxSize(ImageSizes.LARGEICON).addOverlay(
473                            new ImageOverlay(new ImageProvider("warning-small"), 0.5, 0.5, 1.0, 1.0)).get()};
474            String[] tooltips = new String[] {
475                    tr("Return to the previous dialog to enter a more descriptive comment"),
476                    tr("Cancel and return to the previous dialog"),
477                    tr("Ignore this hint and upload anyway")};
478
479            ExtendedDialog dlg = new ExtendedDialog((Component) dialog, title, buttonTexts) {
480                @Override
481                public void setupDialog() {
482                    super.setupDialog();
483                    InputMapUtils.addCtrlEnterAction(getRootPane(), buttons.get(buttons.size() - 1).getAction());
484                }
485            };
486            dlg.setContent("<html>" + message + "</html>");
487            dlg.setButtonIcons(buttonIcons);
488            dlg.setToolTipTexts(tooltips);
489            dlg.setIcon(JOptionPane.WARNING_MESSAGE);
490            dlg.toggleEnable(togglePref);
491            dlg.setCancelButton(1, 2);
492            return dlg.showDialog().getValue() != 3;
493        }
494
495        protected void warnIllegalChunkSize() {
496            HelpAwareOptionPane.showOptionDialog(
497                    (Component) dialog,
498                    tr("Please enter a valid chunk size first"),
499                    tr("Illegal chunk size"),
500                    JOptionPane.ERROR_MESSAGE,
501                    ht("/Dialog/Upload#IllegalChunkSize")
502            );
503        }
504
505        static boolean isUploadCommentTooShort(String comment) {
506            String s = comment.trim();
507            boolean result = true;
508            if (!s.isEmpty()) {
509                UnicodeBlock block = Character.UnicodeBlock.of(s.charAt(0));
510                if (block != null && block.toString().contains("CJK")) {
511                    result = s.length() < 4;
512                } else {
513                    result = s.length() < 10;
514                }
515            }
516            return result;
517        }
518
519        @Override
520        public void actionPerformed(ActionEvent e) {
521            if (isUploadCommentTooShort(dialog.getUploadComment()) && warnUploadComment()) {
522                // abort for missing comment
523                dialog.handleMissingComment();
524                return;
525            }
526            if (dialog.getUploadSource().trim().isEmpty() && warnUploadSource()) {
527                // abort for missing changeset source
528                dialog.handleMissingSource();
529                return;
530            }
531
532            /* test for empty tags in the changeset metadata and proceed only after user's confirmation.
533             * though, accept if key and value are empty (cf. xor). */
534            List<String> emptyChangesetTags = new ArrayList<>();
535            for (final Entry<String, String> i : dialog.getTags(true).entrySet()) {
536                final boolean isKeyEmpty = i.getKey() == null || i.getKey().trim().isEmpty();
537                final boolean isValueEmpty = i.getValue() == null || i.getValue().trim().isEmpty();
538                final boolean ignoreKey = "comment".equals(i.getKey()) || "source".equals(i.getKey());
539                if ((isKeyEmpty ^ isValueEmpty) && !ignoreKey) {
540                    emptyChangesetTags.add(tr("{0}={1}", i.getKey(), i.getValue()));
541                }
542            }
543            if (!emptyChangesetTags.isEmpty() && JOptionPane.OK_OPTION != JOptionPane.showConfirmDialog(
544                    MainApplication.getMainFrame(),
545                    trn(
546                            "<html>The following changeset tag contains an empty key/value:<br>{0}<br>Continue?</html>",
547                            "<html>The following changeset tags contain an empty key/value:<br>{0}<br>Continue?</html>",
548                            emptyChangesetTags.size(), Utils.joinAsHtmlUnorderedList(emptyChangesetTags)),
549                    tr("Empty metadata"),
550                    JOptionPane.OK_CANCEL_OPTION,
551                    JOptionPane.WARNING_MESSAGE
552            )) {
553                dialog.handleMissingComment();
554                return;
555            }
556
557            UploadStrategySpecification strategy = dialog.getUploadStrategySpecification();
558            if (strategy.getStrategy() == UploadStrategy.CHUNKED_DATASET_STRATEGY
559                    && strategy.getChunkSize() == UploadStrategySpecification.UNSPECIFIED_CHUNK_SIZE) {
560                warnIllegalChunkSize();
561                dialog.handleIllegalChunkSize();
562                return;
563            }
564            if (dialog instanceof AbstractUploadDialog) {
565                ((AbstractUploadDialog) dialog).setCanceled(false);
566                ((AbstractUploadDialog) dialog).setVisible(false);
567            }
568        }
569    }
570
571    /**
572     * Action for canceling the dialog.
573     */
574    static class CancelAction extends AbstractAction {
575
576        private final transient IUploadDialog dialog;
577
578        CancelAction(IUploadDialog dialog) {
579            this.dialog = dialog;
580            putValue(NAME, tr("Cancel"));
581            new ImageProvider("cancel").getResource().attachImageIcon(this, true);
582            putValue(SHORT_DESCRIPTION, tr("Cancel the upload and resume editing"));
583        }
584
585        @Override
586        public void actionPerformed(ActionEvent e) {
587            if (dialog instanceof AbstractUploadDialog) {
588                ((AbstractUploadDialog) dialog).setCanceled(true);
589                ((AbstractUploadDialog) dialog).setVisible(false);
590            }
591        }
592    }
593
594    /**
595     * Listens to window closing events and processes them as cancel events.
596     * Listens to window open events and initializes user input
597     */
598    class WindowEventHandler extends WindowAdapter {
599        private boolean activatedOnce;
600
601        @Override
602        public void windowClosing(WindowEvent e) {
603            setCanceled(true);
604        }
605
606        @Override
607        public void windowActivated(WindowEvent e) {
608            if (!activatedOnce && tpConfigPanels.getSelectedIndex() == 0) {
609                pnlBasicUploadSettings.initEditingOfUploadComment();
610                activatedOnce = true;
611            }
612        }
613    }
614
615    /* -------------------------------------------------------------------------- */
616    /* Interface PropertyChangeListener                                           */
617    /* -------------------------------------------------------------------------- */
618    @Override
619    public void propertyChange(PropertyChangeEvent evt) {
620        if (evt.getPropertyName().equals(ChangesetManagementPanel.SELECTED_CHANGESET_PROP)) {
621            Changeset cs = (Changeset) evt.getNewValue();
622            setChangesetTags(dataSet);
623            if (cs == null) {
624                tpConfigPanels.setTitleAt(1, tr("Tags of new changeset"));
625            } else {
626                tpConfigPanels.setTitleAt(1, tr("Tags of changeset {0}", cs.getId()));
627            }
628        }
629    }
630
631    /* -------------------------------------------------------------------------- */
632    /* Interface PreferenceChangedListener                                        */
633    /* -------------------------------------------------------------------------- */
634    @Override
635    public void preferenceChanged(PreferenceChangeEvent e) {
636        if (e.getKey() == null || !"osm-server.url".equals(e.getKey()))
637            return;
638        final Setting<?> newValue = e.getNewValue();
639        final String url;
640        if (newValue == null || newValue.getValue() == null) {
641            url = OsmApi.getOsmApi().getBaseUrl();
642        } else {
643            url = newValue.getValue().toString();
644        }
645        setTitle(tr("Upload to ''{0}''", url));
646    }
647
648    private static String getLastChangesetTagFromHistory(String historyKey, List<String> def) {
649        Collection<String> history = Config.getPref().getList(historyKey, def);
650        int age = (int) (System.currentTimeMillis() / 1000 - Config.getPref().getInt(BasicUploadSettingsPanel.HISTORY_LAST_USED_KEY, 0));
651        if (history != null && age < Config.getPref().getLong(BasicUploadSettingsPanel.HISTORY_MAX_AGE_KEY, TimeUnit.HOURS.toMillis(4))
652                && !history.isEmpty()) {
653            return history.iterator().next();
654        } else {
655            return null;
656        }
657    }
658
659    /**
660     * Returns the last changeset comment from history.
661     * @return the last changeset comment from history
662     */
663    public String getLastChangesetCommentFromHistory() {
664        return getLastChangesetTagFromHistory(BasicUploadSettingsPanel.HISTORY_KEY, new ArrayList<String>());
665    }
666
667    /**
668     * Returns the last changeset source from history.
669     * @return the last changeset source from history
670     */
671    public String getLastChangesetSourceFromHistory() {
672        return getLastChangesetTagFromHistory(BasicUploadSettingsPanel.SOURCE_HISTORY_KEY, BasicUploadSettingsPanel.getDefaultSources());
673    }
674
675    @Override
676    public Map<String, String> getTags(boolean keepEmpty) {
677        return pnlTagSettings.getTags(keepEmpty);
678    }
679
680    @Override
681    public void handleMissingComment() {
682        tpConfigPanels.setSelectedIndex(0);
683        pnlBasicUploadSettings.initEditingOfUploadComment();
684    }
685
686    @Override
687    public void handleMissingSource() {
688        tpConfigPanels.setSelectedIndex(0);
689        pnlBasicUploadSettings.initEditingOfUploadSource();
690    }
691
692    @Override
693    public void handleIllegalChunkSize() {
694        tpConfigPanels.setSelectedIndex(0);
695    }
696
697    /**
698     * Clean dialog state and release resources.
699     * @since 14251
700     */
701    public void clean() {
702        setUploadedPrimitives(null);
703        dataSet = null;
704    }
705}
Note: See TracBrowser for help on using the repository browser.