ZRCola/ZRCola/zrcolacomppnl.cpp

395 lines
14 KiB
C++

/*
Copyright 2015-2016 Amebis
This file is part of ZRCola.
ZRCola is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ZRCola is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ZRCola. If not, see <http://www.gnu.org/licenses/>.
*/
#include "stdafx.h"
//////////////////////////////////////////////////////////////////////////
// wxZRColaComposerPanel
//////////////////////////////////////////////////////////////////////////
BEGIN_EVENT_TABLE(wxZRColaComposerPanel, wxZRColaComposerPanelBase)
EVT_TIMER(wxZRColaComposerPanel::wxID_CHECKPOINT_TIMER, wxZRColaComposerPanel::OnTimerTimeout)
END_EVENT_TABLE()
wxZRColaComposerPanel::wxZRColaComposerPanel(wxWindow* parent) :
m_progress(false),
m_selDecomposed(0, 0),
m_selComposed(0, 0),
wxZRColaComposerPanelBase(parent)
{
m_decomposed->PushEventHandler(&m_keyhandler);
// Create timer for saving the state.
m_timer = new wxTimer(this, wxID_CHECKPOINT_TIMER);
// Restore the previously saved state (if exists).
wxString fileName(GetStateFileName());
if (wxFileExists(fileName)) {
wxFFile file(fileName, wxT("rb"));
if (file.IsOpened()) {
// Load decomposed text.
unsigned __int64 n;
file.Read(&n, sizeof(n));
if (!file.Error()) {
wxString decomposed;
file.Read(wxStringBuffer(decomposed, n), sizeof(wchar_t)*n);
if (!file.Error()) {
// Load composed text.
file.Read(&n, sizeof(n));
if (!file.Error()) {
wxString composed;
file.Read(wxStringBuffer(composed, n), sizeof(wchar_t)*n);
if (!file.Error()) {
// Restore state.
m_progress = true;
m_decomposed->SetValue(decomposed);
m_composed->SetValue(composed);
m_progress = false;
}
}
}
}
}
}
}
wxZRColaComposerPanel::~wxZRColaComposerPanel()
{
if (m_timer)
delete m_timer;
m_decomposed->PopEventHandler();
// This is a controlled exit. Purge saved state.
wxString fileName(GetStateFileName());
if (wxFileExists(fileName))
wxRemoveFile(fileName);
}
void wxZRColaComposerPanel::OnDecomposedPaint(wxPaintEvent& event)
{
event.Skip();
long from, to;
m_decomposed->GetSelection(&from, &to);
if (m_selDecomposed.first != from || m_selDecomposed.second != to) {
// Save new selection first, to avoid loop.
m_selDecomposed.first = from;
m_selDecomposed.second = to;
m_decomposedHex->SetSelection(m_mappingDecomposedHex.to_dst(from), m_mappingDecomposedHex.to_dst(to));
m_composed->SetSelection(from = m_mapping2.to_dst(m_mapping1.to_dst(from)), to = m_mapping2.to_dst(m_mapping1.to_dst(to)));
m_composedHex->SetSelection(m_mappingComposedHex.to_dst(from), m_mappingComposedHex.to_dst(to));
}
}
void wxZRColaComposerPanel::OnDecomposedHexPaint(wxPaintEvent& event)
{
event.Skip();
long from, to;
m_decomposedHex->GetSelection(&from, &to);
if (m_selDecomposedHex.first != from || m_selDecomposedHex.second != to) {
// Save new selection first, to avoid loop.
m_selDecomposedHex.first = from;
m_selDecomposedHex.second = to;
m_decomposed->SetSelection(from = m_mappingDecomposedHex.to_src(from), to = m_mappingDecomposedHex.to_src(to));
m_composed->SetSelection(from = m_mapping2.to_dst(m_mapping1.to_dst(from)), to = m_mapping2.to_dst(m_mapping1.to_dst(to)));
m_composedHex->SetSelection(m_mappingComposedHex.to_dst(from), m_mappingComposedHex.to_dst(to));
}
}
void wxZRColaComposerPanel::OnDecomposedText(wxCommandEvent& event)
{
if (m_progress) {
// We are being updated by wxZRColaComposerPanel::OnComposedText()
event.Skip();
} else {
m_timer->Stop();
#ifdef __WINDOWS__
// Use Windows GetWindowText() function to avoid line ending conversion incompletely imposed by wxWidgets.
WXHWND hWnd = m_decomposed->GetHWND();
size_t len = ::GetWindowTextLengthW(hWnd);
std::vector<wchar_t> src(len + 1);
::GetWindowTextW(hWnd, src.data(), src.size());
#else
wxString src(m_decomposed->GetValue());
size_t len = src.Length();
#endif
std::wstring norm;
((ZRColaApp*)wxTheApp)->m_t_db.Decompose(src.data(), len, norm, &m_mapping1);
std::wstring dst;
((ZRColaApp*)wxTheApp)->m_t_db.Compose(norm.data(), norm.size(), dst, &m_mapping2);
long from, to;
m_decomposed->GetSelection(&from, &to);
// Update decomposed HEX dump.
wxString hex;
GetHex(hex, m_mappingDecomposedHex, src.data(), len);
m_decomposedHex->SetValue(hex);
m_decomposedHex->SetSelection(m_mappingDecomposedHex.to_dst(from), m_mappingDecomposedHex.to_dst(to));
// Update composed text.
m_progress = true;
m_composed->SetValue(dst);
m_composed->SetSelection(from = m_mapping2.to_dst(m_mapping1.to_dst(from)), to = m_mapping2.to_dst(m_mapping1.to_dst(to)));
// Update composed HEX dump.
GetHex(hex, m_mappingComposedHex, dst.data(), dst.length());
m_composedHex->SetValue(hex);
m_composedHex->SetSelection(m_mappingComposedHex.to_dst(from), m_mappingComposedHex.to_dst(to));
event.Skip();
m_progress = false;
// Schedule state save after 3s.
m_timer->Start(3000, true);
}
}
void wxZRColaComposerPanel::OnComposedPaint(wxPaintEvent& event)
{
event.Skip();
long from, to;
m_composed->GetSelection(&from, &to);
if (m_selComposed.first != from || m_selComposed.second != to) {
// Save new selection first, to avoid loop.
m_selComposed.first = from;
m_selComposed.second = to;
m_composedHex->SetSelection(m_mappingComposedHex.to_dst(from), m_mappingComposedHex.to_dst(to));
m_decomposed->SetSelection(from = m_mapping1.to_src(m_mapping2.to_src(from)), to = m_mapping1.to_src(m_mapping2.to_src(to)));
m_decomposedHex->SetSelection(m_mappingDecomposedHex.to_dst(from), m_mappingDecomposedHex.to_dst(to));
}
}
void wxZRColaComposerPanel::OnComposedHexPaint(wxPaintEvent& event)
{
event.Skip();
long from, to;
m_composedHex->GetSelection(&from, &to);
if (m_selComposedHex.first != from || m_selComposedHex.second != to) {
// Save new selection first, to avoid loop.
m_selComposedHex.first = from;
m_selComposedHex.second = to;
m_composed->SetSelection(from = m_mappingComposedHex.to_src(from), to = m_mappingComposedHex.to_src(to));
m_decomposed->SetSelection(from = m_mapping1.to_src(m_mapping2.to_src(from)), to = m_mapping1.to_src(m_mapping2.to_src(to)));
m_decomposedHex->SetSelection(m_mappingDecomposedHex.to_dst(from), m_mappingDecomposedHex.to_dst(to));
}
}
void wxZRColaComposerPanel::OnComposedText(wxCommandEvent& event)
{
if (m_progress) {
// We are being updated by wxZRColaComposerPanel::OnDecomposedText()
event.Skip();
} else {
m_timer->Stop();
#ifdef __WINDOWS__
// Use Windows GetWindowTextLength() function to avoid line ending conversion incompletely imposed by wxWidgets.
WXHWND hWnd = m_composed->GetHWND();
size_t len = ::GetWindowTextLengthW(hWnd);
std::vector<wchar_t> src(len + 1);
::GetWindowTextW(hWnd, src.data(), src.size());
#else
wxString src(m_composed->GetValue());
size_t len = src.Length();
#endif
ZRColaApp *app = (ZRColaApp*)wxTheApp;
std::wstring dst;
wxZRColaFrame *mainWnd = dynamic_cast<wxZRColaFrame*>(wxGetActiveWindow());
if (mainWnd)
app->m_t_db.Decompose(src.data(), len, &app->m_lc_db, mainWnd->m_lang, dst, &m_mapping2);
else
app->m_t_db.Decompose(src.data(), len, dst, &m_mapping2);
m_mapping1.clear();
m_mapping2.invert();
long from, to;
m_composed->GetSelection(&from, &to);
// Update composed HEX dump.
wxString hex;
GetHex(hex, m_mappingComposedHex, src.data(), len);
m_composedHex->SetValue(hex);
m_composedHex->SetSelection(m_mappingComposedHex.to_dst(from), m_mappingComposedHex.to_dst(to));
// Update decomposed text.
m_progress = true;
m_decomposed->SetValue(dst);
m_decomposed->SetSelection(from = m_mapping1.to_src(m_mapping2.to_src(from)), to = m_mapping1.to_src(m_mapping2.to_src(to)));
// Update decomposed HEX dump.
GetHex(hex, m_mappingDecomposedHex, dst.data(), dst.length());
m_decomposedHex->SetValue(hex);
m_decomposedHex->SetSelection(m_mappingDecomposedHex.to_dst(from), m_mappingDecomposedHex.to_dst(to));
event.Skip();
m_progress = false;
// Schedule state save after 3s.
m_timer->Start(3000, true);
}
}
void wxZRColaComposerPanel::OnTimerTimeout(wxTimerEvent& event)
{
wxString fileName(GetStateFileName());
wxFFile file(fileName, wxT("wb"));
if (file.IsOpened()) {
// Save decomposed text.
{
#ifdef __WINDOWS__
// Use Windows GetWindowText() function to avoid line ending conversion incompletely imposed by wxWidgets.
WXHWND hWnd = m_decomposed->GetHWND();
unsigned __int64 len = ::GetWindowTextLengthW(hWnd);
std::vector<wchar_t> text(len + 1);
::GetWindowTextW(hWnd, text.data(), text.size());
#else
wxString text(m_decomposed->GetValue());
unsigned __int64 len = text.Length();
#endif
file.Write(&len, sizeof(len));
file.Write(text.data(), sizeof(wchar_t)*len);
}
// Save composed text.
{
#ifdef __WINDOWS__
// Use Windows GetWindowText() function to avoid line ending conversion incompletely imposed by wxWidgets.
WXHWND hWnd = m_composed->GetHWND();
unsigned __int64 len = ::GetWindowTextLengthW(hWnd);
std::vector<wchar_t> text(len + 1);
::GetWindowTextW(hWnd, text.data(), text.size());
#else
wxString text(m_composed->GetValue());
unsigned __int64 len = text.Length();
#endif
file.Write(&len, sizeof(len));
file.Write(text.data(), sizeof(wchar_t)*len);
}
}
event.Skip();
}
wxString wxZRColaComposerPanel::GetStateFileName()
{
wxString path;
path = wxFileName::GetTempDir();
if (!wxEndsWithPathSeparator(path))
path += wxFILE_SEP_PATH;
if (!wxDirExists(path))
wxMkdir(path);
wxString fileName(path);
fileName += wxT("ZRColaComposerPanel-state.tmp");
return fileName;
}
void wxZRColaComposerPanel::GetHex(wxString &hex, ZRCola::mapping_vector &mapping, const wchar_t *src, size_t len)
{
bool first = true;
hex.clear();
mapping.clear();
for (size_t i = 0; i < len && src[i]; i++) {
wchar_t c = src[i];
if (c == L'\n' || c == '\r') {
hex += c;
first = true;
} else {
hex += wxString::Format(first ? wxT("%04X") : wxT(" %04X"), src[i]);
mapping.push_back(ZRCola::mapping(i + 1, hex.Length()));
first = false;
}
}
}
//////////////////////////////////////////////////////////////////////////
// wxPersistentZRColaComposerPanel
//////////////////////////////////////////////////////////////////////////
wxPersistentZRColaComposerPanel::wxPersistentZRColaComposerPanel(wxZRColaComposerPanel *wnd) : wxPersistentWindow<wxZRColaComposerPanel>(wnd)
{
}
wxString wxPersistentZRColaComposerPanel::GetKind() const
{
return wxT(wxPERSIST_TLW_KIND);
}
void wxPersistentZRColaComposerPanel::Save() const
{
const wxZRColaComposerPanel * const wnd = static_cast<const wxZRColaComposerPanel*>(GetWindow());
SaveValue(wxT("splitDecomposed"), wnd->m_splitterDecomposed->GetSashPosition());
SaveValue(wxT("splitComposed" ), wnd->m_splitterComposed ->GetSashPosition());
}
bool wxPersistentZRColaComposerPanel::Restore()
{
wxZRColaComposerPanel * const wnd = static_cast<wxZRColaComposerPanel*>(GetWindow());
int sashVal;
if (RestoreValue(wxT("splitDecomposed"), &sashVal)) {
// wxFormBuilder sets initial splitter stash in idle event handler after GUI settles. Overriding our loaded value. Disconnect it's idle event handler.
wnd->m_splitterDecomposed->Disconnect( wxEVT_IDLE, wxIdleEventHandler( wxZRColaComposerPanelBase::m_splitterDecomposedOnIdle ), NULL, wnd );
wnd->m_splitterDecomposed->SetSashPosition(sashVal);
}
if (RestoreValue(wxT("splitComposed"), &sashVal)) {
// wxFormBuilder sets initial splitter stash in idle event handler after GUI settles. Overriding our loaded value. Disconnect it's idle event handler.
wnd->m_splitterComposed->Disconnect( wxEVT_IDLE, wxIdleEventHandler( wxZRColaComposerPanelBase::m_splitterComposedOnIdle ), NULL, wnd );
wnd->m_splitterComposed->SetSashPosition(sashVal);
}
return true;
}