~ubuntu-branches/ubuntu/wily/mkvtoolnix/wily

« back to all changes in this revision

Viewing changes to src/mmg/tab_chapters.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Clément Stenac
  • Date: 2005-09-07 19:54:42 UTC
  • Revision ID: james.westby@ubuntu.com-20050907195442-funmigmy8ua340hq
Tags: upstream-1.5.6
Import upstream version 1.5.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   mkvmerge GUI -- utility for splicing together matroska files
 
3
   from component media subtypes
 
4
 
 
5
   Distributed under the GPL
 
6
   see the file COPYING for details
 
7
   or visit http://www.gnu.org/copyleft/gpl.html
 
8
 
 
9
   $Id: tab_chapters.cpp 3047 2005-08-26 08:21:46Z mosu $
 
10
 
 
11
   "chapter editor" tab
 
12
 
 
13
   Written by Moritz Bunkus <moritz@bunkus.org>.
 
14
*/
 
15
 
 
16
#include <errno.h>
 
17
#include <stdio.h>
 
18
 
 
19
#include "wx/wx.h"
 
20
#include "wx/dnd.h"
 
21
#include "wx/listctrl.h"
 
22
#include "wx/notebook.h"
 
23
#include "wx/statline.h"
 
24
 
 
25
#include <ebml/EbmlStream.h>
 
26
 
 
27
#include "chapters.h"
 
28
#include "common.h"
 
29
#include "commonebml.h"
 
30
#include "error.h"
 
31
#include "extern_data.h"
 
32
#include "iso639.h"
 
33
#include "mmg.h"
 
34
#include "mmg_dialog.h"
 
35
#include "kax_analyzer.h"
 
36
#include "tab_chapters.h"
 
37
 
 
38
using namespace std;
 
39
using namespace libebml;
 
40
using namespace libmatroska;
 
41
 
 
42
#if ! wxCHECK_VERSION(2,4,2)
 
43
# define wxTreeItemIdValue long
 
44
#endif
 
45
 
 
46
class chapters_drop_target_c: public wxFileDropTarget {
 
47
private:
 
48
  tab_chapters *owner;
 
49
public:
 
50
  chapters_drop_target_c(tab_chapters *n_owner):
 
51
    owner(n_owner) {};
 
52
  virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &files) {
 
53
    owner->load(files[0]);
 
54
 
 
55
    return true;
 
56
  }
 
57
};
 
58
 
 
59
class chapter_node_data_c: public wxTreeItemData {
 
60
public:
 
61
  bool is_atom;
 
62
  KaxChapterAtom *chapter;
 
63
  KaxEditionEntry *eentry;
 
64
 
 
65
  chapter_node_data_c(KaxChapterAtom *nchapter):
 
66
    is_atom(true),
 
67
    chapter(nchapter) {
 
68
  };
 
69
 
 
70
  chapter_node_data_c(KaxEditionEntry *neentry):
 
71
    is_atom(false),
 
72
    eentry(neentry) {
 
73
  };
 
74
};
 
75
 
 
76
#define ID_CVD_CB_LANGUAGE 12000
 
77
#define ID_CVD_CB_COUNTRY 12001
 
78
 
 
79
class chapter_values_dlg: public wxDialog {
 
80
  DECLARE_CLASS(chapter_values_dlg);
 
81
  DECLARE_EVENT_TABLE();
 
82
public:
 
83
  wxComboBox *cob_language, *cob_country;
 
84
  wxCheckBox *cb_language, *cb_country;
 
85
 
 
86
public:
 
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);
 
92
};
 
93
 
 
94
chapter_values_dlg::chapter_values_dlg(wxWindow *parent,
 
95
                                       bool set_defaults,
 
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;
 
102
  uint32_t i;
 
103
 
 
104
  siz_all = new wxBoxSizer(wxVERTICAL);
 
105
  if (set_defaults) {
 
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 "
 
113
                                      "mmg.")),
 
114
                 0, wxLEFT | wxRIGHT | wxTOP, 10);
 
115
 
 
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);
 
121
 
 
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);
 
128
 
 
129
    siz_input->Add(0, 1, 1, wxGROW, 0);
 
130
    siz_input->Add(0, 1, 1, wxGROW, 0);
 
131
    siz_input->AddGrowableRow(2);
 
132
 
 
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);
 
139
 
 
140
  } else {
 
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 "
 
147
                                      "selected entry.")),
 
148
                 0, wxLEFT | wxRIGHT | wxTOP, 10);
 
149
 
 
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);
 
155
 
 
156
    cb_language =
 
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);
 
165
 
 
166
    siz_input->Add(0, 1, 1, wxGROW, 0);
 
167
    siz_input->Add(0, 1, 1, wxGROW, 0);
 
168
    siz_input->AddGrowableRow(2);
 
169
 
 
170
    cb_country =
 
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);
 
179
 
 
180
  }
 
181
 
 
182
  siz_all->Add(siz_input, 3, wxGROW | wxLEFT | wxRIGHT, 25);
 
183
 
 
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]);
 
188
  }
 
189
 
 
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);
 
194
 
 
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"));
 
199
  b_ok->SetDefault();
 
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);
 
209
  SetSizer(siz_all);
 
210
}
 
211
 
 
212
void
 
213
chapter_values_dlg::on_language_clicked(wxCommandEvent &evt) {
 
214
  cob_language->Enable(cb_language->IsChecked());
 
215
}
 
216
 
 
217
void
 
218
chapter_values_dlg::on_country_clicked(wxCommandEvent &evt) {
 
219
  cob_country->Enable(cb_country->IsChecked());
 
220
}
 
221
 
 
222
void
 
223
expand_subtree(wxTreeCtrl &tree,
 
224
               wxTreeItemId &root,
 
225
               bool expand = true) {
 
226
  wxTreeItemId child;
 
227
  wxTreeItemIdValue cookie;
 
228
 
 
229
  if (!expand)
 
230
    tree.Collapse(root);
 
231
  child = tree.GetFirstChild(root, cookie);
 
232
  while (child > 0) {
 
233
    expand_subtree(tree, child, expand);
 
234
    child = tree.GetNextChild(root, cookie);
 
235
  }
 
236
  if (expand)
 
237
    tree.Expand(root);
 
238
}
 
239
 
 
240
#define Y1 30
 
241
#define X1 100
 
242
 
 
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;
 
249
  uint32_t i;
 
250
 
 
251
  m_chapters = nm_chapters;
 
252
 
 
253
  siz_all = new wxBoxSizer(wxVERTICAL);
 
254
 
 
255
  siz_all->Add(0, 5, 0, 0, 0);
 
256
  siz_all->Add(new wxStaticText(this, wxID_STATIC, wxT("Chapters:")),
 
257
               0, wxLEFT, 10);
 
258
  siz_all->Add(0, 5, 0, 0, 0);
 
259
 
 
260
#ifdef SYS_WINDOWS
 
261
  tc_chapters = new wxTreeCtrl(this, ID_TRC_CHAPTERS);
 
262
#else
 
263
  tc_chapters =
 
264
    new wxTreeCtrl(this, ID_TRC_CHAPTERS, wxDefaultPosition, wxDefaultSize,
 
265
                   wxSUNKEN_BORDER | wxTR_HAS_BUTTONS);
 
266
#endif
 
267
 
 
268
  b_add_chapter =
 
269
    new wxButton(this, ID_B_ADDCHAPTER, wxT("Add chapter"), wxDefaultPosition,
 
270
                 wxSize(120, -1));
 
271
 
 
272
  b_add_subchapter =
 
273
    new wxButton(this, ID_B_ADDSUBCHAPTER, wxT("Add subchapter"),
 
274
                 wxDefaultPosition, wxSize(120, -1));
 
275
 
 
276
  b_remove_chapter =
 
277
    new wxButton(this, ID_B_REMOVECHAPTER, wxT("Remove chapter"),
 
278
                 wxDefaultPosition, wxSize(120, -1));
 
279
 
 
280
  b_set_values =
 
281
    new wxButton(this, ID_B_SETVALUES, wxT("Set values"), wxDefaultPosition,
 
282
                 wxSize(120, -1));
 
283
  b_set_values->SetToolTip(TIP("Here you can set the values for the language "
 
284
                               "and "
 
285
                               "the country that you want to apply to all the "
 
286
                               "chapters below and including the currently "
 
287
                               "selected entry."));
 
