mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-01 01:20:25 +00:00
337 lines
8.1 KiB
C++
337 lines
8.1 KiB
C++
/* ASEPRITE
|
|
* Copyright (C) 2001-2012 David Capello
|
|
*
|
|
* 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 2 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, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <allegro.h>
|
|
|
|
#include "app.h"
|
|
#include "app/file_selector.h"
|
|
#include "base/thread.h"
|
|
#include "commands/command.h"
|
|
#include "console.h"
|
|
#include "document_wrappers.h"
|
|
#include "file/file.h"
|
|
#include "modules/gui.h"
|
|
#include "raster/sprite.h"
|
|
#include "recent_files.h"
|
|
#include "ui/gui.h"
|
|
#include "widgets/statebar.h"
|
|
|
|
struct SaveFileData
|
|
{
|
|
Monitor *monitor;
|
|
FileOp *fop;
|
|
Progress *progress;
|
|
ui::AlertPtr alert_window;
|
|
};
|
|
|
|
/**
|
|
* Thread to do the hard work: save the file to the disk.
|
|
*
|
|
* [saving thread]
|
|
*/
|
|
static void savefile_bg(void *fop_data)
|
|
{
|
|
FileOp *fop = (FileOp *)fop_data;
|
|
try {
|
|
fop_operate(fop);
|
|
}
|
|
catch (const std::exception& e) {
|
|
fop_error(fop, "Error saving file:\n%s", e.what());
|
|
}
|
|
fop_done(fop);
|
|
}
|
|
|
|
/**
|
|
* Called by the gui-monitor (a timer in the gui module that is called
|
|
* every 100 milliseconds).
|
|
*
|
|
* [main thread]
|
|
*/
|
|
static void monitor_savefile_bg(void *_data)
|
|
{
|
|
SaveFileData *data = (SaveFileData *)_data;
|
|
FileOp *fop = (FileOp *)data->fop;
|
|
|
|
if (data->progress)
|
|
data->progress->setPos(fop_get_progress(fop));
|
|
|
|
if (fop_is_done(fop))
|
|
remove_gui_monitor(data->monitor);
|
|
}
|
|
|
|
/**
|
|
* Called when the monitor is destroyed.
|
|
*
|
|
* [main thread]
|
|
*/
|
|
static void monitor_free(void *_data)
|
|
{
|
|
SaveFileData *data = (SaveFileData*)_data;
|
|
|
|
if (data->alert_window != NULL) {
|
|
data->monitor = NULL;
|
|
data->alert_window->closeWindow(NULL);
|
|
}
|
|
}
|
|
|
|
static void save_document_in_background(Document* document, bool mark_as_saved)
|
|
{
|
|
FileOp *fop = fop_to_save_document(document);
|
|
if (!fop)
|
|
return;
|
|
|
|
base::thread thread(&savefile_bg, fop);
|
|
SaveFileData* data = new SaveFileData;
|
|
|
|
data->fop = fop;
|
|
data->progress = app_get_statusbar()->addProgress();
|
|
data->alert_window = ui::Alert::create(PACKAGE
|
|
"<<Saving file:<<%s||&Cancel",
|
|
get_filename(document->getFilename()));
|
|
|
|
/* add a monitor to check the saving (FileOp) progress */
|
|
data->monitor = add_gui_monitor(monitor_savefile_bg,
|
|
monitor_free, data);
|
|
|
|
/* TODO error handling */
|
|
|
|
data->alert_window->open_window_fg();
|
|
|
|
if (data->monitor != NULL)
|
|
remove_gui_monitor(data->monitor);
|
|
|
|
/* wait the `savefile_bg' thread */
|
|
thread.join();
|
|
|
|
/* show any error */
|
|
if (fop->has_error()) {
|
|
Console console;
|
|
console.printf(fop->error.c_str());
|
|
}
|
|
/* no error? */
|
|
else {
|
|
App::instance()->getRecentFiles()->addRecentFile(document->getFilename());
|
|
if (mark_as_saved)
|
|
document->markAsSaved();
|
|
|
|
app_get_statusbar()
|
|
->setStatusText(2000, "File %s, saved.",
|
|
get_filename(document->getFilename()));
|
|
}
|
|
|
|
delete data->progress;
|
|
fop_free(fop);
|
|
delete data;
|
|
}
|
|
|
|
/*********************************************************************/
|
|
|
|
static void save_as_dialog(const DocumentReader& document, const char* dlg_title, bool mark_as_saved)
|
|
{
|
|
char exts[4096];
|
|
base::string filename;
|
|
base::string newfilename;
|
|
int ret;
|
|
|
|
filename = document->getFilename();
|
|
get_writable_extensions(exts, sizeof(exts));
|
|
|
|
for (;;) {
|
|
newfilename = app::show_file_selector(dlg_title, filename, exts);
|
|
if (newfilename.empty())
|
|
return;
|
|
|
|
filename = newfilename;
|
|
|
|
/* does the file exist? */
|
|
if (exists(filename.c_str())) {
|
|
/* ask if the user wants overwrite the file? */
|
|
ret = ui::Alert::show("Warning<<File exists, overwrite it?<<%s||&Yes||&No||&Cancel",
|
|
get_filename(filename.c_str()));
|
|
}
|
|
else
|
|
break;
|
|
|
|
/* "yes": we must continue with the operation... */
|
|
if (ret == 1)
|
|
break;
|
|
/* "cancel" or <esc> per example: we back doing nothing */
|
|
else if (ret != 2)
|
|
return;
|
|
|
|
/* "no": we must back to select other file-name */
|
|
}
|
|
|
|
{
|
|
DocumentWriter documentWriter(document);
|
|
|
|
// Change the document file name
|
|
documentWriter->setFilename(filename.c_str());
|
|
|
|
// Save the document
|
|
save_document_in_background(documentWriter, mark_as_saved);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// save_file
|
|
|
|
class SaveFileCommand : public Command
|
|
{
|
|
public:
|
|
SaveFileCommand();
|
|
Command* clone() { return new SaveFileCommand(*this); }
|
|
|
|
protected:
|
|
bool onEnabled(Context* context);
|
|
void onExecute(Context* context);
|
|
};
|
|
|
|
SaveFileCommand::SaveFileCommand()
|
|
: Command("SaveFile",
|
|
"Save File",
|
|
CmdRecordableFlag)
|
|
{
|
|
}
|
|
|
|
// Returns true if there is a current sprite to save.
|
|
// [main thread]
|
|
bool SaveFileCommand::onEnabled(Context* context)
|
|
{
|
|
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable);
|
|
}
|
|
|
|
// Saves the active document in a file.
|
|
// [main thread]
|
|
void SaveFileCommand::onExecute(Context* context)
|
|
{
|
|
const ActiveDocumentReader document(context);
|
|
|
|
// If the document is associated to a file in the file-system, we can
|
|
// save it directly without user interaction.
|
|
if (document->isAssociatedToFile()) {
|
|
DocumentWriter documentWriter(document);
|
|
|
|
save_document_in_background(documentWriter, true);
|
|
}
|
|
// If the document isn't associated to a file, we must to show the
|
|
// save-as dialog to the user to select for first time the file-name
|
|
// for this document.
|
|
else {
|
|
save_as_dialog(document, "Save File", true);
|
|
}
|
|
|
|
update_screen_for_document(document);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// save_file_as
|
|
|
|
class SaveFileAsCommand : public Command
|
|
{
|
|
public:
|
|
SaveFileAsCommand();
|
|
Command* clone() { return new SaveFileAsCommand(*this); }
|
|
|
|
protected:
|
|
bool onEnabled(Context* context);
|
|
void onExecute(Context* context);
|
|
};
|
|
|
|
SaveFileAsCommand::SaveFileAsCommand()
|
|
: Command("SaveFileAs",
|
|
"Save File As",
|
|
CmdRecordableFlag)
|
|
{
|
|
}
|
|
|
|
bool SaveFileAsCommand::onEnabled(Context* context)
|
|
{
|
|
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable);
|
|
}
|
|
|
|
void SaveFileAsCommand::onExecute(Context* context)
|
|
{
|
|
const ActiveDocumentReader document(context);
|
|
save_as_dialog(document, "Save As", true);
|
|
update_screen_for_document(document);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// save_file_copy_as
|
|
|
|
class SaveFileCopyAsCommand : public Command
|
|
{
|
|
public:
|
|
SaveFileCopyAsCommand();
|
|
Command* clone() { return new SaveFileCopyAsCommand(*this); }
|
|
|
|
protected:
|
|
bool onEnabled(Context* context);
|
|
void onExecute(Context* context);
|
|
};
|
|
|
|
SaveFileCopyAsCommand::SaveFileCopyAsCommand()
|
|
: Command("SaveFileCopyAs",
|
|
"Save File Copy As",
|
|
CmdRecordableFlag)
|
|
{
|
|
}
|
|
|
|
bool SaveFileCopyAsCommand::onEnabled(Context* context)
|
|
{
|
|
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable);
|
|
}
|
|
|
|
void SaveFileCopyAsCommand::onExecute(Context* context)
|
|
{
|
|
const ActiveDocumentReader document(context);
|
|
base::string old_filename = document->getFilename();
|
|
|
|
// show "Save As" dialog
|
|
save_as_dialog(document, "Save Copy As", false);
|
|
|
|
// Restore the file name.
|
|
{
|
|
DocumentWriter documentWriter(document);
|
|
documentWriter->setFilename(old_filename.c_str());
|
|
}
|
|
|
|
update_screen_for_document(document);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// CommandFactory
|
|
|
|
Command* CommandFactory::createSaveFileCommand()
|
|
{
|
|
return new SaveFileCommand;
|
|
}
|
|
|
|
Command* CommandFactory::createSaveFileAsCommand()
|
|
{
|
|
return new SaveFileAsCommand;
|
|
}
|
|
|
|
Command* CommandFactory::createSaveFileCopyAsCommand()
|
|
{
|
|
return new SaveFileCopyAsCommand;
|
|
}
|