mirror of https://github.com/odrling/Aegisub
Perform autosaves on a background thread rather than blocking the UI
This commit is contained in:
parent
44b76d38d2
commit
d253388c8e
|
@ -32,6 +32,7 @@
|
||||||
#include "subtitle_format.h"
|
#include "subtitle_format.h"
|
||||||
#include "text_selection_controller.h"
|
#include "text_selection_controller.h"
|
||||||
|
|
||||||
|
#include <libaegisub/dispatch.h>
|
||||||
#include <libaegisub/format_path.h>
|
#include <libaegisub/format_path.h>
|
||||||
#include <libaegisub/fs.h>
|
#include <libaegisub/fs.h>
|
||||||
#include <libaegisub/path.h>
|
#include <libaegisub/path.h>
|
||||||
|
@ -146,27 +147,18 @@ SubsController::SubsController(agi::Context *context)
|
||||||
: context(context)
|
: context(context)
|
||||||
, undo_connection(context->ass->AddUndoManager(&SubsController::OnCommit, this))
|
, undo_connection(context->ass->AddUndoManager(&SubsController::OnCommit, this))
|
||||||
, text_selection_connection(context->textSelectionController->AddSelectionListener(&SubsController::OnTextSelectionChanged, this))
|
, text_selection_connection(context->textSelectionController->AddSelectionListener(&SubsController::OnTextSelectionChanged, this))
|
||||||
|
, autosave_queue(agi::dispatch::Create())
|
||||||
{
|
{
|
||||||
autosave_timer_changed(&autosave_timer);
|
autosave_timer_changed(&autosave_timer);
|
||||||
OPT_SUB("App/Auto/Save", [=] { 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); });
|
OPT_SUB("App/Auto/Save Every Seconds", [=] { autosave_timer_changed(&autosave_timer); });
|
||||||
|
autosave_timer.Bind(wxEVT_TIMER, [=](wxTimerEvent&) { AutoSave(); });
|
||||||
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.");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SubsController::~SubsController() { }
|
SubsController::~SubsController() {
|
||||||
|
// Make sure there are no autosaves in progress
|
||||||
|
autosave_queue->Sync([]{ });
|
||||||
|
}
|
||||||
|
|
||||||
void SubsController::SetSelectionController(SelectionController *selection_controller) {
|
void SubsController::SetSelectionController(SelectionController *selection_controller) {
|
||||||
active_line_connection = context->selectionController->AddActiveLineListener(&SubsController::OnActiveLineChanged, this);
|
active_line_connection = context->selectionController->AddActiveLineListener(&SubsController::OnActiveLineChanged, this);
|
||||||
|
@ -260,26 +252,43 @@ int SubsController::TryToClose(bool allow_cancel) const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
agi::fs::path SubsController::AutoSave() {
|
void SubsController::AutoSave() {
|
||||||
if (commit_id == autosaved_commit_id)
|
if (commit_id == autosaved_commit_id)
|
||||||
return "";
|
return;
|
||||||
|
|
||||||
auto path = config::path->Decode(OPT_GET("Path/Auto/Save")->GetString());
|
auto directory = config::path->Decode(OPT_GET("Path/Auto/Save")->GetString());
|
||||||
if (path.empty())
|
if (directory.empty())
|
||||||
path = filename.parent_path();
|
directory = filename.parent_path();
|
||||||
|
|
||||||
agi::fs::CreateDirectory(path);
|
|
||||||
|
|
||||||
auto name = filename.filename();
|
auto name = filename.filename();
|
||||||
if (name.empty())
|
if (name.empty())
|
||||||
name = "Untitled";
|
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;
|
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 {
|
bool SubsController::CanSave() const {
|
||||||
|
|
|
@ -22,7 +22,12 @@
|
||||||
#include <wx/timer.h>
|
#include <wx/timer.h>
|
||||||
|
|
||||||
class SelectionController;
|
class SelectionController;
|
||||||
namespace agi { struct Context; }
|
namespace agi {
|
||||||
|
namespace dispatch {
|
||||||
|
class Queue;
|
||||||
|
}
|
||||||
|
struct Context;
|
||||||
|
}
|
||||||
struct AssFileCommit;
|
struct AssFileCommit;
|
||||||
struct ProjectProperties;
|
struct ProjectProperties;
|
||||||
|
|
||||||
|
@ -47,6 +52,9 @@ class SubsController {
|
||||||
/// Timer for triggering autosaves
|
/// Timer for triggering autosaves
|
||||||
wxTimer autosave_timer;
|
wxTimer autosave_timer;
|
||||||
|
|
||||||
|
/// Queue which autosaves are performed on
|
||||||
|
std::unique_ptr<agi::dispatch::Queue> autosave_queue;
|
||||||
|
|
||||||
/// A new file has been opened (filename)
|
/// A new file has been opened (filename)
|
||||||
agi::signal::Signal<agi::fs::path> FileOpen;
|
agi::signal::Signal<agi::fs::path> FileOpen;
|
||||||
/// The file has been saved
|
/// The file has been saved
|
||||||
|
@ -58,6 +66,9 @@ class SubsController {
|
||||||
/// Set the filename, updating things like the MRU and last used path
|
/// Set the filename, updating things like the MRU and last used path
|
||||||
void SetFileName(agi::fs::path const& file);
|
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 OnCommit(AssFileCommit c);
|
||||||
void OnActiveLineChanged();
|
void OnActiveLineChanged();
|
||||||
void OnSelectionChanged();
|
void OnSelectionChanged();
|
||||||
|
@ -97,10 +108,6 @@ public:
|
||||||
/// @return wxYES, wxNO or wxCANCEL (note: all three are true in a boolean context)
|
/// @return wxYES, wxNO or wxCANCEL (note: all three are true in a boolean context)
|
||||||
int TryToClose(bool allow_cancel = true) const;
|
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?
|
/// Can the file be saved in its current format?
|
||||||
bool CanSave() const;
|
bool CanSave() const;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue