From 5f1d8c414d33d38e3f6d3534f29f1980502948c9 Mon Sep 17 00:00:00 2001 From: Niels Martin Hansen Date: Thu, 28 Dec 2006 22:31:33 +0000 Subject: [PATCH] And Automation 4 is now in the trunk! Originally committed to SVN as r647. --- core/ass_export_filter.h | 2 +- core/ass_exporter.cpp | 4 +- core/ass_exporter.h | 2 +- core/ass_file.cpp | 2 +- core/ass_override.cpp | 1 - core/auto4_lua.cpp | 7 +- core/auto4_lua.h | 3 - core/auto4_lua_assfile.cpp | 2 +- core/dialog_automation.cpp | 295 +++++++++++++++++++++++++++++++++++++ core/dialog_automation.h | 94 ++++++++++++ core/dialog_export.cpp | 4 +- core/export_clean_info.cpp | 2 +- core/export_clean_info.h | 9 +- core/export_fixstyle.cpp | 2 +- core/export_fixstyle.h | 2 +- core/export_framerate.cpp | 2 +- core/export_framerate.h | 2 +- core/frame_main.cpp | 134 +++++++++-------- core/frame_main.h | 12 +- core/frame_main_events.cpp | 51 ++++++- core/main.cpp | 4 + core/main.h | 4 + core/options.cpp | 5 +- core/subs_grid.cpp | 25 ++++ core/subs_grid.h | 2 + core/utils.cpp | 2 +- 26 files changed, 577 insertions(+), 97 deletions(-) create mode 100644 core/dialog_automation.cpp create mode 100644 core/dialog_automation.h diff --git a/core/ass_export_filter.h b/core/ass_export_filter.h index 6dc8db64e..b475e2812 100644 --- a/core/ass_export_filter.h +++ b/core/ass_export_filter.h @@ -101,7 +101,7 @@ public: const wxString& GetDescription() const; - virtual void ProcessSubs(AssFile *subs)=0; // Process subtitles - this function must be overriden. + virtual void ProcessSubs(AssFile *subs, wxWindow *export_dialog=0)=0; // Process subtitles - this function must be overriden. virtual wxWindow *GetConfigDialogWindow(wxWindow *parent); // Draw setup controls - this function may optionally be overridden. virtual void LoadSettings(bool IsDefault); // Config dialog is done - extract data now. }; diff --git a/core/ass_exporter.cpp b/core/ass_exporter.cpp index b806584a3..83ffbf617 100644 --- a/core/ass_exporter.cpp +++ b/core/ass_exporter.cpp @@ -126,14 +126,14 @@ wxArrayString AssExporter::GetAllFilterNames() { ////////// // Export -void AssExporter::Export(wxString filename, wxString charset) { +void AssExporter::Export(wxString filename, wxString charset, wxWindow *export_dialog) { // Copy AssFile *Subs = new AssFile(*OriginalSubs); // Run filters for (FilterList::iterator cur=Filters.begin();cur!=Filters.end();cur++) { (*cur)->LoadSettings(IsDefault); - (*cur)->ProcessSubs(Subs); + (*cur)->ProcessSubs(Subs, export_dialog); } /* diff --git a/core/ass_exporter.h b/core/ass_exporter.h index 3c0bda70e..286ad44b4 100644 --- a/core/ass_exporter.h +++ b/core/ass_exporter.h @@ -74,7 +74,7 @@ public: void AddAutoFilters(); void DrawSettings(wxWindow *parent,wxSizer *AddTo); wxSizer *GetSettingsSizer(wxString name); - void Export(wxString file, wxString charset = _T("")); + void Export(wxString file, wxString charset, wxWindow *export_dialog); AssFile *GetOriginalSubs() { return OriginalSubs; } wxString GetDescription(wxString name); }; diff --git a/core/ass_file.cpp b/core/ass_file.cpp index 74a8c48de..9293287df 100644 --- a/core/ass_file.cpp +++ b/core/ass_file.cpp @@ -183,7 +183,7 @@ void AssFile::Save(wxString _filename,bool setfilename,bool addToRecent,const wx void AssFile::Export(wxString _filename) { AssExporter exporter(this); exporter.AddAutoFilters(); - exporter.Export(_filename,_T("UTF-8")); + exporter.Export(_filename,_T("UTF-8"), 0); } diff --git a/core/ass_override.cpp b/core/ass_override.cpp index 39e123b66..9839685a3 100644 --- a/core/ass_override.cpp +++ b/core/ass_override.cpp @@ -501,7 +501,6 @@ void AssOverrideTag::SetText (wxString text) { // Set tag name if (!Name.empty()) { - wxLogDebug(_T("Parsing tag: %s"), Name.c_str()); ParseParameters(text.Mid(Name.length())); valid = true; } diff --git a/core/auto4_lua.cpp b/core/auto4_lua.cpp index c0b074b74..b9e00f785 100644 --- a/core/auto4_lua.cpp +++ b/core/auto4_lua.cpp @@ -768,11 +768,6 @@ namespace Automation4 { } } }; - LuaScriptFactory *_script_factory; + LuaScriptFactory _script_factory; }; - -void Initialise_Auto4Lua() -{ - Automation4::_script_factory = new Automation4::LuaScriptFactory; -} diff --git a/core/auto4_lua.h b/core/auto4_lua.h index ad6813976..4d18c7474 100644 --- a/core/auto4_lua.h +++ b/core/auto4_lua.h @@ -238,7 +238,4 @@ namespace Automation4 { }; -// More or less dummy-function to make sure auto4_lua.cpp is linked in -void Initialise_Auto4Lua(); - #endif diff --git a/core/auto4_lua_assfile.cpp b/core/auto4_lua_assfile.cpp index c7ded085a..f53f9241c 100644 --- a/core/auto4_lua_assfile.cpp +++ b/core/auto4_lua_assfile.cpp @@ -886,7 +886,7 @@ namespace Automation4 { description = wxString(lua_tostring(L, 1), wxConvUTF8); lua_pop(L, 1); } - AssFile::FlagAsModified(description); + AssFile::top->FlagAsModified(); // TODO: make undo system support description of action undone laf->ass = AssFile::top; // make sure we're still working on the most recent undo point return 0; diff --git a/core/dialog_automation.cpp b/core/dialog_automation.cpp new file mode 100644 index 000000000..077a7616c --- /dev/null +++ b/core/dialog_automation.cpp @@ -0,0 +1,295 @@ +// Copyright (c) 2006, Niels Martin Hansen +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Aegisub Group nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// ----------------------------------------------------------------------------- +// +// AEGISUB +// +// Website: http://aegisub.cellosoft.com +// Contact: mailto:jiifurusu@gmail.com +// + +#include "main.h" +#include "dialog_automation.h" +#include "auto4_base.h" +#include "options.h" +#include +#include + + +DialogAutomation::DialogAutomation(wxWindow *parent, Automation4::ScriptManager *_local_manager) +: wxDialog(parent, -1, _("Automation Manager"), wxDefaultPosition, wxDefaultSize) +{ + local_manager = _local_manager; + global_manager = wxGetApp().global_scripts; + + // create main controls + list = new wxListView(this, Automation_List_Box, wxDefaultPosition, wxSize(600, 175), wxLC_REPORT|wxLC_SINGLE_SEL); + add_button = new wxButton(this, Automation_Add_Script, _("&Add")); + remove_button = new wxButton(this, Automation_Remove_Script, _("&Remove")); + reload_button = new wxButton(this, Automation_Reload_Script, _("Re&load")); + info_button = new wxButton(this, Automation_Show_Info, _("Show &Info")); + reload_autoload_button = new wxButton(this, Automation_Reload_Autoload, _("Re&scan Autoload Dir")); + close_button = new wxButton(this, wxID_CLOSE); + + // add headers to list view + list->InsertColumn(0, _T(""), wxLIST_FORMAT_CENTER, 20); + list->InsertColumn(1, _("Name"), wxLIST_FORMAT_LEFT, 140); + list->InsertColumn(2, _("Filename"), wxLIST_FORMAT_LEFT, 90); + list->InsertColumn(3, _("Description"), wxLIST_FORMAT_LEFT, 330); + + // button layout + wxSizer *button_box = new wxBoxSizer(wxHORIZONTAL); + button_box->AddStretchSpacer(2); + button_box->Add(add_button, 0); + button_box->Add(remove_button, 0); + button_box->AddSpacer(10); + button_box->Add(reload_button, 0); + button_box->Add(info_button, 0); + button_box->AddSpacer(10); + button_box->Add(reload_autoload_button, 0); + button_box->AddSpacer(10); + button_box->Add(close_button, 0); + button_box->AddStretchSpacer(2); + + // main layout + wxSizer *main_box = new wxBoxSizer(wxVERTICAL); + main_box->Add(list, 1, wxEXPAND|wxALL, 5); + main_box->Add(button_box, 0, wxEXPAND|wxALL&~wxTOP, 5); + main_box->SetSizeHints(this); + SetSizer(main_box); + Center(); + + RebuildList(); + UpdateDisplay(); +} + + +void DialogAutomation::RebuildList() +{ + script_info.clear(); + list->DeleteAllItems(); + + // fill the list view + const std::vector &global_scripts = global_manager->GetScripts(); + for (std::vector::const_iterator i = global_scripts.begin(); i != global_scripts.end(); ++i) { + ExtraScriptInfo ei; + ei.script = *i; + ei.is_global = true; + AddScript(ei); + } + const std::vector &local_scripts = local_manager->GetScripts(); + for (std::vector::const_iterator i = local_scripts.begin(); i != local_scripts.end(); ++i) { + ExtraScriptInfo ei; + ei.script = *i; + ei.is_global = false; + AddScript(ei); + } + +} + + +void DialogAutomation::AddScript(ExtraScriptInfo &ei) +{ + script_info.push_back(ei); + + wxListItem itm; + if (ei.is_global) { + itm.SetText(_T("G")); + } else { + itm.SetText(_T("L")); + } + itm.SetData((int)script_info.size()-1); + itm.SetId(list->GetItemCount()); + int i = list->InsertItem(itm); + list->SetItem(i, 1, ei.script->GetName()); + list->SetItem(i, 2, wxFileName(ei.script->GetFilename()).GetFullName()); + list->SetItem(i, 3, ei.script->GetDescription()); + if (ei.script->GetLoadedState() == false) { + list->SetItemBackgroundColour(i, wxColour(255,128,128)); + } +} + + +void DialogAutomation::UpdateDisplay() +{ + int i = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + bool selected = i >= 0; + bool global = true; + if (selected) { + const ExtraScriptInfo &ei = script_info[list->GetItemData(i)]; + global = ei.is_global; + } + add_button->Enable(true); + remove_button->Enable(selected && !global); + reload_button->Enable(selected); + info_button->Enable(true); + reload_autoload_button->Enable(true); + close_button->Enable(true); +} + + +BEGIN_EVENT_TABLE(DialogAutomation, wxDialog) + EVT_BUTTON(Automation_Add_Script,DialogAutomation::OnAdd) + EVT_BUTTON(Automation_Remove_Script,DialogAutomation::OnRemove) + EVT_BUTTON(Automation_Reload_Script,DialogAutomation::OnReload) + EVT_BUTTON(Automation_Show_Info,DialogAutomation::OnInfo) + EVT_BUTTON(Automation_Reload_Autoload,DialogAutomation::OnReloadAutoload) + EVT_BUTTON(wxID_CLOSE,DialogAutomation::OnClose) + EVT_LIST_ITEM_SELECTED(Automation_List_Box,DialogAutomation::OnSelectionChange) + EVT_LIST_ITEM_DESELECTED(Automation_List_Box,DialogAutomation::OnSelectionChange) +END_EVENT_TABLE() + + +void DialogAutomation::OnAdd(wxCommandEvent &evt) +{ + // build filename filter list + wxString fnfilter; + const std::vector &factories = Automation4::ScriptFactory::GetFactories(); + for (int i = 0; i < (int)factories.size(); i++) { + const Automation4::ScriptFactory *fact = factories[i]; + if (fact->GetEngineName().IsEmpty() || fact->GetFilenamePattern().IsEmpty()) + continue; + fnfilter = wxString::Format(_T("%s%s scripts|%s|"), fnfilter.c_str(), fact->GetEngineName().c_str(), fact->GetFilenamePattern().c_str()); + } +#ifdef __WINDOWS__ + fnfilter += _T("All files|*.*"); +#else + fnfilter += _T("All files|*"); +#endif + + wxString fname = wxFileSelector(_("Add Automation script"), Options.AsText(_T("Last open automation path")), wxEmptyString, wxEmptyString, fnfilter, wxOPEN|wxFILE_MUST_EXIST, this); + + if (!fname.IsEmpty()) { + + wxFileName fnpath(fname); + Options.SetText(_T("Last open automation path"), fnpath.GetPath()); + + // TODO: make sure each script is only loaded once. check in both local and global managers!! + // it doesn't break for macros, but will for export filters, and maybe for file formats, + // and makes for confusion in the UI anyhow + + try { + ExtraScriptInfo ei; + ei.script = Automation4::ScriptFactory::CreateFromFile(fname); + local_manager->Add(ei.script); + ei.is_global = false; + AddScript(ei); + } + catch (const wchar_t *e) { + wxLogError(e); + } + catch (...) { + wxLogError(_T("Unknown error loading script")); + } + } +} + +void DialogAutomation::OnRemove(wxCommandEvent &evt) +{ + int i = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (i < 0) return; + const ExtraScriptInfo &ei = script_info[list->GetItemData(i)]; + if (ei.is_global) return; + list->DeleteItem(i); + local_manager->Remove(ei.script); + // don't bother doing anything in script_info, it's relatively short-lived, and having any indexes change would break stuff + list->Select(i); +} + +void DialogAutomation::OnReload(wxCommandEvent &evt) +{ + int i = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (i < 0) return; + const ExtraScriptInfo &ei = script_info[list->GetItemData(i)]; + + try { + ei.script->Reload(); + } + catch (const wchar_t *e) { + wxMessageBox(e, _T("Error reloading Automation script"), wxOK|wxICON_ERROR, this); + } + catch (...) { + wxMessageBox(_T("An unknown error occurred reloading Automation script."), _T("Error reloading Automation script"), wxOK|wxICON_ERROR, this); + } + + list->SetItem(i, 1, ei.script->GetName()); + list->SetItem(i, 2, wxFileName(ei.script->GetFilename()).GetFullName()); + list->SetItem(i, 3, ei.script->GetDescription()); + if (ei.script->GetLoadedState() == false) { + list->SetItemBackgroundColour(i, wxColour(255,128,128)); + } +} + +void DialogAutomation::OnInfo(wxCommandEvent &evt) +{ + int i = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + ExtraScriptInfo *ei = 0; + if (i >= 0) + ei = &script_info[list->GetItemData(i)]; + + wxString info = wxString::Format( + _("Total scripts loaded: %d\nGlobal scripts loaded: %d\nLocal scripts loaded: %d\n\n"), + local_manager->GetScripts().size() + global_manager->GetScripts().size(), + global_manager->GetScripts().size(), + local_manager->GetScripts().size()); + + info += _("Scripting engines installed:\n"); + const std::vector &factories = Automation4::ScriptFactory::GetFactories(); + for (std::vector::const_iterator i = factories.begin(); i != factories.end(); ++i) { + info += wxString::Format(_T("- %s (%s)\n"), (*i)->GetEngineName().c_str(), (*i)->GetFilenamePattern().c_str()); + } + + if (ei) { + info += wxString::Format(_("\nScript info:\nName: %s\nDescription: %s\nAuthor: %s\nVersion: %s\nFull path: %s\nCorrectly initialised: %s"), + ei->script->GetName().c_str(), + ei->script->GetDescription().c_str(), + ei->script->GetAuthor().c_str(), + ei->script->GetVersion().c_str(), + ei->script->GetFilename().c_str(), + ei->script->GetLoadedState() ? _("Yes") : _("No")); + } + + wxMessageBox(info, _("Automation Script Info")); +} + +void DialogAutomation::OnReloadAutoload(wxCommandEvent &evt) +{ + global_manager->Reload(); + RebuildList(); + UpdateDisplay(); +} + +void DialogAutomation::OnClose(wxCommandEvent &evt) +{ + EndModal(0); +} + +void DialogAutomation::OnSelectionChange(wxListEvent &evt) +{ + UpdateDisplay(); +} diff --git a/core/dialog_automation.h b/core/dialog_automation.h new file mode 100644 index 000000000..bc1964b9c --- /dev/null +++ b/core/dialog_automation.h @@ -0,0 +1,94 @@ +// Copyright (c) 2005, Niels Martin Hansen +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Aegisub Group nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// ----------------------------------------------------------------------------- +// +// AEGISUB +// +// Website: http://aegisub.cellosoft.com +// Contact: mailto:zeratul@cellosoft.com +// + +#pragma once + +#ifndef DIALOG_AUTOMATION_H +#define DIALOG_AUTOMATION_H + +#include +#include +#include +#include + +namespace Automation4 { class ScriptManager; class Script; }; + +class DialogAutomation : public wxDialog { +private: + struct ExtraScriptInfo { + Automation4::Script *script; + bool is_global; + }; + std::vector script_info; + + Automation4::ScriptManager *local_manager; + Automation4::AutoloadScriptManager *global_manager; + + wxListView *list; + wxButton *add_button; + wxButton *remove_button; + wxButton *reload_button; + wxButton *info_button; + wxButton *reload_autoload_button; + wxButton *close_button; + + void RebuildList(); + void AddScript(ExtraScriptInfo &ei); + void UpdateDisplay(); + + void OnAdd(wxCommandEvent &evt); + void OnRemove(wxCommandEvent &evt); + void OnReload(wxCommandEvent &evt); + void OnInfo(wxCommandEvent &evt); + void OnClose(wxCommandEvent &evt); + void OnReloadAutoload(wxCommandEvent &evt); + void OnSelectionChange(wxListEvent &evt); + +public: + DialogAutomation(wxWindow *parent, Automation4::ScriptManager *_local_manager); + + DECLARE_EVENT_TABLE() +}; + +enum { + Automation_List_Box = 1000, + Automation_Add_Script, + Automation_Remove_Script, + Automation_Reload_Script, + Automation_Show_Info, + Automation_Reload_Autoload +}; + +#endif diff --git a/core/dialog_export.cpp b/core/dialog_export.cpp index 031e1b418..33ab3204f 100644 --- a/core/dialog_export.cpp +++ b/core/dialog_export.cpp @@ -182,7 +182,6 @@ END_EVENT_TABLE() // Process start void DialogExport::OnProcess(wxCommandEvent &event) { // Get destination - //wxString filename = wxFileSelector(_("Export subtitles file"),_T(""),_T(""),_T(""),_T("All Supported Types (*.ass,*.ssa,*.srt,*.prs)|*.ass;*.ssa;*.srt;*.prs|Advanced Substation Alpha (*.ass)|*.ass|Substation Alpha (*.ssa)|*.ssa|SubRip (*.srt)|*.srt|Plain-text (*.txt)|*.txt|Pre-Rendered Subtitles (*.prs)|*.prs"),wxSAVE | wxOVERWRITE_PROMPT,this); wxString filename = wxFileSelector(_("Export subtitles file"),_T(""),_T(""),_T(""),AssFile::GetWildcardList(2),wxSAVE | wxOVERWRITE_PROMPT,this); if (filename.empty()) return; @@ -195,8 +194,9 @@ void DialogExport::OnProcess(wxCommandEvent &event) { // Export try { + wxBusyCursor busy; Export->GetOriginalSubs()->SetScriptInfo(_T("Export Encoding"), CharsetList->GetStringSelection()); - Export->Export(filename, CharsetList->GetStringSelection()); + Export->Export(filename, CharsetList->GetStringSelection(), this); } catch (const wchar_t *error) { wxString err(error); diff --git a/core/export_clean_info.cpp b/core/export_clean_info.cpp index 5e961d794..1b1389950 100644 --- a/core/export_clean_info.cpp +++ b/core/export_clean_info.cpp @@ -62,7 +62,7 @@ void AssTransformCleanInfoFilter::Init() { /////////// // Process -void AssTransformCleanInfoFilter::ProcessSubs(AssFile *subs) { +void AssTransformCleanInfoFilter::ProcessSubs(AssFile *subs, wxWindow *export_dialog) { using std::list; AssEntry *curEntry; entryIter cur, next = subs->Line.begin(); diff --git a/core/export_clean_info.h b/core/export_clean_info.h index 3684660fa..7af8245b7 100644 --- a/core/export_clean_info.h +++ b/core/export_clean_info.h @@ -52,14 +52,7 @@ private: void Init(); public: - void ProcessSubs(AssFile *subs); + void ProcessSubs(AssFile *subs, wxWindow *export_dialog); wxWindow *GetConfigDialogWindow(wxWindow *parent); void LoadSettings(bool IsDefault); }; - - -/////// -// IDs -enum { - Get_Input_From_Video = 2000 -}; diff --git a/core/export_fixstyle.cpp b/core/export_fixstyle.cpp index 2592cee22..37fb52a9f 100644 --- a/core/export_fixstyle.cpp +++ b/core/export_fixstyle.cpp @@ -62,7 +62,7 @@ void AssFixStylesFilter::Init() { /////////// // Process -void AssFixStylesFilter::ProcessSubs(AssFile *subs) { +void AssFixStylesFilter::ProcessSubs(AssFile *subs, wxWindow *export_dialog) { // Build styles list wxArrayString styles = subs->GetStyles(); size_t n = styles.Count(); diff --git a/core/export_fixstyle.h b/core/export_fixstyle.h index 2ea4d113f..87d781497 100644 --- a/core/export_fixstyle.h +++ b/core/export_fixstyle.h @@ -51,5 +51,5 @@ private: void Init(); public: - void ProcessSubs(AssFile *subs); + void ProcessSubs(AssFile *subs, wxWindow *export_dialog); }; diff --git a/core/export_framerate.cpp b/core/export_framerate.cpp index a5ebb8d5f..b8cac644a 100644 --- a/core/export_framerate.cpp +++ b/core/export_framerate.cpp @@ -65,7 +65,7 @@ void AssTransformFramerateFilter::Init() { /////////// // Process -void AssTransformFramerateFilter::ProcessSubs(AssFile *subs) { +void AssTransformFramerateFilter::ProcessSubs(AssFile *subs, wxWindow *export_dialog) { // Transform frame rate if (Input->IsLoaded() && Output->IsLoaded()) { if (Output->GetFrameRateType() == VFR || Output->GetAverage() != Input->GetAverage()) { diff --git a/core/export_framerate.h b/core/export_framerate.h index ff1eeed45..2cbd22206 100644 --- a/core/export_framerate.h +++ b/core/export_framerate.h @@ -68,7 +68,7 @@ private: void Init(); public: - void ProcessSubs(AssFile *subs); + void ProcessSubs(AssFile *subs, wxWindow *export_dialog); wxWindow *GetConfigDialogWindow(wxWindow *parent); void LoadSettings(bool IsDefault); }; diff --git a/core/frame_main.cpp b/core/frame_main.cpp index 07f9b45a6..e1279db4d 100644 --- a/core/frame_main.cpp +++ b/core/frame_main.cpp @@ -58,7 +58,6 @@ #include "version.h" #include "dialog_splash.h" #include "dialog_tip.h" -//#include "automation_filter.h" #include "audio_box.h" #include "video_box.h" #include "drop.h" @@ -66,6 +65,7 @@ #include "utils.h" #include "text_file_reader.h" #include "text_file_writer.h" +#include "auto4_base.h" ///////////////////////// @@ -84,12 +84,15 @@ FrameMain::FrameMain (wxArrayString args) wxPNGHandler *png = new wxPNGHandler; wxImage::AddHandler(png); + // Storage for subs-file-local scripts + local_scripts = new Automation4::ScriptManager(); + // Create menu and tool bars InitToolbar(); InitMenu(); // Create status bar - CreateStatusBar(2); + CreateStatusBar(2); // Set icon SetIcon(wxICON(wxicon)); @@ -137,6 +140,7 @@ FrameMain::FrameMain (wxArrayString args) // FrameMain destructor FrameMain::~FrameMain () { DeInitContents(); + delete local_scripts; } @@ -387,6 +391,7 @@ void FrameMain::InitMenu() { // Create Automation menu automationMenu = new wxMenu(); AppendBitmapMenuItem (automationMenu,Menu_Tools_Automation, _("&Automation..."),_("Open automation manager"), wxBITMAP(automation_toolbutton)); + automationMenu->AppendSeparator(); MenuBar->Append(automationMenu, _("&Automation")); // Create help menu @@ -596,10 +601,6 @@ void FrameMain::LoadSubtitles (wxString filename,wxString charset) { wxMessageBox(wxString(err), _T("Error"), wxOK | wxICON_ERROR, NULL); return; } -// catch (AutomationError &err) { -// wxMessageBox(wxString(_T("Automation exception: ")) + err.message, _T("Error"), wxOK | wxICON_ERROR, NULL); -// return; -// } catch (...) { wxMessageBox(_T("Unknown error"), _T("Error"), wxOK | wxICON_ERROR, NULL); return; @@ -808,15 +809,6 @@ void FrameMain::SynchronizeProject(bool fromSubs) { long videoAr = 0; double videoArValue = 0.0; long videoZoom = 0; -// { -// std::list::const_iterator next = AssAutomationFilter::GetFilterList().begin(), f; -// while (next != AssAutomationFilter::GetFilterList().end()) { -// f = next++; -// AutomationScript *s = (*f)->GetScript(); -// delete (*f); -// delete s; -// } -// } // Get AR wxString arString = subs->GetScriptInfo(_T("Video Aspect Ratio")); @@ -836,40 +828,15 @@ void FrameMain::SynchronizeProject(bool fromSubs) { wxString curSubsAudio = DecodeRelativePath(subs->GetScriptInfo(_T("Audio File")),AssFile::top->filename); wxString AutoScriptString = subs->GetScriptInfo(_T("Automation Scripts")); - // Automation script -/* if (AutoScriptString != _T("")) { - wxStringTokenizer toker(AutoScriptString, _T("|"), wxTOKEN_STRTOK); - wxFileName AssFileName(subs->filename); - while (toker.HasMoreTokens()) { - wxString sfnames; - try { - sfnames = toker.GetNextToken().Trim(false).Trim(true); - wxFileName sfname(sfnames); - sfname.Normalize(wxPATH_NORM_ALL, AssFileName.GetPath()); - sfnames = sfname.GetFullPath(); - AutomationScriptFile *sfile = AutomationScriptFile::CreateFromFile(sfnames); - if (!sfile) { - wxLogWarning(_T("Automation script referenced in subtitle file not found: %s"), sfname.GetName().c_str()); - continue; - } - - //AssAutomationFilters are added to a global list when constructed, this is not a leak - new AssAutomationFilter(new AutomationScript(sfile)); - } - catch (AutomationError &err) { - wxMessageBox(wxString::Format(_T("Error loading Automation script '%s':\r\n\r\n%s"), sfnames.c_str(), err.message.c_str()), _T("Error loading Automation script"), wxOK | wxICON_ERROR, this); - } - catch (...) { - wxMessageBox(_T("An unknown error occurred loading an Automation script referenced in the subtitle file."), _T("Error loading Automation script"), wxOK | wxICON_ERROR, this); - continue; - } - } - }*/ - // Check if there is anything to change int autoLoadMode = Options.AsInt(_T("Autoload linked files")); bool hasToLoad = false; - if (curSubsAudio != audioBox->audioName || curSubsVFR != VFR_Output.GetFilename() || curSubsVideo != videoBox->videoDisplay->videoName || curSubsKeyframes != videoBox->videoDisplay->GetKeyFramesName()) { + if (curSubsAudio != audioBox->audioName || + curSubsVFR != VFR_Output.GetFilename() || + curSubsVideo != videoBox->videoDisplay->videoName || + curSubsKeyframes != videoBox->videoDisplay->GetKeyFramesName() || + !AutoScriptString.IsEmpty() || + local_scripts->GetScripts().size() > 0) { hasToLoad = true; } @@ -907,6 +874,38 @@ void FrameMain::SynchronizeProject(bool fromSubs) { if (curSubsAudio == _T("?video")) LoadAudio(_T(""),true); else LoadAudio(curSubsAudio); } + + // Automation scripts + local_scripts->RemoveAll(); + wxStringTokenizer tok(AutoScriptString, _T("|"), wxTOKEN_STRTOK); + wxFileName subsfn(subs->filename); + wxString autobasefn(Options.AsText(_T("Automation Base Path"))); + while (tok.HasMoreTokens()) { + wxString sfnames = tok.GetNextToken().Trim(true).Trim(false); + wxString sfnamel = sfnames.Left(1); + sfnames.Remove(0, 1); + wxString basepath; + if (sfnamel == _T("~")) { + basepath = subsfn.GetPath(); + } else if (sfnamel == _T("$")) { + basepath = autobasefn; + } else if (sfnamel == _T("/")) { + basepath = _T(""); + } else { + wxLogWarning(_T("Automation Script referenced with unknown location specifier character.\nLocation specifier found: %s\nFilename specified: %s"), + sfnamel.c_str(), sfnames.c_str()); + continue; + } + wxFileName sfname(sfnames); + sfname.MakeAbsolute(basepath); + if (sfname.FileExists()) { + sfnames = sfname.GetFullPath(); + local_scripts->Add(Automation4::ScriptFactory::CreateFromFile(sfnames)); + } else { + wxLogWarning(_T("Automation Script referenced could not be found.\nFilename specified: %s%s\nSearched relative to: %s\nResolved filename: %s"), + sfnamel.c_str(), sfnames.c_str(), basepath.c_str(), sfname.GetFullPath().c_str()); + } + } } // Display @@ -939,21 +938,38 @@ void FrameMain::SynchronizeProject(bool fromSubs) { subs->SetScriptInfo(_T("VFR File"),MakeRelativePath(VFR_Output.GetFilename(),AssFile::top->filename)); subs->SetScriptInfo(_T("Keyframes File"),MakeRelativePath(videoBox->videoDisplay->GetKeyFramesName(),AssFile::top->filename)); - // Create list of Automation scripts -/* wxString scripts; - std::list::const_iterator f = AssAutomationFilter::GetFilterList().begin(); - wxFileName AssFileName(subs->filename); - for (;f != AssAutomationFilter::GetFilterList().end(); ++f) { - if (!(*f)->GetScript()->filename.empty()) { - wxFileName fn((*f)->GetScript()->filename); - fn.MakeRelativeTo(AssFileName.GetPath()); - scripts += wxString::Format(_T("%s|"), fn.GetFullPath().c_str()); + // Store Automation script data + // Algorithm: + // 1. If script filename has Automation Base Path as a prefix, the path is relative to that (ie. "$") + // 2. Otherwise try making it relative to the subs filename + // 3. If step 2 failed, or absolut path is shorter than path relative to subs, use absolute path ("/") + // 4. Otherwise, use path relative to subs ("~") + wxString scripts_string; + wxString autobasefn(Options.AsText(_T("Automation Base Path"))); + + const std::vector &scripts = local_scripts->GetScripts(); + for (int i = 0; i < scripts.size(); i++) { + Automation4::Script *script = scripts[i]; + + if (i != 0) + scripts_string += _T("|"); + + wxString autobase_rel, subsfile_rel; + wxString scriptfn(script->GetFilename()); + autobase_rel = MakeRelativePath(scriptfn, autobasefn); + subsfile_rel = MakeRelativePath(scriptfn, AssFile::top->filename); + + if (autobase_rel.size() <= scriptfn.size() && autobase_rel.size() <= subsfile_rel.size()) { + scriptfn = _T("$") + autobase_rel; + } else if (subsfile_rel.size() <= scriptfn.size() && subsfile_rel.size() <= autobase_rel.size()) { + scriptfn = _T("~") + subsfile_rel; + } else { + scriptfn = _T("/") + wxFileName(scriptfn).GetFullPath(wxPATH_UNIX); } + + scripts_string += scriptfn; } - if (!scripts.empty()) { - scripts.RemoveLast(); - subs->SetScriptInfo(_T("Automation Scripts"), scripts); - }*/ + subs->SetScriptInfo(_T("Automation 4 Scripts"), scripts_string); } } diff --git a/core/frame_main.h b/core/frame_main.h index 54e3506bb..d378a4c0a 100644 --- a/core/frame_main.h +++ b/core/frame_main.h @@ -41,6 +41,7 @@ /////////////////// // Include headers #include +#include //////////////////// @@ -53,6 +54,7 @@ class SubsEditBox; class AudioBox; class VideoBox; class AegisubFileDropTarget; +namespace Automation4 { class FeatureMacro; class ScriptManager; }; //////////////////// @@ -96,6 +98,11 @@ private: wxWindow *PreviousFocus; + Automation4::ScriptManager *local_scripts; + + std::vector activeMacroItems; + void AddMacroMenuItems(wxMenu *menu, const std::vector ¯os); + void InitToolbar(); void InitContents(); void DeInitContents(); @@ -197,7 +204,6 @@ private: void OnOpenTranslation (wxCommandEvent &event); void OnOpenSpellCheck (wxCommandEvent &event); void OnOpenFontsCollector (wxCommandEvent &event); - void OnOpenAutomation (wxCommandEvent &event); void OnSnapSubsStartToVid (wxCommandEvent &event); void OnSnapSubsEndToVid (wxCommandEvent &event); void OnSnapVidToSubsStart (wxCommandEvent &event); @@ -213,6 +219,9 @@ private: void OnOpenOptions (wxCommandEvent &event); void OnGridEvent (wxCommandEvent &event); + void OnOpenAutomation (wxCommandEvent &event); + void OnAutomationMacro(wxCommandEvent &event); + void OnNextFrame(wxCommandEvent &event); void OnPrevFrame(wxCommandEvent &event); void OnFocusSeek(wxCommandEvent &event); @@ -405,6 +414,7 @@ enum { Menu_Audio_Recent = 2400, Menu_Timecodes_Recent = 2500, Menu_Keyframes_Recent = 2600, + Menu_Automation_Macro = 2700, }; diff --git a/core/frame_main_events.cpp b/core/frame_main_events.cpp index 5c2d9c297..a124ccf16 100644 --- a/core/frame_main_events.cpp +++ b/core/frame_main_events.cpp @@ -63,7 +63,6 @@ #include "main.h" #include "dialog_fonts_collector.h" #include "dialog_about.h" -//#include "automation_gui.h" #include "dialog_export.h" #include "audio_box.h" #include "dialog_selection.h" @@ -82,6 +81,8 @@ #include "dialog_progress.h" #include "dialog_options.h" #include "utils.h" +#include "auto4_base.h" +#include "dialog_automation.h" //////////////////// @@ -121,6 +122,7 @@ BEGIN_EVENT_TABLE(FrameMain, wxFrame) EVT_MENU_RANGE(Menu_Audio_Recent,Menu_Audio_Recent+99, FrameMain::OnOpenRecentAudio) EVT_MENU_RANGE(Menu_Timecodes_Recent,Menu_Timecodes_Recent+99, FrameMain::OnOpenRecentTimecodes) EVT_MENU_RANGE(Menu_Keyframes_Recent,Menu_Keyframes_Recent+99, FrameMain::OnOpenRecentKeyframes) + EVT_MENU_RANGE(Menu_Automation_Macro,Menu_Automation_Macro+99, FrameMain::OnAutomationMacro) EVT_MENU_RANGE(MENU_GRID_START+1,MENU_GRID_END-1,FrameMain::OnGridEvent) EVT_MENU(Menu_File_Exit, FrameMain::OnExit) @@ -235,6 +237,15 @@ void FrameMain::OnMenuOpen (wxMenuEvent &event) { //Freeze(); wxMenu *curMenu = event.GetMenu(); + // Start by cleaning up in macro menu items + for (int i = 0; i < activeMacroItems.size(); i++) { + wxMenu *p = 0; + wxMenuItem *it = MenuBar->FindItem(Menu_Automation_Macro + i, &p); + if (it) + p->Delete(it); + } + activeMacroItems.clear(); + // File menu if (curMenu == fileMenu) { // Wipe recent @@ -472,10 +483,33 @@ void FrameMain::OnMenuOpen (wxMenuEvent &event) { MenuBar->Enable(Menu_Edit_Paste_Over,state); } + // Automation menu + else if (curMenu == automationMenu) { + AddMacroMenuItems(automationMenu, wxGetApp().global_scripts->GetMacros(Automation4::MACROMENU_ALL)); + AddMacroMenuItems(automationMenu, local_scripts->GetMacros(Automation4::MACROMENU_ALL)); + } + //Thaw(); } +////////////////////////////// +// Macro menu creation helper +void FrameMain::AddMacroMenuItems(wxMenu *menu, const std::vector ¯os) { + if (macros.empty()) { + return; + } + + int id = activeMacroItems.size();; + for (std::vector::const_iterator i = macros.begin(); i != macros.end(); ++i) { + wxMenuItem * m = menu->Append(Menu_Automation_Macro + id, (*i)->GetName(), (*i)->GetDescription()); + m->Enable((*i)->Validate(SubsBox->ass, SubsBox->GetAbsoluteSelection(), SubsBox->GetFirstSelRow())); + activeMacroItems.push_back(*i); + id++; + } +} + + /////////////////////////////// // Open recent subs menu entry void FrameMain::OnOpenRecentSubs(wxCommandEvent &event) { @@ -919,9 +953,18 @@ void FrameMain::OnOpenOptions (wxCommandEvent &event) { // Open Automation void FrameMain::OnOpenAutomation (wxCommandEvent &event) { videoBox->videoDisplay->Stop(); -// DialogAutomationManager *automan = new DialogAutomationManager(this, SubsBox); -// automan->ShowModal(); -// delete automan; + DialogAutomation dlg(this, local_scripts); + dlg.ShowModal(); +} + + +/////////////////////////////////////////////////////////// +// General handler for all Automation-generated menu items +void FrameMain::OnAutomationMacro (wxCommandEvent &event) { + AssFile *oldtop = AssFile::top; + activeMacroItems[event.GetId()-Menu_Automation_Macro]->Process(SubsBox->ass, SubsBox->GetAbsoluteSelection(), SubsBox->GetFirstSelRow(), this); + // check if modifications were made and put on undo stack + SubsBox->LoadFromAss(AssFile::top, true, true); } diff --git a/core/main.cpp b/core/main.cpp index 9bb0f58db..7713677dd 100644 --- a/core/main.cpp +++ b/core/main.cpp @@ -53,6 +53,7 @@ #include "ass_time.h" #include "ass_dialogue.h" #include "subs_grid.h" +#include "auto4_base.h" /////////////////// @@ -100,6 +101,9 @@ bool AegisubApp::OnInit() { locale.Init(wxLocale::GetSystemLanguage()); #endif + // Load Automation scripts + global_scripts = new Automation4::AutoloadScriptManager(Options.AsText(_T("Automation Autoload Path"))); + // Load export filters AssExportFilterChain::PrepareFilters(); diff --git a/core/main.h b/core/main.h index c1a4ba99c..2748a4054 100644 --- a/core/main.h +++ b/core/main.h @@ -49,6 +49,7 @@ ////////////// // Prototypes class FrameMain; +namespace Automation4 { class AutoloadScriptManager; } //////////////////////////////// @@ -61,6 +62,7 @@ private: public: AegisubLocale locale; FrameMain *frame; + Automation4::AutoloadScriptManager *global_scripts; static wxString fullPath; static wxString folderName; @@ -87,6 +89,8 @@ public: DECLARE_EVENT_TABLE() }; +DECLARE_APP(AegisubApp) + //////////////// // Stack walker diff --git a/core/options.cpp b/core/options.cpp index 4099586b1..2f6e2eb77 100644 --- a/core/options.cpp +++ b/core/options.cpp @@ -127,7 +127,10 @@ void OptionsManager::LoadDefaults() { SetText(_T("Audio Downmixer"),_T("ConvertToMono")); // Automation - SetText(_T("Automation Include Path"), AegisubApp::folderName + _T("automation/include")); + SetText(_T("Automation Base Path"), AegisubApp::folderName + _T("automation/")); + SetText(_T("Automation Include Path"), AegisubApp::folderName + _T("automation/include/")); + SetText(_T("Automation Autoload Path"), AegisubApp::folderName + _T("automation/autoload/")); + SetInt(_T("Automation Trace Level"), 3); // Edit box cosmetic SetBool(_T("Syntax Highlight Enabled"),true); diff --git a/core/subs_grid.cpp b/core/subs_grid.cpp index 02aab6cca..f5f269d1e 100644 --- a/core/subs_grid.cpp +++ b/core/subs_grid.cpp @@ -1390,3 +1390,28 @@ void SubtitlesGrid::SetVideoToSubs(bool start) { video->JumpToFrame(VFR_Output.GetFrameAtTime(cur->End.GetMS(),false)); } } + + +///////////////////////////////////////////////////////////////////// +// Retrieve a list of selected lines in the actual ASS file +// (ie. not as displayed in the grid but as represented in the file) +std::vector SubtitlesGrid::GetAbsoluteSelection() { + std::vector result; + result.reserve(GetNumberSelection()); + + int nrows = GetRows(); + for (int i = 0; i != nrows; ++i) { + if (selMap.at(i)) { + entryIter l = diagMap.at(i); + int n = 0; + for (std::list::iterator j = ass->Line.begin(); j != ass->Line.end(); ++j, ++n) { + if (j == l) { + result.push_back(n); + break; + } + } + } + } + + return result; +} diff --git a/core/subs_grid.h b/core/subs_grid.h index 94dbf3d7f..af06d4178 100644 --- a/core/subs_grid.h +++ b/core/subs_grid.h @@ -128,6 +128,8 @@ public: void CutLines(wxArrayInt lines); void PasteLines(int pos,bool over=false); + std::vector GetAbsoluteSelection(); + DECLARE_EVENT_TABLE() }; diff --git a/core/utils.cpp b/core/utils.cpp index 407b1588c..3fe1490cc 100644 --- a/core/utils.cpp +++ b/core/utils.cpp @@ -110,7 +110,7 @@ wxString DecodeRelativePath(wxString _path,wxString reference) { wxFileName path(_path); wxFileName refPath(reference); if (!path.IsAbsolute()) path.MakeAbsolute(refPath.GetPath()); - return path.GetFullPath(); + return path.GetFullPath(wxPATH_UNIX); // also works on windows }