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

Last change on this file since 12452 was 12452, checked in by bastiK, 7 years ago

see #14794 - javadoc for the josm.gui.io package

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