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

Last change on this file since 3530 was 3530, checked in by stoecker, 14 years ago

fix array preferences

  • Property svn:eol-style set to native
File size: 18.5 KB
Line 
1package org.openstreetmap.josm.gui.io;
2
3import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.BorderLayout;
7import java.awt.Dimension;
8import java.awt.FlowLayout;
9import java.awt.Image;
10import java.awt.event.ActionEvent;
11import java.awt.event.KeyEvent;
12import java.awt.event.WindowAdapter;
13import java.awt.event.WindowEvent;
14import java.beans.PropertyChangeEvent;
15import java.beans.PropertyChangeListener;
16import java.util.Collections;
17import java.util.List;
18import java.util.logging.Logger;
19
20import javax.swing.AbstractAction;
21import javax.swing.BorderFactory;
22import javax.swing.Icon;
23import javax.swing.ImageIcon;
24import javax.swing.InputMap;
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.osm.Changeset;
38import org.openstreetmap.josm.data.osm.OsmPrimitive;
39import org.openstreetmap.josm.gui.ExtendedDialog;
40import org.openstreetmap.josm.gui.HelpAwareOptionPane;
41import org.openstreetmap.josm.gui.SideButton;
42import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
43import org.openstreetmap.josm.gui.help.HelpUtil;
44import org.openstreetmap.josm.io.OsmApi;
45import org.openstreetmap.josm.tools.ImageProvider;
46import org.openstreetmap.josm.tools.WindowGeometry;
47
48/**
49 * This is a dialog for entering upload options like the parameters for
50 * the upload changeset and the strategy for opening/closing a changeset.
51 *
52 */
53public class UploadDialog extends JDialog implements PropertyChangeListener, PreferenceChangedListener{
54 protected static final Logger logger = Logger.getLogger(UploadDialog.class.getName());
55
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 InputMap inputMap = btnUpload.getInputMap();
158 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0), "doUpload");
159 btnUpload.getActionMap().put("doUpload", uploadAction);
160
161 // -- cancel button
162 CancelAction cancelAction = new CancelAction();
163 pnl.add(new SideButton(cancelAction));
164 getRootPane().registerKeyboardAction(
165 cancelAction,
166 KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0),
167 JComponent.WHEN_IN_FOCUSED_WINDOW
168 );
169 pnl.add(new SideButton(new ContextSensitiveHelpAction(ht("/Dialog/UploadDialog"))));
170 HelpUtil.setHelpContext(getRootPane(),ht("/Dialog/UploadDialog"));
171 return pnl;
172 }
173
174 /**
175 * builds the gui
176 */
177 protected void build() {
178 setTitle(tr("Upload to ''{0}''", OsmApi.getOsmApi().getBaseUrl()));
179 getContentPane().setLayout(new BorderLayout());
180 getContentPane().add(buildContentPanel(), BorderLayout.CENTER);
181 getContentPane().add(buildActionPanel(), BorderLayout.SOUTH);
182
183 addWindowListener(new WindowEventHandler());
184
185
186 // make sure the the configuration panels listen to each other
187 // changes
188 //
189 pnlChangesetManagement.addPropertyChangeListener(
190 pnlBasicUploadSettings.getUploadParameterSummaryPanel()
191 );
192 pnlChangesetManagement.addPropertyChangeListener(this);
193 pnlUploadedObjects.addPropertyChangeListener(
194 pnlBasicUploadSettings.getUploadParameterSummaryPanel()
195 );
196 pnlUploadedObjects.addPropertyChangeListener(pnlUploadStrategySelectionPanel);
197 pnlUploadStrategySelectionPanel.addPropertyChangeListener(
198 pnlBasicUploadSettings.getUploadParameterSummaryPanel()
199 );
200
201
202 // users can click on either of two links in the upload parameter
203 // summary handler. This installs the handler for these two events.
204 // We simply select the appropriate tab in the tabbed pane with the
205 // configuration dialogs.
206 //
207 pnlBasicUploadSettings.getUploadParameterSummaryPanel().setConfigurationParameterRequestListener(
208 new ConfigurationParameterRequestHandler() {
209 public void handleUploadStrategyConfigurationRequest() {
210 tpConfigPanels.setSelectedIndex(3);
211 }
212 public void handleChangesetConfigurationRequest() {
213 tpConfigPanels.setSelectedIndex(2);
214 }
215 }
216 );
217
218 pnlBasicUploadSettings.setUploadCommentDownFocusTraversalHandler(
219 new AbstractAction() {
220 public void actionPerformed(ActionEvent e) {
221 btnUpload.requestFocusInWindow();
222 }
223 }
224 );
225
226 Main.pref.addPreferenceChangeListener(this);
227 }
228
229 /**
230 * constructor
231 */
232 public UploadDialog() {
233 super(JOptionPane.getFrameForComponent(Main.parent), ModalityType.DOCUMENT_MODAL);
234 build();
235 }
236
237 /**
238 * Sets the collection of primitives to upload
239 *
240 * @param toUpload the dataset with the objects to upload. If null, assumes the empty
241 * set of objects to upload
242 *
243 */
244 public void setUploadedPrimitives(APIDataSet toUpload) {
245 if (toUpload == null) {
246 List<OsmPrimitive> emptyList = Collections.emptyList();
247 pnlUploadedObjects.setUploadedPrimitives(emptyList, emptyList, emptyList);
248 return;
249 }
250 pnlUploadedObjects.setUploadedPrimitives(
251 toUpload.getPrimitivesToAdd(),
252 toUpload.getPrimitivesToUpdate(),
253 toUpload.getPrimitivesToDelete()
254 );
255 }
256
257 /**
258 * Remembers the user input in the preference settings
259 */
260 public void rememberUserInput() {
261 pnlBasicUploadSettings.rememberUserInput();
262 pnlUploadStrategySelectionPanel.rememberUserInput();
263 }
264
265 /**
266 * Initializes the panel for user input
267 */
268 public void startUserInput() {
269 tpConfigPanels.setSelectedIndex(0);
270 pnlBasicUploadSettings.startUserInput();
271 pnlTagSettings.startUserInput();
272 pnlTagSettings.initFromChangeset(pnlChangesetManagement.getSelectedChangeset());
273 pnlUploadStrategySelectionPanel.initFromPreferences();
274 UploadParameterSummaryPanel pnl = pnlBasicUploadSettings.getUploadParameterSummaryPanel();
275 pnl.setUploadStrategySpecification(pnlUploadStrategySelectionPanel.getUploadStrategySpecification());
276 pnl.setCloseChangesetAfterNextUpload(pnlChangesetManagement.isCloseChangesetAfterUpload());
277 pnl.setNumObjects(pnlUploadedObjects.getNumObjectsToUpload());
278 }
279
280 /**
281 * Replies the current changeset
282 *
283 * @return the current changeset
284 */
285 public Changeset getChangeset() {
286 Changeset cs = pnlChangesetManagement.getSelectedChangeset();
287 if (cs == null) {
288 cs = new Changeset();
289 }
290 cs.setKeys(pnlTagSettings.getTags());
291 return cs;
292 }
293
294 public void setSelectedChangesetForNextUpload(Changeset cs) {
295 pnlChangesetManagement.setSelectedChangesetForNextUpload(cs);
296 }
297
298 /**
299 * Replies the {@see UploadStrategySpecification} the user entered in the dialog.
300 *
301 * @return the {@see UploadStrategySpecification} the user entered in the dialog.
302 */
303 public UploadStrategySpecification getUploadStrategySpecification() {
304 UploadStrategySpecification spec = pnlUploadStrategySelectionPanel.getUploadStrategySpecification();
305 spec.setCloseChangesetAfterUpload(pnlChangesetManagement.isCloseChangesetAfterUpload());
306 return spec;
307 }
308
309 /**
310 * Returns the current value for the upload comment
311 *
312 * @return the current value for the upload comment
313 */
314 protected String getUploadComment() {
315 return changesetCommentModel.getComment();
316 }
317
318 /**
319 * Returns true if the dialog was canceled
320 *
321 * @return true if the dialog was canceled
322 */
323 public boolean isCanceled() {
324 return canceled;
325 }
326
327 /**
328 * Sets whether the dialog was canceled
329 *
330 * @param canceled true if the dialog is canceled
331 */
332 protected void setCanceled(boolean canceled) {
333 this.canceled = canceled;
334 }
335
336 @Override
337 public void setVisible(boolean visible) {
338 if (visible) {
339 new WindowGeometry(
340 getClass().getName() + ".geometry",
341 WindowGeometry.centerInWindow(
342 Main.parent,
343 new Dimension(400,600)
344 )
345 ).applySafe(this);
346 startUserInput();
347 } else if (!visible && isShowing()){
348 new WindowGeometry(this).remember(getClass().getName() + ".geometry");
349 }
350 super.setVisible(visible);
351 }
352
353 /**
354 * Handles an upload
355 *
356 */
357 class UploadAction extends AbstractAction {
358 public UploadAction() {
359 putValue(NAME, tr("Upload Changes"));
360 putValue(SMALL_ICON, ImageProvider.get("upload"));
361 putValue(SHORT_DESCRIPTION, tr("Upload the changed primitives"));
362 }
363
364 /**
365 * returns true if the user wants to revisit, false if they
366 * want to continue
367 */
368 protected boolean warnUploadComment() {
369 ExtendedDialog dlg = new ExtendedDialog(UploadDialog.this,
370 tr("Please revise upload comment"),
371 new String[] {tr("Revise"), tr("Cancel"), tr("Continue as is")});
372 dlg.setContent("<html>" +
373 tr("Your upload comment is <i>empty</i>, or <i>very short</i>.<br /><br />" +
374 "This is technically allowed, but please consider that many users who are<br />" +
375 "watching changes in their area depend on meaningful changeset comments<br />" +
376 "to understand what is going on!<br /><br />" +
377 "If you spend a minute now to explain your change, you will make life<br />" +
378 "easier for many other mappers.") +
379 "</html>");
380 dlg.setButtonIcons(new Icon[] {
381 ImageProvider.get("ok"),
382 ImageProvider.get("cancel"),
383 ImageProvider.overlay(
384 ImageProvider.get("upload"),
385 new ImageIcon(ImageProvider.get("warning-small").getImage().getScaledInstance(10 , 10, Image.SCALE_SMOOTH)),
386 ImageProvider.OverlayPosition.SOUTHEAST)});
387 dlg.setToolTipTexts(new String[] {
388 tr("Return to the previous dialog to enter a more descriptive comment"),
389 tr("Cancel and return to the previous dialog"),
390 tr("Ignore this hint and upload anyway")});
391 dlg.setIcon(JOptionPane.WARNING_MESSAGE);
392 dlg.toggleEnable("upload_comment_is_empty_or_very_short");
393 dlg.setToggleCheckboxText(tr("Do not show this message again"));
394 dlg.setCancelButton(1, 2);
395 return dlg.showDialog().getValue() != 3;
396 }
397
398 protected void warnIllegalChunkSize() {
399 HelpAwareOptionPane.showOptionDialog(
400 UploadDialog.this,
401 tr("Please enter a valid chunk size first"),
402 tr("Illegal chunk size"),
403 JOptionPane.ERROR_MESSAGE,
404 ht("/Dialog/UploadDialog#IllegalChunkSize")
405 );
406 }
407
408 public void actionPerformed(ActionEvent e) {
409 if (getUploadComment().trim().length() < 10) {
410 if (warnUploadComment())
411 {
412 tpConfigPanels.setSelectedIndex(0);
413 pnlBasicUploadSettings.initEditingOfUploadComment();
414 return;
415 }
416 }
417 UploadStrategySpecification strategy = getUploadStrategySpecification();
418 if (strategy.getStrategy().equals(UploadStrategy.CHUNKED_DATASET_STRATEGY)) {
419 if (strategy.getChunkSize() == UploadStrategySpecification.UNSPECIFIED_CHUNK_SIZE) {
420 warnIllegalChunkSize();
421 tpConfigPanels.setSelectedIndex(0);
422 return;
423 }
424 }
425 setCanceled(false);
426 setVisible(false);
427 }
428 }
429
430 /**
431 * Action for canceling the dialog
432 *
433 */
434 class CancelAction extends AbstractAction {
435 public CancelAction() {
436 putValue(NAME, tr("Cancel"));
437 putValue(SMALL_ICON, ImageProvider.get("cancel"));
438 putValue(SHORT_DESCRIPTION, tr("Cancel the upload and resume editing"));
439 }
440
441 public void actionPerformed(ActionEvent e) {
442 setCanceled(true);
443 setVisible(false);
444 }
445 }
446
447 /**
448 * Listens to window closing events and processes them as cancel events.
449 * Listens to window open events and initializes user input
450 *
451 */
452 class WindowEventHandler extends WindowAdapter {
453 @Override
454 public void windowClosing(WindowEvent e) {
455 setCanceled(true);
456 }
457
458 @Override
459 public void windowOpened(WindowEvent e) {
460 //startUserInput();
461 }
462
463 @Override
464 public void windowActivated(WindowEvent arg0) {
465 if (tpConfigPanels.getSelectedIndex() == 0) {
466 pnlBasicUploadSettings.initEditingOfUploadComment();
467 }
468 }
469 }
470
471 /* -------------------------------------------------------------------------- */
472 /* Interface PropertyChangeListener */
473 /* -------------------------------------------------------------------------- */
474 public void propertyChange(PropertyChangeEvent evt) {
475 if (evt.getPropertyName().equals(ChangesetManagementPanel.SELECTED_CHANGESET_PROP)) {
476 Changeset cs = (Changeset)evt.getNewValue();
477 if (cs == null) {
478 tpConfigPanels.setTitleAt(1, tr("Tags of new changeset"));
479 } else {
480 tpConfigPanels.setTitleAt(1, tr("Tags of changeset {0}", cs.getId()));
481 }
482 }
483 }
484
485 /* -------------------------------------------------------------------------- */
486 /* Interface PreferenceChangedListener */
487 /* -------------------------------------------------------------------------- */
488 public void preferenceChanged(PreferenceChangeEvent e) {
489 if (e.getKey() == null || ! e.getKey().equals("osm-server.url"))
490 return;
491 if (e.getNewValue() == null) {
492 setTitle(tr("Upload"));
493 } else {
494 setTitle(tr("Upload to ''{0}''", e.getNewValue()));
495 }
496 }
497}
Note: See TracBrowser for help on using the repository browser.