288
 
 
289
  b_adjust_timecodes =
 
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 "
 
293
                                     "of the "
 
294
                                     "selected chapter and all its childrend "
 
295
                                     "by "
 
296
                                     "a specific amount either increasing or "
 
297
                                     "decreasing it."));
 
298
 
 
299
  siz_fg = new wxFlexGridSizer(2);
 
300
  siz_fg->AddGrowableCol(0);
 
301
  siz_fg->AddGrowableRow(0);
 
302
 
 
303
  siz_fg->Add(tc_chapters, 1, wxGROW | wxRIGHT | wxBOTTOM, 5);
 
304
 
 
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);
 
312
 
 
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);
 
318
 
 
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);
 
323
 
 
324
  siz_fg->Add(siz_line, 0, wxGROW | wxRIGHT, 5);
 
325
  siz_fg->Add(1, 0, 0, 0, 0);
 
326
 
 
327
  siz_fg->Add(0, 5, 0, 0, 0);
 
328
  siz_fg->Add(0, 5, 0, 0, 0);
 
329
 
 
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);
 
350
 
 
351
  siz_fg->Add(siz_line, 0, wxGROW | wxRIGHT, 5);
 
352
  siz_fg->Add(1, 0, 0, 0, 0);
 
353
 
 
354
  siz_all->Add(siz_fg, 1, wxGROW | wxLEFT | wxRIGHT | wxBOTTOM, 10);
 
355
 
 
356
 
 
357
  sb_names = new wxStaticBox(this, wxID_STATIC,
 
358
                             wxT("Chapter names and languages"));
 
359
  siz_sb = new wxStaticBoxSizer(sb_names, wxVERTICAL);
 
360
 
 
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);
 
364
 
 
365
  b_add_chapter_name =
 
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);
 
376
 
 
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,
 
383
                                   wxTE_PROCESS_ENTER);
 
384
  siz_fg->Add(tc_chapter_name, 1, wxGROW | wxBOTTOM, 10);
 
385
 
 
386
  st_language = new wxStaticText(this, wxID_STATIC, wxT("Language:"));
 
387
  siz_fg->Add(st_language, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
 
388
 
 
389
  cob_language_code =
 
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);
 
399
 
 
400
  st_country = new wxStaticText(this, wxID_STATIC, wxT("Country:"));
 
401
  siz_line->Add(st_country, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
 
402
  cob_country_code =
 
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);
 
412
 
 
413
  siz_sb->Add(siz_fg, 0, wxGROW | wxLEFT | wxRIGHT | wxBOTTOM, 10);
 
414
  siz_all->Add(siz_sb, 0, wxGROW | wxLEFT | wxRIGHT | wxBOTTOM, 10);
 
415
 
 
416
  enable_inputs(false);
 
417
 
 
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);
 
423
 
 
424
  file_name = wxT("");
 
425
  chapters = NULL;
 
426
  analyzer = NULL;
 
427
  source_is_kax_file = false;
 
428
  source_is_simple_format = false;
 
429
 
 
430
  no_update = false;
 
431
 
 
432
  SetDropTarget(new chapters_drop_target_c(this));
 
433
  SetSizer(siz_all);
 
434
}
 
435
 
 
436
tab_chapters::~tab_chapters() {
 
437
  if (chapters != NULL)
 
438
    delete chapters;
 
439
  if (analyzer != NULL)
 
440
    delete analyzer;
 
441
}
 
442
 
 
443
void
 
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;
 
464
}
 
465
 
 
466
void
 
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);
 
473
}
 
474
 
 
475
void
 
476
tab_chapters::on_new_chapters(wxCommandEvent &evt) {
 
477
  file_name = wxT("");
 
478
  if (chapters != NULL)
 
479
    delete chapters;
 
480
  tc_chapters->DeleteAllItems();
 
481
  tid_root = tc_chapters->AddRoot(wxT("(new chapter file)"));
 
482
  chapters = new KaxChapters;
 
483
 
 
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);
 
489
 
 
490
  enable_inputs(false);
 
491
  source_is_kax_file = false;
 
492
  if (analyzer != NULL) {
 
493
    delete analyzer;
 
494
    analyzer = NULL;
 
495
  }
 
496
 
 
497
  clear_list_of_unique_uint32(UNIQUE_CHAPTER_IDS);
 
498
  clear_list_of_unique_uint32(UNIQUE_EDITION_IDS);
 
499
 
 
500
  mdlg->set_status_bar(wxT("New chapters created."));
 
501
}
 
502
 
 
503
wxString
 
504
tab_chapters::create_chapter_label(KaxChapterAtom &chapter) {
 
505
  wxString label, s;
 
506
  KaxChapterDisplay *display;
 
507
  KaxChapterString *cstring;
 
508
  KaxChapterTimeStart *tstart;
 
509
  KaxChapterTimeEnd *tend;
 
510
  KaxChapterLanguage *language;
 
511
  int64_t timestamp;
 
512
 
 
513
  label = wxT("(unnamed chapter)");
 
514
  language = NULL;
 
515
  display = FindChild<KaxChapterDisplay>(chapter);
 
516
  if (display != NULL) {
 
517
    cstring = FindChild<KaxChapterString>(*display);
 
518
    if (cstring != NULL)
 
519
      label =
 
520
        UTFstring_to_wxString(*static_cast<EbmlUnicodeString *>(cstring));
 
521
    language = FindChild<KaxChapterLanguage>(*display);
 
522
  }
 
523
  label += wxT(" [");
 
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));
 
528
    label += s;
 
529
 
 
530
    tend = FindChild<KaxChapterTimeEnd>(chapter);
 
531
    if (tend != NULL) {
 
532
      timestamp = uint64(*static_cast<EbmlUInteger *>(tend));
 
533
      s.Printf(wxT(FMT_TIMECODEN), ARG_TIMECODEN(timestamp));
 
534
      label += wxT(" - ") + s;
 
535
    }
 
536
 
 
537
    label += wxT("; ");
 
538
  }
 
539
  if (language != NULL)
 
540
    label += wxU(string(*static_cast<EbmlString *>(language)).c_str());
 
541
  else
 
542
    label += wxT("eng");
 
543
 
 
544
  label += wxT("]");
 
545
 
 
546
  return label;
 
547
}
 
548
 
 
549
void
 
550
tab_chapters::add_recursively(wxTreeItemId &parent,
 
551
                              EbmlMaster &master) {
 
552
  uint32_t i;
 
553
  wxString s;
 
554
  EbmlElement *e;
 
555
  KaxChapterAtom *chapter;
 
556
  KaxEditionEntry *eentry;
 
557
  wxTreeItemId this_item;
 
558
 
 
559
  for (i = 0; i < master.ListSize(); i++) {
 
560
    e = master[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);
 
565
      this_item =
 
566
        tc_chapters->AppendItem(parent, s, -1, -1,
 
567
                                new chapter_node_data_c(eentry));
 
568
      add_recursively(this_item, *static_cast<EbmlMaster *>(e));
 
569
 
 
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));
 
576
    }
 
577
  }
 
578
}
 
579
 
 
580
void
 
581
tab_chapters::fix_missing_languages(EbmlMaster &master) {
 
582
  uint32_t i;
 
583
  EbmlElement *e;
 
584
  KaxChapterDisplay *d;
 
585
  KaxChapterLanguage *l;
 
586
  KaxChapterUID *u;
 
587
  EbmlMaster *m;
 
588
 
 
589
  for (i = 0; i < master.ListSize(); i++) {
 
590
    e = master[i];
 
591
 
 
592
    if (dynamic_cast<EbmlMaster *>(e) != NULL)
 
593
      fix_missing_languages(*dynamic_cast<EbmlMaster *>(e));
 
594
 
 
595
    if (EbmlId(*e) == KaxChapterAtom::ClassInfos.GlobalId) {
 
596
      m = static_cast<EbmlMaster *>(e);
 
597
      d = FindChild<KaxChapterDisplay>(*m);
 
598
      if (d == NULL)
 
599
        d = &GetChild<KaxChapterDisplay>(*m);
 
600
      l = FindChild<KaxChapterLanguage>(*d);
 
601
      if (l == NULL) {
 
602
        l = &GetChild<KaxChapterLanguage>(*d);
 
603
        *static_cast<EbmlString *>(l) = "eng";
 
604
      }
 
605
      u = FindChild<KaxChapterUID>(*m);
 
606
      if (u != NULL)
 
607
        add_unique_uint32(uint32(*static_cast<EbmlUInteger *>(u)),
 
608
                          UNIQUE_CHAPTER_IDS);
 
609
    }
 
610
  }
 
611
}
 
