source: josm/trunk/src/org/openstreetmap/josm/gui/io/SaveLayersDialog.java@ 10428

Last change on this file since 10428 was 10428, checked in by stoecker, 8 years ago

see #9995 - patch mainly by strump - improve HIDPI behaviour

  • Property svn:eol-style set to native
File size: 24.8 KB
RevLine 
[2512]1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.io;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5import static org.openstreetmap.josm.tools.I18n.trn;
6
7import java.awt.BorderLayout;
8import java.awt.Component;
9import java.awt.Dimension;
[5003]10import java.awt.Graphics2D;
[9556]11import java.awt.GraphicsEnvironment;
[2512]12import java.awt.GridBagConstraints;
13import java.awt.GridBagLayout;
[5003]14import java.awt.Image;
[2512]15import java.awt.event.ActionEvent;
16import java.awt.event.WindowAdapter;
17import java.awt.event.WindowEvent;
[5003]18import java.awt.image.BufferedImage;
[2512]19import java.beans.PropertyChangeEvent;
20import java.beans.PropertyChangeListener;
21import java.util.List;
22import java.util.concurrent.CancellationException;
[10212]23import java.util.concurrent.ExecutionException;
[2512]24import java.util.concurrent.ExecutorService;
25import java.util.concurrent.Executors;
26import java.util.concurrent.Future;
27
28import javax.swing.AbstractAction;
29import javax.swing.DefaultListCellRenderer;
[5003]30import javax.swing.ImageIcon;
[6643]31import javax.swing.JButton;
[4618]32import javax.swing.JComponent;
[2512]33import javax.swing.JDialog;
34import javax.swing.JLabel;
35import javax.swing.JList;
36import javax.swing.JOptionPane;
37import javax.swing.JPanel;
38import javax.swing.JScrollPane;
[4618]39import javax.swing.KeyStroke;
[7029]40import javax.swing.ListCellRenderer;
[3441]41import javax.swing.WindowConstants;
[5003]42import javax.swing.event.TableModelEvent;
43import javax.swing.event.TableModelListener;
[2512]44
45import org.openstreetmap.josm.Main;
[8913]46import org.openstreetmap.josm.actions.SessionSaveAsAction;
[2512]47import org.openstreetmap.josm.actions.UploadAction;
48import org.openstreetmap.josm.gui.ExceptionDialogUtil;
49import org.openstreetmap.josm.gui.io.SaveLayersModel.Mode;
[7402]50import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer;
[2512]51import org.openstreetmap.josm.gui.progress.ProgressMonitor;
52import org.openstreetmap.josm.gui.progress.SwingRenderingProgressMonitor;
[6965]53import org.openstreetmap.josm.gui.util.GuiHelper;
[8912]54import org.openstreetmap.josm.tools.GBC;
[2512]55import org.openstreetmap.josm.tools.ImageProvider;
[8919]56import org.openstreetmap.josm.tools.UserCancelException;
[8734]57import org.openstreetmap.josm.tools.Utils;
[2512]58import org.openstreetmap.josm.tools.WindowGeometry;
59
[5003]60public class SaveLayersDialog extends JDialog implements TableModelListener {
[8836]61 public enum UserAction {
[6965]62 /** save/upload layers was successful, proceed with operation */
[2512]63 PROCEED,
[6965]64 /** save/upload of layers was not successful or user canceled operation */
[2512]65 CANCEL
66 }
67
[10190]68 private final SaveLayersModel model = new SaveLayersModel();
[2512]69 private UserAction action = UserAction.CANCEL;
[10179]70 private final UploadAndSaveProgressRenderer pnlUploadLayers = new UploadAndSaveProgressRenderer();
[2512]71
[10179]72 private final SaveAndProceedAction saveAndProceedAction = new SaveAndProceedAction();
73 private final SaveSessionAction saveSessionAction = new SaveSessionAction();
74 private final DiscardAndProceedAction discardAndProceedAction = new DiscardAndProceedAction();
75 private final CancelAction cancelAction = new CancelAction();
[8308]76 private transient SaveAndUploadTask saveAndUploadTask;
[2512]77
[10179]78 private final JButton saveAndProceedActionButton = new JButton(saveAndProceedAction);
79
[2512]80 /**
[10179]81 * Constructs a new {@code SaveLayersDialog}.
82 * @param parent parent component
83 */
84 public SaveLayersDialog(Component parent) {
85 super(GuiHelper.getFrameForComponent(parent), ModalityType.DOCUMENT_MODAL);
86 build();
87 }
88
89 /**
[2512]90 * builds the GUI
91 */
92 protected void build() {
[8510]93 WindowGeometry geometry = WindowGeometry.centerOnScreen(new Dimension(650, 300));
[4932]94 geometry.applySafe(this);
[2512]95 getContentPane().setLayout(new BorderLayout());
96
[5003]97 SaveLayersTable table = new SaveLayersTable(model);
98 JScrollPane pane = new JScrollPane(table);
[2512]99 model.addPropertyChangeListener(table);
[5003]100 table.getModel().addTableModelListener(this);
101
[2512]102 getContentPane().add(pane, BorderLayout.CENTER);
103 getContentPane().add(buildButtonRow(), BorderLayout.SOUTH);
104
105 addWindowListener(new WindowClosingAdapter());
[3441]106 setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
[2512]107 }
108
109 /**
110 * builds the button row
111 *
112 * @return the panel with the button row
113 */
114 protected JPanel buildButtonRow() {
[9543]115 JPanel pnl = new JPanel(new GridBagLayout());
[2512]116
117 model.addPropertyChangeListener(saveAndProceedAction);
[10179]118 pnl.add(saveAndProceedActionButton, GBC.std(0, 0).insets(5, 5, 0, 0).fill(GBC.HORIZONTAL));
[2512]119
[8918]120 pnl.add(new JButton(saveSessionAction), GBC.std(1, 0).insets(5, 5, 5, 0).fill(GBC.HORIZONTAL));
[8913]121
[2512]122 model.addPropertyChangeListener(discardAndProceedAction);
[8913]123 pnl.add(new JButton(discardAndProceedAction), GBC.std(0, 1).insets(5, 5, 0, 5).fill(GBC.HORIZONTAL));
[2512]124
[8918]125 pnl.add(new JButton(cancelAction), GBC.std(1, 1).insets(5, 5, 5, 5).fill(GBC.HORIZONTAL));
[2512]126
[9543]127 JPanel pnl2 = new JPanel(new BorderLayout());
[10179]128 pnl2.add(pnlUploadLayers, BorderLayout.CENTER);
[2512]129 model.addPropertyChangeListener(pnlUploadLayers);
130 pnl2.add(pnl, BorderLayout.SOUTH);
131 return pnl2;
132 }
133
134 public void prepareForSavingAndUpdatingLayersBeforeExit() {
135 setTitle(tr("Unsaved changes - Save/Upload before exiting?"));
136 this.saveAndProceedAction.initForSaveAndExit();
137 this.discardAndProceedAction.initForDiscardAndExit();
138 }
139
140 public void prepareForSavingAndUpdatingLayersBeforeDelete() {
141 setTitle(tr("Unsaved changes - Save/Upload before deleting?"));
142 this.saveAndProceedAction.initForSaveAndDelete();
143 this.discardAndProceedAction.initForDiscardAndDelete();
144 }
145
146 public UserAction getUserAction() {
147 return this.action;
148 }
149
150 public SaveLayersModel getModel() {
151 return model;
152 }
153
154 protected void launchSafeAndUploadTask() {
155 ProgressMonitor monitor = new SwingRenderingProgressMonitor(pnlUploadLayers);
156 monitor.beginTask(tr("Uploading and saving modified layers ..."));
157 this.saveAndUploadTask = new SaveAndUploadTask(model, monitor);
[8736]158 new Thread(saveAndUploadTask, saveAndUploadTask.getClass().getName()).start();
[2512]159 }
160
161 protected void cancelSafeAndUploadTask() {
162 if (this.saveAndUploadTask != null) {
163 this.saveAndUploadTask.cancel();
164 }
165 model.setMode(Mode.EDITING_DATA);
166 }
167
[9556]168 private static class LayerListWarningMessagePanel extends JPanel {
169 private final JLabel lblMessage = new JLabel();
170 private final JList<SaveLayerInfo> lstLayers = new JList<>();
[2512]171
[9556]172 LayerListWarningMessagePanel(String msg, List<SaveLayerInfo> infos) {
173 build();
174 lblMessage.setText(msg);
175 lstLayers.setListData(infos.toArray(new SaveLayerInfo[0]));
176 }
177
[2512]178 protected void build() {
179 setLayout(new GridBagLayout());
180 GridBagConstraints gc = new GridBagConstraints();
181 gc.gridx = 0;
182 gc.gridy = 0;
183 gc.fill = GridBagConstraints.HORIZONTAL;
184 gc.weightx = 1.0;
185 gc.weighty = 0.0;
[9556]186 add(lblMessage, gc);
[2512]187 lblMessage.setHorizontalAlignment(JLabel.LEFT);
188 lstLayers.setCellRenderer(
[7029]189 new ListCellRenderer<SaveLayerInfo>() {
[8285]190 private final DefaultListCellRenderer def = new DefaultListCellRenderer();
[2512]191 @Override
[7029]192 public Component getListCellRendererComponent(JList<? extends SaveLayerInfo> list, SaveLayerInfo info, int index,
[2512]193 boolean isSelected, boolean cellHasFocus) {
[7029]194 def.setIcon(info.getLayer().getIcon());
195 def.setText(info.getName());
196 return def;
[2512]197 }
198 }
199 );
200 gc.gridx = 0;
201 gc.gridy = 1;
202 gc.fill = GridBagConstraints.HORIZONTAL;
203 gc.weightx = 1.0;
204 gc.weighty = 1.0;
[8510]205 add(lstLayers, gc);
[2512]206 }
[9556]207 }
[2512]208
[9556]209 private static void warn(String msg, List<SaveLayerInfo> infos, String title) {
210 JPanel panel = new LayerListWarningMessagePanel(msg, infos);
211 // For unit test coverage in headless mode
212 if (!GraphicsEnvironment.isHeadless()) {
213 JOptionPane.showConfirmDialog(Main.parent, panel, title, JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE);
[2512]214 }
215 }
216
[9556]217 protected static void warnLayersWithConflictsAndUploadRequest(List<SaveLayerInfo> infos) {
218 warn(trn("<html>{0} layer has unresolved conflicts.<br>"
[2512]219 + "Either resolve them first or discard the modifications.<br>"
220 + "Layer with conflicts:</html>",
221 "<html>{0} layers have unresolved conflicts.<br>"
222 + "Either resolve them first or discard the modifications.<br>"
223 + "Layers with conflicts:</html>",
224 infos.size(),
[9556]225 infos.size()),
226 infos, tr("Unsaved data and conflicts"));
[2512]227 }
228
[9556]229 protected static void warnLayersWithoutFilesAndSaveRequest(List<SaveLayerInfo> infos) {
230 warn(trn("<html>{0} layer needs saving but has no associated file.<br>"
[2512]231 + "Either select a file for this layer or discard the changes.<br>"
232 + "Layer without a file:</html>",
233 "<html>{0} layers need saving but have no associated file.<br>"
234 + "Either select a file for each of them or discard the changes.<br>"
235 + "Layers without a file:</html>",
236 infos.size(),
[9556]237 infos.size()),
238 infos, tr("Unsaved data and missing associated file"));
[2512]239 }
240
[9556]241 protected static void warnLayersWithIllegalFilesAndSaveRequest(List<SaveLayerInfo> infos) {
242 warn(trn("<html>{0} layer needs saving but has an associated file<br>"
[2875]243 + "which cannot be written.<br>"
[2512]244 + "Either select another file for this layer or discard the changes.<br>"
245 + "Layer with a non-writable file:</html>",
246 "<html>{0} layers need saving but have associated files<br>"
[2875]247 + "which cannot be written.<br>"
[2512]248 + "Either select another file for each of them or discard the changes.<br>"
249 + "Layers with non-writable files:</html>",
250 infos.size(),
[9556]251 infos.size()),
252 infos, tr("Unsaved data non-writable files"));
[2512]253 }
254
[9556]255 static boolean confirmSaveLayerInfosOK(SaveLayersModel model) {
[2512]256 List<SaveLayerInfo> layerInfos = model.getLayersWithConflictsAndUploadRequest();
257 if (!layerInfos.isEmpty()) {
258 warnLayersWithConflictsAndUploadRequest(layerInfos);
259 return false;
260 }
261
262 layerInfos = model.getLayersWithoutFilesAndSaveRequest();
263 if (!layerInfos.isEmpty()) {
264 warnLayersWithoutFilesAndSaveRequest(layerInfos);
265 return false;
266 }
267
268 layerInfos = model.getLayersWithIllegalFilesAndSaveRequest();
269 if (!layerInfos.isEmpty()) {
270 warnLayersWithIllegalFilesAndSaveRequest(layerInfos);
271 return false;
272 }
273
274 return true;
275 }
276
277 protected void setUserAction(UserAction action) {
278 this.action = action;
279 }
280
[6965]281 /**
282 * Closes this dialog and frees all native screen resources.
283 */
[3441]284 public void closeDialog() {
285 setVisible(false);
286 dispose();
287 }
288
[2512]289 class WindowClosingAdapter extends WindowAdapter {
290 @Override
291 public void windowClosing(WindowEvent e) {
292 cancelAction.cancel();
293 }
294 }
295
296 class CancelAction extends AbstractAction {
[8836]297 CancelAction() {
[2512]298 putValue(NAME, tr("Cancel"));
299 putValue(SHORT_DESCRIPTION, tr("Close this dialog and resume editing in JOSM"));
300 putValue(SMALL_ICON, ImageProvider.get("cancel"));
[4618]301 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
302 .put(KeyStroke.getKeyStroke("ESCAPE"), "ESCAPE");
303 getRootPane().getActionMap().put("ESCAPE", this);
[2512]304 }
305
306 protected void cancelWhenInEditingModel() {
307 setUserAction(UserAction.CANCEL);
[3441]308 closeDialog();
[2512]309 }
310
311 public void cancel() {
312 switch(model.getMode()) {
[10179]313 case EDITING_DATA: cancelWhenInEditingModel();
314 break;
315 case UPLOADING_AND_SAVING: cancelSafeAndUploadTask();
316 break;
[2512]317 }
318 }
319
[6084]320 @Override
[2512]321 public void actionPerformed(ActionEvent e) {
322 cancel();
323 }
324 }
325
[10378]326 class DiscardAndProceedAction extends AbstractAction implements PropertyChangeListener {
[8836]327 DiscardAndProceedAction() {
[2512]328 initForDiscardAndExit();
329 }
330
331 public void initForDiscardAndExit() {
[5003]332 putValue(NAME, tr("Exit now!"));
[2512]333 putValue(SHORT_DESCRIPTION, tr("Exit JOSM without saving. Unsaved changes are lost."));
334 putValue(SMALL_ICON, ImageProvider.get("exit"));
335 }
336
337 public void initForDiscardAndDelete() {
[5003]338 putValue(NAME, tr("Delete now!"));
[2512]339 putValue(SHORT_DESCRIPTION, tr("Delete layers without saving. Unsaved changes are lost."));
340 putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete"));
341 }
342
[6084]343 @Override
[2512]344 public void actionPerformed(ActionEvent e) {
345 setUserAction(UserAction.PROCEED);
[3441]346 closeDialog();
[2512]347 }
[8510]348
[6084]349 @Override
[2512]350 public void propertyChange(PropertyChangeEvent evt) {
351 if (evt.getPropertyName().equals(SaveLayersModel.MODE_PROP)) {
[8510]352 Mode mode = (Mode) evt.getNewValue();
[2512]353 switch(mode) {
[10179]354 case EDITING_DATA: setEnabled(true);
355 break;
356 case UPLOADING_AND_SAVING: setEnabled(false);
357 break;
[2512]358 }
359 }
360 }
361 }
362
[8913]363 class SaveSessionAction extends SessionSaveAsAction {
[9152]364
[9173]365 SaveSessionAction() {
[9152]366 super(false, false);
367 }
368
[8913]369 @Override
370 public void actionPerformed(ActionEvent e) {
371 try {
372 saveSession();
373 setUserAction(UserAction.PROCEED);
374 closeDialog();
[8919]375 } catch (UserCancelException ignore) {
[10420]376 Main.trace(ignore);
[8913]377 }
378 }
379 }
380
[5003]381 final class SaveAndProceedAction extends AbstractAction implements PropertyChangeListener {
[9556]382 private static final int ICON_SIZE = 24;
[5003]383 private static final String BASE_ICON = "BASE_ICON";
[8308]384 private final transient Image save = ImageProvider.get("save").getImage();
385 private final transient Image upld = ImageProvider.get("upload").getImage();
[10428]386 private final transient Image saveDis = new ImageProvider("save").setDisabled(true).get().getImage();
387 private final transient Image upldDis = new ImageProvider("upload").setDisabled(true).get().getImage();
[5003]388
[8836]389 SaveAndProceedAction() {
[2512]390 initForSaveAndExit();
391 }
392
393 public void initForSaveAndExit() {
[5003]394 putValue(NAME, tr("Perform actions before exiting"));
[2512]395 putValue(SHORT_DESCRIPTION, tr("Exit JOSM with saving. Unsaved changes are uploaded and/or saved."));
[5003]396 putValue(BASE_ICON, ImageProvider.get("exit"));
397 redrawIcon();
[2512]398 }
399
400 public void initForSaveAndDelete() {
[5003]401 putValue(NAME, tr("Perform actions before deleting"));
[2512]402 putValue(SHORT_DESCRIPTION, tr("Save/Upload layers before deleting. Unsaved changes are not lost."));
[5003]403 putValue(BASE_ICON, ImageProvider.get("dialogs", "delete"));
404 redrawIcon();
[2512]405 }
406
[5003]407 public void redrawIcon() {
[10190]408 Image base = ((ImageIcon) getValue(BASE_ICON)).getImage();
409 BufferedImage newIco = new BufferedImage(ICON_SIZE*3, ICON_SIZE, BufferedImage.TYPE_4BYTE_ABGR);
410 Graphics2D g = newIco.createGraphics();
[10378]411 // CHECKSTYLE.OFF: SingleSpaceSeparator
[10190]412 g.drawImage(model.getLayersToUpload().isEmpty() ? upldDis : upld, ICON_SIZE*0, 0, ICON_SIZE, ICON_SIZE, null);
413 g.drawImage(model.getLayersToSave().isEmpty() ? saveDis : save, ICON_SIZE*1, 0, ICON_SIZE, ICON_SIZE, null);
414 g.drawImage(base, ICON_SIZE*2, 0, ICON_SIZE, ICON_SIZE, null);
[10378]415 // CHECKSTYLE.ON: SingleSpaceSeparator
[10190]416 putValue(SMALL_ICON, new ImageIcon(newIco));
[5003]417 }
418
[6084]419 @Override
[2512]420 public void actionPerformed(ActionEvent e) {
[9556]421 if (!confirmSaveLayerInfosOK(model))
[2512]422 return;
423 launchSafeAndUploadTask();
424 }
425
[6084]426 @Override
[2512]427 public void propertyChange(PropertyChangeEvent evt) {
428 if (evt.getPropertyName().equals(SaveLayersModel.MODE_PROP)) {
[8510]429 SaveLayersModel.Mode mode = (SaveLayersModel.Mode) evt.getNewValue();
[2512]430 switch(mode) {
[10179]431 case EDITING_DATA: setEnabled(true);
432 break;
433 case UPLOADING_AND_SAVING: setEnabled(false);
434 break;
[2512]435 }
436 }
437 }
438 }
439
440 /**
441 * This is the asynchronous task which uploads modified layers to the server and
442 * saves them to files, if requested by the user.
443 *
444 */
445 protected class SaveAndUploadTask implements Runnable {
446
[8412]447 private final SaveLayersModel model;
448 private final ProgressMonitor monitor;
449 private final ExecutorService worker;
[4310]450 private boolean canceled;
[2512]451 private Future<?> currentFuture;
452 private AbstractIOTask currentTask;
453
454 public SaveAndUploadTask(SaveLayersModel model, ProgressMonitor monitor) {
455 this.model = model;
456 this.monitor = monitor;
[8734]457 this.worker = Executors.newSingleThreadExecutor(Utils.newThreadFactory(getClass() + "-%d", Thread.NORM_PRIORITY));
[2512]458 }
459
460 protected void uploadLayers(List<SaveLayerInfo> toUpload) {
461 for (final SaveLayerInfo layerInfo: toUpload) {
[7402]462 AbstractModifiableLayer layer = layerInfo.getLayer();
[4310]463 if (canceled) {
[7358]464 model.setUploadState(layer, UploadOrSaveState.CANCELED);
[2512]465 continue;
466 }
467 monitor.subTask(tr("Preparing layer ''{0}'' for upload ...", layerInfo.getName()));
468
[7358]469 if (!UploadAction.checkPreUploadConditions(layer)) {
470 model.setUploadState(layer, UploadOrSaveState.FAILED);
[2512]471 continue;
472 }
[7358]473
474 AbstractUploadDialog dialog = layer.getUploadDialog();
475 if (dialog != null) {
476 dialog.setVisible(true);
477 if (dialog.isCanceled()) {
478 model.setUploadState(layer, UploadOrSaveState.CANCELED);
479 continue;
480 }
481 dialog.rememberUserInput();
482 }
483
484 currentTask = layer.createUploadTask(monitor);
485 if (currentTask == null) {
486 model.setUploadState(layer, UploadOrSaveState.FAILED);
[2599]487 continue;
488 }
[2512]489 currentFuture = worker.submit(currentTask);
490 try {
491 // wait for the asynchronous task to complete
492 //
493 currentFuture.get();
[8510]494 } catch (CancellationException e) {
[7358]495 model.setUploadState(layer, UploadOrSaveState.CANCELED);
[10212]496 } catch (InterruptedException | ExecutionException e) {
[6643]497 Main.error(e);
[7358]498 model.setUploadState(layer, UploadOrSaveState.FAILED);
[2512]499 ExceptionDialogUtil.explainException(e);
500 }
[4310]501 if (currentTask.isCanceled()) {
[7358]502 model.setUploadState(layer, UploadOrSaveState.CANCELED);
[2512]503 } else if (currentTask.isFailed()) {
[6643]504 Main.error(currentTask.getLastException());
[2512]505 ExceptionDialogUtil.explainException(currentTask.getLastException());
[7358]506 model.setUploadState(layer, UploadOrSaveState.FAILED);
[2512]507 } else {
[7358]508 model.setUploadState(layer, UploadOrSaveState.OK);
[2512]509 }
510 currentTask = null;
511 currentFuture = null;
512 }
513 }
514
515 protected void saveLayers(List<SaveLayerInfo> toSave) {
516 for (final SaveLayerInfo layerInfo: toSave) {
[4310]517 if (canceled) {
518 model.setSaveState(layerInfo.getLayer(), UploadOrSaveState.CANCELED);
[2512]519 continue;
520 }
[7204]521 // Check save preconditions earlier to avoid a blocking reentring call to EDT (see #10086)
522 if (layerInfo.isDoCheckSaveConditions()) {
523 if (!layerInfo.getLayer().checkSaveConditions()) {
524 continue;
525 }
526 layerInfo.setDoCheckSaveConditions(false);
527 }
528 currentTask = new SaveLayerTask(layerInfo, monitor);
[2512]529 currentFuture = worker.submit(currentTask);
530
531 try {
532 // wait for the asynchronous task to complete
533 //
534 currentFuture.get();
[8510]535 } catch (CancellationException e) {
[4310]536 model.setSaveState(layerInfo.getLayer(), UploadOrSaveState.CANCELED);
[10212]537 } catch (InterruptedException | ExecutionException e) {
[6643]538 Main.error(e);
[2512]539 model.setSaveState(layerInfo.getLayer(), UploadOrSaveState.FAILED);
540 ExceptionDialogUtil.explainException(e);
541 }
[4310]542 if (currentTask.isCanceled()) {
543 model.setSaveState(layerInfo.getLayer(), UploadOrSaveState.CANCELED);
[2512]544 } else if (currentTask.isFailed()) {
545 if (currentTask.getLastException() != null) {
[6643]546 Main.error(currentTask.getLastException());
[2512]547 ExceptionDialogUtil.explainException(currentTask.getLastException());
548 }
549 model.setSaveState(layerInfo.getLayer(), UploadOrSaveState.FAILED);
550 } else {
551 model.setSaveState(layerInfo.getLayer(), UploadOrSaveState.OK);
552 }
553 this.currentTask = null;
554 this.currentFuture = null;
555 }
556 }
557
558 protected void warnBecauseOfUnsavedData() {
559 int numProblems = model.getNumCancel() + model.getNumFailed();
[10179]560 if (numProblems == 0)
561 return;
[8474]562 Main.warn(numProblems + " problems occured during upload/save");
[2848]563 String msg = trn(
[2512]564 "<html>An upload and/or save operation of one layer with modifications<br>"
[4310]565 + "was canceled or has failed.</html>",
[2512]566 "<html>Upload and/or save operations of {0} layers with modifications<br>"
[4310]567 + "were canceled or have failed.</html>",
[2512]568 numProblems,
569 numProblems
570 );
571 JOptionPane.showMessageDialog(
572 Main.parent,
573 msg,
574 tr("Incomplete upload and/or save"),
575 JOptionPane.WARNING_MESSAGE
576 );
577 }
578
[6084]579 @Override
[2512]580 public void run() {
[6965]581 GuiHelper.runInEDTAndWait(new Runnable() {
582 @Override
583 public void run() {
584 model.setMode(SaveLayersModel.Mode.UPLOADING_AND_SAVING);
585 List<SaveLayerInfo> toUpload = model.getLayersToUpload();
586 if (!toUpload.isEmpty()) {
587 uploadLayers(toUpload);
588 }
589 List<SaveLayerInfo> toSave = model.getLayersToSave();
590 if (!toSave.isEmpty()) {
591 saveLayers(toSave);
592 }
593 model.setMode(SaveLayersModel.Mode.EDITING_DATA);
594 if (model.hasUnsavedData()) {
595 warnBecauseOfUnsavedData();
596 model.setMode(Mode.EDITING_DATA);
597 if (canceled) {
598 setUserAction(UserAction.CANCEL);
599 closeDialog();
600 }
601 } else {
602 setUserAction(UserAction.PROCEED);
603 closeDialog();
604 }
[2512]605 }
[6965]606 });
[8412]607 worker.shutdownNow();
[2512]608 }
609
610 public void cancel() {
611 if (currentTask != null) {
612 currentTask.cancel();
613 }
[8412]614 worker.shutdown();
[4310]615 canceled = true;
[2512]616 }
617 }
[5003]618
619 @Override
620 public void tableChanged(TableModelEvent arg0) {
621 boolean dis = model.getLayersToSave().isEmpty() && model.getLayersToUpload().isEmpty();
[8510]622 if (saveAndProceedActionButton != null) {
[5003]623 saveAndProceedActionButton.setEnabled(!dis);
624 }
625 saveAndProceedAction.redrawIcon();
626 }
[2512]627}
Note: See TracBrowser for help on using the repository browser.