diff --git a/aegisub/ass_time.cpp b/aegisub/ass_time.cpp index c7ad3f8b0..06be9db01 100644 --- a/aegisub/ass_time.cpp +++ b/aegisub/ass_time.cpp @@ -131,12 +131,12 @@ void AssTime::SetMS (int _ms) { //////////////// // ASS Formated -wxString AssTime::GetASSFormated () { +wxString AssTime::GetASSFormated (bool msPrecision) { int h,m,s,ms; int _ms = time; // Centisecond precision - if (!UseMSPrecision) _ms = _ms/10*10; + if (!UseMSPrecision && !msPrecision) _ms = _ms/10*10; // Reset h = m = s = ms = 0; diff --git a/aegisub/ass_time.h b/aegisub/ass_time.h index 70e2b5285..09c1844cb 100644 --- a/aegisub/ass_time.h +++ b/aegisub/ass_time.h @@ -57,7 +57,7 @@ public: void SetMS(int ms); // Sets values to miliseconds void ParseASS(const wxString text); // Sets value to text-form time, in ASS format void ParseSRT(const wxString text); // Sets value to text-form time, in SRT format - wxString GetASSFormated(); // Returns the ASS representation of time + wxString GetASSFormated(bool ms=false); // Returns the ASS representation of time wxString GetSRTFormated(); // Returns the SRT representation of time void UpdateFromTextCtrl(wxTextCtrl *ctrl); // Reads value from text control and updates both }; diff --git a/aegisub/subtitle_format_ttxt.cpp b/aegisub/subtitle_format_ttxt.cpp index 59391a0a1..984f33c81 100644 --- a/aegisub/subtitle_format_ttxt.cpp +++ b/aegisub/subtitle_format_ttxt.cpp @@ -37,9 +37,8 @@ /////////// // Headers #include "subtitle_format_ttxt.h" -#include "ass_dialogue.h" #include "ass_time.h" -#include +#include "ass_file.h" /////////////////// @@ -61,8 +60,8 @@ wxArrayString TTXTSubtitleFormat::GetReadWildcards() { /////////////////////// // Get write wildcards wxArrayString TTXTSubtitleFormat::GetWriteWildcards() { - //return GetReadWildcards(); - return wxArrayString(); + return GetReadWildcards(); + //return wxArrayString(); } @@ -76,8 +75,8 @@ bool TTXTSubtitleFormat::CanReadFile(wxString filename) { ///////////////////// // Can write a file? bool TTXTSubtitleFormat::CanWriteFile(wxString filename) { - return false; - //return (filename.Right(5).Lower() == _T(".ttxt")); + //return false; + return (filename.Right(5).Lower() == _T(".ttxt")); } @@ -96,77 +95,24 @@ void TTXTSubtitleFormat::ReadFile(wxString filename,wxString forceEncoding) { // Check version wxString verStr = doc.GetRoot()->GetPropVal(_T("version"),_T("")); - int version = -1; + version = -1; if (verStr == _T("1.0")) version = 0; else if (verStr == _T("1.1")) version = 1; else throw wxString(_T("Unknown TTXT version: ") + verStr); // Get children - AssDialogue *diag = NULL; + diag = NULL; wxXmlNode *child = doc.GetRoot()->GetChildren(); int lines = 0; while (child) { // Line if (child->GetName() == _T("TextSample")) { - // Get properties - wxString sampleTime = child->GetPropVal(_T("sampleTime"),_T("00:00:00.000")); - wxString text; - if (version == 0) text = child->GetPropVal(_T("text"),_T("")); - else text = child->GetNodeContent(); - - // Parse time - AssTime time; - time.ParseASS(sampleTime); - - // Set end time of last line - if (diag) diag->End = time; - diag = NULL; - - // Create line - if (!text.IsEmpty()) { - // Create dialogue - diag = new AssDialogue(); - diag->Start = time; - diag->End.SetMS(time.GetMS()+5000); - diag->group = _T("[Events]"); - diag->Style = _T("Default"); - diag->Comment = false; - diag->StartMS = diag->Start.GetMS(); - - // Process text for 1.0 - if (version == 0) { - wxString finalText; - finalText.Alloc(text.Length()); - bool in = false; - bool first = true; - for (size_t i=0;iText = finalText; - } - - // Process text for 1.1 - else { - text.Replace(_T("\r"),_T("")); - text.Replace(_T("\n"),_T("\\N")); - diag->Text = text; - } - - // Insert dialogue - diag->UpdateData(); - Line->push_back(diag); - lines++; - } + if (ProcessLine(child)) lines++; } // Header else if (child->GetName() == _T("TextStreamHeader")) { - // TODO + ProcessHeader(child); } // Proceed to next child @@ -186,7 +132,213 @@ void TTXTSubtitleFormat::ReadFile(wxString filename,wxString forceEncoding) { } +/////////////////////////// +// Process a dialogue line +bool TTXTSubtitleFormat::ProcessLine(wxXmlNode *node) { + // Get properties + wxString sampleTime = node->GetPropVal(_T("sampleTime"),_T("00:00:00.000")); + wxString text; + if (version == 0) text = node->GetPropVal(_T("text"),_T("")); + else text = node->GetNodeContent(); + + // Parse time + AssTime time; + time.ParseASS(sampleTime); + + // Set end time of last line + if (diag) diag->End = time; + diag = NULL; + + // Create line + if (!text.IsEmpty()) { + // Create dialogue + diag = new AssDialogue(); + diag->Start = time; + diag->End.SetMS(time.GetMS()+5000); + diag->group = _T("[Events]"); + diag->Style = _T("Default"); + diag->Comment = false; + diag->StartMS = diag->Start.GetMS(); + + // Process text for 1.0 + if (version == 0) { + wxString finalText; + finalText.Alloc(text.Length()); + bool in = false; + bool first = true; + for (size_t i=0;iText = finalText; + } + + // Process text for 1.1 + else { + text.Replace(_T("\r"),_T("")); + text.Replace(_T("\n"),_T("\\N")); + diag->Text = text; + } + + // Insert dialogue + diag->UpdateData(); + Line->push_back(diag); + return true; + } + + else return false; +} + + +////////////////////// +// Process the header +void TTXTSubtitleFormat::ProcessHeader(wxXmlNode *node) { + // TODO +} + + //////////////// // Write a file void TTXTSubtitleFormat::WriteFile(wxString filename,wxString encoding) { + // Convert to TTXT + CreateCopy(); + ConvertToTTXT(); + + // Create XML structure + wxXmlDocument doc; + wxXmlNode *root = new wxXmlNode(NULL,wxXML_ELEMENT_NODE,_T("TextStream")); + root->AddProperty(_T("version"),_T("1.1")); + doc.SetRoot(root); + wxXmlNode *node,*prevNode; + + // Create header + node = new wxXmlNode(root,wxXML_ELEMENT_NODE,_T("TextStreamHeader")); + node->AddProperty(_T("width"),_T("400")); + node->AddProperty(_T("height"),_T("60")); + root->AddChild(node); + prevNode = node; + + // Create lines + int i=1; + using std::list; + AssDialogue *prev = NULL; + for (list::iterator cur=Line->begin();cur!=Line->end();cur++) { + AssDialogue *current = AssEntry::GetAsDialogue(*cur); + if (current) { + // Get line + if (current->Comment) throw _T("Unexpected line type (comment)"); + + // If it doesn't start at the end of previous, add blank + if (prev && prev->End != current->Start) { + node = new wxXmlNode(root,wxXML_ELEMENT_NODE,_T("TextSample")); + node->AddProperty(_T("startTime"),_T("0") + prev->End.GetASSFormated(true)); + node->AddProperty(_T("xml:space"),_T("preserve")); + node->SetContent(_T("")); + node->SetNext(prevNode); + prevNode = node; + } + + // Generate and insert node + node = new wxXmlNode(root,wxXML_ELEMENT_NODE,_T("TextSample")); + node->AddProperty(_T("startTime"),_T("0") + current->Start.GetASSFormated(true)); + node->AddProperty(_T("xml:space"),_T("preserve")); + node->SetContent(current->Text); + node->SetNext(prevNode); + prevNode = node; + + // Set as previous + prev = current; + + i++; + } + else throw _T("Unexpected line type"); + } + + // Save XML + //prevNode->SetNext(NULL); + doc.Save(filename); + + // Clear + ClearCopy(); +} + + +/////////////////////// +// Convert line to TTXT +void TTXTSubtitleFormat::DialogueToTTXT(AssDialogue *current,std::list::iterator prev) { + using std::list; + AssDialogue *previous; + if (prev != Line->end()) previous = AssEntry::GetAsDialogue(*prev); + else previous = NULL; + + // Strip ASS tags + current->StripTags(); + + // Join equal lines + if (previous != NULL) { + if (previous->Text == current->Text) { + if (abs(current->Start.GetMS() - previous->End.GetMS()) < 20) { + current->Start = (current->Start < previous->Start ? current->Start : previous->Start); + current->End = (current->End > previous->End ? current->End : previous->End); + delete *prev; + Line->erase(prev); + } + } + } + + // Fix line breaks + current->Text.Replace(_T("\\n"),_T("\r\n"),true); + current->Text.Replace(_T("\\N"),_T("\r\n"),true); + while (current->Text.Replace(_T("\r\n\r\n"),_T("\r\n"),true)); +} + + +////////////////////////////// +// Converts whole file to TTXT +void TTXTSubtitleFormat::ConvertToTTXT () { + using std::list; + + // Sort lines + Line->sort(LessByPointedToValue()); + + // Prepare processing + list::iterator next; + list::iterator prev = Line->end(); + AssTime lastTime; + + // Process lines + bool notfirst = false; + for (list::iterator cur=Line->begin();cur!=Line->end();cur=next) { + next = cur; + next++; + + // Dialogue line (not comment) + AssDialogue *current = AssEntry::GetAsDialogue(*cur); + if (current && !current->Comment) { + DialogueToTTXT(current,prev); + notfirst = true; + prev = cur; + lastTime = current->End; + } + + // Other line, delete it + else { + delete *cur; + Line->erase(cur); + } + } + + // Insert blank line at the end + AssDialogue *diag = new AssDialogue(); + diag->Start = lastTime; + diag->End.SetMS(lastTime.GetMS()+5000); + diag->group = _T("[Events]"); + diag->Style = _T("Default"); + diag->Comment = false; + diag->StartMS = diag->Start.GetMS(); + Line->push_back(diag); } diff --git a/aegisub/subtitle_format_ttxt.h b/aegisub/subtitle_format_ttxt.h index 5342b8544..7d9d60f3d 100644 --- a/aegisub/subtitle_format_ttxt.h +++ b/aegisub/subtitle_format_ttxt.h @@ -39,12 +39,24 @@ /////////// // Headers +#include "ass_dialogue.h" #include "subtitle_format.h" +#include ////////////////////// // TTXT reader/writer class TTXTSubtitleFormat : public SubtitleFormat { +private: + int version; + AssDialogue *diag; + + bool ProcessLine(wxXmlNode *node); + void ProcessHeader(wxXmlNode *node); + + void ConvertToTTXT(); + void DialogueToTTXT(AssDialogue *current,std::list::iterator prev); + public: wxString GetName(); wxArrayString GetReadWildcards();