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

Last change on this file since 10369 was 10105, checked in by Don-vip, 8 years ago

fix coverity 1353745 + add unit test

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