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

Last change on this file since 3719 was 3719, checked in by bastiK, 13 years ago

added missing license information

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