612
 
 
613
void
 
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);
 
618
 
 
619
  if (dlg.ShowModal() == wxID_OK)
 
620
    if (load(dlg.GetPath()))
 
621
      last_open_dir = dlg.GetDirectory();
 
622
}
 
623
 
 
624
bool
 
625
tab_chapters::load(wxString name) {
 
626
  KaxChapters *new_chapters;
 
627
  EbmlElement *e;
 
628
  wxString s;
 
629
  int pos;
 
630
 
 
631
  try {
 
632
    if (kax_analyzer_c::probe(wxMB(name))) {
 
633
      if (analyzer != NULL)
 
634
        delete analyzer;
 
635
      analyzer = new kax_analyzer_c(this, wxMB(name));
 
636
      file_name = name;
 
637
      if (!analyzer->process()) {
 
638
        delete analyzer;
 
639
        analyzer = NULL;
 
640
        return false;
 
641
      }
 
642
      pos = analyzer->find(KaxChapters::ClassInfos.GlobalId);
 
643
      if (pos == -1) {
 
644
        wxMessageBox(wxT("This file does not contain any chapters."),
 
645
                     wxT("No chapters found"), wxOK | wxCENTER |
 
646
                     wxICON_INFORMATION);
 
647
        delete analyzer;
 
648
        analyzer = NULL;
 
649
        return false;
 
650
      }
 
651
 
 
652
      e = analyzer->read_element(pos, KaxChapters::ClassInfos);
 
653
      if (e == NULL)
 
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;
 
658
 
 
659
    } else {
 
660
      new_chapters = parse_chapters(wxMB(name), 0, -1, 0, "", "", true,
 
661
                                    &source_is_simple_format);
 
662
      source_is_kax_file = false;
 
663
    }
 
664
  } catch (error_c ex) {
 
665
    analyzer = NULL;
 
666
    s = wxU(ex.get_error().c_str());
 
667
    break_line(s);
 
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);
 
672
    return false;
 
673
  }
 
674
 
 
675
  if (chapters != NULL)
 
676
    delete chapters;
 
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);
 
684
 
 
685
  file_name = name;
 
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);
 
692
 
 
693
  enable_inputs(false);
 
694
 
 
695
  mdlg->set_last_chapters_in_menu(name);
 
696
  mdlg->set_status_bar(wxT("Chapters loaded."));
 
697
 
 
698
  return true;
 
699
}
 
700
 
 
701
void
 
702
tab_chapters::on_save_chapters(wxCommandEvent &evt) {
 
703
  if (!verify())
 
704
    return;
 
705
 
 
706
  if (source_is_kax_file) {
 
707
    if (analyzer->update_element(chapters))
 
708
      mdlg->set_status_bar(wxT("Chapters written."));
 
709
    return;
 
710
  }
 
711
 
 
712
  if ((file_name.length() == 0) || source_is_simple_format)
 
713
    if (!select_file_name())
 
714
      return;
 
715
  save();
 
716
}
 
717
 
 
718
void
 
719
tab_chapters::on_save_chapters_to_kax_file(wxCommandEvent &evt) {
 
720
  if (!verify())
 
721
    return;
 
722
 
 
723
  wxFileDialog dlg(this, wxT("Choose an output file"), last_open_dir, wxT(""),
 
724
                   wxT("Matroska files (*.mkv;*.mka)|*.mkv;*.mka|"
 
725
                      ALLFILES), wxSAVE);
 
726
  if (dlg.ShowModal() != wxID_OK)
 
727
    return;
 
728
 
 
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);
 
732
    return;
 
733
  }
 
734
 
 
735
  last_open_dir = dlg.GetDirectory();
 
736
  file_name = dlg.GetPath();
 
737
  tc_chapters->SetItemText(tid_root, file_name);
 
738
 
 
739
  source_is_kax_file = true;
 
740
  source_is_simple_format = false;
 
741
 
 
742
  if (analyzer != NULL)
 
743
    delete analyzer;
 
744
  analyzer = new kax_analyzer_c(this, wxMB(file_name));
 
745
  if (!analyzer->process()) {
 
746
    delete analyzer;
 
747
    analyzer = NULL;
 
748
    return;
 
749
  }
 
750
  if (analyzer->update_element(chapters))
 
751
    mdlg->set_status_bar(wxT("Chapters written."));
 
752
  mdlg->set_last_chapters_in_menu(file_name);
 
753
}
 
754
 
 
755
void
 
756
tab_chapters::on_save_chapters_as(wxCommandEvent &evt) {
 
757
  if (!verify())
 
758
    return;
 
759
 
 
760
  if (!select_file_name())
 
761
    return;
 
762
  save();
 
763
}
 
764
 
 
765
bool
 
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);
 
776
      return false;
 
777
    }
 
778
    last_open_dir = dlg.GetDirectory();
 
779
    file_name = dlg.GetPath();
 
780
    tc_chapters->SetItemText(tid_root, file_name);
 
781
    return true;
 
782
  }
 
783
  return false;
 
784
}
 
785
 
 
786
void
 
787
tab_chapters::save() {
 
788
  mm_io_c *out;
 
789
  wxString err;
 
790
 
 
791
  try {
 
792
    out = new mm_file_io_c(wxMB(file_name), MODE_CREATE);
 
793
#if defined(SYS_WINDOWS)
 
794
    out->use_dos_style_newlines(true);
 
795
#endif
 
796
  } catch (...) {
 
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);
 
802
    return;
 
803
  }
 
804
 
 
805
  out->write_bom("UTF-8");
 
806
  out->printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
 
807
              "\n"
 
808
              "<!-- <!DOCTYPE Tags SYSTEM \"matroskatags.dtd\"> -->\n"
 
809
              "\n"
 
810
              "<Chapters>\n");
 
811
  write_chapters_xml(chapters, out);
 
812
  out->printf("</Chapters>\n");
 
813
  delete out;
 
814
 
 
815
  source_is_kax_file = false;
 
816
  source_is_simple_format = false;
 
817
 
 
818
  mdlg->set_last_chapters_in_menu(file_name);
 
819
  mdlg->set_status_bar(wxT("Chapters written."));
 
820
}
 
821
 
 
822
void
 
823
tab_chapters::on_verify_chapters(wxCommandEvent &evt) {
 
824
  verify();
 
825
}
 
826
 
 
827
bool
 
828
tab_chapters::verify_atom_recursively(EbmlElement *e) {
 
829
  KaxChapterUID *uid;
 
830
  KaxChapterAtom *chapter;
 
831
  KaxChapterTimeStart *start;
 
832
  KaxChapterDisplay *display;
 
833
  KaxChapterLanguage *language;
 
834
  KaxChapterString *cs;
 
835
  wxString label;
 
836
  string lang;
 
837
  uint32_t i;
 
838
 
 
839
  if (dynamic_cast<KaxEditionUID *>(e) != NULL)
 
840
    return true;
 
841
  chapter = dynamic_cast<KaxChapterAtom *>(e);
 
842
  if (chapter == NULL)
 
843
    return false;
 
844
 
 
845
  if (FindChild<KaxChapterUID>(*chapter) == NULL) {
 
846
    uid = &GetChild<KaxChapterUID>(*chapter);
 
847
    *static_cast<EbmlUInteger *>(uid) =
 
848
      create_unique_uint32(UNIQUE_CHAPTER_IDS);
 
849
  }
 
850
 
 
851
  cs = NULL;
 
852
  display = FindChild<KaxChapterDisplay>(*chapter);
 
853
  if (display != NULL)
 
854
    cs = FindChild<KaxChapterString>(*display);
 
855
 
 
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 |
 
859
                 wxICON_ERROR);
 
860
    return false;
 
861
  }
 
862
  label =
 
