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

Last change on this file since 12531 was 12531, checked in by simon04, 7 years ago

fix #15089 - UploadDialog: bind Ctrl+Enter to upload action

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