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

Last change on this file since 11553 was 11553, checked in by Don-vip, 7 years ago

refactor handling of null values - use Java 8 Optional where possible

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