2
mkvmerge GUI -- utility for splicing together matroska files
3
from component media subtypes
5
Distributed under the GPL
6
see the file COPYING for details
7
or visit http://www.gnu.org/copyleft/gpl.html
9
$Id: tab_chapters.cpp 3047 2005-08-26 08:21:46Z mosu $
13
Written by Moritz Bunkus <moritz@bunkus.org>.
21
#include "wx/listctrl.h"
22
#include "wx/notebook.h"
23
#include "wx/statline.h"
25
#include <ebml/EbmlStream.h>
29
#include "commonebml.h"
31
#include "extern_data.h"
34
#include "mmg_dialog.h"
35
#include "kax_analyzer.h"
36
#include "tab_chapters.h"
39
using namespace libebml;
40
using namespace libmatroska;
42
#if ! wxCHECK_VERSION(2,4,2)
43
# define wxTreeItemIdValue long
46
class chapters_drop_target_c: public wxFileDropTarget {
50
chapters_drop_target_c(tab_chapters *n_owner):
52
virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &files) {
53
owner->load(files[0]);
59
class chapter_node_data_c: public wxTreeItemData {
62
KaxChapterAtom *chapter;
63
KaxEditionEntry *eentry;
65
chapter_node_data_c(KaxChapterAtom *nchapter):
70
chapter_node_data_c(KaxEditionEntry *neentry):
76
#define ID_CVD_CB_LANGUAGE 12000
77
#define ID_CVD_CB_COUNTRY 12001
79
class chapter_values_dlg: public wxDialog {
80
DECLARE_CLASS(chapter_values_dlg);
81
DECLARE_EVENT_TABLE();
83
wxComboBox *cob_language, *cob_country;
84
wxCheckBox *cb_language, *cb_country;
87
chapter_values_dlg(wxWindow *parent, bool set_defaults,
88
wxString old_def_language = wxT(""),
89
wxString old_def_country = wxT(""));
90
void on_language_clicked(wxCommandEvent &evt);
91
void on_country_clicked(wxCommandEvent &evt);
94
chapter_values_dlg::chapter_values_dlg(wxWindow *parent,
96
wxString old_def_language,
97
wxString old_def_country):
98
wxDialog(parent, 0, wxT(""), wxDefaultPosition, wxSize(350, 200)) {
99
wxBoxSizer *siz_all, *siz_buttons, *siz_line;
100
wxFlexGridSizer *siz_input;
101
wxButton *b_ok, *b_cancel;
104
siz_all = new wxBoxSizer(wxVERTICAL);
106
SetTitle(wxT("Change the default values"));
107
siz_all->Add(new wxStaticText(this, wxID_STATIC,
108
wxT("Here you can set the default values "
109
"that mmg will use\nfor each chapter "
110
"that you create. These values can\n"
111
"then be changed if needed. The default "
112
"values will be\nsaved when you exit "
114
0, wxLEFT | wxRIGHT | wxTOP, 10);
116
siz_input = new wxFlexGridSizer(2);
117
siz_input->AddGrowableCol(1);
118
siz_input->Add(0, 1, 1, wxGROW, 0);
119
siz_input->Add(0, 1, 1, wxGROW, 0);
120
siz_input->AddGrowableRow(0);
122
siz_input->Add(new wxStaticText(this, wxID_STATIC, wxT("Language:")),
123
0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
124
cob_language = new wxComboBox(this, wxID_STATIC, wxT(""),
125
wxDefaultPosition, wxDefaultSize, 0, NULL,
126
wxCB_DROPDOWN | wxCB_READONLY);
127
siz_input->Add(cob_language, 0, wxGROW, 0);
129
siz_input->Add(0, 1, 1, wxGROW, 0);
130
siz_input->Add(0, 1, 1, wxGROW, 0);
131
siz_input->AddGrowableRow(2);
133
siz_input->Add(new wxStaticText(this, wxID_STATIC, wxT("Country:")),
134
0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
135
cob_country = new wxComboBox(this, wxID_STATIC, wxT(""),
136
wxDefaultPosition, wxDefaultSize, 0, NULL,
137
wxCB_DROPDOWN | wxCB_READONLY);
138
siz_input->Add(cob_country, 0, wxGROW, 0);
141
SetTitle(wxT("Select values to be applied"));
142
siz_all->Add(new wxStaticText(this, wxID_STATIC,
143
wxT("Please enter the values for the "
144
"language and the\ncountry that you "
145
"want to apply to all the chapters\n"
146
"below and including the currently "
148
0, wxLEFT | wxRIGHT | wxTOP, 10);
150
siz_input = new wxFlexGridSizer(2);
151
siz_input->AddGrowableCol(1);
152
siz_input->Add(0, 1, 1, wxGROW, 0);
153
siz_input->Add(0, 1, 1, wxGROW, 0);
154
siz_input->AddGrowableRow(0);
157
new wxCheckBox(this, ID_CVD_CB_LANGUAGE, wxT("Set language to:"));
158
cb_language->SetValue(false);
159
siz_input->Add(cb_language, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
160
cob_language = new wxComboBox(this, wxID_STATIC, wxT(""),
161
wxDefaultPosition, wxDefaultSize, 0, NULL,
162
wxCB_DROPDOWN | wxCB_READONLY);
163
cob_language->Enable(false);
164
siz_input->Add(cob_language, 0, wxGROW, 0);
166
siz_input->Add(0, 1, 1, wxGROW, 0);
167
siz_input->Add(0, 1, 1, wxGROW, 0);
168
siz_input->AddGrowableRow(2);
171
new wxCheckBox(this, ID_CVD_CB_COUNTRY, wxT("Set country to:"));
172
cb_country->SetValue(false);
173
siz_input->Add(cb_country, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
174
cob_country = new wxComboBox(this, wxID_STATIC, wxT(""),
175
wxDefaultPosition, wxDefaultSize, 0, NULL,
176
wxCB_DROPDOWN | wxCB_READONLY);
177
cob_country->Enable(false);
178
siz_input->Add(cob_country, 0, wxGROW, 0);
182
siz_all->Add(siz_input, 3, wxGROW | wxLEFT | wxRIGHT, 25);
184
for (i = 0; i < sorted_iso_codes.Count(); i++) {
185
cob_language->Append(sorted_iso_codes[i]);
186
if (extract_language_code(sorted_iso_codes[i]) == old_def_language)
187
cob_language->SetValue(sorted_iso_codes[i]);
190
cob_country->Append(wxT(""));
191
for (i = 0; cctlds[i] != NULL; i++)
192
cob_country->Append(wxU(cctlds[i]));
193
cob_country->SetValue(old_def_country);
195
siz_buttons = new wxBoxSizer(wxVERTICAL);
196
siz_buttons->Add(0, 1, 1, wxGROW, 0);
197
siz_line = new wxBoxSizer(wxHORIZONTAL);
198
b_ok = new wxButton(this, wxID_OK, wxT("Ok"));
200
b_cancel = new wxButton(this, wxID_CANCEL, wxT("Cancel"));
201
b_ok->SetSize(b_cancel->GetSize());
202
siz_line->Add(1, 0, 1, wxGROW, 0);
203
siz_line->Add(b_ok, 0, 0, 0);
204
siz_line->Add(1, 0, 1, wxGROW, 0);
205
siz_line->Add(b_cancel, 0, 0, 0);
206
siz_line->Add(1, 0, 1, wxGROW, 0);
207
siz_buttons->Add(siz_line, 0, wxGROW, 0);
208
siz_all->Add(siz_buttons, 2, wxGROW | wxBOTTOM, 10);
213
chapter_values_dlg::on_language_clicked(wxCommandEvent &evt) {
214
cob_language->Enable(cb_language->IsChecked());
218
chapter_values_dlg::on_country_clicked(wxCommandEvent &evt) {
219
cob_country->Enable(cb_country->IsChecked());
223
expand_subtree(wxTreeCtrl &tree,
225
bool expand = true) {
227
wxTreeItemIdValue cookie;
231
child = tree.GetFirstChild(root, cookie);
233
expand_subtree(tree, child, expand);
234
child = tree.GetNextChild(root, cookie);
243
tab_chapters::tab_chapters(wxWindow *parent,
244
wxMenu *nm_chapters):
245
wxPanel(parent, -1, wxDefaultPosition, wxSize(100, 400), wxTAB_TRAVERSAL) {
246
wxBoxSizer *siz_all, *siz_line, *siz_column;
247
wxStaticBoxSizer *siz_sb;
248
wxFlexGridSizer *siz_fg;
251
m_chapters = nm_chapters;
253
siz_all = new wxBoxSizer(wxVERTICAL);
255
siz_all->Add(0, 5, 0, 0, 0);
256
siz_all->Add(new wxStaticText(this, wxID_STATIC, wxT("Chapters:")),
258
siz_all->Add(0, 5, 0, 0, 0);
261
tc_chapters = new wxTreeCtrl(this, ID_TRC_CHAPTERS);
264
new wxTreeCtrl(this, ID_TRC_CHAPTERS, wxDefaultPosition, wxDefaultSize,
265
wxSUNKEN_BORDER | wxTR_HAS_BUTTONS);
269
new wxButton(this, ID_B_ADDCHAPTER, wxT("Add chapter"), wxDefaultPosition,
273
new wxButton(this, ID_B_ADDSUBCHAPTER, wxT("Add subchapter"),
274
wxDefaultPosition, wxSize(120, -1));
277
new wxButton(this, ID_B_REMOVECHAPTER, wxT("Remove chapter"),
278
wxDefaultPosition, wxSize(120, -1));
281
new wxButton(this, ID_B_SETVALUES, wxT("Set values"), wxDefaultPosition,
283
b_set_values->SetToolTip(TIP("Here you can set the values for the language "
285
"the country that you want to apply to all the "
286
"chapters below and including the currently "
290
new wxButton(this, ID_B_ADJUSTTIMECODES, wxT("Adjust timecodes"),
291
wxDefaultPosition, wxSize(120, -1));
292
b_adjust_timecodes->SetToolTip(TIP("Here you can adjust all the timcdoes "
294
"selected chapter and all its childrend "
296
"a specific amount either increasing or "
299
siz_fg = new wxFlexGridSizer(2);
300
siz_fg->AddGrowableCol(0);
301
siz_fg->AddGrowableRow(0);
303
siz_fg->Add(tc_chapters, 1, wxGROW | wxRIGHT | wxBOTTOM, 5);
305
siz_column = new wxBoxSizer(wxVERTICAL);
306
siz_column->Add(b_add_chapter, 0, wxBOTTOM, 3);
307
siz_column->Add(b_add_subchapter, 0, wxBOTTOM, 3);
308
siz_column->Add(b_remove_chapter, 0, wxBOTTOM, 15);
309
siz_column->Add(b_set_values, 0, wxBOTTOM, 3);
310
siz_column->Add(b_adjust_timecodes, 0, wxBOTTOM, 3);
311
siz_fg->Add(siz_column, 0, wxLEFT | wxBOTTOM, 5);
313
siz_line = new wxBoxSizer(wxHORIZONTAL);
314
st_start = new wxStaticText(this, wxID_STATIC, wxT("Start:"));
315
siz_line->Add(st_start, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
316
tc_start_time = new wxTextCtrl(this, ID_TC_CHAPTERSTART, wxT(""));
317
siz_line->Add(tc_start_time, 1, wxGROW | wxRIGHT, 10);
319
st_end = new wxStaticText(this, wxID_STATIC, wxT("End:"));
320
siz_line->Add(st_end, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
321
tc_end_time = new wxTextCtrl(this, ID_TC_CHAPTEREND, wxT(""));
322
siz_line->Add(tc_end_time, 1, wxGROW, 0);
324
siz_fg->Add(siz_line, 0, wxGROW | wxRIGHT, 5);
325
siz_fg->Add(1, 0, 0, 0, 0);
327
siz_fg->Add(0, 5, 0, 0, 0);
328
siz_fg->Add(0, 5, 0, 0, 0);
330
siz_line = new wxBoxSizer(wxHORIZONTAL);
331
st_uid = new wxStaticText(this, wxID_STATIC, wxT("UID:"));
332
siz_line->Add(st_uid, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
333
tc_uid = new wxTextCtrl(this, ID_TC_UID, wxT(""));
334
tc_uid->SetToolTip(TIP("Each chapter and each edition has a unique "
335
"identifier. This identifier is normally assigned "
336
"automatically by the programs, but it can be "
337
"changed manually if it is really needed."));
338
siz_line->Add(tc_uid, 1, wxGROW | wxRIGHT, 10);
339
cb_flag_hidden = new wxCheckBox(this, ID_CB_CHAPTERHIDDEN, wxT("hidden"));
340
cb_flag_hidden->SetToolTip(TIP("If a chapter is marked 'hidden' then the "
341
"player should not show this chapter entry "
342
"to the user. Such entries could still be "
343
"used by the menu system."));
344
siz_line->Add(cb_flag_hidden, 0, wxRIGHT, 10);
345
cb_flag_enabled = new wxCheckBox(this, ID_CB_CHAPTERENABLED, wxT("enabled"));
346
cb_flag_enabled->SetToolTip(TIP("If a chapter is not marked 'enabled' then "
347
"the player should skip the part of the "
348
"file that this chapter occupies."));
349
siz_line->Add(cb_flag_enabled, 0, 0, 0);
351
siz_fg->Add(siz_line, 0, wxGROW | wxRIGHT, 5);
352
siz_fg->Add(1, 0, 0, 0, 0);
354
siz_all->Add(siz_fg, 1, wxGROW | wxLEFT | wxRIGHT | wxBOTTOM, 10);
357
sb_names = new wxStaticBox(this, wxID_STATIC,
358
wxT("Chapter names and languages"));
359
siz_sb = new wxStaticBoxSizer(sb_names, wxVERTICAL);
361
lb_chapter_names = new wxListBox(this, ID_LB_CHAPTERNAMES);
362
siz_line = new wxBoxSizer(wxHORIZONTAL);
363
siz_line->Add(lb_chapter_names, 1, wxGROW | wxRIGHT, 10);
366
new wxButton(this, ID_B_ADD_CHAPTERNAME, wxT("Add name"),
367
wxDefaultPosition, wxSize(100, -1));
368
b_remove_chapter_name =
369
new wxButton(this, ID_B_REMOVE_CHAPTERNAME, wxT("Remove name"),
370
wxDefaultPosition, wxSize(100, -1));
371
siz_column = new wxBoxSizer(wxVERTICAL);
372
siz_column->Add(b_add_chapter_name, 0, wxBOTTOM, 3);
373
siz_column->Add(b_remove_chapter_name, 0, 0, 0);
374
siz_line->Add(siz_column, 0, 0, 0);
375
siz_sb->Add(siz_line, 1, wxGROW | wxALL, 10);
377
siz_fg = new wxFlexGridSizer(2);
378
siz_fg->AddGrowableCol(1);
379
st_name = new wxStaticText(this, wxID_STATIC, wxT("Name:"));
380
siz_fg->Add(st_name, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT | wxBOTTOM, 10);
381
tc_chapter_name = new wxTextCtrl(this, ID_TC_CHAPTERNAME, wxT(""),
382
wxDefaultPosition, wxDefaultSize,
384
siz_fg->Add(tc_chapter_name, 1, wxGROW | wxBOTTOM, 10);
386
st_language = new wxStaticText(this, wxID_STATIC, wxT("Language:"));
387
siz_fg->Add(st_language, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
390
new wxComboBox(this, ID_CB_CHAPTERSELECTLANGUAGECODE, wxT(""),
391
wxDefaultPosition, wxDefaultSize, 0, NULL,
392
wxCB_DROPDOWN | wxCB_READONLY);
393
for (i = 0; i < sorted_iso_codes.Count(); i++)
394
cob_language_code->Append(sorted_iso_codes[i]);
395
cob_language_code->SetValue(wxT(""));
396
siz_line = new wxBoxSizer(wxHORIZONTAL);
397
siz_line->Add(cob_language_code, 1, wxGROW, 0);
398
siz_line->Add(10, 0, 0, 0, 0);
400
st_country = new wxStaticText(this, wxID_STATIC, wxT("Country:"));
401
siz_line->Add(st_country, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
403
new wxComboBox(this, ID_CB_CHAPTERSELECTCOUNTRYCODE, wxT(""),
404
wxDefaultPosition, wxDefaultSize, 0, NULL,
405
wxCB_DROPDOWN | wxCB_READONLY);
406
cob_country_code->Append(wxT(""));
407
for (i = 0; cctlds[i] != NULL; i++)
408
cob_country_code->Append(wxU(cctlds[i]));
409
cob_country_code->SetValue(wxT(""));
410
siz_line->Add(cob_country_code, 1, wxGROW, 0);
411
siz_fg->Add(siz_line, 0, wxGROW, 0);
413
siz_sb->Add(siz_fg, 0, wxGROW | wxLEFT | wxRIGHT | wxBOTTOM, 10);
414
siz_all->Add(siz_sb, 0, wxGROW | wxLEFT | wxRIGHT | wxBOTTOM, 10);
416
enable_inputs(false);
418
m_chapters->Enable(ID_M_CHAPTERS_SAVE, false);
419
m_chapters->Enable(ID_M_CHAPTERS_SAVEAS, false);
420
m_chapters->Enable(ID_M_CHAPTERS_SAVETOKAX, false);
421
m_chapters->Enable(ID_M_CHAPTERS_VERIFY, false);
422
enable_buttons(false);
427
source_is_kax_file = false;
428
source_is_simple_format = false;
432
SetDropTarget(new chapters_drop_target_c(this));
436
tab_chapters::~tab_chapters() {
437
if (chapters != NULL)
439
if (analyzer != NULL)
444
tab_chapters::enable_inputs(bool enable) {
445
tc_chapter_name->Enable(enable);
446
tc_start_time->Enable(enable);
447
tc_end_time->Enable(enable);
448
tc_uid->Enable(enable);
449
cob_language_code->Enable(enable);
450
cob_country_code->Enable(enable);
451
lb_chapter_names->Enable(enable);
452
b_add_chapter_name->Enable(enable);
453
b_remove_chapter_name->Enable(enable);
454
cb_flag_hidden->Enable(enable);
455
cb_flag_enabled->Enable(enable);
456
st_start->Enable(enable);
457
st_end->Enable(enable);
458
st_uid->Enable(enable);
459
st_name->Enable(enable);
460
st_language->Enable(enable);
461
st_country->Enable(enable);
462
sb_names->Enable(enable);
463
inputs_enabled = enable;
467
tab_chapters::enable_buttons(bool enable) {
468
b_add_chapter->Enable(enable);
469
b_add_subchapter->Enable(enable);
470
b_remove_chapter->Enable(enable);
471
b_set_values->Enable(enable);
472
b_adjust_timecodes->Enable(enable);
476
tab_chapters::on_new_chapters(wxCommandEvent &evt) {
478
if (chapters != NULL)
480
tc_chapters->DeleteAllItems();
481
tid_root = tc_chapters->AddRoot(wxT("(new chapter file)"));
482
chapters = new KaxChapters;
484
m_chapters->Enable(ID_M_CHAPTERS_SAVE, true);
485
m_chapters->Enable(ID_M_CHAPTERS_SAVEAS, true);
486
m_chapters->Enable(ID_M_CHAPTERS_SAVETOKAX, true);
487
m_chapters->Enable(ID_M_CHAPTERS_VERIFY, true);
488
enable_buttons(true);
490
enable_inputs(false);
491
source_is_kax_file = false;
492
if (analyzer != NULL) {
497
clear_list_of_unique_uint32(UNIQUE_CHAPTER_IDS);
498
clear_list_of_unique_uint32(UNIQUE_EDITION_IDS);
500
mdlg->set_status_bar(wxT("New chapters created."));
504
tab_chapters::create_chapter_label(KaxChapterAtom &chapter) {
506
KaxChapterDisplay *display;
507
KaxChapterString *cstring;
508
KaxChapterTimeStart *tstart;
509
KaxChapterTimeEnd *tend;
510
KaxChapterLanguage *language;
513
label = wxT("(unnamed chapter)");
515
display = FindChild<KaxChapterDisplay>(chapter);
516
if (display != NULL) {
517
cstring = FindChild<KaxChapterString>(*display);
520
UTFstring_to_wxString(*static_cast<EbmlUnicodeString *>(cstring));
521
language = FindChild<KaxChapterLanguage>(*display);
524
tstart = FindChild<KaxChapterTimeStart>(chapter);
525
if (tstart != NULL) {
526
timestamp = uint64(*static_cast<EbmlUInteger *>(tstart));
527
s.Printf(wxT(FMT_TIMECODEN), ARG_TIMECODEN(timestamp));
530
tend = FindChild<KaxChapterTimeEnd>(chapter);
532
timestamp = uint64(*static_cast<EbmlUInteger *>(tend));
533
s.Printf(wxT(FMT_TIMECODEN), ARG_TIMECODEN(timestamp));
534
label += wxT(" - ") + s;
539
if (language != NULL)
540
label += wxU(string(*static_cast<EbmlString *>(language)).c_str());
550
tab_chapters::add_recursively(wxTreeItemId &parent,
551
EbmlMaster &master) {
555
KaxChapterAtom *chapter;
556
KaxEditionEntry *eentry;
557
wxTreeItemId this_item;
559
for (i = 0; i < master.ListSize(); i++) {
561
if (EbmlId(*e) == KaxEditionEntry::ClassInfos.GlobalId) {
562
s.Printf(wxT("Edition %d"),
563
(int)tc_chapters->GetChildrenCount(tid_root, false) + 1);
564
eentry = static_cast<KaxEditionEntry *>(e);
566
tc_chapters->AppendItem(parent, s, -1, -1,
567
new chapter_node_data_c(eentry));
568
add_recursively(this_item, *static_cast<EbmlMaster *>(e));
570
} else if (EbmlId(*e) == KaxChapterAtom::ClassInfos.GlobalId) {
571
chapter = static_cast<KaxChapterAtom *>(e);
572
s = create_chapter_label(*chapter);
573
this_item = tc_chapters->AppendItem(parent, s, -1, -1,
574
new chapter_node_data_c(chapter));
575
add_recursively(this_item, *static_cast<EbmlMaster *>(e));
581
tab_chapters::fix_missing_languages(EbmlMaster &master) {
584
KaxChapterDisplay *d;
585
KaxChapterLanguage *l;
589
for (i = 0; i < master.ListSize(); i++) {
592
if (dynamic_cast<EbmlMaster *>(e) != NULL)
593
fix_missing_languages(*dynamic_cast<EbmlMaster *>(e));
595
if (EbmlId(*e) == KaxChapterAtom::ClassInfos.GlobalId) {
596
m = static_cast<EbmlMaster *>(e);
597
d = FindChild<KaxChapterDisplay>(*m);
599
d = &GetChild<KaxChapterDisplay>(*m);
600
l = FindChild<KaxChapterLanguage>(*d);
602
l = &GetChild<KaxChapterLanguage>(*d);
603
*static_cast<EbmlString *>(l) = "eng";
605
u = FindChild<KaxChapterUID>(*m);
607
add_unique_uint32(uint32(*static_cast<EbmlUInteger *>(u)),
614
tab_chapters::on_load_chapters(wxCommandEvent &evt) {
615
wxFileDialog dlg(NULL, wxT("Choose a chapter file"), last_open_dir, wxT(""),
616
wxT("Chapter files (*.xml;*.txt;*.mka;*.mkv;*.cue)|*.xml;"
617
"*.txt;*.mka;*.mkv;*.cue|" ALLFILES), wxOPEN);
619
if (dlg.ShowModal() == wxID_OK)
620
if (load(dlg.GetPath()))
621
last_open_dir = dlg.GetDirectory();
625
tab_chapters::load(wxString name) {
626
KaxChapters *new_chapters;
632
if (kax_analyzer_c::probe(wxMB(name))) {
633
if (analyzer != NULL)
635
analyzer = new kax_analyzer_c(this, wxMB(name));
637
if (!analyzer->process()) {
642
pos = analyzer->find(KaxChapters::ClassInfos.GlobalId);
644
wxMessageBox(wxT("This file does not contain any chapters."),
645
wxT("No chapters found"), wxOK | wxCENTER |
652
e = analyzer->read_element(pos, KaxChapters::ClassInfos);
654
throw error_c("This file does not contain valid chapters.");
655
new_chapters = static_cast<KaxChapters *>(e);
656
source_is_kax_file = true;
657
source_is_simple_format = false;
660
new_chapters = parse_chapters(wxMB(name), 0, -1, 0, "", "", true,
661
&source_is_simple_format);
662
source_is_kax_file = false;
664
} catch (error_c ex) {
666
s = wxU(ex.get_error().c_str());
668
while (s[s.Length() - 1] == wxT('\n'))
669
s.Remove(s.Length() - 1);
670
wxMessageBox(s, wxT("Error parsing the file"),
671
wxOK | wxCENTER | wxICON_ERROR);
675
if (chapters != NULL)
677
tc_chapters->DeleteAllItems();
678
chapters = new_chapters;
679
m_chapters->Enable(ID_M_CHAPTERS_SAVE, true);
680
m_chapters->Enable(ID_M_CHAPTERS_SAVEAS, true);
681
m_chapters->Enable(ID_M_CHAPTERS_SAVETOKAX, true);
682
m_chapters->Enable(ID_M_CHAPTERS_VERIFY, true);
683
enable_buttons(true);
686
clear_list_of_unique_uint32(UNIQUE_CHAPTER_IDS);
687
clear_list_of_unique_uint32(UNIQUE_EDITION_IDS);
688
fix_missing_languages(*chapters);
689
tid_root = tc_chapters->AddRoot(file_name);
690
add_recursively(tid_root, *chapters);
691
expand_subtree(*tc_chapters, tid_root);
693
enable_inputs(false);
695
mdlg->set_last_chapters_in_menu(name);
696
mdlg->set_status_bar(wxT("Chapters loaded."));
702
tab_chapters::on_save_chapters(wxCommandEvent &evt) {
706
if (source_is_kax_file) {
707
if (analyzer->update_element(chapters))
708
mdlg->set_status_bar(wxT("Chapters written."));
712
if ((file_name.length() == 0) || source_is_simple_format)
713
if (!select_file_name())
719
tab_chapters::on_save_chapters_to_kax_file(wxCommandEvent &evt) {
723
wxFileDialog dlg(this, wxT("Choose an output file"), last_open_dir, wxT(""),
724
wxT("Matroska files (*.mkv;*.mka)|*.mkv;*.mka|"
726
if (dlg.ShowModal() != wxID_OK)
729
if (!kax_analyzer_c::probe(wxMB(dlg.GetPath()))) {
730
wxMessageBox(wxT("The file you tried to save to is NOT a Matroska file."),
731
wxT("Wrong file selected"), wxOK | wxCENTER | wxICON_ERROR);
735
last_open_dir = dlg.GetDirectory();
736
file_name = dlg.GetPath();
737
tc_chapters->SetItemText(tid_root, file_name);
739
source_is_kax_file = true;
740
source_is_simple_format = false;
742
if (analyzer != NULL)
744
analyzer = new kax_analyzer_c(this, wxMB(file_name));
745
if (!analyzer->process()) {
750
if (analyzer->update_element(chapters))
751
mdlg->set_status_bar(wxT("Chapters written."));
752
mdlg->set_last_chapters_in_menu(file_name);
756
tab_chapters::on_save_chapters_as(wxCommandEvent &evt) {
760
if (!select_file_name())
766
tab_chapters::select_file_name() {
767
wxFileDialog dlg(this, wxT("Choose an output file"), last_open_dir, wxT(""),
768
wxT("Chapter files (*.xml)|*.xml|"
769
ALLFILES), wxSAVE | wxOVERWRITE_PROMPT);
770
if(dlg.ShowModal() == wxID_OK) {
771
if (kax_analyzer_c::probe(wxMB(dlg.GetPath()))) {
772
wxMessageBox(wxT("The file you tried to save to is a Matroska file. For "
773
"this to work you have to use the 'Save to Matroska "
774
"file' menu option."), wxT("Wrong file selected"),
775
wxOK | wxCENTER | wxICON_ERROR);
778
last_open_dir = dlg.GetDirectory();
779
file_name = dlg.GetPath();
780
tc_chapters->SetItemText(tid_root, file_name);
787
tab_chapters::save() {
792
out = new mm_file_io_c(wxMB(file_name), MODE_CREATE);
793
#if defined(SYS_WINDOWS)
794
out->use_dos_style_newlines(true);
797
err.Printf(wxT("Could not open the destination file '%s' for writing."
798
" Error code: %d (%s)."), file_name.c_str(), errno,
799
wxUCS(strerror(errno)));
800
wxMessageBox(err, wxT("Error opening file"),
801
wxCENTER | wxOK | wxICON_ERROR);
805
out->write_bom("UTF-8");
806
out->printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
808
"<!-- <!DOCTYPE Tags SYSTEM \"matroskatags.dtd\"> -->\n"
811
write_chapters_xml(chapters, out);
812
out->printf("</Chapters>\n");
815
source_is_kax_file = false;
816
source_is_simple_format = false;
818
mdlg->set_last_chapters_in_menu(file_name);
819
mdlg->set_status_bar(wxT("Chapters written."));
823
tab_chapters::on_verify_chapters(wxCommandEvent &evt) {
828
tab_chapters::verify_atom_recursively(EbmlElement *e) {
830
KaxChapterAtom *chapter;
831
KaxChapterTimeStart *start;
832
KaxChapterDisplay *display;
833
KaxChapterLanguage *language;
834
KaxChapterString *cs;
839
if (dynamic_cast<KaxEditionUID *>(e) != NULL)
841
chapter = dynamic_cast<KaxChapterAtom *>(e);
845
if (FindChild<KaxChapterUID>(*chapter) == NULL) {
846
uid = &GetChild<KaxChapterUID>(*chapter);
847
*static_cast<EbmlUInteger *>(uid) =
848
create_unique_uint32(UNIQUE_CHAPTER_IDS);
852
display = FindChild<KaxChapterDisplay>(*chapter);
854
cs = FindChild<KaxChapterString>(*display);
856
if ((display == NULL) || (cs == NULL)) {
857
wxMessageBox(wxT("One of the chapters does not have a name."),
858
wxT("Chapter verification error"), wxCENTER | wxOK |
863
UTFstring_to_wxString(UTFstring(*static_cast<EbmlUnicodeString *>(cs)));
865
start = FindChild<KaxChapterTimeStart>(*chapter);
867
wxMessageBox(wxT("The chapter '") + label +
868
wxT("' is missing the start time."),
869
wxT("Chapter verification error"), wxCENTER | wxOK |
874
language = FindChild<KaxChapterLanguage>(*display);
875
if (language == NULL) {
876
wxMessageBox(wxT("The chapter '") + label +
877
wxT("' is missing its language."),
878
wxT("Chapter verification error"), wxCENTER | wxOK |
882
lang = string(*language);
883
if ((0 == lang.size()) || !is_valid_iso639_2_code(lang.c_str())) {
884
wxMessageBox(wxT("The selected language '") + wxU(lang.c_str()) +
885
wxT("' for the chapter '") + label +
886
wxT("' is not a valid language code. Please select one of "
887
"the predefined ones."),
888
wxT("Chapter verification error"), wxCENTER | wxOK |
893
for (i = 0; i < chapter->ListSize(); i++)
894
if (dynamic_cast<KaxChapterAtom *>((*chapter)[i]) != NULL)
895
if (!verify_atom_recursively((*chapter)[i]))
902
tab_chapters::verify() {
903
KaxEditionEntry *eentry;
907
if (chapters == NULL)
909
if (chapters->ListSize() == 0)
912
id = tc_chapters->GetSelection();
916
fix_mandatory_chapter_elements(chapters);
918
for (eidx = 0; eidx < chapters->ListSize(); eidx++) {
919
eentry = static_cast<KaxEditionEntry *>((*chapters)[eidx]);
920
for (cidx = 0; cidx < eentry->ListSize(); cidx++) {
921
if ((dynamic_cast<KaxChapterAtom *>((*eentry)[cidx]) != NULL) &&
922
!verify_atom_recursively((*eentry)[cidx]))
927
if (!chapters->CheckMandatory())
928
wxdie(wxT("verify failed: chapters->CheckMandatory() is false. This "
929
"should not have happened. Please file a bug report.\n"));
930
chapters->UpdateSize();
936
tab_chapters::on_add_chapter(wxCommandEvent &evt) {
937
wxTreeItemId id, pid;
938
KaxEditionEntry *eentry;
939
KaxChapterAtom *chapter;
941
chapter_node_data_c *d, *pd;
943
vector<EbmlElement *> tmpvec;
946
id = tc_chapters->GetSelection();
951
d = (chapter_node_data_c *)tc_chapters->GetItemData(id);
952
if (id == tid_root) {
955
eentry = new KaxEditionEntry;
956
chapters->PushElement(*eentry);
957
euid = new KaxEditionUID;
958
*static_cast<EbmlUInteger *>(euid) =
959
create_unique_uint32(UNIQUE_EDITION_IDS);
960
eentry->PushElement(*euid);
961
d = new chapter_node_data_c(eentry);
962
s.Printf(wxT("EditionEntry %u"), (unsigned int)chapters->ListSize());
963
id = tc_chapters->AppendItem(tid_root, s, -1, -1, d);
966
chapter = new KaxChapterAtom;
967
while (chapter->ListSize() > 0) {
968
delete (*chapter)[0];
971
KaxChapterDisplay &display = GetEmptyChild<KaxChapterDisplay>(*chapter);
972
*static_cast<EbmlUnicodeString *>(&GetChild<KaxChapterString>(display)) =
973
cstr_to_UTFstring("(unnamed)");
974
if ((default_chapter_language.length() > 0) ||
975
(default_chapter_country.length() > 0)) {
976
if (default_chapter_language.length() > 0)
977
*static_cast<EbmlString *>(&GetChild<KaxChapterLanguage>(display)) =
978
default_chapter_language.c_str();
979
if (default_chapter_country.length() > 0)
980
*static_cast<EbmlString *>(&GetChild<KaxChapterCountry>(display)) =
981
default_chapter_country.c_str();
983
*static_cast<EbmlUInteger *>(&GetChild<KaxChapterUID>(*chapter)) =
984
create_unique_uint32(UNIQUE_CHAPTER_IDS);
985
s = create_chapter_label(*chapter);
988
pid = tc_chapters->GetItemParent(id);
989
pd = (chapter_node_data_c *)tc_chapters->GetItemData(pid);
994
tc_chapters->InsertItem(pid, id, s, -1, -1,
995
new chapter_node_data_c(chapter));
997
start = m->ListSize() + 1;
998
for (i = 0; i < m->ListSize(); i++)
999
if ((*m)[i] == d->chapter) {
1003
if (start >= m->ListSize())
1004
wxdie(wxT("start >= m->ListSize(). This should not have happened. "
1005
"Please file a bug report. Thanks."));
1006
while ((start + 1) < m->ListSize()) {
1007
tmpvec.push_back((*m)[start + 1]);
1008
m->Remove(start + 1);
1010
m->PushElement(*chapter);
1011
for (i = 0; i < tmpvec.size(); i++)
1012
m->PushElement(*tmpvec[i]);
1015
tc_chapters->AppendItem(id, s, -1, -1,
1016
new chapter_node_data_c(chapter));
1017
m->PushElement(*chapter);
1019
id = tc_chapters->GetSelection();
1020
expand_subtree(*tc_chapters, id, true);
1024
tab_chapters::on_add_subchapter(wxCommandEvent &evt) {
1026
KaxEditionEntry *eentry;
1027
KaxChapterAtom *chapter;
1029
chapter_node_data_c *d;
1032
id = tc_chapters->GetSelection();
1037
d = (chapter_node_data_c *)tc_chapters->GetItemData(id);
1038
if (id == tid_root) {
1039
eentry = new KaxEditionEntry;
1040
chapters->PushElement(*eentry);
1041
d = new chapter_node_data_c(eentry);
1042
s.Printf(wxT("EditionEntry %u"), (unsigned int)chapters->ListSize());
1043
id = tc_chapters->AppendItem(tid_root, s, -1, -1, d);
1049
chapter = new KaxChapterAtom;
1050
while (chapter->ListSize() > 0) {
1051
delete (*chapter)[0];
1054
KaxChapterDisplay &display = GetEmptyChild<KaxChapterDisplay>(*chapter);
1055
*static_cast<EbmlUnicodeString *>(&GetChild<KaxChapterString>(display)) =
1056
cstr_to_UTFstring("(unnamed)");
1057
if ((default_chapter_language.length() > 0) ||
1058
(default_chapter_country.length() > 0)) {
1059
if (default_chapter_language.length() > 0)
1060
*static_cast<EbmlString *>(&GetChild<KaxChapterLanguage>(display)) =
1061
default_chapter_language.c_str();
1062
if (default_chapter_country.length() > 0)
1063
*static_cast<EbmlString *>(&GetChild<KaxChapterCountry>(display)) =
1064
default_chapter_country.c_str();
1066
m->PushElement(*chapter);
1067
s = create_chapter_label(*chapter);
1068
tc_chapters->AppendItem(id, s, -1, -1,
1069
new chapter_node_data_c(chapter));
1070
id = tc_chapters->GetSelection();
1071
expand_subtree(*tc_chapters, id, true);
1075
tab_chapters::on_remove_chapter(wxCommandEvent &evt) {
1077
wxTreeItemId id, p_id;
1078
chapter_node_data_c *d, *p_d;
1079
EbmlMaster *m, *del;
1081
id = tc_chapters->GetSelection();
1082
if (!id.IsOk() || (id == tid_root))
1085
p_id = tc_chapters->GetItemParent(id);
1086
if (p_id == tid_root)
1089
p_d = (chapter_node_data_c *)tc_chapters->GetItemData(p_id);
1097
d = (chapter_node_data_c *)tc_chapters->GetItemData(id);
1104
enable_buttons(false);
1105
enable_inputs(false);
1106
for (i = 0; i < m->ListSize(); i++) {
1107
if ((*m)[i] == (EbmlElement *)del) {
1110
tc_chapters->DeleteChildren(id);
1111
tc_chapters->Delete(id);
1118
tab_chapters::on_entry_selected(wxTreeEvent &evt) {
1119
chapter_node_data_c *t;
1120
KaxChapterUID *cuid;
1121
KaxChapterDisplay *display;
1122
KaxChapterString *cstring;
1123
KaxChapterFlagHidden *fhidden;
1124
KaxChapterFlagEnabled *fenabled;
1125
wxString label, language;
1127
wxTreeItemId old_id;
1129
enable_buttons(true);
1131
old_id = evt.GetOldItem();
1132
if (old_id.IsOk() && (old_id != tid_root))
1133
copy_values(old_id);
1135
t = (chapter_node_data_c *)tc_chapters->GetItemData(evt.GetItem());
1136
lb_chapter_names->Clear();
1138
if ((evt.GetItem() == tid_root) || (t == NULL) || !t->is_atom) {
1139
enable_inputs(false);
1141
tc_chapter_name->SetValue(wxT(""));
1142
tc_start_time->SetValue(wxT(""));
1143
tc_end_time->SetValue(wxT(""));
1144
if ((evt.GetItem() != tid_root) && (t != NULL) && !t->is_atom) {
1145
KaxEditionUID *euid;
1148
st_uid->Enable(true);
1149
tc_uid->Enable(true);
1150
euid = FINDFIRST(t->eentry, KaxEditionUID);
1152
s.Printf(wxT("%u"), uint32(*euid));
1153
tc_uid->SetValue(s);
1155
tc_uid->Enable(true);
1156
tc_uid->SetValue(wxT(""));
1157
tc_uid->Enable(false);
1163
enable_inputs(true);
1165
display = FINDFIRST(t->chapter, KaxChapterDisplay);
1166
if (display == NULL)
1167
wxdie(wxT("on_entry_selected: display == NULL. Should not have "
1170
while (display != NULL) {
1171
cstring = FindChild<KaxChapterString>(*display);
1172
if (cstring != NULL)
1174
UTFstring_to_wxString(*static_cast<EbmlUnicodeString *>(cstring));
1176
label = wxT("(unnamed)");
1179
set_display_values(display);
1182
lb_chapter_names->Append(label);
1183
display = FINDNEXT(t->chapter, KaxChapterDisplay, display);
1186
set_timecode_values(t->chapter);
1188
fhidden = FINDFIRST(t->chapter, KaxChapterFlagHidden);
1189
if (fhidden == NULL)
1192
value = uint8(*static_cast<EbmlUInteger *>(fhidden)) != 0;
1193
cb_flag_hidden->SetValue(value);
1195
fenabled = FINDFIRST(t->chapter, KaxChapterFlagEnabled);
1196
if (fenabled == NULL)
1199
value = uint8(*static_cast<EbmlUInteger *>(fenabled)) != 0;
1200
cb_flag_enabled->SetValue(value);
1202
cuid = FINDFIRST(t->chapter, KaxChapterUID);
1206
label.Printf(wxT("%u"), uint32(*cuid));
1207
tc_uid->SetValue(label);
1209
lb_chapter_names->SetSelection(0);
1210
b_remove_chapter_name->Enable(lb_chapter_names->GetCount() > 1);
1211
tc_chapter_name->SetSelection(-1, -1);
1212
tc_chapter_name->SetFocus();
1216
tab_chapters::on_language_code_selected(wxCommandEvent &evt) {
1217
KaxChapterDisplay *cdisplay;
1218
KaxChapterLanguage *clanguage;
1219
chapter_node_data_c *t;
1224
id = tc_chapters->GetSelection();
1227
t = (chapter_node_data_c *)tc_chapters->GetItemData(id);
1233
for (i = 0; i < t->chapter->ListSize(); i++)
1234
if (EbmlId(*(*t->chapter)[i]) == KaxChapterDisplay::ClassInfos.GlobalId) {
1236
if (n == (lb_chapter_names->GetSelection() + 1)) {
1237
cdisplay = (KaxChapterDisplay *)(*t->chapter)[i];
1241
if (cdisplay == NULL)
1244
clanguage = &GetChild<KaxChapterLanguage>(*cdisplay);
1245
*static_cast<EbmlString *>(clanguage) =
1246
wxMB(extract_language_code(cob_language_code->GetStringSelection()));
1248
label = create_chapter_label(*t->chapter);
1249
tc_chapters->SetItemText(id, label);
1253
tab_chapters::on_country_code_selected(wxCommandEvent &evt) {
1254
KaxChapterDisplay *cdisplay;
1255
KaxChapterCountry *ccountry;
1256
chapter_node_data_c *t;
1260
id = tc_chapters->GetSelection();
1263
t = (chapter_node_data_c *)tc_chapters->GetItemData(id);
1269
for (i = 0; i < t->chapter->ListSize(); i++)
1270
if (EbmlId(*(*t->chapter)[i]) == KaxChapterDisplay::ClassInfos.GlobalId) {
1272
if (n == (lb_chapter_names->GetSelection() + 1)) {
1273
cdisplay = (KaxChapterDisplay *)(*t->chapter)[i];
1277
if (cdisplay == NULL)
1280
if (cob_country_code->GetStringSelection().Length() == 0) {
1282
while (i < cdisplay->ListSize()) {
1283
if (EbmlId(*(*cdisplay)[i]) == KaxChapterCountry::ClassInfos.GlobalId) {
1284
delete (*cdisplay)[i];
1285
cdisplay->Remove(i);
1291
ccountry = &GetChild<KaxChapterCountry>(*cdisplay);
1292
*static_cast<EbmlString *>(ccountry) =
1293
wxMB(cob_country_code->GetStringSelection());
1297
tab_chapters::on_chapter_name_changed(wxCommandEvent &evt) {
1298
KaxChapterDisplay *cdisplay;
1299
KaxChapterString *cstring;
1300
chapter_node_data_c *t;
1308
id = tc_chapters->GetSelection();
1311
t = (chapter_node_data_c *)tc_chapters->GetItemData(id);
1317
for (i = 0; i < t->chapter->ListSize(); i++)
1318
if (EbmlId(*(*t->chapter)[i]) == KaxChapterDisplay::ClassInfos.GlobalId) {
1320
if (n == (lb_chapter_names->GetSelection() + 1)) {
1321
cdisplay = (KaxChapterDisplay *)(*t->chapter)[i];
1325
if (cdisplay == NULL)
1328
cstring = &GetChild<KaxChapterString>(*cdisplay);
1330
*static_cast<EbmlUnicodeString *>(cstring) =
1331
cstrutf8_to_UTFstring(wxMB(tc_chapter_name->GetValue()));
1333
*static_cast<EbmlUnicodeString *>(cstring) =
1334
cstr_to_UTFstring(tc_chapter_name->GetValue().c_str());
1337
label = create_chapter_label(*t->chapter);
1338
tc_chapters->SetItemText(id, label);
1339
lb_chapter_names->SetString(lb_chapter_names->GetSelection(),
1340
tc_chapter_name->GetValue());
1344
tab_chapters::on_set_default_values(wxCommandEvent &evt) {
1347
chapter_values_dlg dlg(this, true, wxU(default_chapter_language.c_str()),
1348
wxU(default_chapter_country.c_str()));
1350
if (dlg.ShowModal() != wxID_OK)
1353
language = extract_language_code(dlg.cob_language->GetValue());
1354
if (!is_valid_iso639_2_code(to_utf8(language.c_str()).c_str())) {
1355
wxMessageBox(wxT("The language '") + language +
1356
wxT("' is not a valid language and cannot be selected."),
1357
wxT("Invalid language selected"),
1358
wxICON_ERROR | wxOK);
1361
default_chapter_language = wxMB(language);
1362
default_chapter_country = wxMB(dlg.cob_country->GetValue());
1366
tab_chapters::set_values_recursively(wxTreeItemId id,
1368
bool set_language) {
1370
KaxChapterDisplay *display;
1371
KaxChapterLanguage *language;
1372
KaxChapterCountry *country;
1373
chapter_node_data_c *d;
1374
wxTreeItemId next_child;
1375
wxTreeItemIdValue cookie;
1381
d = (chapter_node_data_c *)tc_chapters->GetItemData(id);
1382
if ((d != NULL) && (d->is_atom)) {
1383
display = FINDFIRST(d->chapter, KaxChapterDisplay);
1384
while (display != NULL) {
1386
while (i < display->ListSize()) {
1387
if ((set_language &&
1388
(dynamic_cast<KaxChapterLanguage *>((*display)[i]) != NULL)) ||
1390
(dynamic_cast<KaxChapterCountry *>((*display)[i]) != NULL))) {
1391
delete (*display)[i];
1398
language = new KaxChapterLanguage;
1399
*static_cast<EbmlString *>(language) = wxMB(s);
1400
display->PushElement(*language);
1402
country = new KaxChapterCountry;
1403
*static_cast<EbmlString *>(country) = wxMB(s);
1404
display->PushElement(*country);
1407
display = FINDNEXT(d->chapter, KaxChapterDisplay, display);
1409
text = create_chapter_label(*d->chapter);
1410
tc_chapters->SetItemText(id, text);
1413
next_child = tc_chapters->GetFirstChild(id, cookie);
1414
while (next_child.IsOk()) {
1415
set_values_recursively(next_child, s, set_language);
1416
next_child = tc_chapters->GetNextChild(id, cookie);
1421
tab_chapters::on_set_values(wxCommandEvent &evt) {
1422
KaxChapterDisplay *cdisplay;
1424
chapter_node_data_c *t;
1427
chapter_values_dlg dlg(this, false);
1429
id = tc_chapters->GetSelection();
1433
if (dlg.ShowModal() != wxID_OK)
1436
if (dlg.cb_language->IsChecked()) {
1437
s = extract_language_code(dlg.cob_language->GetValue());
1438
if (!is_valid_iso639_2_code(to_utf8(s.c_str()).c_str())) {
1439
wxMessageBox(wxT("The language '") + s +
1440
wxT("' is not a valid language and cannot be selected."),
1441
wxT("Invalid language selected"),
1442
wxICON_ERROR | wxOK);
1445
set_values_recursively(id, s, true);
1447
if (dlg.cb_country->IsChecked()) {
1448
s = dlg.cob_country->GetValue();
1449
set_values_recursively(id, s, false);
1452
t = (chapter_node_data_c *)tc_chapters->GetItemData(id);
1453
if ((t == NULL) || !t->is_atom)
1458
for (i = 0; i < t->chapter->ListSize(); i++)
1459
if (EbmlId(*(*t->chapter)[i]) == KaxChapterDisplay::ClassInfos.GlobalId) {
1461
if (n == (lb_chapter_names->GetSelection() + 1)) {
1462
cdisplay = (KaxChapterDisplay *)(*t->chapter)[i];
1466
if (cdisplay == NULL)
1469
set_display_values(cdisplay);
1473
tab_chapters::on_adjust_timecodes(wxCommandEvent &evt) {
1474
KaxChapterDisplay *cdisplay;
1476
chapter_node_data_c *t;
1477
wxString sadjustment;
1478
uint32_t i, n, offset;
1479
int64_t adjustment, mult;
1481
id = tc_chapters->GetSelection();
1486
wxGetTextFromUser(wxT("You can use this function for adjusting the "
1487
"timecodes\nof the selected chapter and all its "
1488
"children by a fixed amount.\nThe amount can be "
1489
"positive or negative. The format used can be\n"
1490
"either just a number in which case it is inter"
1491
"preted as the number of seconds,\nor it can have "
1492
"the usual HH:MM:SS.mmm or HH:MM:SS format.\n"
1493
"Example: -00:05:23 would let all the chpaters "
1494
"begin\n5minutes and 23seconds earlier than now."),
1495
wxT("Adjust chapter timecodes"));
1497
if (sadjustment.Length() == 0)
1500
if (sadjustment.c_str()[0] == wxT('-')) {
1503
} else if (sadjustment.c_str()[0] == wxT('+')) {
1510
sadjustment.Remove(0, offset);
1511
if (sadjustment.Length() == 0)
1513
adjustment = parse_time(sadjustment);
1514
if (adjustment == -1) {
1515
wxMessageBox(wxT("Invalid format used for the adjustment."),
1516
wxT("Input data error"), wxOK | wxCENTER | wxICON_ERROR);
1521
adjust_timecodes_recursively(id, adjustment);
1523
t = (chapter_node_data_c *)tc_chapters->GetItemData(id);
1524
if ((t == NULL) || !t->is_atom)
1527
set_timecode_values(t->chapter);
1531
for (i = 0; i < t->chapter->ListSize(); i++)
1532
if (EbmlId(*(*t->chapter)[i]) == KaxChapterDisplay::ClassInfos.GlobalId) {
1534
if (n == (lb_chapter_names->GetSelection() + 1)) {
1535
cdisplay = (KaxChapterDisplay *)(*t->chapter)[i];
1539
if (cdisplay == NULL)
1542
set_display_values(cdisplay);
1546
tab_chapters::adjust_timecodes_recursively(wxTreeItemId id,
1547
int64_t adjust_by) {
1548
KaxChapterTimeStart *tstart;
1549
KaxChapterTimeEnd *tend;
1550
chapter_node_data_c *d;
1551
wxTreeItemId next_child;
1552
wxTreeItemIdValue cookie;
1559
d = (chapter_node_data_c *)tc_chapters->GetItemData(id);
1560
if ((d != NULL) && (d->is_atom)) {
1561
tstart = FINDFIRST(d->chapter, KaxChapterTimeStart);
1562
if (tstart != NULL) {
1563
t = uint64(*tstart);
1567
*static_cast<EbmlUInteger *>(tstart) = t;
1569
tend = FINDFIRST(d->chapter, KaxChapterTimeEnd);
1575
*static_cast<EbmlUInteger *>(tend) = t;
1577
text = create_chapter_label(*d->chapter);
1578
tc_chapters->SetItemText(id, text);
1581
next_child = tc_chapters->GetFirstChild(id, cookie);
1582
while (next_child.IsOk()) {
1583
adjust_timecodes_recursively(next_child, adjust_by);
1584
next_child = tc_chapters->GetNextChild(id, cookie);
1589
tab_chapters::copy_values(wxTreeItemId id) {
1590
chapter_node_data_c *data;
1592
KaxChapterAtom *chapter;
1594
int64_t ts_start, ts_end;
1595
vector<string> l_codes, c_codes;
1599
data = (chapter_node_data_c *)tc_chapters->GetItemData(id);
1603
label = tc_chapters->GetItemText(id);
1604
chapter = data->chapter;
1606
s = tc_uid->GetValue();
1607
if (s.Length() > 0) {
1608
if (!parse_int(wxMB(s), ts_start))
1609
wxMessageBox(wxT("Invalid UID. A UID is simply a number."),
1610
wxT("Input data error"), wxOK | wxCENTER | wxICON_ERROR);
1613
if (data->is_atom) {
1614
KaxChapterUID *cuid;
1616
cuid = &GetChild<KaxChapterUID>(*data->chapter);
1617
if (ts_start != uint32(*cuid)) {
1618
if (!is_unique_uint32(i, UNIQUE_CHAPTER_IDS)) {
1619
wxMessageBox(wxT("Invalid UID. This chapter UID is already in "
1620
"use. The original UID has not been changed."),
1621
wxT("Input data error"),
1622
wxOK | wxCENTER | wxICON_ERROR);
1623
tc_uid->SetValue(wxString::Format(wxT("%u"), uint32(*cuid)));
1625
remove_unique_uint32(uint32(*cuid), UNIQUE_CHAPTER_IDS);
1626
add_unique_uint32(ts_start, UNIQUE_CHAPTER_IDS);
1627
*static_cast<EbmlUInteger *>(cuid) = ts_start;
1631
KaxEditionUID *euid;
1633
euid = &GetChild<KaxEditionUID>(*data->eentry);
1634
if (ts_start != uint32(*euid)) {
1635
if (!is_unique_uint32(i, UNIQUE_EDITION_IDS)) {
1636
wxMessageBox(wxT("Invalid UID. This edition UID is already in "
1637
"use. The original UID has not been changed."),
1638
wxT("Input data error"),
1639
wxOK | wxCENTER | wxICON_ERROR);
1640
tc_uid->SetValue(wxString::Format(wxT("%u"), uint32(*euid)));
1642
remove_unique_uint32(uint32(*euid), UNIQUE_EDITION_IDS);
1643
add_unique_uint32(ts_start, UNIQUE_EDITION_IDS);
1644
*static_cast<EbmlUInteger *>(euid) = ts_start;
1650
if (data->is_atom) {
1651
s = tc_start_time->GetValue();
1653
ts_start = parse_time(s);
1654
if (ts_start == -1) {
1655
wxMessageBox(wxT("Invalid format used for the start time for '") +
1657
wxT("'. Setting value to 0."), wxT("Input data error"),
1658
wxOK | wxCENTER | wxICON_ERROR);
1662
s = tc_end_time->GetValue();
1664
ts_end = parse_time(s);
1666
wxMessageBox(wxT("Invalid format used for the end time for '") + label +
1667
wxT("'. Setting value to 0."), wxT("Input data error"),
1668
wxOK | wxCENTER | wxICON_ERROR);
1673
while (i < chapter->ListSize()) {
1675
if ((EbmlId(*e) == KaxChapterTimeStart::ClassInfos.GlobalId) ||
1676
(EbmlId(*e) == KaxChapterTimeEnd::ClassInfos.GlobalId)) {
1684
*static_cast<EbmlUInteger *>(&GetChild<KaxChapterTimeStart>(*chapter)) =
1687
*static_cast<EbmlUInteger *>(&GetChild<KaxChapterTimeEnd>(*chapter)) =
1690
label = create_chapter_label(*chapter);
1691
tc_chapters->SetItemText(id, label);
1699
tab_chapters::on_add_chapter_name(wxCommandEvent &evt) {
1700
KaxChapterDisplay *cdisplay;
1701
chapter_node_data_c *t;
1706
id = tc_chapters->GetSelection();
1709
t = (chapter_node_data_c *)tc_chapters->GetItemData(id);
1715
for (i = 0; i < t->chapter->ListSize(); i++)
1716
if (EbmlId(*(*t->chapter)[i]) == KaxChapterDisplay::ClassInfos.GlobalId) {
1718
if (n == (lb_chapter_names->GetSelection() + 1)) {
1719
cdisplay = (KaxChapterDisplay *)(*t->chapter)[i];
1723
if (cdisplay == NULL)
1726
cdisplay = new KaxChapterDisplay;
1727
*static_cast<EbmlUnicodeString *>(&GetChild<KaxChapterString>(*cdisplay)) =
1728
cstr_to_UTFstring("(unnamed)");
1729
if (default_chapter_language.length() > 0)
1730
s = wxU(default_chapter_language.c_str());
1733
*static_cast<EbmlString *>(&GetChild<KaxChapterLanguage>(*cdisplay)) =
1735
if (default_chapter_country.length() > 0)
1736
*static_cast<EbmlString *>(&GetChild<KaxChapterCountry>(*cdisplay)) =
1737
default_chapter_country.c_str();
1738
// Workaround for a bug in libebml
1739
if (i == (t->chapter->ListSize() - 1))
1740
t->chapter->PushElement(*cdisplay);
1742
t->chapter->InsertElement(*cdisplay, i + 1);
1743
s = wxT("(unnamed)");
1744
lb_chapter_names->InsertItems(1, &s, lb_chapter_names->GetSelection() + 1);
1745
lb_chapter_names->SetSelection(lb_chapter_names->GetSelection() + 1);
1746
set_display_values(cdisplay);
1748
b_remove_chapter_name->Enable(true);
1749
tc_chapter_name->SetFocus();
1753
tab_chapters::on_remove_chapter_name(wxCommandEvent &evt) {
1754
KaxChapterDisplay *cdisplay;
1755
chapter_node_data_c *t;
1760
id = tc_chapters->GetSelection();
1763
t = (chapter_node_data_c *)tc_chapters->GetItemData(id);
1769
for (i = 0; i < t->chapter->ListSize(); i++)
1770
if (EbmlId(*(*t->chapter)[i]) == KaxChapterDisplay::ClassInfos.GlobalId) {
1772
if (n == (lb_chapter_names->GetSelection() + 1)) {
1773
cdisplay = (KaxChapterDisplay *)(*t->chapter)[i];
1778
if (cdisplay == NULL)
1781
t->chapter->Remove(i);
1784
n = lb_chapter_names->GetSelection();
1785
lb_chapter_names->Delete(n);
1786
lb_chapter_names->SetSelection(n == 0 ? 0 : n - 1);
1788
s = create_chapter_label(*t->chapter);
1789
tc_chapters->SetItemText(id, s);
1794
for (i = 0; i < t->chapter->ListSize(); i++)
1795
if (EbmlId(*(*t->chapter)[i]) == KaxChapterDisplay::ClassInfos.GlobalId) {
1797
if (n == (lb_chapter_names->GetSelection() + 1)) {
1798
cdisplay = (KaxChapterDisplay *)(*t->chapter)[i];
1803
if (cdisplay != NULL)
1804
set_display_values(cdisplay);
1805
tc_chapter_name->SetFocus();
1806
b_remove_chapter_name->Enable(lb_chapter_names->GetCount() > 1);
1810
tab_chapters::on_chapter_name_selected(wxCommandEvent &evt) {
1811
KaxChapterDisplay *cdisplay;
1812
chapter_node_data_c *t;
1817
id = tc_chapters->GetSelection();
1820
t = (chapter_node_data_c *)tc_chapters->GetItemData(id);
1825
for (i = 0; i < t->chapter->ListSize(); i++)
1826
if (EbmlId(*(*t->chapter)[i]) == KaxChapterDisplay::ClassInfos.GlobalId) {
1828
if (n == (lb_chapter_names->GetSelection() + 1)) {
1829
cdisplay = (KaxChapterDisplay *)(*t->chapter)[i];
1833
if (cdisplay == NULL)
1836
set_display_values(cdisplay);
1837
tc_chapter_name->SetFocus();
1841
tab_chapters::on_chapter_name_enter(wxCommandEvent &evt) {
1843
wxTreeItemIdValue cookie;
1845
id = tc_chapters->GetSelection();
1848
id = tc_chapters->GetNextSibling(id);
1850
tc_chapters->SelectItem(id);
1854
id = tc_chapters->GetItemParent(tc_chapters->GetSelection());
1857
id = tc_chapters->GetNextSibling(id);
1859
id = tc_chapters->GetFirstChild(id, cookie);
1861
tc_chapters->SelectItem(id);
1866
id = tc_chapters->GetRootItem();
1869
id = tc_chapters->GetFirstChild(id, cookie);
1872
id = tc_chapters->GetFirstChild(id, cookie);
1874
tc_chapters->SelectItem(id);
1878
tab_chapters::on_flag_hidden(wxCommandEvent &evt) {
1879
wxTreeItemId selected;
1880
chapter_node_data_c *t;
1883
selected = tc_chapters->GetSelection();
1884
if (!selected.IsOk() || (selected == tid_root))
1886
t = (chapter_node_data_c *)tc_chapters->GetItemData(selected);
1887
if ((t == NULL) || !t->is_atom)
1890
if (cb_flag_hidden->IsChecked())
1891
*static_cast<EbmlUInteger *>
1892
(&GetChild<KaxChapterFlagHidden>(*t->chapter)) = 1;
1894
for (i = 0; i < t->chapter->ListSize(); i++)
1895
if (is_id((*t->chapter)[i], KaxChapterFlagHidden)) {
1896
t->chapter->Remove(i);
1902
tab_chapters::on_flag_enabled(wxCommandEvent &evt) {
1903
wxTreeItemId selected;
1904
chapter_node_data_c *t;
1907
selected = tc_chapters->GetSelection();
1908
if (!selected.IsOk() || (selected == tid_root))
1910
t = (chapter_node_data_c *)tc_chapters->GetItemData(selected);
1911
if ((t == NULL) || !t->is_atom)
1914
if (!cb_flag_enabled->IsChecked())
1915
*static_cast<EbmlUInteger *>
1916
(&GetChild<KaxChapterFlagEnabled>(*t->chapter)) = 0;
1918
for (i = 0; i < t->chapter->ListSize(); i++)
1919
if (is_id((*t->chapter)[i], KaxChapterFlagEnabled)) {
1920
t->chapter->Remove(i);
1926
tab_chapters::set_timecode_values(KaxChapterAtom *atom) {
1927
KaxChapterTimeStart *tstart;
1928
KaxChapterTimeEnd *tend;
1934
tstart = FINDFIRST(atom, KaxChapterTimeStart);
1935
if (tstart != NULL) {
1936
timestamp = uint64(*static_cast<EbmlUInteger *>(tstart));
1937
label.Printf(wxT(FMT_TIMECODEN), ARG_TIMECODEN(timestamp));
1938
tc_start_time->SetValue(label);
1940
tc_start_time->SetValue(wxT(""));
1942
tend = FINDFIRST(atom, KaxChapterTimeEnd);
1944
timestamp = uint64(*static_cast<EbmlUInteger *>(tend));
1945
label.Printf(wxT(FMT_TIMECODEN), ARG_TIMECODEN(timestamp));
1946
tc_end_time->SetValue(label);
1948
tc_end_time->SetValue(wxT(""));
1954
tab_chapters::set_display_values(KaxChapterDisplay *display) {
1955
KaxChapterString *cstring;
1956
KaxChapterLanguage *clanguage;
1957
KaxChapterCountry *ccountry;
1964
cstring = FINDFIRST(display, KaxChapterString);
1965
if (cstring != NULL) {
1967
UTFstring_to_wxString(*static_cast<EbmlUnicodeString *>(cstring));
1968
tc_chapter_name->SetValue(tmp);
1970
tc_chapter_name->SetValue(wxT("(unnamed)"));
1972
clanguage = FINDFIRST(display, KaxChapterLanguage);
1973
if (clanguage != NULL)
1974
language = wxU(string(*static_cast<EbmlString *>(clanguage)).c_str());
1976
language = wxT("eng");
1977
for (i = 0; i < sorted_iso_codes.Count(); i++)
1978
if (extract_language_code(sorted_iso_codes[i]) == language) {
1979
language = sorted_iso_codes[i];
1983
count = cob_language_code->GetCount();
1985
for (i = 0; i < count; i++)
1986
if (cob_language_code->GetString(i) == language) {
1991
cob_language_code->SetSelection(i);
1993
cob_language_code->SetValue(language);
1995
ccountry = FINDFIRST(display, KaxChapterCountry);
1996
if (ccountry != NULL)
1997
cob_country_code->SetValue(wxU(string(*static_cast<EbmlString *>
1998
(ccountry)).c_str()));
2000
cob_country_code->SetValue(wxT(""));
2006
tab_chapters::parse_time(wxString s) {
2013
if (utf8s.length() == 0)
2019
if (parse_timecode(utf8s, nsecs))
2025
if (!parse_int(utf8s, nsecs))
2027
return nsecs * 1000000000;
2031
tab_chapters::is_empty() {
2032
if (!tid_root.IsOk())
2034
return tc_chapters->GetCount() < 2;
2037
IMPLEMENT_CLASS(chapter_values_dlg, wxDialog);
2038
BEGIN_EVENT_TABLE(chapter_values_dlg, wxDialog)
2039
EVT_CHECKBOX(ID_CVD_CB_LANGUAGE, chapter_values_dlg::on_language_clicked)
2040
EVT_CHECKBOX(ID_CVD_CB_COUNTRY, chapter_values_dlg::on_country_clicked)
2043
IMPLEMENT_CLASS(tab_chapters, wxPanel);
2044
BEGIN_EVENT_TABLE(tab_chapters, wxPanel)
2045
EVT_BUTTON(ID_B_ADDCHAPTER, tab_chapters::on_add_chapter)
2046
EVT_BUTTON(ID_B_ADDSUBCHAPTER, tab_chapters::on_add_subchapter)
2047
EVT_BUTTON(ID_B_REMOVECHAPTER, tab_chapters::on_remove_chapter)
2048
EVT_BUTTON(ID_B_SETVALUES, tab_chapters::on_set_values)
2049
EVT_BUTTON(ID_B_ADJUSTTIMECODES, tab_chapters::on_adjust_timecodes)
2050
EVT_BUTTON(ID_B_ADD_CHAPTERNAME, tab_chapters::on_add_chapter_name)
2051
EVT_BUTTON(ID_B_REMOVE_CHAPTERNAME, tab_chapters::on_remove_chapter_name)
2052
EVT_TREE_SEL_CHANGED(ID_TRC_CHAPTERS, tab_chapters::on_entry_selected)
2053
EVT_COMBOBOX(ID_CB_CHAPTERSELECTLANGUAGECODE,
2054
tab_chapters::on_language_code_selected)
2055
EVT_COMBOBOX(ID_CB_CHAPTERSELECTCOUNTRYCODE,
2056
tab_chapters::on_country_code_selected)
2057
EVT_LISTBOX(ID_LB_CHAPTERNAMES, tab_chapters::on_chapter_name_selected)
2058
EVT_TEXT(ID_TC_CHAPTERNAME, tab_chapters::on_chapter_name_changed)
2059
EVT_CHECKBOX(ID_CB_CHAPTERHIDDEN, tab_chapters::on_flag_hidden)
2060
EVT_CHECKBOX(ID_CB_CHAPTERENABLED, tab_chapters::on_flag_enabled)
2061
EVT_TEXT_ENTER(ID_TC_CHAPTERNAME, tab_chapters::on_chapter_name_enter)