/* * @(#)AbstractSaveUnsavedChangesAction.java * * Copyright (c) 1996-2010 The authors and contributors of JHotDraw. * You may not use, copy or modify this file, except in compliance with the * accompanying license terms. */ package org.jhotdraw.app.action; import javax.annotation.Nullable; import org.jhotdraw.gui.filechooser.ExtensionFileFilter; import org.jhotdraw.gui.*; import org.jhotdraw.gui.event.*; import org.jhotdraw.util.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.io.*; import java.net.URI; import org.jhotdraw.app.Application; import org.jhotdraw.app.View; import org.jhotdraw.gui.URIChooser; import org.jhotdraw.gui.JFileURIChooser; import org.jhotdraw.net.URIUtil; /** * This abstract class can be extended to implement an {@code Action} that asks * to save unsaved changes of a {@link org.jhotdraw.app.View} before a destructive * action is performed. * <p> * If the view has no unsaved changes, method {@code doIt} is invoked immediately. * If unsaved changes are present, a dialog is shown asking whether the user * wants to discard the changes, cancel or save the changes before doing it. * If the user chooses to discard the changes, {@code doIt} is invoked immediately. * If the user chooses to cancel, the action is aborted. * If the user chooses to save the changes, the view is saved, and {@code doIt} * is only invoked after the view was successfully saved. * * @author Werner Randelshofer * @version $Id$ */ public abstract class AbstractSaveUnsavedChangesAction extends AbstractViewAction { private static final long serialVersionUID = 1L; @Nullable private Component oldFocusOwner; /** Creates a new instance. */ public AbstractSaveUnsavedChangesAction(Application app, @Nullable View view) { super(app, view); } @Override public void actionPerformed(ActionEvent evt) { Application app=getApplication(); View av = getActiveView(); if (av == null) { if (isMayCreateView()) { av= app.createView(); app.add(av); app.show(av); } else { return; } } final View v=av; if (v.isEnabled()) { final ResourceBundleUtil labels = ResourceBundleUtil.getBundle("org.jhotdraw.app.Labels"); Window wAncestor = SwingUtilities.getWindowAncestor(v.getComponent()); oldFocusOwner = (wAncestor == null) ? null : wAncestor.getFocusOwner(); v.setEnabled(false); if (v.hasUnsavedChanges()) { URI unsavedURI = v.getURI(); JOptionPane pane = new JOptionPane( "<html>" + UIManager.getString("OptionPane.css") +// "<b>" + labels.getFormatted("file.saveBefore.doYouWantToSave.message",// (unsavedURI == null) ? labels.getString("unnamedFile") : URIUtil.getName(unsavedURI)) + "</b><p>" +// labels.getString("file.saveBefore.doYouWantToSave.details"), JOptionPane.WARNING_MESSAGE); Object[] options = { // labels.getString("file.saveBefore.saveOption.text"),// labels.getString("file.saveBefore.cancelOption.text"), // labels.getString("file.saveBefore.dontSaveOption.text")// }; pane.setOptions(options); pane.setInitialValue(options[0]); pane.putClientProperty("Quaqua.OptionPane.destructiveOption", 2); JSheet.showSheet(pane, v.getComponent(), new SheetListener() { @Override public void optionSelected(SheetEvent evt) { Object value = evt.getValue(); if (value == null || value.equals(labels.getString("file.saveBefore.cancelOption.text"))) { v.setEnabled(true); } else if (value.equals(labels.getString("file.saveBefore.dontSaveOption.text"))) { doIt(v); v.setEnabled(true); } else if (value.equals(labels.getString("file.saveBefore.saveOption.text"))) { saveView(v); } } }); } else { doIt(v); v.setEnabled(true); if (oldFocusOwner != null) { oldFocusOwner.requestFocus(); } } } } protected URIChooser getChooser(View view) { URIChooser chsr = (URIChooser) (view.getComponent()).getClientProperty("saveChooser"); if (chsr == null) { chsr = getApplication().getModel().createSaveChooser(getApplication(), view); view.getComponent().putClientProperty("saveChooser", chsr); } return chsr; } protected void saveView(final View v) { if (v.getURI() == null) { URIChooser chooser = getChooser(v); //int option = fileChooser.showSaveDialog(this); JSheet.showSaveSheet(chooser, v.getComponent(), new SheetListener() { @Override public void optionSelected(final SheetEvent evt) { if (evt.getOption() == JFileChooser.APPROVE_OPTION) { final URI uri; if ((evt.getChooser() instanceof JFileURIChooser) && evt.getFileChooser().getFileFilter() instanceof ExtensionFileFilter) { uri = ((ExtensionFileFilter) evt.getFileChooser().getFileFilter()).makeAcceptable(evt.getFileChooser().getSelectedFile()).toURI(); } else { uri = evt.getChooser().getSelectedURI(); } saveViewToURI(v, uri, evt.getChooser()); } else { v.setEnabled(true); if (oldFocusOwner != null) { oldFocusOwner.requestFocus(); } } } }); } else { saveViewToURI(v, v.getURI(), null); } } protected void saveViewToURI(final View v, final URI uri, @Nullable final URIChooser chooser) { v.execute(new BackgroundTask() { @Override protected void construct() throws IOException { v.write(uri, chooser); } @Override protected void done() { v.setURI(uri); v.markChangesAsSaved(); doIt(v); } @Override protected void failed(Throwable value) { String message = (value.getMessage() != null) ? value.getMessage() : value.toString(); ResourceBundleUtil labels = ResourceBundleUtil.getBundle("org.jhotdraw.app.Labels"); JSheet.showMessageSheet(getActiveView().getComponent(), "<html>" + UIManager.getString("OptionPane.css") + "<b>" + labels.getFormatted("file.save.couldntSave.message", URIUtil.getName(uri)) + "</b><p>" + ((message == null) ? "" : message), JOptionPane.ERROR_MESSAGE); } @Override protected void finished() { v.setEnabled(true); if (oldFocusOwner != null) { oldFocusOwner.requestFocus(); } } }); } protected abstract void doIt(View p); }