diff --git a/aegisub/build/Aegisub/Aegisub.vcxproj b/aegisub/build/Aegisub/Aegisub.vcxproj index 2c72d80a8..3a399f5c5 100644 --- a/aegisub/build/Aegisub/Aegisub.vcxproj +++ b/aegisub/build/Aegisub/Aegisub.vcxproj @@ -23,18 +23,15 @@ {9DDDB9E5-E4A1-423D-A224-F6D4E5AAC06A} Aegisub - exe true ..\..\src\ - - aegisub$(AegisubPlatformSuffix) @@ -47,7 +44,6 @@ /Zm150 %(AdditionalOptions) - @@ -81,7 +77,6 @@ {7b56955d-5162-4698-aa5b-47484edc8783} - @@ -253,13 +248,15 @@ + Create agi_pre.h - + + @@ -372,11 +369,13 @@ NotUsing - + + NotUsing - + + @@ -447,12 +446,12 @@ + - - + \ No newline at end of file diff --git a/aegisub/build/Aegisub/Aegisub.vcxproj.filters b/aegisub/build/Aegisub/Aegisub.vcxproj.filters index 11f7c7baf..34f790da2 100644 --- a/aegisub/build/Aegisub/Aegisub.vcxproj.filters +++ b/aegisub/build/Aegisub/Aegisub.vcxproj.filters @@ -145,6 +145,9 @@ {39646be7-5dce-471c-ab93-1e3f7f6f9fe1} + + {fde3be82-3653-4519-88f5-8c16ddfb1531} + @@ -654,6 +657,9 @@ Controls + + Features\Autosave + @@ -1202,10 +1208,13 @@ Commands + + Features\Autosave + Resources - + \ No newline at end of file diff --git a/aegisub/src/Makefile b/aegisub/src/Makefile index 5c012b5ef..fbc6c1da1 100644 --- a/aegisub/src/Makefile +++ b/aegisub/src/Makefile @@ -164,6 +164,7 @@ SRC += \ dialog_about.cpp \ dialog_attachments.cpp \ dialog_automation.cpp \ + dialog_autosave.cpp \ dialog_colorpicker.cpp \ dialog_detached_video.cpp \ dialog_dummy_video.cpp \ diff --git a/aegisub/src/command/subtitle.cpp b/aegisub/src/command/subtitle.cpp index 449d16838..453e63897 100644 --- a/aegisub/src/command/subtitle.cpp +++ b/aegisub/src/command/subtitle.cpp @@ -50,6 +50,7 @@ #include "../ass_file.h" #include "../compat.h" #include "../dialog_attachments.h" +#include "../dialog_autosave.h" #include "../dialog_manager.h" #include "../dialog_properties.h" #include "../dialog_search_replace.h" @@ -268,6 +269,19 @@ struct subtitle_open : public Command { } }; +struct subtitle_open_autosave : public Command { + CMD_NAME("subtitle/open/autosave") + STR_MENU("Open A&utosaved Subtitles...") + STR_DISP("Open Autosaved Subtitles") + STR_HELP("Open a previous version of a file which was autosaved by Aegisub") + + void operator()(agi::Context *c) { + DialogAutosave dialog(c->parent); + if (dialog.ShowModal() == wxID_OK) + wxGetApp().frame->LoadSubtitles(dialog.ChosenFile()); + } +}; + /// Opens a subtitles file with a specific charset. struct subtitle_open_charset : public Command { @@ -455,6 +469,7 @@ namespace cmd { reg(new subtitle_insert_before_videotime); reg(new subtitle_new); reg(new subtitle_open); + reg(new subtitle_open_autosave); reg(new subtitle_open_charset); reg(new subtitle_open_video); reg(new subtitle_properties); diff --git a/aegisub/src/dialog_autosave.cpp b/aegisub/src/dialog_autosave.cpp new file mode 100644 index 000000000..5be8f447b --- /dev/null +++ b/aegisub/src/dialog_autosave.cpp @@ -0,0 +1,125 @@ +// Copyright (c) 2012, Thomas Goyne +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// +// Aegisub Project http://www.aegisub.org/ + +#include "config.h" + +#include "dialog_autosave.h" + +#include "compat.h" +#include "main.h" +#include "standard_paths.h" + +#include + +#ifndef AGI_PRE +#include + +#include +#endif + +DialogAutosave::DialogAutosave(wxWindow *parent) +: wxDialog(parent, -1, _("Open autosave file"), wxDefaultPosition, wxSize(800, 350)) +, directory(StandardPaths::DecodePath(to_wx(OPT_GET("Path/Auto/Save")->GetString()))) +{ + wxSizer *files_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Files")); + file_list = new wxListBox(this, -1); + file_list->Bind(wxEVT_COMMAND_LISTBOX_SELECTED, &DialogAutosave::OnSelectFile, this); + files_box->Add(file_list, wxSizerFlags(1).Expand().Border()); + + wxSizer *versions_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Versions")); + version_list = new wxListBox(this, -1); + version_list->Bind(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, [=](wxCommandEvent&) { EndModal(wxID_OK); }); + versions_box->Add(version_list, wxSizerFlags(1).Expand().Border()); + + wxSizer *boxes_sizer = new wxBoxSizer(wxHORIZONTAL); + boxes_sizer->Add(files_box, wxSizerFlags(1).Expand().Border()); + boxes_sizer->Add(versions_box, wxSizerFlags(1).Expand().Border()); + + wxStdDialogButtonSizer *btn_sizer = CreateStdDialogButtonSizer(wxOK | wxCANCEL); + btn_sizer->GetAffirmativeButton()->SetLabelText(_("Open")); + + wxSizer *main_sizer = new wxBoxSizer(wxVERTICAL); + main_sizer->Add(boxes_sizer, wxSizerFlags(1).Expand().Border()); + main_sizer->Add(btn_sizer, wxSizerFlags().Expand().Border(wxALL & ~wxTOP)); + SetSizer(main_sizer); + + Populate(); + if (file_list->IsEmpty()) + btn_sizer->GetAffirmativeButton()->Disable(); +} + +void DialogAutosave::Populate() { + wxDir dir; + if (!dir.Open(directory)) return; + + wxString fn; + if (!dir.GetFirst(&fn, "*.AUTOSAVE.ass", wxDIR_FILES)) + return; + + std::map files_map; + do { + wxString date_str; + wxString name = fn.Left(fn.size() - 13).BeforeLast('.', &date_str); + if (!name) continue; + + wxDateTime date; + if (!date.ParseFormat(date_str, "%Y-%m-%d-%H-%M-%S")) + continue; + + auto it = files_map.find(name); + if (it == files_map.end()) + it = files_map.emplace(name, name).first; + it->second.versions.emplace_back(fn, date); + } while (dir.GetNext(&fn)); + + for (auto& file : files_map | boost::adaptors::map_values) + files.emplace_back(std::move(file)); + + for (auto& file : files) { + sort(begin(file.versions), end(file.versions), + [](Version const& a, Version const& b) { return a.date > b.date; }); + } + + sort(begin(files), end(files), + [](AutosaveFile const& a, AutosaveFile const& b) { return a.versions[0].date > b.versions[0].date; }); + + for (auto const& file : files) + file_list->Append(file.name); + file_list->SetSelection(0); + + wxCommandEvent evt; + OnSelectFile(evt); +} + +void DialogAutosave::OnSelectFile(wxCommandEvent&) { + version_list->Clear(); + int sel_file = file_list->GetSelection(); + if (sel_file < 0) return; + + for (auto const& version : files[sel_file].versions) + version_list->Append(version.date.Format()); + version_list->SetSelection(0); +} + +wxString DialogAutosave::ChosenFile() const { + int sel_file = file_list->GetSelection(); + if (sel_file < 0) return ""; + + int sel_version = version_list->GetSelection(); + if (sel_version < 0) return ""; + + return wxFileName(directory, files[sel_file].versions[sel_version].filename).GetFullPath(); +} diff --git a/aegisub/src/dialog_autosave.h b/aegisub/src/dialog_autosave.h new file mode 100644 index 000000000..b4fc0d38e --- /dev/null +++ b/aegisub/src/dialog_autosave.h @@ -0,0 +1,53 @@ +// Copyright (c) 2012, Thomas Goyne +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// +// Aegisub Project http://www.aegisub.org/ + +#ifndef AGI_PRE +#include +#include + +#include +#include +#endif + +class wxListBox; + +class DialogAutosave : public wxDialog { + struct Version { + wxString filename; + wxDateTime date; + Version(wxString const& filename, wxDateTime const& date) + : filename(filename), date(date) { } + }; + + struct AutosaveFile { + wxString name; + std::vector versions; + AutosaveFile(wxString const& name) : name(name) { } + }; + + wxString directory; + std::vector files; + + wxListBox *file_list; + wxListBox *version_list; + + void Populate(); + void OnSelectFile(wxCommandEvent&); + +public: + DialogAutosave(wxWindow *parent); + wxString ChosenFile() const; +}; diff --git a/aegisub/src/libresrc/default_menu.json b/aegisub/src/libresrc/default_menu.json index a9d4cc9ff..a2fa48e68 100644 --- a/aegisub/src/libresrc/default_menu.json +++ b/aegisub/src/libresrc/default_menu.json @@ -42,6 +42,7 @@ { "command" : "subtitle/open" }, { "command" : "subtitle/open/charset" }, { "command" : "subtitle/open/video" }, + { "command" : "subtitle/open/autosave" }, { "command" : "subtitle/save" }, { "command" : "subtitle/save/as" }, { "command" : "tool/export" }, diff --git a/aegisub/src/libresrc/osx/default_menu.json b/aegisub/src/libresrc/osx/default_menu.json index c9bf1d88e..8206655c7 100644 --- a/aegisub/src/libresrc/osx/default_menu.json +++ b/aegisub/src/libresrc/osx/default_menu.json @@ -42,6 +42,7 @@ { "command" : "subtitle/open" }, { "command" : "subtitle/open/charset" }, { "command" : "subtitle/open/video" }, + { "command" : "subtitle/open/autosave" }, { "recent" : "Subtitle" }, { "command" : "subtitle/save" }, { "command" : "subtitle/save/as" },