First part of a new chapter editor.

This commit is contained in:
Moritz Bunkus 2003-09-17 22:07:07 +00:00
parent ff40fde6c9
commit 05337a1d88
4 changed files with 491 additions and 3 deletions

View File

@ -5,14 +5,18 @@ bin_PROGRAMS = mmg
INCLUDES = -I.. -I../..
mmg_SOURCES = mmg.cpp mmg.h \
../chapters.cpp ../chapters.h \
../chapter_parser_xml.cpp \
../common.cpp ../common.h \
extern_data.cpp extern_data.h \
../iso639.cpp ../iso639.h \
../mm_io.cpp ../mm_io.h \
mux_dialog.cpp \
tab_attachments.cpp \
tab_chapters.cpp \
tab_input.cpp \
tab_global.cpp \
tab_settings.cpp
mmg_LDADD = @PROFILING_LIBS@ @EBML_LIBS@ @WXWINDOWS_LIBS@ @MINGW_LIBS@ \
@MINGW_GUIAPP@ @ICONV_LIBS@
mmg_LDADD = @PROFILING_LIBS@ @MATROSKA_LIBS@ @EBML_LIBS@ @EXPAT_LIBS@ \
@WXWINDOWS_LIBS@ @MINGW_LIBS@ @MINGW_GUIAPP@ @ICONV_LIBS@

View File

