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

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

see #15182 - move UploadStrategySpecification and required enums from gui.io to io

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