/*
* Copyright (C) 2012 Jason Gedge <http://www.gedge.ca>
*
* This file is part of the OpGraph project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ca.gedge.opgraph.app.commands.core;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import javax.swing.filechooser.FileNameExtensionFilter;
import ca.gedge.opgraph.app.GraphDocument;
import ca.gedge.opgraph.app.GraphEditorModel;
import ca.gedge.opgraph.app.components.ErrorDialog;
import ca.gedge.opgraph.io.OpGraphSerializer;
import ca.gedge.opgraph.io.OpGraphSerializerFactory;
import ca.gedge.opgraph.io.OpGraphSerializerInfo;
/**
* A command that saves the active graph and saves it to disk.
*/
public class SaveCommand extends AbstractAction {
private static final Logger LOGGER = Logger.getLogger(SaveCommand.class.getName());
/** Whether or not to force the save dialog */
private boolean forceDialog;
/**
* Constructs a save command that does not force the dialog.
*/
public SaveCommand() {
this(false);
}
/**
* Constructs a save command.
*
* @param forceDialog if <code>true</code>, a save dialog will always be
* shown. If <code>false</code>, a save dialog is shown
* only if the file is currently not saved to disk.
*/
public SaveCommand(boolean forceDialog) {
super(forceDialog ? "Save As..." : "Save");
this.forceDialog = forceDialog;
int modifiers = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
if(forceDialog)
modifiers |= InputEvent.SHIFT_MASK;
putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_S, modifiers));
}
@Override
public void actionPerformed(ActionEvent e) {
final GraphDocument document = GraphEditorModel.getActiveDocument();
if(document != null) {
File saveFile = document.getSource();
if(forceDialog)
saveFile = null;
saveDocument(document, saveFile);
}
}
/**
* Saves an application model to a file.
*
* @param model the model to save
* @param saveFile The file to save to. if <code>null</code>, a dialog is
* popped up asking the user to select a file to save to.
*
* @return <code>true</code> if the model was successfully saved to file,
* in which case the model's source is set to the selected file.
* <code>false</code> otherwise.
*/
public static boolean saveDocument(GraphDocument model, File saveFile) {
// Get the serializer
final OpGraphSerializer serializer = OpGraphSerializerFactory.getDefaultSerializer();
if(serializer == null) {
final String message = "No default serializer available";
LOGGER.severe(message);
ErrorDialog.showError(message);
return false;
}
// Get the serializer's info
String description = "Opgraph Files";
String extension = "";
final OpGraphSerializerInfo info = serializer.getClass().getAnnotation(OpGraphSerializerInfo.class);
if(info != null) {
description = info.description();
extension = info.extension();
}
// Find a save file
boolean ret = true;
if(model != null && model.getGraph() != null && (saveFile == null || model.hasModifications())) {
ret = false;
if(saveFile == null) {
final JFileChooser chooser = new JFileChooser();
chooser.setAcceptAllFileFilterUsed(false);
chooser.setFileFilter(new FileNameExtensionFilter(description, extension));
chooser.setDialogTitle("Save Visual Graph");
// Loop for picking file
boolean running = true;
do {
final int retVal = chooser.showSaveDialog(null);
if(retVal == JFileChooser.APPROVE_OPTION) {
saveFile = chooser.getSelectedFile();
if(chooser.getSelectedFile().exists()) {
final int overwriteVal =
JOptionPane.showConfirmDialog(null,
"Overwrite selected file?",
"Overwrite File",
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE);
//
// Yes - overwrite file
// No - don't overwrite file, but ask for another file
// Cancel - don't overwrite file, don't ask for another file
//
switch(overwriteVal) {
case JOptionPane.YES_OPTION:
running = false;
break;
case JOptionPane.NO_OPTION:
saveFile = null;
break;
case JOptionPane.CANCEL_OPTION:
saveFile = null;
running = false;
break;
}
} else running = false;
} else running = false;
} while(running);
}
}
// If a non-null file, save the graph to disk
if(saveFile != null) {
try {
// serialize xml into an in-memory stream
final ByteArrayOutputStream bout = new ByteArrayOutputStream();
serializer.write(model.getGraph(), bout);
// assume overwrite warning was issued and accepted...
final FileOutputStream stream = new FileOutputStream(saveFile);
stream.write(bout.toByteArray());
stream.flush();
stream.close();
model.setSource(saveFile);
model.markAsUnmodified();
ret = true;
} catch(IOException exc) {
final String message = "Could not save graph to file: " + exc.getLocalizedMessage();
LOGGER.severe(message);
ErrorDialog.showError(exc, message);
}
}
return ret;
}
}