@ -153,6 +153,22 @@ mmg_dialog::mmg_dialog(): wxFrame(NULL, -1, "mkvmerge GUI v" VERSION,
_T("Sa&ve command line\tCtrl-V"),
_T("Save the command line to a file"));
wxMenu *chapter_menu = new wxMenu();
chapter_menu->Append(ID_M_CHAPTERS_NEW, _T("&New"),
_T("Create a new chapter file"));
chapter_menu->Append(ID_M_CHAPTERS_LOAD, _T("&Load"),
_T("Load a chapter file (simple/OGM format or XML "
"format)"));
chapter_menu->Append(ID_M_CHAPTERS_SAVE, _T("&Save"),
_T("Save the current chapters to a XML file"));
chapter_menu->Append(ID_M_CHAPTERS_SAVEAS, _T("Save &as"),
_T("Save the current chapters to a file with another "
"name"));
chapter_menu->AppendSeparator();
chapter_menu->Append(ID_M_CHAPTERS_VERIFY, _T("&Verify"),
_T("Verify the current chapter entries to see if there "
"are any errors"));
wxMenu *help_menu = new wxMenu();
help_menu->Append(ID_M_HELP_ABOUT, _T("&About\tF1"),
_T("Show program information"));
@ -160,6 +176,7 @@ mmg_dialog::mmg_dialog(): wxFrame(NULL, -1, "mkvmerge GUI v" VERSION,
wxMenuBar *menu_bar = new wxMenuBar();
menu_bar->Append(file_menu, _T("&File"));
menu_bar->Append(muxing_menu, _T("&Muxing"));
menu_bar->Append(chapter_menu, _T("&Chapter Editor"));
menu_bar->Append(help_menu, _T("&Help"));
SetMenuBar(menu_bar);
@ -180,11 +197,13 @@ mmg_dialog::mmg_dialog(): wxFrame(NULL, -1, "mkvmerge GUI v" VERSION,
attachments_page = new tab_attachments(notebook);
global_page = new tab_global(notebook);
settings_page = new tab_settings(notebook);
chapter_editor_page = new tab_chapters(notebook, chapter_menu);
notebook->AddPage(input_page, _("Input"));
notebook->AddPage(attachments_page, _("Attachments"));
notebook->AddPage(global_page, _("Global"));
notebook->AddPage(settings_page, _("Settings"));
notebook->AddPage(chapter_editor_page, _("Chapter Editor"));
bs_main->Add(notebook, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);
@ -759,6 +778,26 @@ void mmg_dialog::update_file_menu() {
}
}
void mmg_dialog::on_new_chapters(wxCommandEvent &evt) {
chapter_editor_page->on_new_chapters(evt);
}
void mmg_dialog::on_load_chapters(wxCommandEvent &evt) {
chapter_editor_page->on_load_chapters(evt);
}
void mmg_dialog::on_save_chapters(wxCommandEvent &evt) {
chapter_editor_page->on_save_chapters(evt);
}
void mmg_dialog::on_save_chapters_as(wxCommandEvent &evt) {
chapter_editor_page->on_save_chapters_as(evt);
}
void mmg_dialog::on_verify_chapters(wxCommandEvent &evt) {
chapter_editor_page->on_verify_chapters(evt);
}
IMPLEMENT_CLASS(mmg_dialog, wxFrame);
BEGIN_EVENT_TABLE(mmg_dialog, wxFrame)
EVT_BUTTON(ID_B_BROWSEOUTPUT, mmg_dialog::on_browse_output)
@ -775,6 +814,11 @@ BEGIN_EVENT_TABLE(mmg_dialog, wxFrame)
EVT_MENU(ID_M_FILE_LOADLAST2, mmg_dialog::on_file_load_last)
EVT_MENU(ID_M_FILE_LOADLAST3, mmg_dialog::on_file_load_last)
EVT_MENU(ID_M_FILE_LOADLAST4, mmg_dialog::on_file_load_last)
EVT_MENU(ID_M_CHAPTERS_NEW, mmg_dialog::on_new_chapters)
EVT_MENU(ID_M_CHAPTERS_LOAD, mmg_dialog::on_load_chapters)
EVT_MENU(ID_M_CHAPTERS_SAVE, mmg_dialog::on_save_chapters)
EVT_MENU(ID_M_CHAPTERS_SAVEAS, mmg_dialog::on_save_chapters_as)
EVT_MENU(ID_M_CHAPTERS_VERIFY, mmg_dialog::on_verify_chapters)
END_EVENT_TABLE();
bool mmg_app::OnInit() {

View File

@ -25,11 +25,15 @@
#include <vector>
#include <stdint.h>
#include "matroska/KaxChapters.h"
#include "os.h"
#include "wx/confbase.h"
#include "wx/process.h"
#include "wx/treectrl.h"
using namespace std;
using namespace libmatroska;
#ifdef SYS_WINDOWS
#define ALLFILES "All Files (*.*)|*.*"
@ -98,6 +102,15 @@ using namespace std;
#define ID_B_MUX_ABORT 10057
#define ID_T_ATTACHMENTVALUES 10058
#define ID_T_INPUTVALUES 10059
#define ID_TRC_CHAPTERS 10060
#define ID_B_ADDCHAPTER 10061
#define ID_B_REMOVECHAPTER 10062
#define ID_T_CHAPTERVALUES 10063
#define ID_TC_CHAPTERNAME 10064
#define ID_TC_CHAPTERLANGUAGES 10065
#define ID_TC_CHAPTERCOUNTRYCODES 10066
#define ID_TC_CHAPTERSTART 10067
#define ID_TC_CHAPTEREND 10068
#define ID_M_FILE_LOAD 20000
#define ID_M_FILE_SAVE 20001
@ -112,7 +125,13 @@ using namespace std;
#define ID_M_MUXING_COPY_CMDLINE 20101
#define ID_M_MUXING_SAVE_CMDLINE 20102
#define ID_M_HELP_ABOUT 20200
#define ID_M_CHAPTERS_NEW 20200
#define ID_M_CHAPTERS_LOAD 20201
#define ID_M_CHAPTERS_SAVE 20202
#define ID_M_CHAPTERS_SAVEAS 20203
#define ID_M_CHAPTERS_VERIFY 20204
#define ID_M_HELP_ABOUT 29900
typedef struct {
char type;
@ -272,6 +291,42 @@ public:
bool validate_settings();
};
class tab_chapters: public wxPanel {
DECLARE_CLASS(tab_chapters);
DECLARE_EVENT_TABLE();
public:
wxTreeCtrl *tc_chapters;
wxTreeItemId tid_root;
wxButton *b_add_chapter, *b_remove_chapter;
wxMenu *m_chapters;
wxTextCtrl *tc_chapter_name, *tc_language_codes, *tc_country_codes;
wxTextCtrl *tc_start_time, *tc_end_time;
wxTimer value_copy_timer;
wxString file_name;
KaxChapters *chapters;
public:
tab_chapters(wxWindow *parent, wxMenu *nm_chapters);
~tab_chapters();
void on_new_chapters(wxCommandEvent &evt);
void on_load_chapters(wxCommandEvent &evt);
void on_save_chapters(wxCommandEvent &evt);
void on_save_chapters_as(wxCommandEvent &evt);
void on_verify_chapters(wxCommandEvent &evt);
void on_add_chapter(wxCommandEvent &evt);
void on_remove_chapter(wxCommandEvent &evt);
void on_copy_values(wxTimerEvent &evt);
void on_entry_selected(wxTreeEvent &evt);
void add_recursively(wxTreeItemId &parent, EbmlMaster &master);
wxString create_chapter_label(KaxChapterAtom &chapter);
};
class mux_dialog: public wxDialog {
DECLARE_CLASS(mux_dialog);
DECLARE_EVENT_TABLE();
@ -326,6 +381,7 @@ protected:
tab_attachments *attachments_page;
tab_global *global_page;
tab_settings *settings_page;
tab_chapters *chapter_editor_page;
public:
mmg_dialog();
@ -354,6 +410,12 @@ public:
void set_last_settings_in_menu(wxString name);
void on_file_load_last(wxCommandEvent &evt);
void update_file_menu();
void on_new_chapters(wxCommandEvent &evt);
void on_load_chapters(wxCommandEvent &evt);
void on_save_chapters(wxCommandEvent &evt);
void on_save_chapters_as(wxCommandEvent &evt);
void on_verify_chapters(wxCommandEvent &evt);
};
class mmg_app: public wxApp {

378
src/mmg/tab_chapters.cpp Normal file
View File

@ -0,0 +1,378 @@
/*
mkvmerge GUI -- utility for splicing together matroska files
from component media subtypes
tab_chapters.cpp
Written by Moritz Bunkus <moritz@bunkus.org>
Parts of this code were written by Florian Wager <root@sirelvis.de>
Distributed under the GPL
see the file COPYING for details
or visit http://www.gnu.org/copyleft/gpl.html
*/
/*!
\file
\version $Id: tab_chapters.cpp 1045 2003-09-17 11:56:16Z mosu $
\brief "chapter editor" tab
\author Moritz Bunkus <moritz@bunkus.org>
*/
#include "wx/wxprec.h"
#include "wx/wx.h"
#include "wx/notebook.h"
#include "wx/listctrl.h"
#include "wx/statline.h"
#include "mmg.h"
#include "chapters.h"
#include "common.h"
#include "error.h"
#include "extern_data.h"
class tree_node_data: public wxTreeItemData {
public:
bool is_atom;
KaxChapterAtom *chapter;
KaxEditionEntry *eentry;
tree_node_data(KaxChapterAtom *nchapter):
is_atom(true),
chapter(nchapter) {
};
tree_node_data(KaxEditionEntry *neentry):
is_atom(false),
eentry(neentry) {
};
};
void expand_subtree(wxTreeCtrl &tree, wxTreeItemId &root, bool expand = true) {
wxTreeItemId child;
long cookie;
if (!expand)
tree.Collapse(root);
child = tree.GetFirstChild(root, cookie);
while (child > 0) {
expand_subtree(tree, child, expand);
child = tree.GetNextChild(root, cookie);
}
if (expand)
tree.Expand(root);
}
#define Y1 30
#define X1 140
#define XS 360
tab_chapters::tab_chapters(wxWindow *parent, wxMenu *nm_chapters):
wxPanel(parent, -1, wxDefaultPosition, wxSize(100, 400), wxTAB_TRAVERSAL) {
m_chapters = nm_chapters;
new wxStaticText(this, wxID_STATIC, _("Chapters:"), wxPoint(10, 5),
wxDefaultSize, 0);
tc_chapters =
new wxTreeCtrl(this, ID_TRC_CHAPTERS, wxPoint(10, 24), wxSize(350, 250),
wxSIMPLE_BORDER | wxTR_HAS_BUTTONS);
b_add_chapter =
new wxButton(this, ID_B_ADDCHAPTER, _("Add chapter"), wxPoint(370, 24),
wxSize(120, -1));
b_remove_chapter =
new wxButton(this, ID_B_REMOVECHAPTER, _("Remove chapter"),
wxPoint(370, 50), wxSize(120, -1));
new wxStaticText(this, wxID_STATIC, _("Chapter name:"), wxPoint(10, 285));
tc_chapter_name =
new wxTextCtrl(this, ID_TC_CHAPTERNAME, _(""), wxPoint(X1, 285 + YOFF),
wxSize(XS - X1, -1));
new wxStaticText(this, wxID_STATIC, _("Start time:"),
wxPoint(10, 285 + Y1));
tc_start_time =
new wxTextCtrl(this, ID_TC_CHAPTERSTART, _(""),
wxPoint(X1, 285 + Y1 + YOFF), wxSize(XS - X1, -1));
new wxStaticText(this, wxID_STATIC, _("End time:"),
wxPoint(10, 285 + 2 * Y1));
tc_end_time =
new wxTextCtrl(this, ID_TC_CHAPTEREND, _(""),
wxPoint(X1, 285 + 2 * Y1 + YOFF), wxSize(XS - X1, -1));
new wxStaticText(this, wxID_STATIC, _("Language codes:"),
wxPoint(10, 285 + 3 * Y1));
tc_language_codes =
new wxTextCtrl(this, ID_TC_CHAPTERLANGUAGES, _(""),
wxPoint(X1, 285 + 3 * Y1 + YOFF), wxSize(XS - X1, -1));
new wxStaticText(this, wxID_STATIC, _("Country codes:"),
wxPoint(10, 285 + 4 * Y1));
tc_country_codes =
new wxTextCtrl(this, ID_TC_CHAPTERCOUNTRYCODES, _(""),
wxPoint(X1, 285 + 4 * Y1 + YOFF), wxSize(XS - X1, -1));
m_chapters->Enable(ID_M_CHAPTERS_SAVE, false);
m_chapters->Enable(ID_M_CHAPTERS_SAVEAS, false);
m_chapters->Enable(ID_M_CHAPTERS_VERIFY, false);
b_add_chapter->Enable(false);
b_remove_chapter->Enable(false);
file_name = "";
chapters = NULL;
value_copy_timer.SetOwner(this, ID_T_CHAPTERVALUES);
value_copy_timer.Start(333);
}
tab_chapters::~tab_chapters() {
if (chapters != NULL)
delete chapters;
}
void tab_chapters::on_new_chapters(wxCommandEvent &evt) {
file_name = "";
if (chapters != NULL)
delete chapters;
tc_chapters->DeleteAllItems();
tid_root = tc_chapters->AddRoot(_T("(new chapter file)"));
chapters = new KaxChapters;
m_chapters->Enable(ID_M_CHAPTERS_SAVE, true);
m_chapters->Enable(ID_M_CHAPTERS_SAVEAS, true);
m_chapters->Enable(ID_M_CHAPTERS_VERIFY, true);
b_add_chapter->Enable(true);
b_remove_chapter->Enable(true);
mdlg->set_status_bar("New chapters created.");
}
wxString tab_chapters::create_chapter_label(KaxChapterAtom &chapter) {
wxString label, s;
char *tmpstr;
KaxChapterDisplay *display;
KaxChapterString *cstring;
KaxChapterTimeStart *tstart;
KaxChapterTimeEnd *tend;
KaxChapterLanguage *language;
int64_t timestamp;
label = "(unnamed chapter)";
language = NULL;
display = FindChild<KaxChapterDisplay>(chapter);
if (display != NULL) {
cstring = FindChild<KaxChapterString>(*display);
if (cstring != NULL) {
tmpstr = UTFstring_to_cstr(*static_cast<EbmlUnicodeString *>(cstring));
label = tmpstr;
safefree(tmpstr);
}
language = FindChild<KaxChapterLanguage>(*display);
}
label += " [";
tstart = FindChild<KaxChapterTimeStart>(chapter);
if (tstart != NULL) {
timestamp = uint64(*static_cast<EbmlUInteger *>(tstart)) / 1000000;
s.Printf("%02d:%02d:%02d.%03d",
(int)(timestamp / 1000 / 60 / 60),
(int)((timestamp / 1000 / 60) % 60),
(int)((timestamp / 1000) % 60),
(int)(timestamp % 1000));
label += s;
tend = FindChild<KaxChapterTimeEnd>(chapter);
if (tend != NULL) {
timestamp = uint64(*static_cast<EbmlUInteger *>(tend)) / 1000000;
s.Printf("%02d:%02d:%02d.%03d",
(int)(timestamp / 1000 / 60 / 60),
(int)((timestamp / 1000 / 60) % 60),
(int)((timestamp / 1000) % 60),
(int)(timestamp % 1000));
label += " - " + s;
}
label += "; ";
}
if (language != NULL)
label += string(*static_cast<EbmlString *>(language)).c_str();
else
label += "eng";
label += "]";
return label;
}
void tab_chapters::add_recursively(wxTreeItemId &parent, EbmlMaster &master) {
uint32_t i;
wxString s;
EbmlElement *e;
KaxChapterAtom *chapter;
KaxEditionEntry *eentry;
wxTreeItemId this_item;
for (i = 0; i < master.ListSize(); i++) {
e = master[i];
if (EbmlId(*e) == KaxEditionEntry::ClassInfos.GlobalId) {
s.Printf("Edition %d", tc_chapters->GetChildrenCount(tid_root, false) +
1);
eentry = static_cast<KaxEditionEntry *>(e);
this_item =
tc_chapters->AppendItem(parent, s, -1, -1, new tree_node_data(eentry));
add_recursively(this_item, *static_cast<EbmlMaster *>(e));
} else if (EbmlId(*e) == KaxChapterAtom::ClassInfos.GlobalId) {
chapter = static_cast<KaxChapterAtom *>(e);
s = create_chapter_label(*chapter);
this_item = tc_chapters->AppendItem(parent, s, -1, -1,
new tree_node_data(chapter));
add_recursively(this_item, *static_cast<EbmlMaster *>(e));
}
}
}
void tab_chapters::on_load_chapters(wxCommandEvent &evt) {
KaxChapters *new_chapters;
wxString s;
wxFileDialog dlg(NULL, "Choose a chapter file", last_open_dir, "",
_T("Chapter files (*.xml;*.txt)|*.xml;*.txt|" ALLFILES),
wxOPEN);
if(dlg.ShowModal() == wxID_OK) {
last_open_dir = dlg.GetDirectory();
try {
new_chapters = parse_chapters(dlg.GetPath().c_str(), 0, -1, 0, NULL,
NULL, true);
} catch (error_c e) {
s = (const char *)e;
break_line(s);
while (s[s.Length() - 1] == '\n')
s.Remove(s.Length() - 1);
wxMessageBox(s, _T("Error parsing the chapter file"),
wxOK | wxCENTER | wxICON_ERROR);
return;
}
if (chapters != NULL)
delete chapters;
tc_chapters->DeleteAllItems();
chapters = new_chapters;
m_chapters->Enable(ID_M_CHAPTERS_SAVE, true);
m_chapters->Enable(ID_M_CHAPTERS_SAVEAS, true);
m_chapters->Enable(ID_M_CHAPTERS_VERIFY, true);
b_add_chapter->Enable(true);
b_remove_chapter->Enable(true);
file_name = dlg.GetPath();
tid_root = tc_chapters->AddRoot(file_name);
add_recursively(tid_root, *chapters);
expand_subtree(*tc_chapters, tid_root);
mdlg->set_status_bar("Chapters loaded.");
}
}
void tab_chapters::on_save_chapters(wxCommandEvent &evt) {
}
void tab_chapters::on_save_chapters_as(wxCommandEvent &evt) {
}
void tab_chapters::on_verify_chapters(wxCommandEvent &evt) {
}
void tab_chapters::on_add_chapter(wxCommandEvent &evt) {
}
void tab_chapters::on_remove_chapter(wxCommandEvent &evt) {
}
void tab_chapters::on_copy_values(wxTimerEvent &evt) {
}
void tab_chapters::on_entry_selected(wxTreeEvent &evt) {
tree_node_data *t;
KaxChapterDisplay *display;
KaxChapterString *cstring;
KaxChapterTimeStart *tstart;
KaxChapterTimeEnd *tend;
EbmlElement *e;
wxString label, languages, countries;
int64_t timestamp;
uint32_t i;
char *tmpstr;
t = (tree_node_data *)tc_chapters->GetItemData(evt.GetItem());
if ((evt.GetItem() == tid_root) || (t == NULL) || !t->is_atom) {
tc_chapter_name->SetValue("");
tc_start_time->SetValue("");
tc_end_time->SetValue("");
tc_language_codes->SetValue("");
tc_country_codes->SetValue("");
return;
}
label = "(unnamed chapter)";
languages = "";
countries = "";
display = FindChild<KaxChapterDisplay>(*t->chapter);
if (display != NULL) {
cstring = FindChild<KaxChapterString>(*display);
if (cstring != NULL) {
tmpstr = UTFstring_to_cstr(*static_cast<EbmlUnicodeString *>(cstring));
label = tmpstr;
safefree(tmpstr);
}
for (i = 0; i < display->ListSize(); i++) {
e = (*display)[i];
if (EbmlId(*e) == KaxChapterLanguage::ClassInfos.GlobalId) {
if (languages.length() > 0)
languages += " ";
languages += string(*static_cast<EbmlString *>(e)).c_str();
} else if (EbmlId(*e) == KaxChapterCountry::ClassInfos.GlobalId) {
if (countries.length() > 0)
countries += " ";
countries += string(*static_cast<EbmlString *>(e)).c_str();
}
}
}
tc_chapter_name->SetValue(label);
tc_language_codes->SetValue(languages);
tc_country_codes->SetValue(countries);
tstart = FindChild<KaxChapterTimeStart>(*t->chapter);
if (tstart != NULL) {
timestamp = uint64(*static_cast<EbmlUInteger *>(tstart)) / 1000000;
label.Printf("%02d:%02d:%02d.%03d",
(int)(timestamp / 1000 / 60 / 60),
(int)((timestamp / 1000 / 60) % 60),
(int)((timestamp / 1000) % 60),
(int)(timestamp % 1000));
tc_start_time->SetValue(label);
} else
tc_start_time->SetValue("");
tend = FindChild<KaxChapterTimeEnd>(*t->chapter);
if (tend != NULL) {
timestamp = uint64(*static_cast<EbmlUInteger *>(tend)) / 1000000;
label.Printf("%02d:%02d:%02d.%03d",
(int)(timestamp / 1000 / 60 / 60),
(int)((timestamp / 1000 / 60) % 60),
(int)((timestamp / 1000) % 60),
(int)(timestamp % 1000));
tc_end_time->SetValue(label);
} else
tc_end_time->SetValue("");
}
IMPLEMENT_CLASS(tab_chapters, wxPanel);
BEGIN_EVENT_TABLE(tab_chapters, wxPanel)
EVT_BUTTON(ID_B_ADDCHAPTER, tab_chapters::on_add_chapter)
EVT_BUTTON(ID_B_REMOVECHAPTER, tab_chapters::on_remove_chapter)
EVT_TIMER(ID_T_CHAPTERVALUES, tab_chapters::on_copy_values)
EVT_TREE_SEL_CHANGED(ID_TRC_CHAPTERS, tab_chapters::on_entry_selected)
END_EVENT_TABLE();