2006-01-16 22:02:54 +01:00
|
|
|
// Copyright (c) 2005, Rodrigo Braz Monteiro
|
|
|
|
// 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.
|
|
|
|
//
|
2009-07-29 07:43:02 +02:00
|
|
|
// Aegisub Project http://www.aegisub.org/
|
2006-01-16 22:02:54 +01:00
|
|
|
//
|
2009-07-29 07:43:02 +02:00
|
|
|
// $Id$
|
|
|
|
|
|
|
|
/// @file ass_file.cpp
|
|
|
|
/// @brief Overall storage of subtitle files, undo management and more
|
|
|
|
/// @ingroup subs_storage
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2009-01-04 07:31:48 +01:00
|
|
|
#include "config.h"
|
|
|
|
|
2009-09-10 15:06:40 +02:00
|
|
|
#ifndef AGI_PRE
|
2010-06-22 02:03:33 +02:00
|
|
|
#include <algorithm>
|
2006-01-19 02:42:39 +01:00
|
|
|
#include <fstream>
|
2009-09-10 15:06:40 +02:00
|
|
|
#include <list>
|
|
|
|
|
2006-07-01 06:35:50 +02:00
|
|
|
#include <wx/filename.h>
|
2007-09-12 01:22:26 +02:00
|
|
|
#include <wx/log.h>
|
|
|
|
#include <wx/msgdlg.h>
|
2009-09-10 15:06:40 +02:00
|
|
|
#endif
|
|
|
|
|
2006-06-30 23:59:20 +02:00
|
|
|
#include "ass_attachment.h"
|
2009-09-10 15:06:40 +02:00
|
|
|
#include "ass_dialogue.h"
|
2006-01-16 22:02:54 +01:00
|
|
|
#include "ass_exporter.h"
|
2009-09-10 15:06:40 +02:00
|
|
|
#include "ass_file.h"
|
|
|
|
#include "ass_override.h"
|
|
|
|
#include "ass_style.h"
|
2010-06-03 22:31:43 +02:00
|
|
|
#include "charset_detect.h"
|
2010-05-21 03:13:36 +02:00
|
|
|
#include "compat.h"
|
|
|
|
#include "main.h"
|
2006-01-16 22:02:54 +01:00
|
|
|
#include "options.h"
|
2009-09-10 15:06:40 +02:00
|
|
|
#include "subtitle_format.h"
|
2006-01-16 22:02:54 +01:00
|
|
|
#include "text_file_reader.h"
|
|
|
|
#include "text_file_writer.h"
|
|
|
|
#include "version.h"
|
2009-09-10 15:06:40 +02:00
|
|
|
#include "vfr.h"
|
Note: This was done using a script! it's far from perfect but 95% of the work has been done already formatting-wise.
Document all functions, class, struct, union, enum, macro, variable, typedefs. This isn't the actual document in itself but empty documentation using any old documentation if it was there.
This was done using exuberant ctags to get tag info, then a TCL script to parse/remove old comments and convert them into Doxygen-style.
Some notes:
* Anything labeled 'DOCME' needs to be documented, @param and @return have been left blank as it would be annoying to delete the 'DOCME' from every one of those.
* Some multiline comments may have been munged into single line comments
* Leave the /// comments above global variables with a space, if they're harder to read then we'll be less likey to use them.
* Enum comments can go after the enumeration itself '[value] /// comment'
* include/aegisub/*.h haven't been converted yet, this will be done in a later commit
* Some documentation blocks are in the wrong place, in the .h when it should be in the .cpp, or vice versa.
See http://devel.aegisub.org/wiki/Doxygen for some details on Doxygen and a 'style guide'.
Originally committed to SVN as r3312.
2009-07-30 00:59:22 +02:00
|
|
|
|
2010-05-19 02:44:44 +02:00
|
|
|
/// @brief AssFile constructor
|
2006-01-16 22:02:54 +01:00
|
|
|
AssFile::AssFile () {
|
|
|
|
AssOverrideTagProto::LoadProtos();
|
|
|
|
Clear();
|
|
|
|
}
|
|
|
|
|
Note: This was done using a script! it's far from perfect but 95% of the work has been done already formatting-wise.
Document all functions, class, struct, union, enum, macro, variable, typedefs. This isn't the actual document in itself but empty documentation using any old documentation if it was there.
This was done using exuberant ctags to get tag info, then a TCL script to parse/remove old comments and convert them into Doxygen-style.
Some notes:
* Anything labeled 'DOCME' needs to be documented, @param and @return have been left blank as it would be annoying to delete the 'DOCME' from every one of those.
* Some multiline comments may have been munged into single line comments
* Leave the /// comments above global variables with a space, if they're harder to read then we'll be less likey to use them.
* Enum comments can go after the enumeration itself '[value] /// comment'
* include/aegisub/*.h haven't been converted yet, this will be done in a later commit
* Some documentation blocks are in the wrong place, in the .h when it should be in the .cpp, or vice versa.
See http://devel.aegisub.org/wiki/Doxygen for some details on Doxygen and a 'style guide'.
Originally committed to SVN as r3312.
2009-07-30 00:59:22 +02:00
|
|
|
/// @brief AssFile destructor
|
2006-01-16 22:02:54 +01:00
|
|
|
AssFile::~AssFile() {
|
|
|
|
Clear();
|
|
|
|
}
|
|
|
|
|
2010-06-03 22:31:43 +02:00
|
|
|
void AssFile::Load (const wxString &_filename,wxString charset,bool addToRecent) {
|
2010-06-20 21:03:05 +02:00
|
|
|
bool ok = false;
|
2006-01-16 22:02:54 +01:00
|
|
|
|
|
|
|
try {
|
|
|
|
// Try to open file
|
2006-10-20 00:53:06 +02:00
|
|
|
FILE *file;
|
|
|
|
#ifdef WIN32
|
|
|
|
file = _tfopen(_filename.c_str(), _T("r"));
|
|
|
|
#else
|
2006-10-24 00:17:27 +02:00
|
|
|
file = fopen(_filename.mb_str(*wxConvFileName), "r");
|
2006-10-20 00:53:06 +02:00
|
|
|
#endif
|
|
|
|
if (!file) {
|
2006-01-16 22:02:54 +01:00
|
|
|
throw _T("Unable to open file \"") + _filename + _T("\". Check if it exists and if you have permissions to read it.");
|
|
|
|
}
|
2006-10-20 00:53:06 +02:00
|
|
|
fclose(file);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
|
|
|
// Find file encoding
|
2010-06-03 22:31:43 +02:00
|
|
|
if (charset.empty()) {
|
|
|
|
charset = CharSetDetect::GetEncoding(_filename);
|
|
|
|
}
|
2006-01-16 22:02:54 +01:00
|
|
|
|
|
|
|
// Generic preparation
|
|
|
|
Clear();
|
|
|
|
|
2006-02-27 01:06:46 +01:00
|
|
|
// Get proper format reader
|
2006-02-27 22:57:10 +01:00
|
|
|
SubtitleFormat *reader = SubtitleFormat::GetReader(_filename);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2006-02-27 01:06:46 +01:00
|
|
|
// Read file
|
|
|
|
if (reader) {
|
|
|
|
reader->SetTarget(this);
|
2010-06-03 22:31:43 +02:00
|
|
|
reader->ReadFile(_filename,charset);
|
2010-06-20 21:03:05 +02:00
|
|
|
ok = true;
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Couldn't find a type
|
2006-02-27 01:06:46 +01:00
|
|
|
else throw _T("Unknown file type.");
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// String error
|
2006-04-14 18:46:38 +02:00
|
|
|
catch (const wchar_t *except) {
|
2006-01-16 22:02:54 +01:00
|
|
|
wxMessageBox(except,_T("Error loading file"),wxICON_ERROR | wxOK);
|
|
|
|
}
|
|
|
|
|
|
|
|
catch (wxString except) {
|
|
|
|
wxMessageBox(except,_T("Error loading file"),wxICON_ERROR | wxOK);
|
2010-06-20 21:03:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Real exception
|
|
|
|
catch (agi::Exception &e) {
|
|
|
|
wxMessageBox(wxString(e.GetChainedMessage().c_str(), wxConvUTF8), L"Error loading file", wxICON_ERROR|wxOK);
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Other error
|
|
|
|
catch (...) {
|
|
|
|
wxMessageBox(_T("Unknown error"),_T("Error loading file"),wxICON_ERROR | wxOK);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify loading
|
|
|
|
if (ok) filename = _filename;
|
|
|
|
else LoadDefault();
|
|
|
|
|
|
|
|
// Set general data
|
|
|
|
loaded = true;
|
|
|
|
|
|
|
|
// Add comments and set vars
|
2006-05-07 14:38:33 +02:00
|
|
|
AddComment(_T("Script generated by Aegisub ") + GetAegisubLongVersionString());
|
2010-01-06 06:23:58 +01:00
|
|
|
AddComment(_T("http://www.aegisub.org/"));
|
2006-01-16 22:02:54 +01:00
|
|
|
SetScriptInfo(_T("ScriptType"),_T("v4.00+"));
|
2006-12-26 05:48:53 +01:00
|
|
|
|
|
|
|
// Add to recent
|
|
|
|
if (addToRecent) AddToRecent(_filename);
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void AssFile::Save(wxString _filename,bool setfilename,bool addToRecent,const wxString encoding) {
|
|
|
|
// Finds last dot
|
|
|
|
int i = 0;
|
|
|
|
for (i=(int)_filename.size();--i>=0;) {
|
|
|
|
if (_filename[i] == '.') break;
|
|
|
|
}
|
|
|
|
wxString extension = _filename.substr(i+1);
|
|
|
|
extension.Lower();
|
|
|
|
|
2006-02-27 22:57:10 +01:00
|
|
|
// Get writer
|
|
|
|
SubtitleFormat *writer = SubtitleFormat::GetWriter(_filename);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2006-02-27 22:57:10 +01:00
|
|
|
// Write file
|
|
|
|
if (writer) {
|
|
|
|
writer->SetTarget(this);
|
|
|
|
writer->WriteFile(_filename,encoding);
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2006-02-27 22:57:10 +01:00
|
|
|
// Couldn't find a type
|
|
|
|
else throw _T("Unknown file type.");
|
|
|
|
|
|
|
|
// Add to recent
|
|
|
|
if (addToRecent) AddToRecent(_filename);
|
2006-02-27 21:22:15 +01:00
|
|
|
|
|
|
|
// Done
|
|
|
|
if (setfilename) {
|
|
|
|
Modified = false;
|
|
|
|
filename = _filename;
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-01-26 23:55:42 +01:00
|
|
|
void AssFile::SaveMemory(std::vector<char> &dst,const wxString encoding) {
|
|
|
|
// Set encoding
|
|
|
|
wxString enc = encoding;
|
|
|
|
if (enc.IsEmpty()) enc = _T("UTF-8");
|
|
|
|
if (enc != _T("UTF-8")) throw _T("Memory writer only supports UTF-8 for now.");
|
|
|
|
|
2007-10-29 03:09:45 +01:00
|
|
|
// Check if subs contain at least one style
|
|
|
|
// Add a default style if they don't for compatibility with libass/asa
|
|
|
|
if (GetStyles().Count() == 0)
|
|
|
|
InsertStyle(new AssStyle());
|
|
|
|
|
2007-01-26 23:55:42 +01:00
|
|
|
// Prepare vector
|
|
|
|
dst.clear();
|
|
|
|
dst.reserve(0x4000);
|
|
|
|
|
|
|
|
// Write file
|
|
|
|
entryIter cur;
|
|
|
|
unsigned int lineSize = 0;
|
|
|
|
unsigned int targetSize = 0;
|
|
|
|
unsigned int pos = 0;
|
|
|
|
wxCharBuffer buffer;
|
|
|
|
for (cur=Line.begin();cur!=Line.end();cur++) {
|
|
|
|
// Convert
|
|
|
|
wxString temp = (*cur)->GetEntryData() + _T("\r\n");
|
|
|
|
buffer = temp.mb_str(wxConvUTF8);
|
|
|
|
lineSize = strlen(buffer);
|
|
|
|
|
|
|
|
// Raise capacity if needed
|
|
|
|
targetSize = dst.size() + lineSize;
|
|
|
|
if (dst.capacity() < targetSize) {
|
|
|
|
unsigned int newSize = dst.capacity();
|
|
|
|
while (newSize < targetSize) newSize *= 2;
|
|
|
|
dst.reserve(newSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Append line
|
|
|
|
pos = dst.size();
|
|
|
|
dst.resize(targetSize);
|
|
|
|
memcpy(&dst[pos],buffer,lineSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
void AssFile::Export(wxString _filename) {
|
|
|
|
AssExporter exporter(this);
|
|
|
|
exporter.AddAutoFilters();
|
2007-01-21 07:30:19 +01:00
|
|
|
exporter.Export(_filename,_T("UTF-8"));
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2006-06-29 00:51:33 +02:00
|
|
|
bool AssFile::CanSave() {
|
|
|
|
// ASS format?
|
2008-03-07 00:36:43 +01:00
|
|
|
wxString ext = filename.Lower().Right(4);
|
|
|
|
if (ext == _T(".ass")) return true;
|
|
|
|
|
|
|
|
// Never save texts
|
|
|
|
if (ext == _T(".txt")) return false;
|
2006-06-29 00:51:33 +02:00
|
|
|
|
|
|
|
// Check if it's a known extension
|
|
|
|
SubtitleFormat *writer = SubtitleFormat::GetWriter(filename);
|
|
|
|
if (!writer) return false;
|
|
|
|
|
2008-03-07 00:36:43 +01:00
|
|
|
// Check if format supports timing
|
|
|
|
bool canTime = true;
|
|
|
|
//if (filename.Lower().Right(4) == _T(".txt")) canTime = false;
|
|
|
|
|
2006-06-29 00:51:33 +02:00
|
|
|
// Scan through the lines
|
|
|
|
AssStyle defstyle;
|
|
|
|
AssStyle *curstyle;
|
|
|
|
AssDialogue *curdiag;
|
2006-07-01 07:15:56 +02:00
|
|
|
AssAttachment *attach;
|
2006-06-29 00:51:33 +02:00
|
|
|
for (entryIter cur=Line.begin();cur!=Line.end();cur++) {
|
|
|
|
// Check style, if anything non-default is found, return false
|
2010-05-19 02:44:52 +02:00
|
|
|
curstyle = dynamic_cast<AssStyle*>(*cur);
|
2006-06-29 00:51:33 +02:00
|
|
|
if (curstyle) {
|
|
|
|
if (curstyle->GetEntryData() != defstyle.GetEntryData()) return false;
|
|
|
|
}
|
|
|
|
|
2006-07-01 07:15:56 +02:00
|
|
|
// Check for attachments, if any is found, return false
|
2010-05-19 02:44:52 +02:00
|
|
|
attach = dynamic_cast<AssAttachment*>(*cur);
|
2006-07-01 07:15:56 +02:00
|
|
|
if (attach) return false;
|
|
|
|
|
2006-06-29 00:51:33 +02:00
|
|
|
// Check dialog
|
2010-05-19 02:44:52 +02:00
|
|
|
curdiag = dynamic_cast<AssDialogue*>(*cur);
|
2006-06-29 00:51:33 +02:00
|
|
|
if (curdiag) {
|
2008-03-07 00:36:43 +01:00
|
|
|
// Timed?
|
|
|
|
if (!canTime && (curdiag->Start.GetMS() != 0 || curdiag->End.GetMS() != 0)) return false;
|
|
|
|
|
|
|
|
// Overrides?
|
2006-06-29 00:51:33 +02:00
|
|
|
curdiag->ParseASSTags();
|
|
|
|
for (size_t i=0;i<curdiag->Blocks.size();i++) {
|
2008-01-14 01:30:00 +01:00
|
|
|
if (curdiag->Blocks[i]->GetType() != BLOCK_PLAIN) return false;
|
2006-06-29 00:51:33 +02:00
|
|
|
}
|
|
|
|
curdiag->ClearBlocks();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Success
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-06-16 08:20:14 +02:00
|
|
|
// I strongly advice you against touching this function unless you know what you're doing;
|
|
|
|
// even moving things out of order might break ASS parsing - AMZ.
|
2010-06-22 02:03:33 +02:00
|
|
|
void AssFile::AddLine(wxString data,wxString group,int &version,wxString *outGroup) {
|
2006-07-01 02:54:33 +02:00
|
|
|
// Group
|
2006-01-16 22:02:54 +01:00
|
|
|
AssEntry *entry = NULL;
|
2006-07-01 02:54:33 +02:00
|
|
|
wxString origGroup = group;
|
|
|
|
static wxString keepGroup;
|
|
|
|
if (!keepGroup.IsEmpty()) group = keepGroup;
|
2006-07-01 04:27:37 +02:00
|
|
|
if (outGroup) *outGroup = group;
|
2007-04-21 01:07:22 +02:00
|
|
|
wxString lowGroup = group.Lower();
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2006-06-30 23:59:20 +02:00
|
|
|
// Attachment
|
2007-04-21 01:07:22 +02:00
|
|
|
if (lowGroup == _T("[fonts]") || lowGroup == _T("[graphics]")) {
|
2006-06-30 23:59:20 +02:00
|
|
|
// Check if it's valid data
|
2006-07-01 01:37:30 +02:00
|
|
|
size_t dataLen = data.Length();
|
|
|
|
bool validData = (dataLen > 0) && (dataLen <= 80);
|
|
|
|
for (size_t i=0;i<dataLen;i++) {
|
2006-06-30 23:59:20 +02:00
|
|
|
if (data[i] < 33 || data[i] >= 97) validData = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Is the filename line?
|
2010-06-11 04:24:59 +02:00
|
|
|
bool isFilename = (data.StartsWith(_T("fontname: ")) || data.StartsWith(_T("filename: ")));
|
2006-06-30 23:59:20 +02:00
|
|
|
|
|
|
|
// The attachment file is static, since it is built through several calls to this
|
|
|
|
// After it's done building, it's reset to NULL
|
|
|
|
static AssAttachment *attach = NULL;
|
|
|
|
|
|
|
|
// Attachment exists, and data is over
|
|
|
|
if (attach && (!validData || isFilename)) {
|
|
|
|
attach->Finish();
|
2006-07-01 02:54:33 +02:00
|
|
|
keepGroup.Clear();
|
|
|
|
group = origGroup;
|
2007-04-21 01:07:22 +02:00
|
|
|
lowGroup = group.Lower();
|
2006-06-30 23:59:20 +02:00
|
|
|
Line.push_back(attach);
|
|
|
|
attach = NULL;
|
|
|
|
}
|
|
|
|
|
2006-07-01 01:37:30 +02:00
|
|
|
// Create attachment if needed
|
|
|
|
if (isFilename) {
|
|
|
|
attach = new AssAttachment(data.Mid(10));
|
|
|
|
attach->group = group;
|
2006-07-01 02:54:33 +02:00
|
|
|
keepGroup = group;
|
2010-05-19 02:44:44 +02:00
|
|
|
return;
|
2006-07-01 01:37:30 +02:00
|
|
|
}
|
2006-06-30 23:59:20 +02:00
|
|
|
|
2006-07-01 01:37:30 +02:00
|
|
|
// Valid data?
|
2008-11-23 03:37:25 +01:00
|
|
|
if (attach && validData) {
|
2006-06-30 23:59:20 +02:00
|
|
|
// Insert data
|
|
|
|
attach->AddData(data);
|
|
|
|
|
|
|
|
// Done building
|
|
|
|
if (data.Length() < 80) {
|
|
|
|
attach->Finish();
|
2006-07-01 02:54:33 +02:00
|
|
|
keepGroup.Clear();
|
|
|
|
group = origGroup;
|
2007-04-21 01:07:22 +02:00
|
|
|
lowGroup = group.Lower();
|
2006-06-30 23:59:20 +02:00
|
|
|
entry = attach;
|
|
|
|
attach = NULL;
|
|
|
|
}
|
2006-07-01 01:37:30 +02:00
|
|
|
|
|
|
|
// Not done
|
2006-07-01 02:54:33 +02:00
|
|
|
else {
|
2010-05-19 02:44:44 +02:00
|
|
|
return;
|
2006-07-01 02:54:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dialogue
|
2007-04-21 01:07:22 +02:00
|
|
|
if (lowGroup == _T("[events]")) {
|
2010-06-11 04:24:59 +02:00
|
|
|
if (data.StartsWith(_T("Dialogue:")) || data.StartsWith(_T("Comment:"))) {
|
2007-01-08 02:00:44 +01:00
|
|
|
AssDialogue *diag = new AssDialogue(data,version);
|
2006-07-01 02:54:33 +02:00
|
|
|
//diag->ParseASSTags();
|
|
|
|
entry = diag;
|
|
|
|
entry->group = group;
|
|
|
|
}
|
2010-06-11 04:24:59 +02:00
|
|
|
else if (data.StartsWith(_T("Format:"))) {
|
2006-07-01 02:54:33 +02:00
|
|
|
entry = new AssEntry(_T("Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text"));
|
|
|
|
entry->group = group;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Style
|
2007-04-21 01:07:22 +02:00
|
|
|
else if (lowGroup == _T("[v4+ styles]")) {
|
2010-06-11 04:24:59 +02:00
|
|
|
if (data.StartsWith(_T("Style:"))) {
|
2007-01-08 02:00:44 +01:00
|
|
|
AssStyle *style = new AssStyle(data,version);
|
2006-07-01 02:54:33 +02:00
|
|
|
entry = style;
|
|
|
|
entry->group = group;
|
|
|
|
}
|
2010-06-11 04:24:59 +02:00
|
|
|
if (data.StartsWith(_T("Format:"))) {
|
2006-07-01 02:54:33 +02:00
|
|
|
entry = new AssEntry(_T("Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding"));
|
|
|
|
entry->group = group;
|
2006-06-30 23:59:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Script info
|
2007-04-21 01:07:22 +02:00
|
|
|
else if (lowGroup == _T("[script info]")) {
|
2006-06-30 23:59:20 +02:00
|
|
|
// Comment
|
2010-06-11 04:24:59 +02:00
|
|
|
if (data.StartsWith(_T(";"))) {
|
2006-01-16 22:02:54 +01:00
|
|
|
// Skip stupid comments added by other programs
|
2006-06-30 23:59:20 +02:00
|
|
|
// Of course, we'll add our own in place later... ;)
|
2010-05-19 02:44:44 +02:00
|
|
|
return;
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
2006-06-30 23:59:20 +02:00
|
|
|
|
|
|
|
// Version
|
2010-06-11 04:24:59 +02:00
|
|
|
if (data.StartsWith(_T("ScriptType:"))) {
|
2007-01-08 02:00:44 +01:00
|
|
|
wxString versionString = data.Mid(11);
|
|
|
|
versionString.Trim(true);
|
|
|
|
versionString.Trim(false);
|
|
|
|
versionString.MakeLower();
|
|
|
|
int trueVersion;
|
|
|
|
if (versionString == _T("v4.00")) trueVersion = 0;
|
|
|
|
else if (versionString == _T("v4.00+")) trueVersion = 1;
|
|
|
|
else if (versionString == _T("v4.00++")) trueVersion = 2;
|
2007-07-18 15:46:38 +02:00
|
|
|
else throw _T("Unknown SSA file format version");
|
2007-01-08 02:00:44 +01:00
|
|
|
if (trueVersion != version) {
|
2007-01-08 02:54:02 +01:00
|
|
|
if (!(trueVersion == 2 && version == 1)) wxLogMessage(_T("Warning: File has the wrong extension."));
|
2007-01-08 02:00:44 +01:00
|
|
|
version = trueVersion;
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
}
|
2006-06-30 23:59:20 +02:00
|
|
|
|
|
|
|
// Everything
|
2006-01-16 22:02:54 +01:00
|
|
|
entry = new AssEntry(data);
|
|
|
|
entry->group = group;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Common entry
|
|
|
|
if (entry == NULL) {
|
|
|
|
entry = new AssEntry(data);
|
|
|
|
entry->group = group;
|
|
|
|
}
|
|
|
|
|
2006-06-30 23:59:20 +02:00
|
|
|
// Insert the line
|
2006-01-16 22:02:54 +01:00
|
|
|
Line.push_back(entry);
|
2010-05-19 02:44:44 +02:00
|
|
|
return;
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void AssFile::Clear () {
|
2010-06-11 04:25:34 +02:00
|
|
|
for (entryIter cur=Line.begin();cur != Line.end();cur++) {
|
|
|
|
delete *cur;
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
Line.clear();
|
|
|
|
|
|
|
|
loaded = false;
|
|
|
|
filename = _T("");
|
|
|
|
Modified = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AssFile::LoadDefault (bool defline) {
|
|
|
|
Clear();
|
|
|
|
|
|
|
|
// Write headers
|
|
|
|
AssStyle defstyle;
|
2007-01-08 02:00:44 +01:00
|
|
|
int version = 1;
|
2010-05-19 02:44:44 +02:00
|
|
|
AddLine(_T("[Script Info]"),_T("[Script Info]"),version);
|
|
|
|
AddLine(_T("Title: Default Aegisub file"),_T("[Script Info]"),version);
|
|
|
|
AddLine(_T("ScriptType: v4.00+"),_T("[Script Info]"),version);
|
|
|
|
AddLine(_T("WrapStyle: 0"), _T("[Script Info]"),version);
|
|
|
|
AddLine(_T("PlayResX: 640"),_T("[Script Info]"),version);
|
|
|
|
AddLine(_T("PlayResY: 480"),_T("[Script Info]"),version);
|
|
|
|
AddLine(_T("ScaledBorderAndShadow: yes"),_T("[Script Info]"),version);
|
|
|
|
AddLine(_T(""),_T("[Script Info]"),version);
|
|
|
|
AddLine(_T("[V4+ Styles]"),_T("[V4+ Styles]"),version);
|
|
|
|
AddLine(_T("Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding"),_T("[V4+ Styles]"),version);
|
|
|
|
AddLine(defstyle.GetEntryData(),_T("[V4+ Styles]"),version);
|
|
|
|
AddLine(_T(""),_T("[V4+ Styles]"),version);
|
|
|
|
AddLine(_T("[Events]"),_T("[Events]"),version);
|
|
|
|
AddLine(_T("Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text"),_T("[Events]"),version);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
|
|
|
if (defline) {
|
|
|
|
AssDialogue def;
|
2010-05-19 02:44:44 +02:00
|
|
|
AddLine(def.GetEntryData(),_T("[Events]"),version);
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
loaded = true;
|
|
|
|
}
|
|
|
|
|
2010-06-22 02:03:33 +02:00
|
|
|
AssFile::AssFile (const AssFile &from) {
|
2006-01-16 22:02:54 +01:00
|
|
|
filename = from.filename;
|
|
|
|
loaded = from.loaded;
|
|
|
|
Modified = from.Modified;
|
2010-06-22 02:03:33 +02:00
|
|
|
std::transform(from.Line.begin(), from.Line.end(), std::back_inserter(Line), std::mem_fun(&AssEntry::Clone));
|
|
|
|
}
|
|
|
|
AssFile& AssFile::operator=(AssFile from) {
|
|
|
|
filename = from.filename;
|
|
|
|
loaded = from.loaded;
|
|
|
|
Modified = from.Modified;
|
|
|
|
std::swap(Line, from.Line);
|
|
|
|
return *this;
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void AssFile::InsertStyle (AssStyle *style) {
|
|
|
|
using std::list;
|
|
|
|
AssEntry *curEntry;
|
2006-01-19 02:42:39 +01:00
|
|
|
list<AssEntry*>::iterator lastStyle = Line.end();
|
2006-01-16 22:02:54 +01:00
|
|
|
list<AssEntry*>::iterator cur;
|
|
|
|
wxString lastGroup;
|
|
|
|
|
|
|
|
// Look for insert position
|
|
|
|
for (cur=Line.begin();cur!=Line.end();cur++) {
|
|
|
|
curEntry = *cur;
|
2006-02-27 03:23:50 +01:00
|
|
|
if (curEntry->GetType() == ENTRY_STYLE || (lastGroup == _T("[V4+ Styles]") && curEntry->GetEntryData().substr(0,7) == _T("Format:"))) {
|
2006-01-16 22:02:54 +01:00
|
|
|
lastStyle = cur;
|
|
|
|
}
|
|
|
|
lastGroup = curEntry->group;
|
|
|
|
}
|
|
|
|
|
|
|
|
// No styles found, add them
|
2006-01-19 02:42:39 +01:00
|
|
|
if (lastStyle == Line.end()) {
|
2006-01-16 22:02:54 +01:00
|
|
|
// Add space
|
|
|
|
curEntry = new AssEntry(_T(""));
|
|
|
|
curEntry->group = lastGroup;
|
|
|
|
Line.push_back(curEntry);
|
|
|
|
|
|
|
|
// Add header
|
|
|
|
curEntry = new AssEntry(_T("[V4+ Styles]"));
|
|
|
|
curEntry->group = _T("[V4+ Styles]");
|
|
|
|
Line.push_back(curEntry);
|
|
|
|
|
|
|
|
// Add format line
|
|
|
|
curEntry = new AssEntry(_T("Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding"));
|
|
|
|
curEntry->group = _T("[V4+ Styles]");
|
|
|
|
Line.push_back(curEntry);
|
|
|
|
|
|
|
|
// Add style
|
|
|
|
style->group = _T("[V4+ Styles]");
|
|
|
|
Line.push_back(style);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add to end of list
|
|
|
|
else {
|
|
|
|
lastStyle++;
|
|
|
|
style->group = (*lastStyle)->group;
|
|
|
|
Line.insert(lastStyle,style);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-07-01 06:08:01 +02:00
|
|
|
void AssFile::InsertAttachment (AssAttachment *attach) {
|
|
|
|
// Search for insertion point
|
|
|
|
std::list<AssEntry*>::iterator insPoint=Line.end(),cur;
|
|
|
|
for (cur=Line.begin();cur!=Line.end();cur++) {
|
|
|
|
// Check if it's another attachment
|
2010-05-19 02:44:52 +02:00
|
|
|
AssAttachment *att = dynamic_cast<AssAttachment*>(*cur);
|
2006-07-01 06:08:01 +02:00
|
|
|
if (att) {
|
|
|
|
if (attach->group == att->group) insPoint = cur;
|
|
|
|
}
|
|
|
|
|
|
|
|
// See if it's the start of group
|
|
|
|
else if ((*cur)->GetType() == ENTRY_BASE) {
|
|
|
|
AssEntry *entry = (AssEntry*) (*cur);
|
|
|
|
if (entry->GetEntryData() == attach->group) insPoint = cur;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Found point, insert there
|
|
|
|
if (insPoint != Line.end()) {
|
|
|
|
insPoint++;
|
|
|
|
Line.insert(insPoint,attach);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, create the [Fonts] group and insert
|
|
|
|
else {
|
2007-01-08 02:00:44 +01:00
|
|
|
int version=1;
|
2010-05-19 02:44:44 +02:00
|
|
|
AddLine(_T(""),Line.back()->group,version);
|
|
|
|
AddLine(attach->group,attach->group,version);
|
2006-07-01 06:08:01 +02:00
|
|
|
Line.push_back(attach);
|
2010-05-19 02:44:44 +02:00
|
|
|
AddLine(_T(""),attach->group,version);
|
2006-07-01 06:08:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-07-01 06:35:50 +02:00
|
|
|
void AssFile::InsertAttachment (wxString filename) {
|
|
|
|
wxFileName fname(filename);
|
|
|
|
AssAttachment *newAttach = new AssAttachment(fname.GetFullName());
|
|
|
|
|
|
|
|
try {
|
|
|
|
newAttach->Import(filename);
|
|
|
|
}
|
|
|
|
catch (...) {
|
|
|
|
delete newAttach;
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert
|
2007-07-30 02:25:26 +02:00
|
|
|
wxString ext = filename.Right(4).Lower();
|
|
|
|
if (ext == _T(".ttf") || ext == _T(".ttc") || ext == _T(".pfb")) newAttach->group = _T("[Fonts]");
|
2006-07-01 07:00:03 +02:00
|
|
|
else newAttach->group = _T("[Graphics]");
|
2006-07-01 06:35:50 +02:00
|
|
|
InsertAttachment(newAttach);
|
|
|
|
}
|
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
wxString AssFile::GetScriptInfo(const wxString _key) {
|
|
|
|
wxString key = _key;;
|
|
|
|
key.Lower();
|
|
|
|
key += _T(":");
|
|
|
|
std::list<AssEntry*>::iterator cur;
|
|
|
|
bool GotIn = false;
|
|
|
|
|
|
|
|
for (cur=Line.begin();cur!=Line.end();cur++) {
|
|
|
|
if ((*cur)->group == _T("[Script Info]")) {
|
|
|
|
GotIn = true;
|
2006-02-27 03:23:50 +01:00
|
|
|
wxString curText = (*cur)->GetEntryData();
|
2006-01-16 22:02:54 +01:00
|
|
|
curText.Lower();
|
|
|
|
|
2010-06-11 04:24:59 +02:00
|
|
|
if (curText.StartsWith(key)) {
|
2006-01-16 22:02:54 +01:00
|
|
|
wxString result = curText.Mid(key.length());
|
|
|
|
result.Trim(false);
|
|
|
|
result.Trim(true);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (GotIn) break;
|
|
|
|
}
|
|
|
|
|
2010-06-16 08:20:14 +02:00
|
|
|
return "";
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int AssFile::GetScriptInfoAsInt(const wxString key) {
|
|
|
|
long temp = 0;
|
|
|
|
try {
|
|
|
|
GetScriptInfo(key).ToLong(&temp);
|
|
|
|
}
|
|
|
|
catch (...) {
|
|
|
|
temp = 0;
|
|
|
|
}
|
|
|
|
return temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AssFile::SetScriptInfo(const wxString _key,const wxString value) {
|
|
|
|
wxString key = _key;;
|
|
|
|
key.Lower();
|
|
|
|
key += _T(":");
|
|
|
|
std::list<AssEntry*>::iterator cur;
|
|
|
|
std::list<AssEntry*>::iterator prev;
|
|
|
|
bool GotIn = false;
|
|
|
|
|
|
|
|
// Look for it
|
|
|
|
for (cur=Line.begin();cur!=Line.end();cur++) {
|
|
|
|
if ((*cur)->group == _T("[Script Info]")) {
|
|
|
|
GotIn = true;
|
2006-02-27 03:23:50 +01:00
|
|
|
wxString curText = (*cur)->GetEntryData();
|
2006-01-16 22:02:54 +01:00
|
|
|
curText.Lower();
|
|
|
|
|
|
|
|
// Found
|
2010-06-11 04:24:59 +02:00
|
|
|
if (curText.StartsWith(key)) {
|
2006-01-16 22:02:54 +01:00
|
|
|
// Set value
|
|
|
|
if (value != _T("")) {
|
|
|
|
wxString result = _key;
|
|
|
|
result += _T(": ");
|
|
|
|
result += value;
|
2006-02-27 03:23:50 +01:00
|
|
|
(*cur)->SetEntryData(result);
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Remove key
|
|
|
|
else {
|
|
|
|
Line.erase(cur);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-02-27 03:23:50 +01:00
|
|
|
if (!(*cur)->GetEntryData().empty()) prev = cur;
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Add
|
|
|
|
else if (GotIn) {
|
|
|
|
if (value != _T("")) {
|
|
|
|
wxString result = _key;
|
|
|
|
result += _T(": ");
|
|
|
|
result += value;
|
|
|
|
AssEntry *entry = new AssEntry(result);
|
|
|
|
entry->group = (*prev)->group;
|
|
|
|
Line.insert(++prev,entry);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-07-01 09:22:57 +02:00
|
|
|
void AssFile::GetResolution(int &sw,int &sh) {
|
|
|
|
wxString temp = GetScriptInfo(_T("PlayResY"));
|
|
|
|
if (temp.IsEmpty() || !temp.IsNumber()) {
|
2007-05-03 19:19:50 +02:00
|
|
|
sh = 0;
|
2006-07-01 09:22:57 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
long templ;
|
|
|
|
temp.ToLong(&templ);
|
|
|
|
sh = templ;
|
|
|
|
}
|
|
|
|
|
|
|
|
temp = GetScriptInfo(_T("PlayResX"));
|
|
|
|
if (temp.IsEmpty() || !temp.IsNumber()) {
|
2007-05-03 19:19:50 +02:00
|
|
|
sw = 0;
|
2006-07-01 09:22:57 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
long templ;
|
|
|
|
temp.ToLong(&templ);
|
|
|
|
sw = templ;
|
|
|
|
}
|
2007-05-03 19:19:50 +02:00
|
|
|
|
|
|
|
// Gabest logic?
|
|
|
|
if (sw == 0 && sh == 0) {
|
|
|
|
sw = 384;
|
|
|
|
sh = 288;
|
|
|
|
} else if (sw == 0) {
|
|
|
|
if (sh == 1024)
|
|
|
|
sw = 1280;
|
|
|
|
else
|
|
|
|
sw = sh * 4 / 3;
|
|
|
|
} else if (sh == 0) {
|
2010-06-16 08:20:14 +02:00
|
|
|
// you are not crazy; this doesn't make any sense
|
2007-05-03 19:19:50 +02:00
|
|
|
if (sw == 1280)
|
|
|
|
sh = 1024;
|
|
|
|
else
|
|
|
|
sh = sw * 3 / 4;
|
|
|
|
}
|
2006-07-01 09:22:57 +02:00
|
|
|
}
|
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
void AssFile::AddComment(const wxString _comment) {
|
|
|
|
wxString comment = _T("; ");
|
|
|
|
comment += _comment;
|
|
|
|
std::list<AssEntry*>::iterator cur;
|
|
|
|
int step = 0;
|
|
|
|
|
|
|
|
for (cur=Line.begin();cur!=Line.end();cur++) {
|
|
|
|
// Start of group
|
|
|
|
if (step == 0 && (*cur)->group == _T("[Script Info]")) step = 1;
|
|
|
|
|
|
|
|
// First line after a ;
|
2010-06-11 04:24:59 +02:00
|
|
|
else if (step == 1 && !(*cur)->GetEntryData().StartsWith(_T(";"))) {
|
2006-01-16 22:02:54 +01:00
|
|
|
AssEntry *prev = *cur;
|
|
|
|
AssEntry *comm = new AssEntry(comment);
|
|
|
|
comm->group = prev->group;
|
|
|
|
Line.insert(cur,comm);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
wxArrayString AssFile::GetStyles() {
|
|
|
|
wxArrayString styles;
|
|
|
|
AssStyle *curstyle;
|
|
|
|
for (entryIter cur=Line.begin();cur!=Line.end();cur++) {
|
2010-05-19 02:44:52 +02:00
|
|
|
curstyle = dynamic_cast<AssStyle*>(*cur);
|
2006-01-16 22:02:54 +01:00
|
|
|
if (curstyle) {
|
|
|
|
styles.Add(curstyle->name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return styles;
|
|
|
|
}
|
|
|
|
|
|
|
|
AssStyle *AssFile::GetStyle(wxString name) {
|
|
|
|
for (entryIter cur=Line.begin();cur!=Line.end();cur++) {
|
2010-06-16 08:20:14 +02:00
|
|
|
AssStyle *curstyle = dynamic_cast<AssStyle*>(*cur);
|
|
|
|
if (curstyle && curstyle->name == name)
|
|
|
|
return curstyle;
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AssFile::AddToRecent(wxString file) {
|
2010-06-18 04:23:27 +02:00
|
|
|
config::mru->Add("Subtitle", STD_STR(file));
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2006-12-26 05:48:53 +01:00
|
|
|
wxString AssFile::GetWildcardList(int mode) {
|
2006-12-26 19:26:13 +01:00
|
|
|
if (mode == 0) return SubtitleFormat::GetWildcards(0);
|
2006-12-26 05:48:53 +01:00
|
|
|
else if (mode == 1) return _T("Advanced Substation Alpha (*.ass)|*.ass");
|
2006-12-26 19:26:13 +01:00
|
|
|
else if (mode == 2) return SubtitleFormat::GetWildcards(1);
|
2006-12-26 05:48:53 +01:00
|
|
|
else return _T("");
|
|
|
|
}
|
|
|
|
|
2010-06-16 08:20:14 +02:00
|
|
|
void AssFile::CompressForStack() {
|
2006-02-21 22:52:32 +01:00
|
|
|
for (entryIter cur=Line.begin();cur!=Line.end();cur++) {
|
2010-06-22 02:03:28 +02:00
|
|
|
AssDialogue *diag = dynamic_cast<AssDialogue*>(*cur);
|
|
|
|
if (diag) diag->ClearBlocks();
|
2006-02-21 22:52:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
bool AssFile::IsModified() {
|
|
|
|
return Modified;
|
|
|
|
}
|
|
|
|
|
2007-01-26 01:47:42 +01:00
|
|
|
void AssFile::FlagAsModified(wxString desc) {
|
2006-02-20 22:32:58 +01:00
|
|
|
if (!RedoStack.empty()) {
|
|
|
|
//StackPush();
|
|
|
|
//UndoStack.push_back(new AssFile(*UndoStack.back()));
|
|
|
|
for (std::list<AssFile*>::iterator cur=RedoStack.begin();cur!=RedoStack.end();cur++) {
|
|
|
|
delete *cur;
|
|
|
|
}
|
|
|
|
RedoStack.clear();
|
|
|
|
}
|
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
Modified = true;
|
2007-01-26 01:47:42 +01:00
|
|
|
StackPush(desc);
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2007-01-26 01:47:42 +01:00
|
|
|
void AssFile::StackPush(wxString desc) {
|
2006-01-16 22:02:54 +01:00
|
|
|
// Places copy on stack
|
|
|
|
AssFile *curcopy = new AssFile(*top);
|
2010-06-16 08:20:14 +02:00
|
|
|
curcopy->CompressForStack();
|
2007-01-26 01:47:42 +01:00
|
|
|
curcopy->undodescription = desc;
|
2006-02-20 22:32:58 +01:00
|
|
|
UndoStack.push_back(curcopy);
|
2006-01-16 22:02:54 +01:00
|
|
|
StackModified = true;
|
|
|
|
|
|
|
|
// Cap depth
|
|
|
|
int n = 0;
|
2006-02-20 22:32:58 +01:00
|
|
|
for (std::list<AssFile*>::iterator cur=UndoStack.begin();cur!=UndoStack.end();cur++) {
|
2006-01-16 22:02:54 +01:00
|
|
|
n++;
|
|
|
|
}
|
2010-05-21 03:13:36 +02:00
|
|
|
int depth = OPT_GET("Limits/Undo Levels")->GetInt();
|
2006-01-16 22:02:54 +01:00
|
|
|
while (n > depth) {
|
2006-02-20 22:32:58 +01:00
|
|
|
delete UndoStack.front();
|
|
|
|
UndoStack.pop_front();
|
2006-01-16 22:02:54 +01:00
|
|
|
n--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AssFile::StackPop() {
|
|
|
|
bool addcopy = false;
|
2010-06-16 08:20:14 +02:00
|
|
|
wxString undodesc="";
|
2007-01-26 01:47:42 +01:00
|
|
|
|
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
if (StackModified) {
|
2007-01-26 01:47:42 +01:00
|
|
|
undodesc=UndoStack.back()->undodescription;
|
2009-06-03 21:55:39 +02:00
|
|
|
delete UndoStack.back();
|
2006-02-20 22:32:58 +01:00
|
|
|
UndoStack.pop_back();
|
2006-01-16 22:02:54 +01:00
|
|
|
StackModified = false;
|
|
|
|
addcopy = true;
|
|
|
|
}
|
|
|
|
|
2006-02-20 22:32:58 +01:00
|
|
|
if (!UndoStack.empty()) {
|
|
|
|
//delete top;
|
2007-01-26 01:47:42 +01:00
|
|
|
AssFile *undo = UndoStack.back();
|
2010-06-16 08:20:14 +02:00
|
|
|
top->CompressForStack();
|
2007-01-26 01:47:42 +01:00
|
|
|
top->undodescription = undodesc;
|
2006-02-20 22:32:58 +01:00
|
|
|
RedoStack.push_back(top);
|
2007-01-26 01:47:42 +01:00
|
|
|
top = undo;
|
2006-02-20 22:32:58 +01:00
|
|
|
UndoStack.pop_back();
|
2006-01-16 22:02:54 +01:00
|
|
|
Popping = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addcopy) {
|
2007-01-26 01:47:42 +01:00
|
|
|
StackPush(top->undodescription);
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-02-20 22:32:58 +01:00
|
|
|
void AssFile::StackRedo() {
|
|
|
|
bool addcopy = false;
|
|
|
|
if (StackModified) {
|
2009-06-03 21:55:39 +02:00
|
|
|
delete UndoStack.back();
|
2006-02-20 22:32:58 +01:00
|
|
|
UndoStack.pop_back();
|
|
|
|
StackModified = false;
|
|
|
|
addcopy = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!RedoStack.empty()) {
|
2010-06-16 08:20:14 +02:00
|
|
|
top->CompressForStack();
|
2006-02-20 22:32:58 +01:00
|
|
|
UndoStack.push_back(top);
|
|
|
|
top = RedoStack.back();
|
|
|
|
RedoStack.pop_back();
|
|
|
|
Popping = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addcopy) {
|
2007-01-26 01:47:42 +01:00
|
|
|
StackPush(top->undodescription);
|
2006-02-20 22:32:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
void AssFile::StackClear() {
|
2006-02-20 22:32:58 +01:00
|
|
|
for (std::list<AssFile*>::iterator cur=UndoStack.begin();cur!=UndoStack.end();cur++) {
|
|
|
|
delete *cur;
|
|
|
|
}
|
|
|
|
UndoStack.clear();
|
|
|
|
|
|
|
|
for (std::list<AssFile*>::iterator cur=RedoStack.begin();cur!=RedoStack.end();cur++) {
|
2006-01-16 22:02:54 +01:00
|
|
|
delete *cur;
|
|
|
|
}
|
2006-02-20 22:32:58 +01:00
|
|
|
RedoStack.clear();
|
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
Popping = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AssFile::StackReset() {
|
|
|
|
StackClear();
|
|
|
|
delete top;
|
|
|
|
top = new AssFile;
|
|
|
|
StackModified = false;
|
|
|
|
}
|
|
|
|
|
2006-02-20 22:32:58 +01:00
|
|
|
bool AssFile::IsUndoStackEmpty() {
|
|
|
|
if (StackModified) return (UndoStack.size() <= 1);
|
|
|
|
else return UndoStack.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AssFile::IsRedoStackEmpty() {
|
|
|
|
return RedoStack.empty();
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2007-01-26 01:47:42 +01:00
|
|
|
wxString AssFile::GetUndoDescription() {
|
|
|
|
return (IsUndoStackEmpty())?_T(""):(UndoStack.back())->undodescription;
|
|
|
|
}
|
|
|
|
|
|
|
|
wxString AssFile::GetRedoDescription() {
|
|
|
|
return (IsRedoStackEmpty())?_T(""):(RedoStack.back())->undodescription;
|
2010-05-19 02:44:44 +02:00
|
|
|
}
|
2007-01-26 01:47:42 +01:00
|
|
|
|
2010-05-19 02:44:44 +02:00
|
|
|
bool AssFile::CompStart(const AssDialogue* lft, const AssDialogue* rgt) {
|
|
|
|
return lft->Start < rgt->Start;
|
|
|
|
}
|
|
|
|
bool AssFile::CompEnd(const AssDialogue* lft, const AssDialogue* rgt) {
|
|
|
|
return lft->End < rgt->End;
|
|
|
|
}
|
|
|
|
bool AssFile::CompStyle(const AssDialogue* lft, const AssDialogue* rgt) {
|
|
|
|
return lft->Style < rgt->Style;
|
2007-01-26 01:47:42 +01:00
|
|
|
}
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2010-05-19 02:44:44 +02:00
|
|
|
void AssFile::Sort(CompFunc comp) {
|
|
|
|
Sort(Line, comp);
|
|
|
|
}
|
2010-05-19 05:24:07 +02:00
|
|
|
namespace {
|
|
|
|
struct AssEntryComp : public std::binary_function<const AssEntry*, const AssEntry*, bool> {
|
|
|
|
AssFile::CompFunc comp;
|
2010-05-19 02:44:44 +02:00
|
|
|
bool operator()(const AssEntry* a, const AssEntry* b) const {
|
|
|
|
return comp(static_cast<const AssDialogue*>(a), static_cast<const AssDialogue*>(b));
|
|
|
|
}
|
2010-05-19 05:24:07 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
void AssFile::Sort(std::list<AssEntry*> &lst, CompFunc comp) {
|
|
|
|
AssEntryComp compE;
|
2010-05-19 02:44:44 +02:00
|
|
|
compE.comp = comp;
|
|
|
|
// Sort each block of AssDialogues separately, leaving everything else untouched
|
|
|
|
for (entryIter begin = lst.begin(); begin != lst.end(); ++begin) {
|
|
|
|
if (!dynamic_cast<AssDialogue*>(*begin)) continue;
|
|
|
|
entryIter end = begin;
|
|
|
|
while (end != lst.end() && dynamic_cast<AssDialogue*>(*end)) ++end;
|
|
|
|
|
|
|
|
// std::list::sort doesn't support sorting only part of the list, but
|
|
|
|
// splice is constant-time, so just sort a temp list with only the part we
|
|
|
|
// want sorted
|
|
|
|
std::list<AssEntry*> tmp;
|
|
|
|
tmp.splice(tmp.begin(), lst, begin, end);
|
|
|
|
tmp.sort(compE);
|
|
|
|
lst.splice(end, tmp);
|
|
|
|
|
|
|
|
begin = --end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void AssFile::Sort(std::list<AssDialogue*> &lst, CompFunc comp) {
|
|
|
|
lst.sort(comp);
|
|
|
|
}
|
Note: This was done using a script! it's far from perfect but 95% of the work has been done already formatting-wise.
Document all functions, class, struct, union, enum, macro, variable, typedefs. This isn't the actual document in itself but empty documentation using any old documentation if it was there.
This was done using exuberant ctags to get tag info, then a TCL script to parse/remove old comments and convert them into Doxygen-style.
Some notes:
* Anything labeled 'DOCME' needs to be documented, @param and @return have been left blank as it would be annoying to delete the 'DOCME' from every one of those.
* Some multiline comments may have been munged into single line comments
* Leave the /// comments above global variables with a space, if they're harder to read then we'll be less likey to use them.
* Enum comments can go after the enumeration itself '[value] /// comment'
* include/aegisub/*.h haven't been converted yet, this will be done in a later commit
* Some documentation blocks are in the wrong place, in the .h when it should be in the .cpp, or vice versa.
See http://devel.aegisub.org/wiki/Doxygen for some details on Doxygen and a 'style guide'.
Originally committed to SVN as r3312.
2009-07-30 00:59:22 +02:00
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
AssFile *AssFile::top;
|
2006-02-20 22:32:58 +01:00
|
|
|
std::list<AssFile*> AssFile::UndoStack;
|
|
|
|
std::list<AssFile*> AssFile::RedoStack;
|
2006-01-16 22:02:54 +01:00
|
|
|
bool AssFile::Popping;
|
|
|
|
bool AssFile::StackModified;
|