863
    UTFstring_to_wxString(UTFstring(*static_cast<EbmlUnicodeString *>(cs)));
 
864
 
 
865
  start = FindChild<KaxChapterTimeStart>(*chapter);
 
866
  if (start == NULL) {
 
867
    wxMessageBox(wxT("The chapter '") + label +
 
868
                 wxT("' is missing the start time."),
 
869
                 wxT("Chapter verification error"), wxCENTER | wxOK |
 
870
                 wxICON_ERROR);
 
871
    return false;
 
872
  }
 
873
 
 
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 |
 
879
                 wxICON_ERROR);
 
880
    return false;
 
881
  }
 
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 |
 
889
                 wxICON_ERROR);
 
890
    return false;
 
891
  }
 
892
 
 
893
  for (i = 0; i < chapter->ListSize(); i++)
 
894
    if (dynamic_cast<KaxChapterAtom *>((*chapter)[i]) != NULL)
 
895
      if (!verify_atom_recursively((*chapter)[i]))
 
896
        return false;
 
897
 
 
898
  return true;
 
899
}
 
900
 
 
901
bool
 
902
tab_chapters::verify() {
 
903
  KaxEditionEntry *eentry;
 
904
  wxTreeItemId id;
 
905
  uint32_t eidx, cidx;
 
906
 
 
907
  if (chapters == NULL)
 
908
    return false;
 
909
  if (chapters->ListSize() == 0)
 
910
    return false;
 
911
 
 
912
  id = tc_chapters->GetSelection();
 
913
  if (id.IsOk())
 
914
    copy_values(id);
 
915
 
 
916
  fix_mandatory_chapter_elements(chapters);
 
917
 
 
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]))
 
923
        return false;
 
924
    }
 
925
  }
 
926
 
 
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();
 
931
 
 
932
  return true;
 
933
}
 
934
 
 
935
void
 
936
tab_chapters::on_add_chapter(wxCommandEvent &evt) {
 
937
  wxTreeItemId id, pid;
 
938
  KaxEditionEntry *eentry;
 
939
  KaxChapterAtom *chapter;
 
940
  EbmlMaster *m;
 
941
  chapter_node_data_c *d, *pd;
 
942
  wxString s;
 
943
  vector<EbmlElement *> tmpvec;
 
944
  uint32_t start, i;
 
945
 
 
946
  id = tc_chapters->GetSelection();
 
947
  if (!id.IsOk())
 
948
    return;
 
949
  copy_values(id);
 
950
 
 
951
  d = (chapter_node_data_c *)tc_chapters->GetItemData(id);
 
952
  if (id == tid_root) {
 
953
    KaxEditionUID *euid;
 
954
 
 
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);
 
964
  }
 
965
 
 
966
  chapter = new KaxChapterAtom;
 
967
  while (chapter->ListSize() > 0) {
 
968
    delete (*chapter)[0];
 
969
    chapter->Remove(0);
 
970
  }
 
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();
 
982
  }
 
983
  *static_cast<EbmlUInteger *>(&GetChild<KaxChapterUID>(*chapter)) =
 
984
    create_unique_uint32(UNIQUE_CHAPTER_IDS);
 
985
  s = create_chapter_label(*chapter);
 
986
 
 
987
  if (d->is_atom) {
 
988
    pid = tc_chapters->GetItemParent(id);
 
989
    pd = (chapter_node_data_c *)tc_chapters->GetItemData(pid);
 
990
    if (pd->is_atom)
 
991
      m = pd->chapter;
 
992
    else
 
993
      m = pd->eentry;
 
994
    tc_chapters->InsertItem(pid, id, s, -1, -1,
 
995
                            new chapter_node_data_c(chapter));
 
996
 
 
997
    start = m->ListSize() + 1;
 
998
    for (i = 0; i < m->ListSize(); i++)
 
999
      if ((*m)[i] == d->chapter) {
 
1000
        start = i;
 
1001
        break;
 
1002
      }
 
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);
 
1009
    }
 
1010
    m->PushElement(*chapter);
 
1011
    for (i = 0; i < tmpvec.size(); i++)
 
1012
      m->PushElement(*tmpvec[i]);
 
1013
  } else {
 
1014
    m = d->eentry;
 
1015
    tc_chapters->AppendItem(id, s, -1, -1,
 
1016
                            new chapter_node_data_c(chapter));
 
1017
    m->PushElement(*chapter);
 
1018
  }
 
1019
  id = tc_chapters->GetSelection();
 
1020
  expand_subtree(*tc_chapters, id, true);
 
1021
}
 
1022
 
 
1023
void
 
1024
tab_chapters::on_add_subchapter(wxCommandEvent &evt) {
 
1025
  wxTreeItemId id;
 
1026
  KaxEditionEntry *eentry;
 
1027
  KaxChapterAtom *chapter;
 
1028
  EbmlMaster *m;
 
1029
  chapter_node_data_c *d;
 
1030
  wxString s;
 
1031
 
 
1032
  id = tc_chapters->GetSelection();
 
1033
  if (!id.IsOk())
 
1034
    return;
 
1035
  copy_values(id);
 
1036
 
 
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);
 
1044
  }
 
1045
  if (d->is_atom)
 
1046
    m = d->chapter;
 
1047
  else
 
1048
    m = d->eentry;
 
1049
  chapter = new KaxChapterAtom;
 
1050
  while (chapter->ListSize() > 0) {
 
1051
    delete (*chapter)[0];
 
1052
    chapter->Remove(0);
 
1053
  }
 
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();
 
1065
  }
 
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);
 
1072
}
 
1073
 
 
1074
void
 
1075
tab_chapters::on_remove_chapter(wxCommandEvent &evt) {
 
1076
  uint32_t i;
 
1077
  wxTreeItemId id, p_id;
 
1078
  chapter_node_data_c *d, *p_d;
 
1079
  EbmlMaster *m, *del;
 
1080
 
 
1081
  id = tc_chapters->GetSelection();
 
1082
  if (!id.IsOk() || (id == tid_root))
 
1083
    return;
 
1084
 
 
1085
  p_id = tc_chapters->GetItemParent(id);
 
1086
  if (p_id == tid_root)
 
1087
    m = chapters;
 
1088
  else {
 
1089
    p_d = (chapter_node_data_c *)tc_chapters->GetItemData(p_id);
 
1090
    if (p_d == NULL)
 
1091
      return;
 
1092
    if (p_d->is_atom)
 
1093
      m = p_d->chapter;
 
1094
    else
 
1095
      m = p_d->eentry;
 
1096
  }
 
1097
  d = (chapter_node_data_c *)tc_chapters->GetItemData(id);
 
1098
  if (d == NULL)
 
1099
    return;
 
1100
  if (d->is_atom)
 
1101
    del = d->chapter;
 
1102
  else
 
1103
    del = d->eentry;
 
1104
  enable_buttons(false);
 
1105
  enable_inputs(false);
 
1106
  for (i = 0; i < m->ListSize(); i++) {
 
1107
    if ((*m)[i] == (EbmlElement *)del) {
 
1108
      delete del;
 
1109
      m->Remove(i);
 
1110
      tc_chapters->DeleteChildren(id);
 
1111
      tc_chapters->Delete(id);
 
1112
      return;
 
1113
    }
 
1114
  }
 
1115
}
 
1116
 
 
1117
void
 
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;
 
1126
  bool first, value;
 
1127
  wxTreeItemId old_id;
 
1128
 
 
1129
  enable_buttons(true);
 
1130
 
 
1131
  old_id = evt.GetOldItem();
 
1132
  if (old_id.IsOk() && (old_id != tid_root))
 
1133
    copy_values(old_id);
 
1134
 
 
1135
  t = (chapter_node_data_c *)tc_chapters->GetItemData(evt.GetItem());
 
1136
  lb_chapter_names->Clear();
 
1137
 
 
1138
  if ((evt.GetItem() == tid_root) || (t == NULL) || !t->is_atom) {
 
1139
    enable_inputs(false);
 
1140
    no_update = true;
 
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;
 
1146
      wxString s;
 
1147
 
 
1148
      st_uid->Enable(true);
 
1149
      tc_uid->Enable(true);
 
1150
      euid = FINDFIRST(t->eentry, KaxEditionUID);
 
1151
      if (euid != NULL)
 
1152
        s.Printf(wxT("%u"), uint32(*euid));
 
1153
      tc_uid->SetValue(s);
 
1154
    } else {
 
1155
      tc_uid->Enable(true);
 
1156
      tc_uid->SetValue(wxT(""));
 
1157
      tc_uid->Enable(false);
 
1158
    }
 
