diff --git a/src/ass_file.cpp b/src/ass_file.cpp index e7598054c..8397ff132 100644 --- a/src/ass_file.cpp +++ b/src/ass_file.cpp @@ -84,6 +84,7 @@ void AssFile::swap(AssFile& from) throw() { Events.swap(from.Events); Attachments.swap(from.Attachments); Extradata.swap(from.Extradata); + std::swap(Properties, from.Properties); std::swap(next_extradata_id, from.next_extradata_id); } @@ -121,22 +122,6 @@ int AssFile::GetScriptInfoAsInt(std::string const& key) const { return atoi(GetScriptInfo(key).c_str()); } -std::string AssFile::GetUIState(std::string const& key) const { - auto value = GetScriptInfo("Aegisub " + key); - if (value.empty()) - value = GetScriptInfo(key); - return value; -} - -int AssFile::GetUIStateAsInt(std::string const& key) const { - return atoi(GetUIState(key).c_str()); -} - -void AssFile::SaveUIState(std::string const& key, std::string const& value) { - if (OPT_GET("App/Save UI State")->GetBool()) - SetScriptInfo("Aegisub " + key, value); -} - void AssFile::SetScriptInfo(std::string const& key, std::string const& value) { for (auto it = Info.begin(); it != Info.end(); ++it) { if (boost::iequals(key, it->Key())) { @@ -300,4 +285,3 @@ void AssFile::CleanExtradata() { Extradata.erase(id); } } - diff --git a/src/ass_file.h b/src/ass_file.h index 6e864c0cd..bc098c727 100644 --- a/src/ass_file.h +++ b/src/ass_file.h @@ -27,11 +27,6 @@ // // Aegisub Project http://www.aegisub.org/ -/// @file ass_file.h -/// @see ass_file.cpp -/// @ingroup subs_storage -/// - #include "ass_entry.h" #include @@ -58,6 +53,26 @@ struct AssFileCommit { AssDialogue *single_line; }; +struct ProjectProperties { + std::string automation_scripts; + std::string export_filters; + std::string export_encoding; + std::string style_storage; + std::string audio_file; + std::string video_file; + std::string timecodes_file; + std::string keyframes_file; + std::map automation_settings; + + // UI State + double video_zoom = 0.; + double ar_value = 0.; + int scroll_position = 0; + int active_row = 0; + int ar_mode = 0; + int video_position = 0; +}; + class AssFile { /// A set of changes has been committed to the file (AssFile::COMMITType) agi::signal::Signal const&> AnnounceCommit; @@ -69,6 +84,7 @@ public: EntryList Events; std::vector Attachments; AegisubExtradataMap Extradata; + ProjectProperties Properties; uint32_t next_extradata_id = 0; @@ -104,9 +120,6 @@ public: std::string GetScriptInfo(std::string const& key) const; /// Set the value of a [Script Info] key. Adds it if it doesn't exist. void SetScriptInfo(std::string const& key, std::string const& value); - std::string GetUIState(std::string const& key) const; - int GetUIStateAsInt(std::string const& key) const; - void SaveUIState(std::string const& key, std::string const& value); /// @brief Add a new extradata entry /// @param key Class identifier/owner for the extradata diff --git a/src/ass_parser.cpp b/src/ass_parser.cpp index ced410ec4..f2cb17c2e 100644 --- a/src/ass_parser.cpp +++ b/src/ass_parser.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -31,9 +32,71 @@ #include #include #include +#include +#include + +class AssParser::HeaderToProperty { + using field = boost::variant< + std::string ProjectProperties::*, + int ProjectProperties::*, + double ProjectProperties::* + >; + std::unordered_map fields; + +public: + HeaderToProperty() + : fields({ + {"Automation Scripts", &ProjectProperties::automation_scripts}, + {"Export Filters", &ProjectProperties::export_filters}, + {"Export Encoding", &ProjectProperties::export_encoding}, + {"Last Style Storage", &ProjectProperties::style_storage}, + {"Audio URI", &ProjectProperties::audio_file}, + {"Audio File", &ProjectProperties::audio_file}, + {"Video File", &ProjectProperties::video_file}, + {"Timecodes File", &ProjectProperties::timecodes_file}, + {"Keyframes File", &ProjectProperties::keyframes_file}, + {"Video Zoom Percent", &ProjectProperties::video_zoom}, + {"Scroll Position", &ProjectProperties::scroll_position}, + {"Active Line", &ProjectProperties::active_row}, + {"Video Position", &ProjectProperties::video_position}, + {"Video AR Mode", &ProjectProperties::ar_mode}, + {"Video AR Value", &ProjectProperties::ar_value}, + {"Aegisub Video Zoom Percent", &ProjectProperties::video_zoom}, + {"Aegisub Scroll Position", &ProjectProperties::scroll_position}, + {"Aegisub Active Line", &ProjectProperties::active_row}, + {"Aegisub Video Position", &ProjectProperties::video_position} + }) + { + } + + bool ProcessProperty(AssFile *target, std::string const& key, std::string const& value) { + auto it = fields.find(key); + if (it != end(fields)) { + using namespace agi::util; + struct { + using result_type = void; + ProjectProperties &obj; + std::string const& value; + void operator()(std::string ProjectProperties::*f) const { obj.*f = value; } + void operator()(int ProjectProperties::*f) const { try_parse(value, &(obj.*f)); } + void operator()(double ProjectProperties::*f) const { try_parse(value, &(obj.*f)); } + } visitor {target->Properties, value}; + boost::apply_visitor(visitor, it->second); + return true; + } + + if (boost::starts_with(key, "Automation Settings ")) { + target->Properties.automation_settings[key.substr(strlen("Automation Settings"))] = value; + return true; + } + + return false; + } +}; AssParser::AssParser(AssFile *target, int version) -: target(target) +: property_handler(new HeaderToProperty) +, target(target) , version(version) , state(&AssParser::ParseScriptInfoLine) { @@ -94,7 +157,23 @@ void AssParser::ParseScriptInfoLine(std::string const& data) { size_t pos = data.find(':'); if (pos == data.npos) return; - target->Info.push_back(*new AssInfo(data.substr(0, pos), boost::trim_left_copy(data.substr(pos + 1)))); + auto key = data.substr(0, pos); + auto value = data.substr(pos + 1); + boost::trim_left(value); + + if (!property_handler->ProcessProperty(target, key, value)) + target->Info.push_back(*new AssInfo(std::move(key), std::move(value))); +} + +void AssParser::ParseMetadataLine(std::string const& data) { + size_t pos = data.find(':'); + if (pos == data.npos) return; + + auto key = data.substr(0, pos); + auto value = data.substr(pos + 1); + boost::trim_left(value); + + property_handler->ProcessProperty(target, key, value); } void AssParser::ParseEventLine(std::string const& data) { @@ -171,12 +250,14 @@ void AssParser::AddLine(std::string const& data) { state = &AssParser::ParseEventLine; else if (low == "[script info]") state = &AssParser::ParseScriptInfoLine; + else if (low == "[aegisub project garbage]") + state = &AssParser::ParseMetadataLine; + else if (low == "[aegisub extradata]") + state = &AssParser::ParseExtradataLine; else if (low == "[graphics]") state = &AssParser::ParseGraphicsLine; else if (low == "[fonts]") state = &AssParser::ParseFontLine; - else if (low == "[aegisub extradata]") - state = &AssParser::ParseExtradataLine; else state = &AssParser::UnknownLine; return; diff --git a/src/ass_parser.h b/src/ass_parser.h index c51c20204..41396fb1f 100644 --- a/src/ass_parser.h +++ b/src/ass_parser.h @@ -20,6 +20,9 @@ class AssAttachment; class AssFile; class AssParser { + class HeaderToProperty; + std::unique_ptr property_handler; + AssFile *target; int version; std::unique_ptr attach; @@ -29,6 +32,7 @@ class AssParser { void ParseEventLine(std::string const& data); void ParseStyleLine(std::string const& data); void ParseScriptInfoLine(std::string const& data); + void ParseMetadataLine(std::string const& data); void ParseFontLine(std::string const& data); void ParseGraphicsLine(std::string const& data); void ParseExtradataLine(std::string const &data); diff --git a/src/auto4_base.cpp b/src/auto4_base.cpp index 16eb35acd..8f15129fd 100644 --- a/src/auto4_base.cpp +++ b/src/auto4_base.cpp @@ -182,14 +182,14 @@ namespace Automation4 { std::string ExportFilter::GetScriptSettingsIdentifier() { - return inline_string_encode("Automation Settings " + GetName()); + return inline_string_encode(GetName()); } wxWindow* ExportFilter::GetConfigDialogWindow(wxWindow *parent, agi::Context *c) { config_dialog = GenerateConfigDialog(parent, c); if (config_dialog) { - std::string val = c->ass->GetScriptInfo(GetScriptSettingsIdentifier()); + std::string const& val = c->ass->Properties.automation_settings[GetScriptSettingsIdentifier()]; if (!val.empty()) config_dialog->Unserialise(val); return config_dialog->CreateWindow(parent); @@ -199,11 +199,8 @@ namespace Automation4 { } void ExportFilter::LoadSettings(bool is_default, agi::Context *c) { - if (config_dialog) { - std::string val = config_dialog->Serialise(); - if (!val.empty()) - c->ass->SetScriptInfo(GetScriptSettingsIdentifier(), val); - } + if (config_dialog) + c->ass->Properties.automation_settings[GetScriptSettingsIdentifier()] = config_dialog->Serialise(); } // ProgressSink @@ -285,10 +282,6 @@ namespace Automation4 { } // ScriptManager - ScriptManager::~ScriptManager() - { - } - void ScriptManager::Add(std::unique_ptr