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

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

fix #13198 - Add new flow layout that does the right height computation (patch by michael2402, modified) - gsoc-core

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