1159
    no_update = false;
 
1160
    return;
 
1161
  }
 
1162
 
 
1163
  enable_inputs(true);
 
1164
 
 
1165
  display = FINDFIRST(t->chapter, KaxChapterDisplay);
 
1166
  if (display == NULL)
 
1167
    wxdie(wxT("on_entry_selected: display == NULL. Should not have "
 
1168
              "happened."));
 
1169
  first = true;
 
1170
  while (display != NULL) {
 
1171
    cstring = FindChild<KaxChapterString>(*display);
 
1172
    if (cstring != NULL)
 
1173
      label =
 
1174
        UTFstring_to_wxString(*static_cast<EbmlUnicodeString *>(cstring));
 
1175
    else
 
1176
      label = wxT("(unnamed)");
 
1177
 
 
1178
    if (first) {
 
1179
      set_display_values(display);
 
1180
      first = false;
 
1181
    }
 
1182
    lb_chapter_names->Append(label);
 
1183
    display = FINDNEXT(t->chapter, KaxChapterDisplay, display);
 
1184
  }
 
1185
 
 
1186
  set_timecode_values(t->chapter);
 
1187
 
 
1188
  fhidden = FINDFIRST(t->chapter, KaxChapterFlagHidden);
 
1189
  if (fhidden == NULL)
 
1190
    value = false;
 
1191
  else
 
1192
    value = uint8(*static_cast<EbmlUInteger *>(fhidden)) != 0;
 
1193
  cb_flag_hidden->SetValue(value);
 
1194
 
 
1195
  fenabled = FINDFIRST(t->chapter, KaxChapterFlagEnabled);
 
1196
  if (fenabled == NULL)
 
1197
    value = true;
 
1198
  else
 
1199
    value = uint8(*static_cast<EbmlUInteger *>(fenabled)) != 0;
 
1200
  cb_flag_enabled->SetValue(value);
 
1201
 
 
1202
  cuid = FINDFIRST(t->chapter, KaxChapterUID);
 
1203
  if (cuid == NULL)
 
1204
    label = wxT("");
 
1205
  else
 
1206
    label.Printf(wxT("%u"), uint32(*cuid));
 
1207
  tc_uid->SetValue(label);
 
1208
 
 
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();
 
1213
}
 
1214
 
 
1215
void
 
1216
tab_chapters::on_language_code_selected(wxCommandEvent &evt) {
 
1217
  KaxChapterDisplay *cdisplay;
 
1218
  KaxChapterLanguage *clanguage;
 
1219
  chapter_node_data_c *t;
 
1220
  uint32_t i, n;
 
1221
  wxString label;
 
1222
  wxTreeItemId id;
 
1223
 
 
1224
  id = tc_chapters->GetSelection();
 
1225
  if (!id.IsOk())
 
1226
    return;
 
1227
  t = (chapter_node_data_c *)tc_chapters->GetItemData(id);
 
1228
  if (!t->is_atom)
 
1229
    return;
 
1230
 
 
1231
  cdisplay = NULL;
 
1232
  n = 0;
 
1233
  for (i = 0; i < t->chapter->ListSize(); i++)
 
1234
    if (EbmlId(*(*t->chapter)[i]) == KaxChapterDisplay::ClassInfos.GlobalId) {
 
1235
      n++;
 
1236
      if (n == (lb_chapter_names->GetSelection() + 1)) {
 
1237
        cdisplay = (KaxChapterDisplay *)(*t->chapter)[i];
 
1238
        break;
 
1239
      }
 
1240
    }
 
1241
  if (cdisplay == NULL)
 
1242
    return;
 
1243
 
 
1244
  clanguage = &GetChild<KaxChapterLanguage>(*cdisplay);
 
1245
  *static_cast<EbmlString *>(clanguage) =
 
1246
    wxMB(extract_language_code(cob_language_code->GetStringSelection()));
 
1247
 
 
1248
  label = create_chapter_label(*t->chapter);
 
1249
  tc_chapters->SetItemText(id, label);
 
1250
}
 
1251
 
 
1252
void
 
1253
tab_chapters::on_country_code_selected(wxCommandEvent &evt) {
 
1254
  KaxChapterDisplay *cdisplay;
 
1255
  KaxChapterCountry *ccountry;
 
1256
  chapter_node_data_c *t;
 
1257
  uint32_t i, n;
 
1258
  wxTreeItemId id;
 
1259
 
 
1260
  id = tc_chapters->GetSelection();
 
1261
  if (!id.IsOk())
 
1262
    return;
 
1263
  t = (chapter_node_data_c *)tc_chapters->GetItemData(id);
 
1264
  if (!t->is_atom)
 
1265
    return;
 
1266
 
 
1267
  cdisplay = NULL;
 
1268
  n = 0;
 
1269
  for (i = 0; i < t->chapter->ListSize(); i++)
 
1270
    if (EbmlId(*(*t->chapter)[i]) == KaxChapterDisplay::ClassInfos.GlobalId) {
 
1271
      n++;
 
1272
      if (n == (lb_chapter_names->GetSelection() + 1)) {
 
1273
        cdisplay = (KaxChapterDisplay *)(*t->chapter)[i];
 
1274
        break;
 
1275
      }
 
1276
    }
 
1277
  if (cdisplay == NULL)
 
1278
    return;
 
1279
 
 
1280
  if (cob_country_code->GetStringSelection().Length() == 0) {
 
1281
    i = 0;
 
1282
    while (i < cdisplay->ListSize()) {
 
1283
      if (EbmlId(*(*cdisplay)[i]) == KaxChapterCountry::ClassInfos.GlobalId) {
 
1284
        delete (*cdisplay)[i];
 
1285
        cdisplay->Remove(i);
 
1286
      } else
 
1287
        i++;
 
1288
    }
 
1289
    return;
 
1290
  }
 
1291
  ccountry = &GetChild<KaxChapterCountry>(*cdisplay);
 
1292
  *static_cast<EbmlString *>(ccountry) =
 
1293
    wxMB(cob_country_code->GetStringSelection());
 
1294
}
 
1295
 
 
1296
void
 
1297
tab_chapters::on_chapter_name_changed(wxCommandEvent &evt) {
 
1298
  KaxChapterDisplay *cdisplay;
 
1299
  KaxChapterString *cstring;
 
1300
  chapter_node_data_c *t;
 
1301
  uint32_t i, n;
 
1302
  wxString label;
 
1303
  wxTreeItemId id;
 
1304
 
 
1305
  if (no_update)
 
1306
    return;
 
1307
 
 
1308
  id = tc_chapters->GetSelection();
 
1309
  if (!id.IsOk())
 
1310
    return;
 
1311
  t = (chapter_node_data_c *)tc_chapters->GetItemData(id);
 
1312
  if (!t->is_atom)
 
1313
    return;
 
1314
 
 
1315
  cdisplay = NULL;
 
1316
  n = 0;
 
1317
  for (i = 0; i < t->chapter->ListSize(); i++)
 
1318
    if (EbmlId(*(*t->chapter)[i]) == KaxChapterDisplay::ClassInfos.GlobalId) {
 
1319
      n++;
 
1320
      if (n == (lb_chapter_names->GetSelection() + 1)) {
 
1321
        cdisplay = (KaxChapterDisplay *)(*t->chapter)[i];
 
1322
        break;
 
1323
      }
 
1324
    }
 
1325
  if (cdisplay == NULL)
 
1326
    return;
 
1327
 
 
1328
  cstring = &GetChild<KaxChapterString>(*cdisplay);
 
1329
#if WXUNICODE
 
1330
  *static_cast<EbmlUnicodeString *>(cstring) =
 
1331
    cstrutf8_to_UTFstring(wxMB(tc_chapter_name->GetValue()));
 
1332
#else
 
1333
  *static_cast<EbmlUnicodeString *>(cstring) =
 
1334
    cstr_to_UTFstring(tc_chapter_name->GetValue().c_str());
 
1335
#endif
 
1336
 
 
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());
 
