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

Last change on this file since 5673 was 5412, checked in by Don-vip, 12 years ago

see #7943 - fix NPE when switching back to default OSM API server after having tried to upload data to another server instance

  • Property svn:eol-style set to native
File size: 19.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;
6
7import java.awt.BorderLayout;
8import java.awt.Dimension;
9import java.awt.FlowLayout;
10import java.awt.Image;
11import java.awt.event.ActionEvent;
12import java.awt.event.KeyEvent;
13import java.awt.event.WindowAdapter;
14import java.awt.event.WindowEvent;
15import java.beans.PropertyChangeEvent;
16import java.beans.PropertyChangeListener;
17import java.util.Collections;
18import java.util.List;
19import java.util.Map;
20
21import javax.swing.AbstractAction;
22import javax.swing.BorderFactory;
23import javax.swing.Icon;
24import javax.swing.ImageIcon;
25import javax.swing.JButton;
26import javax.swing.JComponent;
27import javax.swing.JDialog;
28import javax.swing.JOptionPane;
29import javax.swing.JPanel;
30import javax.swing.JTabbedPane;
31import javax.swing.KeyStroke;
32
33import org.openstreetmap.josm.Main;
34import org.openstreetmap.josm.data.APIDataSet;
35import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent;
36import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener;
37import org.openstreetmap.josm.data.Preferences.Setting;
38import org.openstreetmap.josm.data.osm.Changeset;
39import org.openstreetmap.josm.data.osm.OsmPrimitive;
40import org.openstreetmap.josm.gui.ExtendedDialog;
41import org.openstreetmap.josm.gui.HelpAwareOptionPane;
42import org.openstreetmap.josm.gui.SideButton;
43import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
44import org.openstreetmap.josm.gui.help.HelpUtil;
45import org.openstreetmap.josm.io.OsmApi;
46import org.openstreetmap.josm.tools.ImageProvider;
47import org.openstreetmap.josm.tools.InputMapUtils;
48import org.openstreetmap.josm.tools.WindowGeometry;
49
50/**
51 * This is a dialog for entering upload options like the parameters for
52 * the upload changeset and the strategy for opening/closing a changeset.
53 *
54 */
55public class UploadDialog extends JDialog implements PropertyChangeListener, PreferenceChangedListener{
56 /** the unique instance of the upload dialog */
57 static private UploadDialog uploadDialog;
58
59 /**
60 * Replies the unique instance of the upload dialog
61 *
62 * @return the unique instance of the upload dialog
63 */
64 static public UploadDialog getUploadDialog() {
65 if (uploadDialog == null) {
66 uploadDialog = new UploadDialog();
67 }
68 return uploadDialog;
69 }
70
71 /** the panel with the objects to upload */
72 private UploadedObjectsSummaryPanel pnlUploadedObjects;
73 /** the panel to select the changeset used */
74 private ChangesetManagementPanel pnlChangesetManagement;
75
76 private BasicUploadSettingsPanel pnlBasicUploadSettings;
77
78 private UploadStrategySelectionPanel pnlUploadStrategySelectionPanel;
79
80 /** checkbox for selecting whether an atomic upload is to be used */
81 private TagSettingsPanel pnlTagSettings;
82 /** the tabbed pane used below of the list of primitives */
83 private JTabbedPane tpConfigPanels;
84 /** the upload button */
85 private JButton btnUpload;
86 private boolean canceled = false;
87
88 /** the changeset comment model keeping the state of the changeset comment */
89 private ChangesetCommentModel changesetCommentModel;
90
91 /**
92 * builds the content panel for the upload dialog
93 *
94 * @return the content panel
95 */
96 protected JPanel buildContentPanel() {
97 JPanel pnl = new JPanel();
98 pnl.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
99 pnl.setLayout(new BorderLayout());
100
101 // the panel with the list of uploaded objects
102 //
103 pnl.add(pnlUploadedObjects = new UploadedObjectsSummaryPanel(), BorderLayout.CENTER);
104
105 // a tabbed pane with two configuration panels in the
106 // lower half
107 //
108 tpConfigPanels = new JTabbedPane() {
109 @Override
110 public Dimension getPreferredSize() {
111 // make sure the tabbed pane never grabs more space than necessary
112 //
113 return super.getMinimumSize();
114 }
115 };
116 tpConfigPanels.add(new JPanel());
117 tpConfigPanels.add(new JPanel());
118 tpConfigPanels.add(new JPanel());
119 tpConfigPanels.add(new JPanel());
120
121 changesetCommentModel = new ChangesetCommentModel();
122
123 tpConfigPanels.setComponentAt(0, pnlBasicUploadSettings = new BasicUploadSettingsPanel(changesetCommentModel));
124 tpConfigPanels.setTitleAt(0, tr("Settings"));
125 tpConfigPanels.setToolTipTextAt(0, tr("Decide how to upload the data and which changeset to use"));
126
127 tpConfigPanels.setComponentAt(1,pnlTagSettings = new TagSettingsPanel(changesetCommentModel));
128 tpConfigPanels.setTitleAt(1, tr("Tags of new changeset"));
129 tpConfigPanels.setToolTipTextAt(1, tr("Apply tags to the changeset data is uploaded to"));
130
131 tpConfigPanels.setComponentAt(2,pnlChangesetManagement = new ChangesetManagementPanel(changesetCommentModel));
132 tpConfigPanels.setTitleAt(2, tr("Changesets"));
133 tpConfigPanels.setToolTipTextAt(2, tr("Manage open changesets and select a changeset to upload to"));
134
135 tpConfigPanels.setComponentAt(3, pnlUploadStrategySelectionPanel = new UploadStrategySelectionPanel());
136 tpConfigPanels.setTitleAt(3, tr("Advanced"));
137 tpConfigPanels.setToolTipTextAt(3, tr("Configure advanced settings"));
138
139 pnl.add(tpConfigPanels, BorderLayout.SOUTH);
140 return pnl;
141 }
142
143 /**
144 * builds the panel with the OK and CANCEL buttons
145 *
146 * @return
147 */
148 protected JPanel buildActionPanel() {
149 JPanel pnl = new JPanel();
150 pnl.setLayout(new FlowLayout(FlowLayout.CENTER));
151 pnl.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
152
153 // -- upload button
154 UploadAction uploadAction = new UploadAction();
155 pnl.add(btnUpload = new SideButton(uploadAction));
156 btnUpload.setFocusable(true);
157 InputMapUtils.enableEnter(btnUpload);
158
159 // -- cancel button
160 CancelAction cancelAction = new CancelAction();
161 pnl.add(new SideButton(cancelAction));
162 getRootPane().registerKeyboardAction(
163 cancelAction,
164 KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0),
165 JComponent.WHEN_IN_FOCUSED_WINDOW
166 );
167 pnl.add(new SideButton(new ContextSensitiveHelpAction(ht("/Dialog/Upload"))));
168 HelpUtil.setHelpContext(getRootPane(),ht("/Dialog/Upload"));
169 return pnl;
170 }
171
172 /**
173 * builds the gui
174 */
175 protected void build() {
176 setTitle(tr("Upload to ''{0}''", OsmApi.getOsmApi().getBaseUrl()));
177 getContentPane().setLayout(new BorderLayout());
178 getContentPane().add(buildContentPanel(), BorderLayout.CENTER);
179 getContentPane().add(buildActionPanel(), BorderLayout.SOUTH);
180
181 addWindowListener(new WindowEventHandler());
182
183
184 // make sure the configuration panels listen to each other
185 // changes
186 //
187 pnlChangesetManagement.addPropertyChangeListener(
188 pnlBasicUploadSettings.getUploadParameterSummaryPanel()
189 );
190 pnlChangesetManagement.addPropertyChangeListener(this);
191 pnlUploadedObjects.addPropertyChangeListener(
192 pnlBasicUploadSettings.getUploadParameterSummaryPanel()
193 );
194 pnlUploadedObjects.addPropertyChangeListener(pnlUploadStrategySelectionPanel);
195 pnlUploadStrategySelectionPanel.addPropertyChangeListener(
196 pnlBasicUploadSettings.getUploadParameterSummaryPanel()
197 );
198
199
200 // users can click on either of two links in the upload parameter
201 // summary handler. This installs the handler for these two events.
202 // We simply select the appropriate tab in the tabbed pane with the
203 // configuration dialogs.
204 //
205 pnlBasicUploadSettings.getUploadParameterSummaryPanel().setConfigurationParameterRequestListener(
206 new ConfigurationParameterRequestHandler() {
207 public void handleUploadStrategyConfigurationRequest() {
208 tpConfigPanels.setSelectedIndex(3);
209 }
210 public void handleChangesetConfigurationRequest() {
211 tpConfigPanels.setSelectedIndex(2);
212 }
213 }
214 );
215
216 pnlBasicUploadSettings.setUploadCommentDownFocusTraversalHandler(
217 new AbstractAction() {
218 public void actionPerformed(ActionEvent e) {
219 btnUpload.requestFocusInWindow();
220 }
221 }
222 );
223
224 Main.pref.addPreferenceChangeListener(this);
225 }
226
227 /**
228 * constructor
229 */
230 public UploadDialog() {
231 super(JOptionPane.getFrameForComponent(Main.parent), ModalityType.DOCUMENT_MODAL);
232 build();
233 }
234
235 /**
236 * Sets the collection of primitives to upload
237 *
238 * @param toUpload the dataset with the objects to upload. If null, assumes the empty
239 * set of objects to upload
240 *
241 */
242 public void setUploadedPrimitives(APIDataSet toUpload) {
243 if (toUpload == null) {
244 List<OsmPrimitive> emptyList = Collections.emptyList();
245 pnlUploadedObjects.setUploadedPrimitives(emptyList, emptyList, emptyList);
246 return;
247 }
248 pnlUploadedObjects.setUploadedPrimitives(
249 toUpload.getPrimitivesToAdd(),
250 toUpload.getPrimitivesToUpdate(),
251 toUpload.getPrimitivesToDelete()
252 );
253 }
254
255 /**
256 * Remembers the user input in the preference settings
257 */
258 public void rememberUserInput() {
259 pnlBasicUploadSettings.rememberUserInput();
260 pnlUploadStrategySelectionPanel.rememberUserInput();
261 }
262
263 /**
264 * Initializes the panel for user input
265 */
266 public void startUserInput() {
267 tpConfigPanels.setSelectedIndex(0);
268 pnlBasicUploadSettings.startUserInput();
269 pnlTagSettings.startUserInput();
270 pnlTagSettings.initFromChangeset(pnlChangesetManagement.getSelectedChangeset());
271 pnlUploadStrategySelectionPanel.initFromPreferences();
272 UploadParameterSummaryPanel pnl = pnlBasicUploadSettings.getUploadParameterSummaryPanel();
273 pnl.setUploadStrategySpecification(pnlUploadStrategySelectionPanel.getUploadStrategySpecification());
274 pnl.setCloseChangesetAfterNextUpload(pnlChangesetManagement.isCloseChangesetAfterUpload());
275 pnl.setNumObjects(pnlUploadedObjects.getNumObjectsToUpload());
276 }
277
278 /**
279 * Replies the current changeset
280 *
281 * @return the current changeset
282 */
283 public Changeset getChangeset() {
284 Changeset cs = pnlChangesetManagement.getSelectedChangeset();
285 if (cs == null) {
286 cs = new Changeset();
287 }
288 cs.setKeys(pnlTagSettings.getTags());
289 return cs;
290 }
291
292 public void setSelectedChangesetForNextUpload(Changeset cs) {
293 pnlChangesetManagement.setSelectedChangesetForNextUpload(cs);
294 }
295
296 public Map<String, String> getDefaultChangesetTags() {
297 return pnlTagSettings.getDefaultTags();
298 }
299
300 public void setDefaultChangesetTags(Map<String, String> tags) {
301 pnlTagSettings.setDefaultTags(tags);
302 for (String key: tags.keySet()) {
303 if (key.equals("comment")) {
304 changesetCommentModel.setComment(tags.get(key));
305 }
306 }
307 }
308
309 /**
310 * Replies the {@link UploadStrategySpecification} the user entered in the dialog.
311 *
312 * @return the {@link UploadStrategySpecification} the user entered in the dialog.
313 */
314 public UploadStrategySpecification getUploadStrategySpecification() {
315 UploadStrategySpecification spec = pnlUploadStrategySelectionPanel.getUploadStrategySpecification();
316 spec.setCloseChangesetAfterUpload(pnlChangesetManagement.isCloseChangesetAfterUpload());
317 return spec;
318 }
319
320 /**
321 * Returns the current value for the upload comment
322 *
323 * @return the current value for the upload comment
324 */
325 protected String getUploadComment() {
326 return changesetCommentModel.getComment();
327 }
328
329 /**
330 * Returns true if the dialog was canceled
331 *
332 * @return true if the dialog was canceled
333 */
334 public boolean isCanceled() {
335 return canceled;
336 }
337
338 /**
339 * Sets whether the dialog was canceled
340 *
341 * @param canceled true if the dialog is canceled
342 */
343 protected void setCanceled(boolean canceled) {
344 this.canceled = canceled;
345 }
346
347 @Override
348 public void setVisible(boolean visible) {
349 if (visible) {
350 new WindowGeometry(
351 getClass().getName() + ".geometry",
352 WindowGeometry.centerInWindow(
353 Main.parent,
354 new Dimension(400,600)
355 )
356 ).applySafe(this);
357 startUserInput();
358 } else if (!visible && isShowing()){
359 new WindowGeometry(this).remember(getClass().getName() + ".geometry");
360 }
361 super.setVisible(visible);
362 }
363
364 /**
365 * Handles an upload
366 *
367 */
368 class UploadAction extends AbstractAction {
369 public UploadAction() {
370 putValue(NAME, tr("Upload Changes"));
371 putValue(SMALL_ICON, ImageProvider.get("upload"));
372 putValue(SHORT_DESCRIPTION, tr("Upload the changed primitives"));
373 }
374
375 /**
376 * returns true if the user wants to revisit, false if they
377 * want to continue
378 */
379 protected boolean warnUploadComment() {
380 ExtendedDialog dlg = new ExtendedDialog(UploadDialog.this,
381 tr("Please revise upload comment"),
382 new String[] {tr("Revise"), tr("Cancel"), tr("Continue as is")});
383 dlg.setContent("<html>" +
384 tr("Your upload comment is <i>empty</i>, or <i>very short</i>.<br /><br />" +
385 "This is technically allowed, but please consider that many users who are<br />" +
386 "watching changes in their area depend on meaningful changeset comments<br />" +
387 "to understand what is going on!<br /><br />" +
388 "If you spend a minute now to explain your change, you will make life<br />" +
389 "easier for many other mappers.") +
390 "</html>");
391 dlg.setButtonIcons(new Icon[] {
392 ImageProvider.get("ok"),
393 ImageProvider.get("cancel"),
394 ImageProvider.overlay(
395 ImageProvider.get("upload"),
396 new ImageIcon(ImageProvider.get("warning-small").getImage().getScaledInstance(10 , 10, Image.SCALE_SMOOTH)),
397 ImageProvider.OverlayPosition.SOUTHEAST)});
398 dlg.setToolTipTexts(new String[] {
399 tr("Return to the previous dialog to enter a more descriptive comment"),
400 tr("Cancel and return to the previous dialog"),
401 tr("Ignore this hint and upload anyway")});
402 dlg.setIcon(JOptionPane.WARNING_MESSAGE);
403 dlg.toggleEnable("upload_comment_is_empty_or_very_short");
404 dlg.setToggleCheckboxText(tr("Do not show this message again"));
405 dlg.setCancelButton(1, 2);
406 return dlg.showDialog().getValue() != 3;
407 }
408
409 protected void warnIllegalChunkSize() {
410 HelpAwareOptionPane.showOptionDialog(
411 UploadDialog.this,
412 tr("Please enter a valid chunk size first"),
413 tr("Illegal chunk size"),
414 JOptionPane.ERROR_MESSAGE,
415 ht("/Dialog/Upload#IllegalChunkSize")
416 );
417 }
418
419 public void actionPerformed(ActionEvent e) {
420 if (getUploadComment().trim().length() < 10) {
421 if (warnUploadComment())
422 {
423 tpConfigPanels.setSelectedIndex(0);
424 pnlBasicUploadSettings.initEditingOfUploadComment();
425 return;
426 }
427 }
428 UploadStrategySpecification strategy = getUploadStrategySpecification();
429 if (strategy.getStrategy().equals(UploadStrategy.CHUNKED_DATASET_STRATEGY)) {
430 if (strategy.getChunkSize() == UploadStrategySpecification.UNSPECIFIED_CHUNK_SIZE) {
431 warnIllegalChunkSize();
432 tpConfigPanels.setSelectedIndex(0);
433 return;
434 }
435 }
436 setCanceled(false);
437 setVisible(false);
438 }
439 }
440
441 /**
442 * Action for canceling the dialog
443 *
444 */
445 class CancelAction extends AbstractAction {
446 public CancelAction() {
447 putValue(NAME, tr("Cancel"));
448 putValue(SMALL_ICON, ImageProvider.get("cancel"));
449 putValue(SHORT_DESCRIPTION, tr("Cancel the upload and resume editing"));
450 }
451
452 public void actionPerformed(ActionEvent e) {
453 setCanceled(true);
454 setVisible(false);
455 }
456 }
457
458 /**
459 * Listens to window closing events and processes them as cancel events.
460 * Listens to window open events and initializes user input
461 *
462 */
463 class WindowEventHandler extends WindowAdapter {
464 @Override
465 public void windowClosing(WindowEvent e) {
466 setCanceled(true);
467 }
468
469 @Override
470 public void windowOpened(WindowEvent e) {
471 //startUserInput();
472 }
473
474 @Override
475 public void windowActivated(WindowEvent arg0) {
476 if (tpConfigPanels.getSelectedIndex() == 0) {
477 pnlBasicUploadSettings.initEditingOfUploadComment();
478 }
479 }
480 }
481
482 /* -------------------------------------------------------------------------- */
483 /* Interface PropertyChangeListener */
484 /* -------------------------------------------------------------------------- */
485 public void propertyChange(PropertyChangeEvent evt) {
486 if (evt.getPropertyName().equals(ChangesetManagementPanel.SELECTED_CHANGESET_PROP)) {
487 Changeset cs = (Changeset)evt.getNewValue();
488 if (cs == null) {
489 tpConfigPanels.setTitleAt(1, tr("Tags of new changeset"));
490 } else {
491 tpConfigPanels.setTitleAt(1, tr("Tags of changeset {0}", cs.getId()));
492 }
493 }
494 }
495
496 /* -------------------------------------------------------------------------- */
497 /* Interface PreferenceChangedListener */
498 /* -------------------------------------------------------------------------- */
499 public void preferenceChanged(PreferenceChangeEvent e) {
500 if (e.getKey() == null || ! e.getKey().equals("osm-server.url"))
501 return;
502 final Setting<?> newValue = e.getNewValue();
503 final String url;
504 if (newValue == null || newValue.getValue() == null) {
505 url = OsmApi.getOsmApi().getBaseUrl();
506 } else {
507 url = newValue.getValue().toString();
508 }
509 setTitle(tr("Upload to ''{0}''", url));
510 }
511}
Note: See TracBrowser for help on using the repository browser.