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

Last change on this file since 17379 was 17339, checked in by simon04, 4 years ago

https://errorprone.info/bugpattern/StringSplitter

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