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

Last change on this file since 9152 was 9152, checked in by simon04, 8 years ago

fix #12183 - "Registered toolbar action save_as-session overwritten"

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