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

Last change on this file since 18467 was 18467, checked in by taylor.smock, 2 years ago

Fix #20025, #22080: Notify users when changeset tags are programmatically modified

This only works for non-late upload hooks.

  • Property svn:eol-style set to native
File size: 25.5 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.marktr;
6import static org.openstreetmap.josm.tools.I18n.tr;
7import static org.openstreetmap.josm.tools.I18n.trn;
8
9import java.awt.BorderLayout;
10import java.awt.Color;
11import java.awt.Component;
12import java.awt.Dimension;
13import java.awt.FlowLayout;
14import java.awt.GridBagConstraints;
15import java.awt.GridBagLayout;
16import java.awt.event.ActionEvent;
17import java.awt.event.WindowAdapter;
18import java.awt.event.WindowEvent;
19import java.beans.PropertyChangeEvent;
20import java.beans.PropertyChangeListener;
21import java.lang.Character.UnicodeBlock;
22import java.util.ArrayList;
23import java.util.Collections;
24import java.util.HashMap;
25import java.util.List;
26import java.util.Locale;
27import java.util.Map;
28import java.util.Map.Entry;
29import java.util.stream.Collectors;
30
31import javax.swing.AbstractAction;
32import javax.swing.BorderFactory;
33import javax.swing.JButton;
34import javax.swing.JOptionPane;
35import javax.swing.JPanel;
36import javax.swing.JSplitPane;
37import javax.swing.JTabbedPane;
38import javax.swing.event.ChangeListener;
39
40import org.openstreetmap.josm.data.APIDataSet;
41import org.openstreetmap.josm.data.osm.Changeset;
42import org.openstreetmap.josm.data.osm.DataSet;
43import org.openstreetmap.josm.data.osm.OsmPrimitive;
44import org.openstreetmap.josm.data.preferences.NamedColorProperty;
45import org.openstreetmap.josm.gui.HelpAwareOptionPane;
46import org.openstreetmap.josm.gui.MainApplication;
47import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
48import org.openstreetmap.josm.gui.help.HelpUtil;
49import org.openstreetmap.josm.gui.tagging.TagEditorPanel;
50import org.openstreetmap.josm.gui.util.GuiHelper;
51import org.openstreetmap.josm.gui.util.MultiLineFlowLayout;
52import org.openstreetmap.josm.gui.util.WindowGeometry;
53import org.openstreetmap.josm.io.OsmApi;
54import org.openstreetmap.josm.io.UploadStrategy;
55import org.openstreetmap.josm.io.UploadStrategySpecification;
56import org.openstreetmap.josm.spi.preferences.Config;
57import org.openstreetmap.josm.spi.preferences.PreferenceChangeEvent;
58import org.openstreetmap.josm.spi.preferences.PreferenceChangedListener;
59import org.openstreetmap.josm.spi.preferences.Setting;
60import org.openstreetmap.josm.tools.GBC;
61import org.openstreetmap.josm.tools.ImageProvider;
62import org.openstreetmap.josm.tools.InputMapUtils;
63import org.openstreetmap.josm.tools.Utils;
64
65/**
66 * This is a dialog for entering upload options like the parameters for
67 * the upload changeset and the strategy for opening/closing a changeset.
68 * @since 2025
69 */
70public class UploadDialog extends AbstractUploadDialog implements PreferenceChangedListener, PropertyChangeListener {
71 /** A warning color to indicate something is non-default in the changeset tags */
72 private static final Color WARNING_BACKGROUND = new NamedColorProperty(
73 marktr("Changesets: Non-default advanced settings"), new Color(0xF89042)).get();
74 /** the unique instance of the upload dialog */
75 private static UploadDialog uploadDialog;
76
77 /** the panel with the objects to upload */
78 private UploadedObjectsSummaryPanel pnlUploadedObjects;
79
80 /** the "description" tab */
81 private BasicUploadSettingsPanel pnlBasicUploadSettings;
82
83 /** the panel to select the changeset used */
84 private ChangesetManagementPanel pnlChangesetManagement;
85 /** the panel to select the upload strategy */
86 private UploadStrategySelectionPanel pnlUploadStrategySelectionPanel;
87
88 /** the tag editor panel */
89 private TagEditorPanel pnlTagEditor;
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 model keeping the state of the changeset tags */
96 private final transient UploadDialogModel model = new UploadDialogModel();
97
98 private transient DataSet dataSet;
99 private ChangeListener changesetTagListener;
100
101 /**
102 * Constructs a new {@code UploadDialog}.
103 */
104 protected UploadDialog() {
105 super(GuiHelper.getFrameForComponent(MainApplication.getMainFrame()), ModalityType.DOCUMENT_MODAL);
106 build();
107 pack();
108 }
109
110 /**
111 * Replies the unique instance of the upload dialog
112 *
113 * @return the unique instance of the upload dialog
114 */
115 public static synchronized UploadDialog getUploadDialog() {
116 if (uploadDialog == null) {
117 uploadDialog = new UploadDialog();
118 }
119 return uploadDialog;
120 }
121
122 /**
123 * builds the content panel for the upload dialog
124 *
125 * @return the content panel
126 */
127 protected JPanel buildContentPanel() {
128 final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
129 splitPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
130
131 // the panel with the list of uploaded objects
132 pnlUploadedObjects = new UploadedObjectsSummaryPanel();
133 pnlUploadedObjects.setMinimumSize(new Dimension(200, 50));
134 splitPane.setLeftComponent(pnlUploadedObjects);
135
136 // a tabbed pane with configuration panels in the lower half
137 tpConfigPanels = new CompactTabbedPane();
138 splitPane.setRightComponent(tpConfigPanels);
139
140 pnlBasicUploadSettings = new BasicUploadSettingsPanel(model);
141 tpConfigPanels.add(pnlBasicUploadSettings);
142 tpConfigPanels.setTitleAt(0, tr("Description"));
143 tpConfigPanels.setToolTipTextAt(0, tr("Describe the changes you made"));
144
145 JPanel pnlSettings = new JPanel(new GridBagLayout());
146 pnlSettings.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
147 JPanel pnlTagEditorBorder = new JPanel(new BorderLayout());
148 pnlTagEditorBorder.setBorder(BorderFactory.createTitledBorder(tr("Changeset tags:")));
149 pnlTagEditor = new TagEditorPanel(model, null, Changeset.MAX_CHANGESET_TAG_LENGTH);
150 pnlTagEditorBorder.add(pnlTagEditor, BorderLayout.CENTER);
151
152 pnlChangesetManagement = new ChangesetManagementPanel();
153 pnlUploadStrategySelectionPanel = new UploadStrategySelectionPanel();
154 pnlSettings.add(pnlChangesetManagement, GBC.eop().fill(GridBagConstraints.HORIZONTAL));
155 pnlSettings.add(pnlUploadStrategySelectionPanel, GBC.eop().fill(GridBagConstraints.HORIZONTAL));
156 pnlSettings.add(pnlTagEditorBorder, GBC.eol().fill(GridBagConstraints.BOTH));
157
158 // if another tab is added, please don't forget to update setChangesetTagsModifiedProgramatically
159 tpConfigPanels.add(pnlSettings);
160 tpConfigPanels.setTitleAt(1, tr("Settings"));
161 tpConfigPanels.setToolTipTextAt(1, tr("Decide how to upload the data and which changeset to use"));
162
163 JPanel pnl = new JPanel(new BorderLayout());
164 pnl.add(splitPane, BorderLayout.CENTER);
165 pnl.add(buildActionPanel(), BorderLayout.SOUTH);
166 return pnl;
167 }
168
169 /**
170 * builds the panel with the OK and CANCEL buttons
171 *
172 * @return The panel with the OK and CANCEL buttons
173 */
174 protected JPanel buildActionPanel() {
175 JPanel pnl = new JPanel(new MultiLineFlowLayout(FlowLayout.CENTER));
176 pnl.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
177
178 // -- upload button
179 btnUpload = new JButton(new UploadAction(this));
180 pnl.add(btnUpload);
181 btnUpload.setFocusable(true);
182 InputMapUtils.enableEnter(btnUpload);
183 InputMapUtils.addCtrlEnterAction(getRootPane(), btnUpload.getAction());
184
185 // -- cancel button
186 CancelAction cancelAction = new CancelAction(this);
187 pnl.add(new JButton(cancelAction));
188 InputMapUtils.addEscapeAction(getRootPane(), cancelAction);
189
190 // -- help button
191 pnl.add(new JButton(new ContextSensitiveHelpAction(ht("/Dialog/Upload"))));
192 HelpUtil.setHelpContext(getRootPane(), ht("/Dialog/Upload"));
193 return pnl;
194 }
195
196 /**
197 * builds the gui
198 */
199 protected void build() {
200 setTitle(tr("Upload to ''{0}''", OsmApi.getOsmApi().getBaseUrl()));
201 setContentPane(buildContentPanel());
202
203 addWindowListener(new WindowEventHandler());
204
205 // make sure the configuration panels listen to each others changes
206 //
207 UploadParameterSummaryPanel sp = pnlBasicUploadSettings.getUploadParameterSummaryPanel();
208 // the summary panel must know everything
209 pnlChangesetManagement.addPropertyChangeListener(sp);
210 pnlUploadedObjects.addPropertyChangeListener(sp);
211 pnlUploadStrategySelectionPanel.addPropertyChangeListener(sp);
212
213 // update tags from selected changeset
214 pnlChangesetManagement.addPropertyChangeListener(this);
215
216 // users can click on either of two links in the upload parameter
217 // summary handler. This installs the handler for these two events.
218 // We simply select the appropriate tab in the tabbed pane with the configuration dialogs.
219 //
220 pnlBasicUploadSettings.getUploadParameterSummaryPanel().setConfigurationParameterRequestListener(
221 () -> tpConfigPanels.setSelectedIndex(2)
222 );
223
224 // Enable/disable the upload button if at least an upload validator rejects upload
225 pnlBasicUploadSettings.getUploadTextValidators().forEach(v -> v.addChangeListener(e -> btnUpload.setEnabled(
226 pnlBasicUploadSettings.getUploadTextValidators().stream().noneMatch(UploadTextComponentValidator::isUploadRejected))));
227
228 setMinimumSize(new Dimension(600, 350));
229
230 Config.getPref().addPreferenceChangeListener(this);
231 }
232
233 /**
234 * Initializes this life cycle of the dialog.
235 *
236 * Initializes the dialog each time before it is made visible. We cannot do
237 * this in the constructor because the dialog is a singleton.
238 *
239 * @param dataSet The Dataset we want to upload
240 * @since 18173
241 */
242 public void initLifeCycle(DataSet dataSet) {
243 Map<String, String> map = new HashMap<>();
244 this.dataSet = dataSet;
245 pnlBasicUploadSettings.initLifeCycle(map);
246 pnlChangesetManagement.initLifeCycle();
247 model.clear();
248 model.putAll(map); // init with tags from history
249 model.putAll(this.dataSet); // overwrite with tags from the dataset
250 if (Config.getPref().getBoolean("upload.source.obtainautomatically", false)
251 && this.dataSet.getChangeSetTags().containsKey(UploadDialogModel.SOURCE)) {
252 model.put(UploadDialogModel.SOURCE, pnlBasicUploadSettings.getSourceFromLayer());
253 }
254
255 tpConfigPanels.setSelectedIndex(0);
256 pnlTagEditor.initAutoCompletion(MainApplication.getLayerManager().getEditLayer());
257 pnlUploadStrategySelectionPanel.initFromPreferences();
258
259 // update the summary
260 UploadParameterSummaryPanel sumPnl = pnlBasicUploadSettings.getUploadParameterSummaryPanel();
261 sumPnl.setUploadStrategySpecification(pnlUploadStrategySelectionPanel.getUploadStrategySpecification());
262 sumPnl.setCloseChangesetAfterNextUpload(pnlChangesetManagement.isCloseChangesetAfterUpload());
263 }
264
265 /**
266 * Sets the collection of primitives to upload
267 *
268 * @param toUpload the dataset with the objects to upload. If null, assumes the empty
269 * set of objects to upload
270 *
271 */
272 public void setUploadedPrimitives(APIDataSet toUpload) {
273 UploadParameterSummaryPanel sumPnl = pnlBasicUploadSettings.getUploadParameterSummaryPanel();
274 if (toUpload == null) {
275 if (pnlUploadedObjects != null) {
276 List<OsmPrimitive> emptyList = Collections.emptyList();
277 pnlUploadedObjects.setUploadedPrimitives(emptyList, emptyList, emptyList);
278 sumPnl.setNumObjects(0);
279 }
280 return;
281 }
282 List<OsmPrimitive> l = toUpload.getPrimitives();
283 pnlBasicUploadSettings.setUploadedPrimitives(l);
284 pnlUploadedObjects.setUploadedPrimitives(
285 toUpload.getPrimitivesToAdd(),
286 toUpload.getPrimitivesToUpdate(),
287 toUpload.getPrimitivesToDelete()
288 );
289 sumPnl.setNumObjects(l.size());
290 pnlUploadStrategySelectionPanel.setNumUploadedObjects(l.size());
291 }
292
293 /**
294 * Sets the input focus to upload button.
295 * @since 18173
296 */
297 public void setFocusToUploadButton() {
298 btnUpload.requestFocus();
299 }
300
301 @Override
302 public void rememberUserInput() {
303 pnlBasicUploadSettings.rememberUserInput();
304 pnlUploadStrategySelectionPanel.rememberUserInput();
305 }
306
307 /**
308 * Returns the changeset to use complete with tags
309 *
310 * @return the changeset to use
311 */
312 public Changeset getChangeset() {
313 Changeset cs = pnlChangesetManagement.getSelectedChangeset();
314 cs.setKeys(getTags(true));
315 return cs;
316 }
317
318 /**
319 * Sets the changeset to be used in the next upload
320 *
321 * @param cs the changeset
322 */
323 public void setSelectedChangesetForNextUpload(Changeset cs) {
324 pnlChangesetManagement.setSelectedChangesetForNextUpload(cs);
325 }
326
327 @Override
328 public UploadStrategySpecification getUploadStrategySpecification() {
329 UploadStrategySpecification spec = pnlUploadStrategySelectionPanel.getUploadStrategySpecification();
330 spec.setCloseChangesetAfterUpload(pnlChangesetManagement.isCloseChangesetAfterUpload());
331 return spec;
332 }
333
334 /**
335 * Get the upload dialog model.
336 *
337 * @return The model.
338 * @since 18173
339 */
340 public UploadDialogModel getModel() {
341 return model;
342 }
343
344 @Override
345 public String getUploadComment() {
346 return model.getValue(UploadDialogModel.COMMENT);
347 }
348
349 @Override
350 public String getUploadSource() {
351 return model.getValue(UploadDialogModel.SOURCE);
352 }
353
354 @Override
355 public void setVisible(boolean visible) {
356 if (visible) {
357 new WindowGeometry(
358 getClass().getName() + ".geometry",
359 WindowGeometry.centerInWindow(
360 MainApplication.getMainFrame(),
361 new Dimension(800, 600)
362 )
363 ).applySafe(this);
364 } else if (isShowing()) { // Avoid IllegalComponentStateException like in #8775
365 new WindowGeometry(this).remember(getClass().getName() + ".geometry");
366 }
367 super.setVisible(visible);
368 }
369
370 /**
371 * This is called by {@link UploadAction} if {@link org.openstreetmap.josm.actions.upload.UploadHook}s change
372 * the changeset tags.
373 */
374 public void setChangesetTagsModifiedProgramatically() {
375 final Color originalColor = this.tpConfigPanels.getBackgroundAt(1);
376 this.tpConfigPanels.setBackgroundAt(1, WARNING_BACKGROUND);
377 this.tpConfigPanels.setIconAt(1, ImageProvider.get("warning-small"));
378 if (this.changesetTagListener != null) {
379 this.tpConfigPanels.removeChangeListener(this.changesetTagListener);
380 }
381 this.changesetTagListener = event -> {
382 if (this.tpConfigPanels.getSelectedIndex() == 1) {
383 tpConfigPanels.setBackgroundAt(1, originalColor);
384 tpConfigPanels.setIconAt(1, ImageProvider.get("apply"));
385 this.tpConfigPanels.removeChangeListener(this.changesetTagListener);
386 changesetTagListener = null;
387 }
388 };
389
390 this.tpConfigPanels.addChangeListener(this.changesetTagListener);
391 }
392
393 static final class CompactTabbedPane extends JTabbedPane {
394 @Override
395 public Dimension getPreferredSize() {
396 // This probably fixes #18523. Don't know why. Don't know how. It just does.
397 super.getPreferredSize();
398 // make sure the tabbed pane never grabs more space than necessary
399 return super.getMinimumSize();
400 }
401 }
402
403 /**
404 * Handles an upload.
405 */
406 static class UploadAction extends AbstractAction {
407
408 private final transient IUploadDialog dialog;
409
410 UploadAction(IUploadDialog dialog) {
411 this.dialog = dialog;
412 putValue(NAME, tr("Upload Changes"));
413 new ImageProvider("upload").getResource().attachImageIcon(this, true);
414 putValue(SHORT_DESCRIPTION, tr("Upload the changed primitives"));
415 }
416
417 protected void warnIllegalChunkSize() {
418 HelpAwareOptionPane.showOptionDialog(
419 (Component) dialog,
420 tr("Please enter a valid chunk size first"),
421 tr("Illegal chunk size"),
422 JOptionPane.ERROR_MESSAGE,
423 ht("/Dialog/Upload#IllegalChunkSize")
424 );
425 }
426
427 static boolean isUploadCommentTooShort(String comment) {
428 String s = Utils.strip(comment);
429 if (s.isEmpty()) {
430 return true;
431 }
432 UnicodeBlock block = Character.UnicodeBlock.of(s.charAt(0));
433 if (block != null && block.toString().contains("CJK")) {
434 return s.length() < 4;
435 } else {
436 return s.length() < 10;
437 }
438 }
439
440 private static String lower(String s) {
441 return s.toLowerCase(Locale.ENGLISH);
442 }
443
444 static String validateUploadTag(String uploadValue, String preferencePrefix,
445 List<String> defMandatory, List<String> defForbidden, List<String> defException) {
446 String uploadValueLc = lower(uploadValue);
447 // Check mandatory terms
448 List<String> missingTerms = Config.getPref().getList(preferencePrefix+".mandatory-terms", defMandatory)
449 .stream().map(UploadAction::lower).filter(x -> !uploadValueLc.contains(x)).collect(Collectors.toList());
450 if (!missingTerms.isEmpty()) {
451 return tr("The following required terms are missing: {0}", missingTerms);
452 }
453 // Check forbidden terms
454 List<String> exceptions = Config.getPref().getList(preferencePrefix+".exception-terms", defException);
455 List<String> forbiddenTerms = Config.getPref().getList(preferencePrefix+".forbidden-terms", defForbidden)
456 .stream().map(UploadAction::lower)
457 .filter(x -> uploadValueLc.contains(x) && exceptions.stream().noneMatch(uploadValueLc::contains))
458 .collect(Collectors.toList());
459 if (!forbiddenTerms.isEmpty()) {
460 return tr("The following forbidden terms have been found: {0}", forbiddenTerms);
461 }
462 return null;
463 }
464
465 @Override
466 public void actionPerformed(ActionEvent e) {
467 Map<String, String> tags = dialog.getTags(true);
468
469 // If there are empty tags in the changeset proceed only after user's confirmation.
470 List<String> emptyChangesetTags = new ArrayList<>();
471 for (final Entry<String, String> i : tags.entrySet()) {
472 final boolean isKeyEmpty = Utils.isStripEmpty(i.getKey());
473 final boolean isValueEmpty = Utils.isStripEmpty(i.getValue());
474 final boolean ignoreKey = UploadDialogModel.isCommentOrSource(i.getKey());
475 if ((isKeyEmpty || isValueEmpty) && !ignoreKey) {
476 emptyChangesetTags.add(tr("{0}={1}", i.getKey(), i.getValue()));
477 }
478 }
479 if (!emptyChangesetTags.isEmpty() && JOptionPane.OK_OPTION != JOptionPane.showConfirmDialog(
480 MainApplication.getMainFrame(),
481 trn(
482 "<html>The following changeset tag contains an empty key/value:<br>{0}<br>Continue?</html>",
483 "<html>The following changeset tags contain an empty key/value:<br>{0}<br>Continue?</html>",
484 emptyChangesetTags.size(), Utils.joinAsHtmlUnorderedList(emptyChangesetTags)),
485 tr("Empty metadata"),
486 JOptionPane.OK_CANCEL_OPTION,
487 JOptionPane.WARNING_MESSAGE
488 )) {
489 dialog.handleMissingComment();
490 return;
491 }
492
493 UploadStrategySpecification strategy = dialog.getUploadStrategySpecification();
494 if (strategy.getStrategy() == UploadStrategy.CHUNKED_DATASET_STRATEGY
495 && strategy.getChunkSize() == UploadStrategySpecification.UNSPECIFIED_CHUNK_SIZE) {
496 warnIllegalChunkSize();
497 dialog.handleIllegalChunkSize();
498 return;
499 }
500 if (dialog instanceof AbstractUploadDialog) {
501 ((AbstractUploadDialog) dialog).setCanceled(false);
502 ((AbstractUploadDialog) dialog).setVisible(false);
503 }
504 }
505 }
506
507 /**
508 * Action for canceling the dialog.
509 */
510 static class CancelAction extends AbstractAction {
511
512 private final transient IUploadDialog dialog;
513
514 CancelAction(IUploadDialog dialog) {
515 this.dialog = dialog;
516 putValue(NAME, tr("Cancel"));
517 new ImageProvider("cancel").getResource().attachImageIcon(this, true);
518 putValue(SHORT_DESCRIPTION, tr("Cancel the upload and resume editing"));
519 }
520
521 @Override
522 public void actionPerformed(ActionEvent e) {
523 if (dialog instanceof AbstractUploadDialog) {
524 ((AbstractUploadDialog) dialog).setCanceled(true);
525 ((AbstractUploadDialog) dialog).setVisible(false);
526 }
527 }
528 }
529
530 /**
531 * Listens to window closing events and processes them as cancel events.
532 * Listens to window open events and initializes user input
533 */
534 class WindowEventHandler extends WindowAdapter {
535 private boolean activatedOnce;
536
537 @Override
538 public void windowClosing(WindowEvent e) {
539 setCanceled(true);
540 }
541
542 @Override
543 public void windowActivated(WindowEvent e) {
544 if (!activatedOnce && tpConfigPanels.getSelectedIndex() == 0) {
545 pnlBasicUploadSettings.initEditingOfUploadComment();
546 activatedOnce = true;
547 }
548 }
549 }
550
551 /* -------------------------------------------------------------------------- */
552 /* Interface PropertyChangeListener */
553 /* -------------------------------------------------------------------------- */
554 @Override
555 public void propertyChange(PropertyChangeEvent evt) {
556 if (evt.getPropertyName().equals(ChangesetManagementPanel.SELECTED_CHANGESET_PROP)) {
557 // put the tags from the newly selected changeset into the model
558 Changeset cs = (Changeset) evt.getNewValue();
559 if (cs != null) {
560 for (Map.Entry<String, String> entry : cs.getKeys().entrySet()) {
561 String key = entry.getKey();
562 // do NOT overwrite comment and source when selecting a changeset, it is confusing
563 if (!UploadDialogModel.isCommentOrSource(key))
564 model.put(key, entry.getValue());
565 }
566 }
567 }
568 }
569
570 /* -------------------------------------------------------------------------- */
571 /* Interface PreferenceChangedListener */
572 /* -------------------------------------------------------------------------- */
573 @Override
574 public void preferenceChanged(PreferenceChangeEvent e) {
575 if (e.getKey() != null
576 && e.getSource() != getClass()
577 && e.getSource() != BasicUploadSettingsPanel.class) {
578 switch (e.getKey()) {
579 case "osm-server.url":
580 osmServerUrlChanged(e.getNewValue());
581 break;
582 default:
583 return;
584 }
585 }
586 }
587
588 private void osmServerUrlChanged(Setting<?> newValue) {
589 final String url;
590 if (newValue == null || newValue.getValue() == null) {
591 url = OsmApi.getOsmApi().getBaseUrl();
592 } else {
593 url = newValue.getValue().toString();
594 }
595 setTitle(tr("Upload to ''{0}''", url));
596 }
597
598 /* -------------------------------------------------------------------------- */
599 /* Interface IUploadDialog */
600 /* -------------------------------------------------------------------------- */
601 @Override
602 public Map<String, String> getTags(boolean keepEmpty) {
603 saveEdits();
604 return model.getTags(keepEmpty);
605 }
606
607 @Override
608 public void handleMissingComment() {
609 tpConfigPanels.setSelectedIndex(0);
610 pnlBasicUploadSettings.initEditingOfUploadComment();
611 }
612
613 @Override
614 public void handleMissingSource() {
615 tpConfigPanels.setSelectedIndex(0);
616 pnlBasicUploadSettings.initEditingOfUploadSource();
617 }
618
619 @Override
620 public void handleIllegalChunkSize() {
621 tpConfigPanels.setSelectedIndex(0);
622 }
623
624 /**
625 * Save all outstanding edits to the model.
626 * <p>
627 * The combobox editors and the tag cell editor need to be manually saved
628 * because they normally save on focus loss, eg. when the "Upload" button is
629 * pressed, but there's no focus change when Ctrl+Enter is pressed.
630 *
631 * @since 18173
632 */
633 public void saveEdits() {
634 pnlBasicUploadSettings.saveEdits();
635 pnlTagEditor.saveEdits();
636 }
637
638 /**
639 * Clean dialog state and release resources.
640 * @since 14251
641 */
642 public void clean() {
643 setUploadedPrimitives(null);
644 dataSet = null;
645 if (this.changesetTagListener != null) {
646 this.changesetTagListener.stateChanged(null);
647 this.tpConfigPanels.removeChangeListener(this.changesetTagListener);
648 this.changesetTagListener = null;
649 }
650 }
651}
Note: See TracBrowser for help on using the repository browser.