From 5f755aa3d92763d6c1d449cc91036e35e361328e Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Fri, 22 Apr 2016 13:29:30 +0200 Subject: [PATCH] Auto-Save & Restore of text added (closes #16) --- ZRCola/ZRCola.fbp | 2 +- ZRCola/stdafx.h | 1 + ZRCola/zrcolacomppnl.cpp | 156 +++++++++++++++++++++++++++++++++++++++ ZRCola/zrcolacomppnl.h | 32 +++++++- ZRCola/zrcolafrm.cpp | 1 - ZRCola/zrcolagui.cpp | 2 +- ZRCola/zrcolagui.h | 2 +- 7 files changed, 191 insertions(+), 5 deletions(-) diff --git a/ZRCola/ZRCola.fbp b/ZRCola/ZRCola.fbp index 8d42908..7912864 100644 --- a/ZRCola/ZRCola.fbp +++ b/ZRCola/ZRCola.fbp @@ -805,7 +805,7 @@ - + ZRColaComposerPanel wxTAB_TRAVERSAL diff --git a/ZRCola/stdafx.h b/ZRCola/stdafx.h index b6360e2..6f92d90 100644 --- a/ZRCola/stdafx.h +++ b/ZRCola/stdafx.h @@ -25,6 +25,7 @@ #include "zrcolafrm.h" #include "zrcolakeyhndlr.h" +#include #include #include #include diff --git a/ZRCola/zrcolacomppnl.cpp b/ZRCola/zrcolacomppnl.cpp index 62fdb1a..f5c2e07 100644 --- a/ZRCola/zrcolacomppnl.cpp +++ b/ZRCola/zrcolacomppnl.cpp @@ -24,6 +24,11 @@ // wxZRColaComposerPanel ////////////////////////////////////////////////////////////////////////// +BEGIN_EVENT_TABLE(wxZRColaComposerPanel, wxZRColaComposerPanelBase) + EVT_TIMER(1, wxZRColaComposerPanel::OnTimerTimeout) +END_EVENT_TABLE() + + wxZRColaComposerPanel::wxZRColaComposerPanel(wxWindow* parent) : m_progress(false), m_selDecomposed(0, 0), @@ -31,12 +36,22 @@ wxZRColaComposerPanel::wxZRColaComposerPanel(wxWindow* parent) : wxZRColaComposerPanelBase(parent) { m_decomposed->PushEventHandler(&m_keyhandler); + + m_timer = new wxTimer(this, 1); + + wxPersistentZRColaComposerPanel(this).Restore(); } wxZRColaComposerPanel::~wxZRColaComposerPanel() { + if (m_timer) + delete m_timer; + m_decomposed->PopEventHandler(); + + // This is a controlled exit. Purge saved state. + wxPersistentZRColaComposerPanel(this).Clear(); } @@ -86,6 +101,9 @@ void wxZRColaComposerPanel::OnDecomposedText(wxCommandEvent& event) m_composed->SetSelection(m_mapping2.to_dst(m_mapping1.to_dst(from)), m_mapping2.to_dst(m_mapping1.to_dst(to))); event.Skip(); m_progress = false; + + // Schedule state save after 3s. + m_timer->Start(3000, true); } } @@ -141,5 +159,143 @@ void wxZRColaComposerPanel::OnComposedText(wxCommandEvent& event) m_decomposed->SetSelection(m_mapping1.to_src(m_mapping2.to_src(from)), m_mapping1.to_src(m_mapping2.to_src(to))); event.Skip(); m_progress = false; + + // Schedule state save after 3s. + m_timer->Start(3000, true); } } + + +void wxZRColaComposerPanel::OnTimerTimeout(wxTimerEvent& event) +{ + wxPersistentZRColaComposerPanel(this).Save(); + + event.Skip(); +} + + +////////////////////////////////////////////////////////////////////////// +// wxPersistentZRColaComposerPanel +////////////////////////////////////////////////////////////////////////// + +wxPersistentZRColaComposerPanel::wxPersistentZRColaComposerPanel(wxZRColaComposerPanel *wnd) : wxPersistentWindow(wnd) +{ +} + + +wxString wxPersistentZRColaComposerPanel::GetKind() const +{ + return wxT("ZRColaComposerPanel"); +} + + +void wxPersistentZRColaComposerPanel::Save() const +{ + wxString fileName(GetStateFileName()); + wxFFile file(fileName, wxT("wb")); + if (!file.IsOpened()) + return; + + const wxZRColaComposerPanel * const wnd = static_cast(GetWindow()); + + // Save decomposed text. + { +#ifdef __WINDOWS__ + // Use Windows GetWindowText() function to avoid line ending conversion incompletely imposed by wxWidgets. + WXHWND hWnd = wnd->m_decomposed->GetHWND(); + std::vector text((std::vector::size_type)::GetWindowTextLengthW(hWnd) + 1); + ::GetWindowTextW(hWnd, text.data(), text.size()); + unsigned __int64 n = text.size() - 1; +#else + wxString text(m_decomposed->GetValue()); + unsigned __int64 n = text.size(); +#endif + file.Write(&n, sizeof(n)); + file.Write(text.data(), sizeof(wchar_t)*n); + } + + // Save composed text. + { +#ifdef __WINDOWS__ + // Use Windows GetWindowText() function to avoid line ending conversion incompletely imposed by wxWidgets. + WXHWND hWnd = wnd->m_composed->GetHWND(); + std::vector text((std::vector::size_type)::GetWindowTextLengthW(hWnd) + 1); + ::GetWindowTextW(hWnd, text.data(), text.size()); + unsigned __int64 n = text.size() - 1; +#else + wxString text(m_composed->GetValue()); + unsigned __int64 n = text.size(); +#endif + file.Write(&n, sizeof(n)); + file.Write(text.data(), sizeof(wchar_t)*n); + } +} + + +bool wxPersistentZRColaComposerPanel::Restore() +{ + wxString fileName(GetStateFileName()); + + if (!wxFileExists(fileName)) + return false; + + wxFFile file(fileName, wxT("rb")); + if (!file.IsOpened()) + return false; + + wxZRColaComposerPanel * const wnd = static_cast(GetWindow()); + + // 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. + wnd->m_progress = true; + wnd->m_decomposed->SetValue(decomposed); + wnd->m_composed->SetValue(composed); + wnd->m_progress = false; + return true; + } + } + } + } + + return false; +} + + +void wxPersistentZRColaComposerPanel::Clear() const +{ + wxString fileName(GetStateFileName()); + + if (wxFileExists(fileName)) + wxRemoveFile(fileName); +} + + +wxString wxPersistentZRColaComposerPanel::GetStateFileName() const +{ + wxString path; + + path = wxFileName::GetTempDir(); + if (!wxEndsWithPathSeparator(path)) + path += wxFILE_SEP_PATH; + + if (!wxDirExists(path)) + wxMkdir(path); + + wxString fileName(path); + fileName += GetKind(); + fileName += wxT("-state.tmp"); + + return fileName; +} diff --git a/ZRCola/zrcolacomppnl.h b/ZRCola/zrcolacomppnl.h index 3f25d8d..9e297df 100644 --- a/ZRCola/zrcolacomppnl.h +++ b/ZRCola/zrcolacomppnl.h @@ -27,6 +27,8 @@ class wxZRColaComposerPanel; #include "zrcolagui.h" #include "zrcolakeyhndlr.h" +#include +#include #include @@ -39,13 +41,16 @@ public: wxZRColaComposerPanel(wxWindow* parent); virtual ~wxZRColaComposerPanel(); - friend class wxZRColaFrame; // Allow main frame direct access to our members. + friend class wxZRColaFrame; // Allow main frame direct access to our members. + friend class wxPersistentZRColaComposerPanel; // Allow saving/restoring window state. protected: virtual void OnDecomposedPaint(wxPaintEvent& event); virtual void OnDecomposedText(wxCommandEvent& event); virtual void OnComposedPaint(wxPaintEvent& event); virtual void OnComposedText(wxCommandEvent& event); + virtual void OnTimerTimeout(wxTimerEvent& event); + DECLARE_EVENT_TABLE() protected: bool m_progress; ///< Boolean flag to avoid recursive updates of composed and decomposed text controls @@ -55,4 +60,29 @@ protected: m_selDecomposed, ///< Character index of selected text in decomposed text control m_selComposed; ///< Character index of selected text in composed text control wxZRColaKeyHandler m_keyhandler; ///< Key handler for decomposed window + wxTimer *m_timer; ///< Timer to trigger the state save }; + + +/// +/// Supports saving/restoring wxZRColaComposerPanel state +/// +class wxPersistentZRColaComposerPanel : public wxPersistentWindow +{ +public: + wxPersistentZRColaComposerPanel(wxZRColaComposerPanel *wnd); + + virtual wxString GetKind() const; + virtual void Save() const; + virtual bool Restore(); + virtual void Clear() const; + +protected: + wxString GetStateFileName() const; +}; + + +inline wxPersistentObject *wxCreatePersistentObject(wxZRColaComposerPanel *wnd) +{ + return new wxPersistentZRColaComposerPanel(wnd); +} diff --git a/ZRCola/zrcolafrm.cpp b/ZRCola/zrcolafrm.cpp index 615115e..8b64f15 100644 --- a/ZRCola/zrcolafrm.cpp +++ b/ZRCola/zrcolafrm.cpp @@ -298,7 +298,6 @@ wxPersistentZRColaFrame::wxPersistentZRColaFrame(wxZRColaFrame *wnd) : wxPersist void wxPersistentZRColaFrame::Save() const { - // const wxZRColaFrame * const wnd = static_cast(GetWindow()); SaveValue(wxT("lang"), wxString::FromAscii(wnd->m_lang, sizeof(wnd->m_lang))); diff --git a/ZRCola/zrcolagui.cpp b/ZRCola/zrcolagui.cpp index 0b74a13..394497a 100644 --- a/ZRCola/zrcolagui.cpp +++ b/ZRCola/zrcolagui.cpp @@ -160,7 +160,7 @@ wxZRColaFrameBase::~wxZRColaFrameBase() } -wxZRColaComposerPanelBase::wxZRColaComposerPanelBase( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style ) +wxZRColaComposerPanelBase::wxZRColaComposerPanelBase( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : wxPanel( parent, id, pos, size, style, name ) { wxBoxSizer* bSizerEditor; bSizerEditor = new wxBoxSizer( wxVERTICAL ); diff --git a/ZRCola/zrcolagui.h b/ZRCola/zrcolagui.h index f62eeb9..7523308 100644 --- a/ZRCola/zrcolagui.h +++ b/ZRCola/zrcolagui.h @@ -96,7 +96,7 @@ class wxZRColaComposerPanelBase : public wxPanel public: - wxZRColaComposerPanelBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxTAB_TRAVERSAL ); + wxZRColaComposerPanelBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxTAB_TRAVERSAL, const wxString& name = wxT("ZRColaComposerPanel") ); ~wxZRColaComposerPanelBase(); };