1341
}
 
1342
 
 
1343
void
 
1344
tab_chapters::on_set_default_values(wxCommandEvent &evt) {
 
1345
  wxString language;
 
1346
 
 
1347
  chapter_values_dlg dlg(this, true, wxU(default_chapter_language.c_str()),
 
1348
                         wxU(default_chapter_country.c_str()));
 
1349
 
 
1350
  if (dlg.ShowModal() != wxID_OK)
 
1351
    return;
 
1352
 
 
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);
 
1359
    return;
 
1360
  }
 
1361
  default_chapter_language = wxMB(language);
 
1362
  default_chapter_country = wxMB(dlg.cob_country->GetValue());
 
1363
}
 
1364
 
 
1365
void
 
1366
tab_chapters::set_values_recursively(wxTreeItemId id,
 
1367
                                     const wxString &s,
 
1368
                                     bool set_language) {
 
1369
  uint32_t i;
 
1370
  KaxChapterDisplay *display;
 
1371
  KaxChapterLanguage *language;
 
1372
  KaxChapterCountry *country;
 
1373
  chapter_node_data_c *d;
 
1374
  wxTreeItemId next_child;
 
1375
  wxTreeItemIdValue cookie;
 
1376
  wxString text;
 
1377
 
 
1378
  if (!id.IsOk())
 
1379
    return;
 
1380
 
 
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) {
 
1385
      i = 0;
 
1386
      while (i < display->ListSize()) {
 
1387
        if ((set_language &&
 
1388
             (dynamic_cast<KaxChapterLanguage *>((*display)[i]) != NULL)) ||
 
1389
            (!set_language &&
 
1390
             (dynamic_cast<KaxChapterCountry *>((*display)[i]) != NULL))) {
 
1391
          delete (*display)[i];
 
1392
          display->Remove(i);
 
1393
        } else
 
1394
          i++;
 
1395
      }
 
1396
 
 
1397
      if (set_language) {
 
1398
        language = new KaxChapterLanguage;
 
1399
        *static_cast<EbmlString *>(language) = wxMB(s);
 
1400
        display->PushElement(*language);
 
1401
      } else {
 
1402
        country = new KaxChapterCountry;
 
1403
        *static_cast<EbmlString *>(country) = wxMB(s);
 
1404
        display->PushElement(*country);
 
1405
      }
 
1406
 
 
1407
      display = FINDNEXT(d->chapter, KaxChapterDisplay, display);
 
1408
    }
 
1409
    text = create_chapter_label(*d->chapter);
 
1410
    tc_chapters->SetItemText(id, text);
 
1411
  }
 
1412
 
 
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);
 
1417
  }
 
1418
}
 
1419
 
 
1420
void
 
1421
tab_chapters::on_set_values(wxCommandEvent &evt) {
 
1422
  KaxChapterDisplay *cdisplay;
 
1423
  wxTreeItemId id;
 
1424
  chapter_node_data_c *t;
 
1425
  wxString s;
 
1426
  uint32_t i, n;
 
1427
  chapter_values_dlg dlg(this, false);
 
1428
 
 
1429
  id = tc_chapters->GetSelection();
 
1430
  if (!id.IsOk())
 
1431
    return;
 
1432
 
 
1433
  if (dlg.ShowModal() != wxID_OK)
 
1434
    return;
 
1435
 
 
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);
 
1443
      return;
 
1444
    }
 
1445
    set_values_recursively(id, s, true);
 
1446
  }
 
1447
  if (dlg.cb_country->IsChecked()) {
 
1448
    s = dlg.cob_country->GetValue();
 
1449
    set_values_recursively(id, s, false);
 
1450
  }
 
1451
 
 
1452
  t = (chapter_node_data_c *)tc_chapters->GetItemData(id);
 
1453
  if ((t == NULL) || !t->is_atom)
 
1454
    return;
 
1455
 
 
1456
  cdisplay = NULL;
 
1457
  n = 0;
 
1458
  for (i = 0; i < t->chapter->ListSize(); i++)
 
1459
    if (EbmlId(*(*t->chapter)[i]) == KaxChapterDisplay::ClassInfos.GlobalId) {
 
1460
      n++;
 
1461
      if (n == (lb_chapter_names->GetSelection() + 1)) {
 
1462
        cdisplay = (KaxChapterDisplay *)(*t->chapter)[i];
 
1463
        break;
 
1464
      }
 
1465
    }
 
1466
  if (cdisplay == NULL)
 
1467
    return;
 
1468
 
 
1469
  set_display_values(cdisplay);
 
1470
}
 
1471
 
 
1472
void
 
1473
tab_chapters::on_adjust_timecodes(wxCommandEvent &evt) {
 
1474
  KaxChapterDisplay *cdisplay;
 
1475
  wxTreeItemId id;
 
1476
  chapter_node_data_c *t;
 
1477
  wxString sadjustment;
 
1478
  uint32_t i, n, offset;
 
1479
  int64_t adjustment, mult;
 
1480
 
 
1481
  id = tc_chapters->GetSelection();
 
1482
  if (!id.IsOk())
 
1483
    return;
 
1484
 
 
1485
  sadjustment =
 
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"));
 
1496
  strip(sadjustment);
 
1497
  if (sadjustment.Length() == 0)
 
1498
    return;
 
1499
 
 
1500
  if (sadjustment.c_str()[0] == wxT('-')) {
 
1501
    mult = -1;
 
1502
    offset = 1;
 
1503
  } else if (sadjustment.c_str()[0] == wxT('+')) {
 
1504
    mult = 1;
 
1505
    offset = 1;
 
1506
  } else {
 
1507
    mult = 1;
 
1508
    offset = 0;
 
1509
  }
 
1510
  sadjustment.Remove(0, offset);
 
1511
  if (sadjustment.Length() == 0)
 
1512
    return;
 
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);
 
1517
    return;
 
1518
  }
 
1519
  adjustment *= mult;
 
1520
 
 
1521
  adjust_timecodes_recursively(id, adjustment);
 
1522
 
 
1523
  t = (chapter_node_data_c *)tc_chapters->GetItemData(id);
 
1524
  if ((t == NULL) || !t->is_atom)
 
1525
    return;
 
1526
 
 
1527
  set_timecode_values(t->chapter);
 
1528
 
 
1529
  cdisplay = NULL;
 
1530
  n = 0;
 
1531
  for (i = 0; i < t->chapter->ListSize(); i++)
 
1532
    if (EbmlId(*(*t->chapter)[i]) == KaxChapterDisplay::ClassInfos.GlobalId) {
 
1533
      n++;
 
1534
      if (n == (lb_chapter_names->GetSelection() + 1)) {
 
1535
        cdisplay = (KaxChapterDisplay *)(*t->chapter)[i];
 
1536
        break;
 
1537
      }
 
1538
    }
 
1539
  if (cdisplay == NULL)
 
1540
    return;
 
1541
 
 
1542
  set_display_values(cdisplay);
 
1543
}
 
1544
 
 
1545
void
 
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;
 
1553
  wxString text;
 
1554
  int64_t t;
 
1555
 
 
1556
  if (!id.IsOk())
 
1557
    return;
 
1558
 
 
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);
 
1564
      t += adjust_by;
 
1565
      if (t < 0)
 
1566
        t = 0;
 
1567
      *static_cast<EbmlUInteger *>(tstart) = t;
 
1568
    }
 
1569
    tend = FINDFIRST(d->chapter, KaxChapterTimeEnd);
 
1570
    if (tend != NULL) {
 
1571
      t = uint64(*tend);
 
1572
      t += adjust_by;
 
1573
      if (t < 0)
 
1574
        t = 0;
 
1575
      *static_cast<EbmlUInteger *>(tend) = t;
 
1576
    }
 
1577
    text = create_chapter_label(*d->chapter);
 
1578
    tc_chapters->SetItemText(id, text);
 
1579
  }
 
1580
 
 
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);
 
1585
  }
 
1586
}
 
1587
 
 
1588
bool
 
