mkvtoolnix/mkvinfo_gui.cpp

337 lines
9.5 KiB
C++

#include "config.h"
#ifdef HAVE_WXWINDOWS
#include "wx/wx.h"
#include "wx/treectrl.h"
#include "wx/dnd.h"
#include "EbmlVersion.h"
#include "KaxVersion.h"
#include "common.h"
#include "mkvinfo.h"
#include "matroska.xpm"
using namespace libebml;
using namespace libmatroska;
mi_frame *frame;
enum {
mi_file_quit = 1,
mi_file_open = 2,
mi_file_savetext = 3,
mi_options_showall = 101,
mi_options_expandimportant = 102,
mi_help_about = wxID_ABOUT
};
bool mi_app::OnInit() {
char *initial_file;
parse_args(argc, argv, initial_file, use_gui);
if (!use_gui) {
console_main(argc, argv);
return false;
}
frame = new mi_frame(_T("mkvinfo"), wxPoint(50, 50), wxSize(600, 400));
frame->Show(true);
frame->Refresh(true);
frame->Update();
while (Pending())
Dispatch();
if (initial_file != NULL)
frame->open_file(initial_file);
return true;
}
mi_frame::mi_frame(const wxString &title, const wxPoint &pos,
const wxSize &size, long style) :
wxFrame(NULL, -1, title, pos, size, style) {
wxMenu *menu_help;
wxMenuBar *menu_bar;
file_open = false;
tree = NULL;
if (verbose == 0)
show_all_elements = false;
else
show_all_elements = true;
expand_important_elements = true;
SetIcon(wxICON(matroska));
menu_file = new wxMenu();
menu_options = new wxMenu();
menu_help = new wxMenu();
menu_bar = new wxMenuBar();
menu_file->Append(mi_file_open, _T("&Open\tCtrl-O"),
_T("Open a Matroska file"));
menu_file->Append(mi_file_savetext, _T("&Save info as text\tCtrl-S"),
_T("Saves the information from the current file to a "
"text file"));
menu_file->Enable(mi_file_savetext, false);
menu_file->AppendSeparator();
menu_file->Append(mi_file_quit, _T("E&xit\tCtrl-Q"),
_T("Quits mkvinfo"));
menu_options->AppendCheckItem(mi_options_showall,
_T("Show &all elements\tCtrl-A"),
_T("Parse the file completely and show all "
"elements"));
menu_options->Check(mi_options_showall, show_all_elements);
menu_options->AppendCheckItem(mi_options_expandimportant,
_T("&Expand important elements\tCtrl-E"),
_T("After loading a file expand the most "
"important elements"));
menu_options->Check(mi_options_expandimportant, expand_important_elements);
menu_help->Append(mi_help_about, _T("&About...\tF1"),
_T("Show about dialog"));
menu_bar->Append(menu_file, _T("&File"));
menu_bar->Append(menu_options, _T("&Options"));
menu_bar->Append(menu_help, _T("&Help"));
SetMenuBar(menu_bar);
tree = new wxTreeCtrl(this, -1);
dnd_load = new mi_dndfile();
tree->SetDropTarget(dnd_load);
CreateStatusBar(1);
SetStatusText(_T("ready"));
last_dir = wxGetWorkingDirectory();
}
void mi_frame::open_file(const char *file_name) {
tree->DeleteAllItems();
item_ids[0] = tree->AddRoot(file_name);
last_percent = -1;
num_elements = 0;
menu_file->Enable(mi_file_open, false);
menu_file->Enable(mi_file_savetext, false);
menu_options->Enable(mi_options_showall, false);
if (process_file(file_name)) {
file_open = true;
menu_file->Enable(mi_file_savetext, true);
current_file = file_name;
if (expand_important_elements)
expand_elements();
} else {
tree->DeleteAllItems();
menu_file->Enable(mi_file_savetext, false);
}
menu_file->Enable(mi_file_open, true);
menu_options->Enable(mi_options_showall, true);
SetStatusText(_T("ready"));
tree->Refresh();
}
void mi_frame::show_progress(int percent, const char *msg) {
wxString s;
if ((percent / 5) != (last_percent / 5)) {
s.Printf("%s: %d%%", msg, percent);
SetStatusText(s);
last_percent = percent;
}
wxYield();
}
void mi_frame::expand_all_elements(wxTreeItemId &root, bool expand) {
wxTreeItemId child;
long cookie;
if (expand)
tree->Expand(root);
else
tree->Collapse(root);
child = tree->GetFirstChild(root, cookie);
while (child > 0) {
expand_all_elements(child, expand);
child = tree->GetNextChild(root, cookie);
}
}
void mi_frame::expand_elements() {
wxTreeItemId l0, l1;
long cl0, cl1;
Freeze();
expand_all_elements(item_ids[0], false);
tree->Expand(item_ids[0]);
l0 = tree->GetFirstChild(item_ids[0], cl0);
while (l0 > 0) {
tree->Expand(l0);
if (tree->GetItemText(l0).find("Segment") == 0) {
l1 = tree->GetFirstChild(l0, cl1);
while (l1 > 0) {
if ((tree->GetItemText(l1).find("Segment information") == 0) ||
(tree->GetItemText(l1).find("Segment tracks") == 0))
expand_all_elements(l1);
l1 = tree->GetNextChild(l0, cl1);
}
}
l0 = tree->GetNextChild(item_ids[0], cl0);
}
Thaw();
}
void mi_frame::add_item(int level, const char *text) {
item_ids[level + 1] = tree->AppendItem(item_ids[level], text);
num_elements++;
}
void mi_frame::show_error(const char *msg) {
wxMessageBox(msg, _T("Error"), wxOK | wxICON_ERROR | wxCENTER, this);
}
void mi_frame::save_elements(wxTreeItemId &root, int level, FILE *f) {
wxTreeItemId child;
long cookie;
char level_buffer[10];
int pcnt_before, pcnt_now;
if (level >= 0) {
memset(&level_buffer[1], ' ', 9);
level_buffer[0] = '|';
level_buffer[level] = 0;
fprintf(f, "(%s) %s+ %s\n", NAME, level_buffer,
tree->GetItemText(root).c_str());
pcnt_before = elements_saved * 100 / num_elements;
pcnt_now = (elements_saved + 1) * 100 / num_elements;
if ((pcnt_before / 5) != (pcnt_now / 5))
show_progress(pcnt_now, "Writing info");
elements_saved++;
}
child = tree->GetFirstChild(root, cookie);
while (child > 0) {
save_elements(child, level + 1, f);
child = tree->GetNextChild(root, cookie);
}
}
void mi_frame::on_file_open(wxCommandEvent &WXUNUSED(event)) {
wxFileDialog file_dialog(this, _T("Select Matroska file"), _T(""), _T(""),
_T("Matroska files (*.mkv;*.mka;*.mks)|"
"*.mkv;*.mka;*.mks|All files|*.*"));
file_dialog.SetDirectory(last_dir);
if (file_dialog.ShowModal() == wxID_OK) {
open_file(file_dialog.GetPath().c_str());
last_dir = file_dialog.GetDirectory();
}
}
void mi_frame::on_file_savetext(wxCommandEvent &WXUNUSED(event)) {
FILE *f;
wxFileDialog file_dialog(this, _T("Select output file"), _T(""), _T(""),
_T("Text files (*.txt)|*.txt|All files|*.*"),
wxSAVE | wxOVERWRITE_PROMPT);
file_dialog.SetDirectory(last_dir);
if (file_dialog.ShowModal() == wxID_OK) {
last_dir = file_dialog.GetDirectory();
f = fopen(file_dialog.GetPath().c_str(), "w");
if (f == NULL) {
wxString s;
s.Printf("Could not create the file '%s'.",
file_dialog.GetPath().c_str());
show_error(s.c_str());
return;
}
menu_file->Enable(mi_file_open, false);
menu_file->Enable(mi_file_savetext, false);
menu_options->Enable(mi_options_showall, false);
save_elements(item_ids[0], -1, f);
menu_file->Enable(mi_file_open, true);
menu_file->Enable(mi_file_savetext, true);
menu_options->Enable(mi_options_showall, true);
fclose(f);
}
}
void mi_frame::on_file_quit(wxCommandEvent &WXUNUSED(event)) {
Close(true);
}
void mi_frame::on_options_showall(wxCommandEvent &WXUNUSED(event)) {
show_all_elements = !show_all_elements;
menu_options->Check(mi_options_showall, show_all_elements);
if (show_all_elements)
verbose = 2;
else
verbose = 0;
if (file_open)
open_file(current_file);
}
void mi_frame::on_options_expandimportant(wxCommandEvent &WXUNUSED(event)) {
expand_important_elements = !expand_important_elements;
menu_options->Check(mi_options_expandimportant,
expand_important_elements);
}
void mi_frame::on_help_about(wxCommandEvent &WXUNUSED(event)) {
wxString msg;
msg.Printf(_T(VERSIONINFO ".\nCompiled with libebml %s + "
"libmatroska %s.\n\nThis program is licensed under the "
"GPL v2 (see COPYING).\nIt was written by Moritz Bunkus "
"<moritz@bunkus.org>.\nSources and the latest binaries are "
"always available at\nhttp://www.bunkus.org/videotools/"
"mkvtoolnix/"),
EbmlCodeVersion.c_str(), KaxCodeVersion.c_str());
wxMessageBox(msg, _T("About mkvinfo"), wxOK | wxICON_INFORMATION, this);
}
bool mi_dndfile::OnDropFiles(wxCoord x, wxCoord y,
const wxArrayString &filenames) {
wxString dnd_file;
unsigned int i;
for (i = 0; i < filenames.GetCount(); i++) {
dnd_file = filenames[i];
if ((dnd_file.Right(3).Lower() == "mka") ||
(dnd_file.Right(3).Lower() == "mkv") ||
(dnd_file.Right(3).Lower() == "mks")) {
frame->open_file(dnd_file);
} else {
wxString msg;
msg.Printf("The dragged file '%s'\nis not a Matroska file.",
dnd_file.c_str());
frame->show_error(msg.c_str());
break;
}
}
return true;
}
BEGIN_EVENT_TABLE(mi_frame, wxFrame)
EVT_MENU(mi_file_open, mi_frame::on_file_open)
EVT_MENU(mi_file_savetext, mi_frame::on_file_savetext)
EVT_MENU(mi_file_quit, mi_frame::on_file_quit)
EVT_MENU(mi_options_showall, mi_frame::on_options_showall)
EVT_MENU(mi_options_expandimportant, mi_frame::on_options_expandimportant)
EVT_MENU(mi_help_about, mi_frame::on_help_about)
END_EVENT_TABLE()
#if defined(SYS_WINDOWS)
IMPLEMENT_APP(mi_app)
#else
IMPLEMENT_APP_NO_MAIN(mi_app)
#endif
#endif // HAVE_WXWINDOWS