diff options
Diffstat (limited to 'wxgui.cpp')
| -rw-r--r-- | wxgui.cpp | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/wxgui.cpp b/wxgui.cpp new file mode 100644 index 0000000..83007de --- /dev/null +++ b/wxgui.cpp @@ -0,0 +1,416 @@ +#define EXTERN_WX_GUI +#include "transcode.h" + +IMPLEMENT_APP(TranscodeGUI) + +bool TranscodeGUI::OnInit() +{ + TranscodeFrame *transcodeFrame = new TranscodeFrame; + transcodeFrame->Show(true); + + SetTopWindow(transcodeFrame); + + return true; +} + +TranscodeFrame::TranscodeFrame(): + wxFrame(nullptr, wxID_ANY, wxT("SlavConvert: Transcoding Tool"), + wxDefaultPosition, wxSize(640,480), + wxDEFAULT_FRAME_STYLE & ~(wxRESIZE_BORDER | wxMAXIMIZE_BOX)) +{ + wxString config_dir = wxStandardPaths::Get().GetUserConfigDir(); + config_filepath = config_dir + path_separator +#ifdef _WIN32 + + "SlavConvert.ini"; +#else + + ".slavconvertrc"; +#endif + read_config_file(config_filepath, config_options); + config_params.do_greek = to_bool(config_options[L"greek"]); + config_params.do_font_select = to_bool(config_options[L"fontsel"]); + + main_panel = new wxPanel(this, wxID_ANY); + main_sizer = new wxBoxSizer(wxVERTICAL); + + infile_sizer = new wxBoxSizer(wxHORIZONTAL); + infile_label = new wxStaticText(main_panel, wxID_ANY, + wxT("File to Convert"), + wxDefaultPosition, wxDefaultSize); + infile_field = new wxTextCtrl(main_panel, wxID_ANY, wxEmptyString, + wxDefaultPosition, wxDefaultSize, + wxCB_READONLY); + infile_button = new wxButton(main_panel, wxID_ANY, wxT("Select")); + main_sizer->Add(infile_label, 0, wxALL); + infile_sizer->Add(infile_field, 2, wxEXPAND | wxALL); + infile_sizer->Add(infile_button, 0, wxALL | wxALIGN_CENTER_VERTICAL); + main_sizer->Add(infile_sizer, 0, wxEXPAND | wxALL, 2); + wxString infile_from_cfg = config_options[L"in"]; + if (wxFileExists(infile_from_cfg)) { + infile_path = infile_from_cfg; + infile_field->ChangeValue(infile_path); + } + + csvfile_sizer = new wxBoxSizer(wxHORIZONTAL); + csvfile_label = new wxStaticText(main_panel, wxID_ANY, + wxT("Character Table (TSV)"), + wxDefaultPosition, wxDefaultSize); + csvfile_field = new wxTextCtrl(main_panel, wxID_ANY, wxEmptyString, + wxDefaultPosition, wxDefaultSize, + wxCB_READONLY); + csvfile_button = new wxButton(main_panel, wxID_ANY, wxT("Select")); + main_sizer->Add(csvfile_label, 0, wxALL); + csvfile_sizer->Add(csvfile_field, 2, wxEXPAND | wxALL); + csvfile_sizer->Add(csvfile_button, 0, wxALL | wxALIGN_CENTER_VERTICAL); + main_sizer->Add(csvfile_sizer, 0, wxEXPAND | wxALL, 2); + wxString csvfile_from_cfg = config_options[L"csv"]; + if (wxFileExists(csvfile_from_cfg)) { + csvfile_path = csvfile_from_cfg; + csvfile_field->ChangeValue(csvfile_path); + } + + fontsel_sizer = new wxBoxSizer(wxHORIZONTAL); + fontsel_label = new wxStaticText(main_panel, wxID_ANY, + wxT("Target Unicode Font"), + wxDefaultPosition, wxDefaultSize); + fontsel_field = new wxTextCtrl(main_panel, wxID_ANY, wxEmptyString, + wxDefaultPosition, wxDefaultSize, + wxCB_READONLY); + fontsel_name = config_options[L"font"]; + if (fontsel_name.length() > 0) + fontsel_field->ChangeValue(fontsel_name); + fontsel_button = new wxButton(main_panel, wxID_ANY, wxT("Select")); + main_sizer->Add(fontsel_label, 0, wxALL); + fontsel_sizer->Add(fontsel_field, 2, wxEXPAND | wxALL); + fontsel_sizer->Add(fontsel_button, 0, wxALL | wxALIGN_CENTER_VERTICAL); + main_sizer->Add(fontsel_sizer, 0, wxEXPAND | wxALL, 2); + + infile_button->Bind(wxEVT_BUTTON, &TranscodeFrame::SelectDoc, this); + csvfile_button->Bind(wxEVT_BUTTON, &TranscodeFrame::SelectCSV, this); + fontsel_button->Bind(wxEVT_BUTTON, &TranscodeFrame::DoFontDialog, this); + + check_greek = new wxCheckBox(main_panel, wxID_ANY, + wxT("Convert Greek combining characters to precomposed")); + check_greek->Bind(wxEVT_COMMAND_CHECKBOX_CLICKED, + &TranscodeFrame::ChkGrk, this); + check_greek->SetValue(config_params.do_greek); + main_sizer->Add(check_greek, 0, wxEXPAND, 2); + + check_fontsel = new wxCheckBox(main_panel, wxID_ANY, + wxT("Display list of fonts to select prior to conversion")); + check_fontsel->Bind(wxEVT_COMMAND_CHECKBOX_CLICKED, + &TranscodeFrame::ChkFontSel, this); + check_fontsel->SetValue(config_params.do_font_select); + main_sizer->Add(check_fontsel, 0, wxEXPAND, 2); + + transcode_button = new wxButton(main_panel, wxID_OK, wxT("Run")); + transcode_button->Bind(wxEVT_BUTTON, + &TranscodeFrame::Transcode, this); + + clear_button = new wxButton(main_panel, wxID_CLEAR, wxT("Clear")); + clear_button->Bind(wxEVT_BUTTON, + &TranscodeFrame::Reset, this); + + quit_button = new wxButton(main_panel, wxID_EXIT, wxT("Exit")); + quit_button->Bind(wxEVT_BUTTON, + &TranscodeFrame::Quit, this); + + button_sizer = new wxBoxSizer(wxHORIZONTAL); + button_sizer->Add(transcode_button, 2, wxEXPAND | wxALL); + button_sizer->Add(quit_button, 2, wxEXPAND | wxALL); + button_sizer->Add(clear_button, 2, wxEXPAND | wxALL); + main_sizer->Add(button_sizer, 0, wxEXPAND, 2); + + status_messages = new wxTextCtrl(main_panel, wxID_ANY, wxEmptyString, + wxDefaultPosition, wxDefaultSize, + wxTE_MULTILINE); + main_sizer->Add(status_messages, 2, wxEXPAND | wxALL, 5); + + main_panel->SetSizer(main_sizer); +} + +void TranscodeFrame::Quit(wxCommandEvent& WXUNUSED(event)) +{ + write_config_file(config_filepath, config_options); + Close(true); +} + +void TranscodeFrame::Reset(wxCommandEvent& WXUNUSED(event)) +{ + status_messages->Clear(); + + infile_field->Clear(); + config_options[L"in"] = L""; + infile_path.Clear(); // wxString + csvfile_field->Clear(); + csvfile_path.Clear(); // wxString + config_options[L"csv"] = L""; + fontsel_field->Clear(); + fontsel_name.clear(); // wstring + config_options[L"font"] = L""; + + write_config_file(config_filepath, config_options); +} + +void TranscodeFrame::SelectDoc(wxCommandEvent& WXUNUSED(event)) +{ + wxFileDialog docx_dialog(main_panel, wxT("Select Document to Convert"), + wxEmptyString, wxEmptyString, + "Word OpenXML Document (*.docx)|*.docx", + wxFD_OPEN | wxFD_FILE_MUST_EXIST); + + if (docx_dialog.ShowModal() == wxID_OK) { + infile_path = docx_dialog.GetPath(); + infile_field->ChangeValue(infile_path); + config_options[L"in"] = infile_path; + write_config_file(config_filepath, config_options); + } + else if ( !(csvfile_path.length() > 0 + && !wxFileExists(csvfile_path)) ) { + wxMessageBox(wxT("Please select a valid file!"), wxT("Error"), + wxOK | wxICON_ERROR); + } +} + +void TranscodeFrame::SelectCSV(wxCommandEvent& WXUNUSED(event)) +{ + wxFileDialog csv_dialog(this, wxT("Select Character Table File"), + wxEmptyString, wxEmptyString, + "Tab-Separated Data (*.tsv)|*.tsv", + wxFD_OPEN | wxFD_FILE_MUST_EXIST); + + if (csv_dialog.ShowModal() == wxID_OK) { + csvfile_path = csv_dialog.GetPath(); + csvfile_field->ChangeValue(csvfile_path); + config_options[L"csv"] = csvfile_path; + write_config_file(config_filepath, config_options); + } + else if ( !(csvfile_path.length() > 0 + && wxFileExists(csvfile_path)) ) { + wxMessageBox(wxT("Please select a valid file!"), wxT("Error"), + wxOK | wxICON_ERROR); + } +} + +void TranscodeFrame::LoadCharmap(wxString& charfile, const wchar_t sep, + map<wstring, vector<wstring>>& char_map, + vector<wstring>& utf_chars) +{ + wxTextFile cfile; + wxString lstr; + + vector<wstring> fonts; + wstring col; + + if (!cfile.Open(charfile)) { + wxMessageBox(wxT("Could not open character table!"), + wxT("File Error"), wxOK | wxICON_ERROR); + return; + } + + // initialize the map with font names from headers + lstr = cfile.GetFirstLine(); + + wstringstream fline_ss(lstr.ToStdWstring()); + // skip the first column, it's always UTF-8 + getline(fline_ss, col, sep); + while(getline(fline_ss, col, sep)) { + char_map.insert({col, {}}); + fonts.push_back(col); + } + + // Now process the remaining lines + while (!cfile.Eof()) { + size_t cn = 0; + lstr = cfile.GetNextLine(); + wstringstream line_ss(lstr.ToStdWstring()); + + // the first column is always UTF-8 + getline(line_ss, col, sep); + utf_chars.push_back(col); + + while(getline(line_ss, col, sep)) { + if (cn < fonts.size()) + char_map[fonts[cn]].push_back(col); + cn++; + } + } +} + +void TranscodeFrame::DoFontDialog(wxCommandEvent& WXUNUSED(event)) +{ + wxFontDialog font_dialog(this); + if (font_dialog.ShowModal() == wxID_OK) { + auto font_chosen = font_dialog.GetFontData().GetChosenFont(); + fontsel_name = font_chosen.GetFaceName(); + fontsel_field->ChangeValue(fontsel_name); + } + config_options[L"font"] = fontsel_name; + write_config_file(config_filepath, config_options); +} + +void TranscodeFrame::ChkGrk(wxCommandEvent& WXUNUSED(event)) +{ + if (check_greek->GetValue()) { + config_params.do_greek = true; + config_options[L"greek"] = L"1"; + } else { + config_params.do_greek = false; + config_options[L"greek"] = L"0"; + } + + write_config_file(config_filepath, config_options); +} + +void TranscodeFrame::ChkFontSel(wxCommandEvent& WXUNUSED(event)) +{ + if (check_fontsel->GetValue()) { + config_params.do_font_select = true; + config_options[L"fontsel"] = L"1"; + } else { + config_params.do_font_select = false; + config_options[L"fontsel"] = L"0"; + } + + write_config_file(config_filepath, config_options); +} + +void TranscodeFrame::ZipCreate(const wxString& files_dir, + const wxString& zip_file) +{ + wxFileOutputStream fos(zip_file); + wxZipOutputStream zos(fos); + + wxDir dir(files_dir); + wxArrayString files; + dir.Open(files_dir); + // we need hidden files (dotfiles), but can ignore empty dirs + dir.GetAllFiles(files_dir, &files, wxEmptyString, + wxDIR_FILES | wxDIR_DIRS | wxDIR_HIDDEN); + chdir(files_dir); + for (wxString& file: files) { + file.Replace(files_dir + path_separator, ""); + wxFileInputStream fis(file); + zos.PutNextEntry(file); + zos.Write(fis); + } +} + +// based on example at https://wiki.wxwidgets.org/WxZipInputStream +void TranscodeFrame::ZipExtract(const wxString& zip_file, + const wxString& dir_target) +{ + wxFileInputStream fis(zip_file); + wxZipInputStream zis(fis); + + unique_ptr<wxZipEntry> zptr; + while (zptr.reset(zis.GetNextEntry()), zptr) // != nullptr + { + wxString zip_file = dir_target + + wxFileName::GetPathSeparator() + + zptr->GetName(); + wxFileName fn; + + if (zptr->IsDir()) fn.AssignDir(zip_file); + else fn.Assign(zip_file); + + if (!wxDirExists(fn.GetPath())) { + wxFileName::Mkdir(fn.GetPath(), wxS_DIR_DEFAULT, + wxPATH_MKDIR_FULL); + } + if (zptr->IsDir()) continue; + + wxFileOutputStream fos(zip_file); + zis.Read(fos); + } +} + +void TranscodeFrame::Transcode(wxCommandEvent& WXUNUSED(event)) +{ + vector<wstring> doc_fonts, doc_fonts_sel, doc_encs, utf_chars; + map<wstring, vector<wstring>> char_map; + + wxString cwd_0 = wxGetCwd(); + + // redirect stdout and stderr (wchar) to text field + cerr.rdbuf(cout.rdbuf()); + wxStreamToTextRedirector redirect(status_messages); + + if ( !(csvfile_path.length() > 0 && infile_path.length() > 0 + && fontsel_name.length() > 0) ) { + wxMessageBox(wxT("Please select input file, character table, and font!"), + wxT("Error"), wxOK | wxICON_ERROR); + return; + } + + wxFileName fn(infile_path); + wxString outfile_dir = fn.GetPath(); + wxString outfile_basename = fn.GetName(); + wxString outfile_name = outfile_basename + "_UTF.docx"; + + wxString outfile_path; + wxFileDialog outfile_dialog(this, wxT("Save Converted File"), + outfile_dir, outfile_name, + "Word OpenXML Document (*.docx)|*.docx", + wxFD_SAVE | wxFD_OVERWRITE_PROMPT); + if (outfile_dialog.ShowModal() == wxID_CANCEL) return; + else outfile_path = outfile_dialog.GetPath(); + + cout << "Processing file " << infile_path << endl; + + TranscodeFrame::LoadCharmap(csvfile_path, L'\t', char_map, utf_chars); + + wxString tempdir = wxFileName::GetTempDir(); + wxString temp_path = tempdir + path_separator + random_anum_string(6); + wxMkdir(temp_path, wxS_DIR_DEFAULT); + TranscodeFrame::ZipExtract(infile_path, temp_path); + wxSetWorkingDirectory(temp_path); + + wstring default_paragraph_font; + get_default_pfont(default_paragraph_font, styles_xmlfile); + if (default_paragraph_font.length() > 0) + doc_fonts.push_back(default_paragraph_font); + + for (const auto& convfile: convfiles) + detect_fonts(convfile, doc_fonts, doc_encs); + + // We only want to get the unique fonts + uniq(doc_fonts); + uniq(doc_encs); + + cout << "Unique fonts discovered in document: " << endl; + for (const auto& doc_font: doc_fonts) + cout << " - " << doc_font << endl; + + wxArrayString flist_choices; + for (const auto& f_wstr: doc_fonts) { + if (char_map.count(f_wstr) != 0) + flist_choices.Add(wxString(f_wstr.c_str())); + } + + if (config_params.do_font_select) { + wxMultiChoiceDialog flist_dialog(this, wxT("Select fonts to convert:"), + wxT("Font Selection"), flist_choices, wxOK); + flist_dialog.ShowModal(); + wxArrayInt flist_sel = flist_dialog.GetSelections(); + for (int index: flist_sel) + doc_fonts_sel.push_back(flist_choices[index].ToStdWstring()); + } + else doc_fonts_sel = doc_fonts; + + for (const auto& convfile: convfiles) { + if (!wxFileExists(convfile)) continue; + cout << "Processing XML source file: " << convfile << endl; + process_xml(convfile, fontsel_name, doc_fonts_sel, doc_encs, + char_map, utf_chars, default_paragraph_font, + config_params.do_greek); + } + + update_default_pfont(styles_xmlfile, fontsel_name, doc_fonts); + + cout << "Conversion completed!" << endl; + + TranscodeFrame::ZipCreate(temp_path, outfile_path); + wxFileName::Rmdir(temp_path, wxPATH_RMDIR_RECURSIVE); + wxSetWorkingDirectory(cwd_0); + write_config_file(config_filepath, config_options); +} |