1589
tab_chapters::copy_values(wxTreeItemId id) {
 
1590
  chapter_node_data_c *data;
 
1591
  wxString label;
 
1592
  KaxChapterAtom *chapter;
 
1593
  EbmlElement *e;
 
1594
  int64_t ts_start, ts_end;
 
1595
  vector<string> l_codes, c_codes;
 
1596
  wxString s;
 
1597
  uint32_t i;
 
1598
 
 
1599
  data = (chapter_node_data_c *)tc_chapters->GetItemData(id);
 
1600
  if (data == NULL)
 
1601
    return true;
 
1602
 
 
1603
  label = tc_chapters->GetItemText(id);
 
1604
  chapter = data->chapter;
 
1605
 
 
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);
 
1611
    else {
 
1612
      i = ts_start;
 
1613
      if (data->is_atom) {
 
1614
        KaxChapterUID *cuid;
 
1615
 
 
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)));
 
1624
          } else {
 
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;
 
1628
          }
 
1629
        }
 
1630
      } else {
 
1631
        KaxEditionUID *euid;
 
1632
 
 
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)));
 
1641
          } else {
 
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;
 
1645
          }
 
1646
        }
 
1647
      }
 
1648
    }
 
1649
  }
 
1650
  if (data->is_atom) {
 
1651
    s = tc_start_time->GetValue();
 
1652
    strip(s);
 
1653
    ts_start = parse_time(s);
 
1654
    if (ts_start == -1) {
 
1655
      wxMessageBox(wxT("Invalid format used for the start time for '") +
 
1656
                   label +
 
1657
                   wxT("'. Setting value to 0."), wxT("Input data error"),
 
1658
                   wxOK | wxCENTER | wxICON_ERROR);
 
1659
      ts_start = 0;
 
1660
    }
 
1661
 
 
1662
    s = tc_end_time->GetValue();
 
1663
    strip(s);
 
1664
    ts_end = parse_time(s);
 
1665
    if (ts_end == -1) {
 
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);
 
1669
      ts_end = 0;
 
1670
    }
 
1671
 
 
1672
    i = 0;
 
1673
    while (i < chapter->ListSize()) {
 
1674
      e = (*chapter)[i];
 
1675
      if ((EbmlId(*e) == KaxChapterTimeStart::ClassInfos.GlobalId) ||
 
1676
          (EbmlId(*e) == KaxChapterTimeEnd::ClassInfos.GlobalId)) {
 
1677
        chapter->Remove(i);
 
1678
        delete e;
 
1679
      } else
 
1680
        i++;
 
1681
    }
 
1682
 
 
1683
    if (ts_start >= 0)
 
1684
      *static_cast<EbmlUInteger *>(&GetChild<KaxChapterTimeStart>(*chapter)) =
 
1685
        ts_start;
 
1686
    if (ts_end >= 0)
 
1687
      *static_cast<EbmlUInteger *>(&GetChild<KaxChapterTimeEnd>(*chapter)) =
 
1688
        ts_end;
 
1689
 
 
1690
    label = create_chapter_label(*chapter);
 
1691
    tc_chapters->SetItemText(id, label);
 
1692
  }
 
1693
 
 
1694
 
 
1695
  return true;
 
1696
}
 
1697
 
 
1698
void
 
1699
tab_chapters::on_add_chapter_name(wxCommandEvent &evt) {
 
1700
  KaxChapterDisplay *cdisplay;
 
1701
  chapter_node_data_c *t;
 
1702
  uint32_t i, n;
 
1703
  wxTreeItemId id;
 
1704
  wxString s;
 
1705
 
 
1706
  id = tc_chapters->GetSelection();
 
1707
  if (!id.IsOk())
 
1708
    return;
 
1709
  t = (chapter_node_data_c *)tc_chapters->GetItemData(id);
 
1710
  if (!t->is_atom)
 
1711
    return;
 
1712
 
 
1713
  cdisplay = NULL;
 
1714
  n = 0;
 
1715
  for (i = 0; i < t->chapter->ListSize(); i++)
 
1716
    if (EbmlId(*(*t->chapter)[i]) == KaxChapterDisplay::ClassInfos.GlobalId) {
 
1717
      n++;
 
1718
      if (n == (lb_chapter_names->GetSelection() + 1)) {
 
1719
        cdisplay = (KaxChapterDisplay *)(*t->chapter)[i];
 
1720
        break;
 
1721
      }
 
1722
    }
 
1723
  if (cdisplay == NULL)
 
1724
    return;
 
1725
 
 
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());
 
1731
  else
 
1732
    s = wxT("eng");
 
1733
  *static_cast<EbmlString *>(&GetChild<KaxChapterLanguage>(*cdisplay)) =
 
1734
    wxMB(s);
 
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);
 
1741
  else
 
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);
 
1747
 
 
1748
  b_remove_chapter_name->Enable(true);
 
1749
  tc_chapter_name->SetFocus();
 
1750
}
 
1751
 
 
1752
void
 
1753
tab_chapters::on_remove_chapter_name(wxCommandEvent &evt) {
 
1754
  KaxChapterDisplay *cdisplay;
 
1755
  chapter_node_data_c *t;
 
1756
  uint32_t i, n;
 
1757
  wxTreeItemId id;
 
1758
  wxString s;
 
1759
 
 
1760
  id = tc_chapters->GetSelection();
 
1761
  if (!id.IsOk())
 
1762
    return;
 
1763
  t = (chapter_node_data_c *)tc_chapters->GetItemData(id);
 
1764
  if (!t->is_atom)
 
1765
    return;
 
1766
 
 
1767
  cdisplay = NULL;
 
1768
  n = 0;
 
1769
  for (i = 0; i < t->chapter->ListSize(); i++)
 
1770
    if (EbmlId(*(*t->chapter)[i]) == KaxChapterDisplay::ClassInfos.GlobalId) {
 
1771
      n++;
 
1772
      if (n == (lb_chapter_names->GetSelection() + 1)) {
 
1773
        cdisplay = (KaxChapterDisplay *)(*t->chapter)[i];
 
1774
        break;
 
1775
      }
 
1776
    }
 
1777
 
 
1778
  if (cdisplay == NULL)
 
1779
    return;
 
1780
 
 
1781
  t->chapter->Remove(i);
 
1782
  delete cdisplay;
 
1783
 
 
1784
  n = lb_chapter_names->GetSelection();
 
1785
  lb_chapter_names->Delete(n);
 
1786
  lb_chapter_names->SetSelection(n == 0 ? 0 : n - 1);
 
1787
  if (n == 0) {
 
1788
    s = create_chapter_label(*t->chapter);
 
1789
    tc_chapters->SetItemText(id, s);
 
1790
  }
 
1791
 
 
1792
  cdisplay = NULL;
 
1793
  n = 0;
 
1794
  for (i = 0; i < t->chapter->ListSize(); i++)
 
1795
    if (EbmlId(*(*t->chapter)[i]) == KaxChapterDisplay::ClassInfos.GlobalId) {
 
1796
      n++;
 
1797
      if (n == (lb_chapter_names->GetSelection() + 1)) {
 
1798
        cdisplay = (KaxChapterDisplay *)(*t->chapter)[i];
 
1799
        break;
 
1800
      }
 
1801
    }
 
1802
 
 
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);
 
1807
}
 
1808
 
 
1809
void
 
1810
tab_chapters::on_chapter_name_selected(wxCommandEvent &evt) {
 
1811
  KaxChapterDisplay *cdisplay;
 
1812
  chapter_node_data_c *t;
 
1813
  uint32_t i, n;
 
1814
  wxTreeItemId id;
 
1815
  wxString s;
 
1816
 
 
1817
  id = tc_chapters->GetSelection();
 
1818
  if (!id.IsOk())
 
1819
    return;
 
1820
  t = (chapter_node_data_c *)tc_chapters->GetItemData(id);
 
1821
  if (!t->is_atom)
 
1822
    return;
 
1823
  cdisplay = NULL;
 
1824
  n = 0;
 
1825
  for (i = 0; i < t->chapter->ListSize(); i++)
 
1826
    if (EbmlId(*(*t->chapter)[i]) == KaxChapterDisplay::ClassInfos.GlobalId) {
 
1827
      n++;
 
1828
      if (n == (lb_chapter_names->GetSelection() + 1)) {
 
1829
        cdisplay = (KaxChapterDisplay *)(*t->chapter)[i];
 
1830
        break;
 
1831
      }
 
1832
    }
 
1833
  if (cdisplay == NULL)
 
1834
    return;
 
1835
 
 
1836
  set_display_values(cdisplay);
 
1837
  tc_chapter_name->SetFocus();
 
1838
}
 
