Perform autosaves on a background thread rather than blocking the UI

This commit is contained in:
Thomas Goyne 2015-08-16 18:17:33 -07:00
parent 44b76d38d2
commit d253388c8e
2 changed files with 47 additions and 31 deletions

View file

@ -32,6 +32,7 @@
#include "subtitle_format.h"
#include "text_selection_controller.h"
#include <libaegisub/dispatch.h>
#include <libaegisub/format_path.h>
#include <libaegisub/fs.h>
#include <libaegisub/path.h>
@ -146,27 +147,18 @@ SubsController::SubsController(agi::Context *context)
: context(context)
, undo_connection(context->ass->AddUndoManager(&SubsController::OnCommit, this))
, text_selection_connection(context->textSelectionController->AddSelectionListener(&SubsController::OnTextSelectionChanged, this))
, autosave_queue(agi::dispatch::Create())
{
autosave_timer_changed(&autosave_timer);
OPT_SUB("App/Auto/Save", [=] { autosave_timer_changed(&autosave_timer); });
OPT_SUB("App/Auto/Save Every Seconds", [=] { autosave_timer_changed(&autosave_timer); });
autosave_timer.Bind(wxEVT_TIMER, [=](wxTimerEvent&) {
try {
auto fn = AutoSave();
if (!fn.empty())
context->frame->StatusTimeout(fmt_tl("File backup saved as \"%s\".", fn));
}
catch (const agi::Exception& err) {
context->frame->StatusTimeout(to_wx("Exception when attempting to autosave file: " + err.GetMessage()));
}
catch (...) {
context->frame->StatusTimeout("Unhandled exception when attempting to autosave file.");
}
});
autosave_timer.Bind(wxEVT_TIMER, [=](wxTimerEvent&) { AutoSave(); });
}
SubsController::~SubsController() { }
SubsController::~SubsController() {
// Make sure there are no autosaves in progress
autosave_queue->Sync([]{ });
}
void SubsController::SetSelectionController(SelectionController *selection_controller) {
active_line_connection = context->selectionController->AddActiveLineListener(&SubsController::OnActiveLineChanged, this);
@ -260,26 +252,43 @@ int SubsController::TryToClose(bool allow_cancel) const {
return result;
}
agi::fs::path SubsController::AutoSave() {
void SubsController::AutoSave() {
if (commit_id == autosaved_commit_id)
return "";
return;
auto path = config::path->Decode(OPT_GET("Path/Auto/Save")->GetString());
if (path.empty())
path = filename.parent_path();
agi::fs::CreateDirectory(path);
auto directory = config::path->Decode(OPT_GET("Path/Auto/Save")->GetString());
if (directory.empty())
directory = filename.parent_path();
auto name = filename.filename();
if (name.empty())
name = "Untitled";
path /= agi::format("%s.%s.AUTOSAVE.ass", name.string(), agi::util::strftime("%Y-%m-%d-%H-%M-%S"));
SubtitleFormat::GetWriter(path)->WriteFile(context->ass.get(), path, 0);
autosaved_commit_id = commit_id;
auto frame = context->frame;
auto subs_copy = new AssFile(*context->ass);
autosave_queue->Async([subs_copy, name, directory, frame] {
wxString msg;
std::unique_ptr<AssFile> subs(subs_copy);
return path;
try {
agi::fs::CreateDirectory(directory);
auto path = directory / agi::format("%s.%s.AUTOSAVE.ass", name.string(),
agi::util::strftime("%Y-%m-%d-%H-%M-%S"));
SubtitleFormat::GetWriter(path)->WriteFile(subs.get(), path, 0);
msg = fmt_tl("File backup saved as \"%s\".", path);
}
catch (const agi::Exception& err) {
msg = to_wx("Exception when attempting to autosave file: " + err.GetMessage());
}
catch (...) {
msg = "Unhandled exception when attempting to autosave file.";
}
agi::dispatch::Main().Async([frame, msg] {
frame->StatusTimeout(msg);
});
});
}
bool SubsController::CanSave() const {

View file

@ -22,7 +22,12 @@
#include <wx/timer.h>
class SelectionController;
namespace agi { struct Context; }
namespace agi {
namespace dispatch {
class Queue;
}
struct Context;
}
struct AssFileCommit;
struct ProjectProperties;
@ -47,6 +52,9 @@ class SubsController {
/// Timer for triggering autosaves
wxTimer autosave_timer;
/// Queue which autosaves are performed on
std::unique_ptr<agi::dispatch::Queue> autosave_queue;
/// A new file has been opened (filename)
agi::signal::Signal<agi::fs::path> FileOpen;
/// The file has been saved
@ -58,6 +66,9 @@ class SubsController {
/// Set the filename, updating things like the MRU and last used path
void SetFileName(agi::fs::path const& file);
/// Autosave the file if there have been any chances since the last autosave
void AutoSave();
void OnCommit(AssFileCommit c);
void OnActiveLineChanged();
void OnSelectionChanged();
@ -97,10 +108,6 @@ public:
/// @return wxYES, wxNO or wxCANCEL (note: all three are true in a boolean context)
int TryToClose(bool allow_cancel = true) const;
/// @brief Autosave the file if there have been any chances since the last autosave
/// @return File name used or empty if no save was performed
agi::fs::path AutoSave();
/// Can the file be saved in its current format?
bool CanSave() const;