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

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

fix #15572 - use ImageProvider attach API for all JOSM actions to ensure proper icon size everywhere

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