1839
 
 
1840
void
 
1841
tab_chapters::on_chapter_name_enter(wxCommandEvent &evt) {
 
1842
  wxTreeItemId id;
 
1843
  wxTreeItemIdValue cookie;
 
1844
 
 
1845
  id = tc_chapters->GetSelection();
 
1846
  if (!id.IsOk())
 
1847
    return;
 
1848
  id = tc_chapters->GetNextSibling(id);
 
1849
  if (id.IsOk()) {
 
1850
    tc_chapters->SelectItem(id);
 
1851
    return;
 
1852
  }
 
1853
 
 
1854
  id = tc_chapters->GetItemParent(tc_chapters->GetSelection());
 
1855
  if (!id.IsOk())
 
1856
    return;
 
1857
  id = tc_chapters->GetNextSibling(id);
 
1858
  if (id.IsOk()) {
 
1859
    id = tc_chapters->GetFirstChild(id, cookie);
 
1860
    if (id.IsOk()) {
 
1861
      tc_chapters->SelectItem(id);
 
1862
      return;
 
1863
    }
 
1864
  }
 
1865
 
 
1866
  id = tc_chapters->GetRootItem();
 
1867
  if (!id.IsOk())
 
1868
    return;
 
1869
  id = tc_chapters->GetFirstChild(id, cookie);
 
1870
  if (!id.IsOk())
 
1871
    return;
 
1872
  id = tc_chapters->GetFirstChild(id, cookie);
 
1873
  if (id.IsOk())
 
1874
    tc_chapters->SelectItem(id);
 
1875
}
 
1876
 
 
1877
void
 
1878
tab_chapters::on_flag_hidden(wxCommandEvent &evt) {
 
1879
  wxTreeItemId selected;
 
1880
  chapter_node_data_c *t;
 
1881
  int i;
 
1882
 
 
1883
  selected = tc_chapters->GetSelection();
 
1884
  if (!selected.IsOk() || (selected == tid_root))
 
1885
    return;
 
1886
  t = (chapter_node_data_c *)tc_chapters->GetItemData(selected);
 
1887
  if ((t == NULL) || !t->is_atom)
 
1888
    return;
 
1889
 
 
1890
  if (cb_flag_hidden->IsChecked())
 
1891
    *static_cast<EbmlUInteger *>
 
1892
      (&GetChild<KaxChapterFlagHidden>(*t->chapter)) = 1;
 
1893
  else
 
1894
    for (i = 0; i < t->chapter->ListSize(); i++)
 
1895
      if (is_id((*t->chapter)[i], KaxChapterFlagHidden)) {
 
1896
        t->chapter->Remove(i);
 
1897
        return;
 
1898
      }
 
1899
}
 
1900
 
 
1901
void
 
1902
tab_chapters::on_flag_enabled(wxCommandEvent &evt) {
 
1903
  wxTreeItemId selected;
 
1904
  chapter_node_data_c *t;
 
1905
  int i;
 
1906
 
 
1907
  selected = tc_chapters->GetSelection();
 
1908
  if (!selected.IsOk() || (selected == tid_root))
 
1909
    return;
 
1910
  t = (chapter_node_data_c *)tc_chapters->GetItemData(selected);
 
1911
  if ((t == NULL) || !t->is_atom)
 
1912
    return;
 
1913
 
 
1914
  if (!cb_flag_enabled->IsChecked())
 
1915
    *static_cast<EbmlUInteger *>
 
1916
      (&GetChild<KaxChapterFlagEnabled>(*t->chapter)) = 0;
 
1917
  else
 
1918
    for (i = 0; i < t->chapter->ListSize(); i++)
 
1919
      if (is_id((*t->chapter)[i], KaxChapterFlagEnabled)) {
 
1920
        t->chapter->Remove(i);
 
1921
        return;
 
1922
      }
 
1923
}
 
1924
 
 
1925
void
 
1926
tab_chapters::set_timecode_values(KaxChapterAtom *atom) {
 
1927
  KaxChapterTimeStart *tstart;
 
1928
  KaxChapterTimeEnd *tend;
 
1929
  wxString label;
 
1930
  int64_t timestamp;
 
1931
 
 
1932
  no_update = true;
 
1933
 
 
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);
 
1939
  } else
 
1940
    tc_start_time->SetValue(wxT(""));
 
1941
 
 
1942
  tend = FINDFIRST(atom, KaxChapterTimeEnd);
 
1943
  if (tend != NULL) {
 
1944
    timestamp = uint64(*static_cast<EbmlUInteger *>(tend));
 
1945
    label.Printf(wxT(FMT_TIMECODEN), ARG_TIMECODEN(timestamp));
 
1946
    tc_end_time->SetValue(label);
 
1947
  } else
 
1948
    tc_end_time->SetValue(wxT(""));
 
1949
 
 
1950
  no_update = false;
 
1951
}
 
1952
 
 
1953
void
 
1954
tab_chapters::set_display_values(KaxChapterDisplay *display) {
 
1955
  KaxChapterString *cstring;
 
1956
  KaxChapterLanguage *clanguage;
 
1957
  KaxChapterCountry *ccountry;
 
1958
  wxString language;
 
1959
  uint32_t i, count;
 
1960
  bool found;
 
1961
 
 
1962
  no_update = true;
 
1963
 
 
1964
  cstring = FINDFIRST(display, KaxChapterString);
 
1965
  if (cstring != NULL) {
 
1966
    wxString tmp =
 
1967
      UTFstring_to_wxString(*static_cast<EbmlUnicodeString *>(cstring));
 
1968
    tc_chapter_name->SetValue(tmp);
 
1969
  } else
 
1970
    tc_chapter_name->SetValue(wxT("(unnamed)"));
 
1971
 
 
1972
  clanguage = FINDFIRST(display, KaxChapterLanguage);
 
1973
  if (clanguage != NULL)
 
1974
    language = wxU(string(*static_cast<EbmlString *>(clanguage)).c_str());
 
1975
  else
 
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];
 
1980
      break;
 
1981
    }
 
1982
 
 
1983
  count = cob_language_code->GetCount();
 
1984
  found = false;
 
1985
  for (i = 0; i < count; i++)
 
1986
    if (cob_language_code->GetString(i) == language) {
 
1987
      found = true;
 
1988
      break;
 
1989
    }
 
1990
  if (found)
 
1991
    cob_language_code->SetSelection(i);
 
1992
  else
 
1993
    cob_language_code->SetValue(language);
 
1994
 
 
1995
  ccountry = FINDFIRST(display, KaxChapterCountry);
 
1996
  if (ccountry != NULL)
 
1997
    cob_country_code->SetValue(wxU(string(*static_cast<EbmlString *>
 
1998
                                          (ccountry)).c_str()));
 
1999
  else
 
2000
    cob_country_code->SetValue(wxT(""));
 
2001
 
 
2002
  no_update = false;
 
2003
}
 
2004
 
 
2005
int64_t
 
2006
tab_chapters::parse_time(wxString s) {
 
2007
  int64_t nsecs;
 
2008
  string utf8s;
 
2009
  const char *c;
 
2010
 
 
2011
  utf8s = wxMB(s);
 
2012
  strip(utf8s);
 
2013
  if (utf8s.length() == 0)
 
2014
    return -2;
 
2015
 
 
2016
  c = utf8s.c_str();
 
2017
  while (*c != 0) {
 
2018
    if (!isdigit(*c)) {
 
2019
      if (parse_timecode(utf8s, nsecs))
 
2020
        return nsecs;
 
2021
      return -1;
 
2022
    }
 
2023
    c++;
 
2024
  }
 
2025
  if (!parse_int(utf8s, nsecs))
 
2026
    return -1;
 
2027
  return nsecs * 1000000000;
 
2028
}
 
2029
 
 
2030
bool
 
2031
tab_chapters::is_empty() {
 
2032
  if (!tid_root.IsOk())
 
2033
    return true;
 
2034
  return tc_chapters->GetCount() < 2;
 
2035
}
 
2036
 
 
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)
 
2041
END_EVENT_TABLE();
 
2042
 
 
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)
 
2062
END_EVENT_TABLE();