diff --git a/app.cpp b/app.cpp index befcee3..c97cf4f 100644 --- a/app.cpp +++ b/app.cpp @@ -192,7 +192,7 @@ void App::OnError(wxCommandEvent& event) { // We use this to display errors where throwing would cause problems, as in a destructor // Instead we post an event to be handled in due course. - wxMessageDialog dlg(singletonFrame, event.GetString(), _T("Error"), wxICON_ERROR); + wxMessageDialog dlg(singletonFrame, event.GetString(), wsz_error, wxICON_ERROR); dlg.SetId(myID_ERRORMESSAGE); dlg.ShowModal(); } diff --git a/display_wallet.cpp b/display_wallet.cpp index bf6c864..1c624ba 100644 --- a/display_wallet.cpp +++ b/display_wallet.cpp @@ -2,7 +2,8 @@ using ro::base58; display_wallet::display_wallet(wxWindow* parent, wxFileName& walletfile) : wxPanel(parent, myID_WALLET_UI, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _T("Wallet")), - m_db(nullptr) + m_db(nullptr), + m_menuitem_close(this, &display_wallet::close_menu_event_handler) { wxLogMessage(_T("Loading %s"), walletfile.GetFullPath()); if (!walletfile.IsOk() || !walletfile.HasName() || !walletfile.HasExt()) throw MyException("unexpected file name"); @@ -55,8 +56,28 @@ display_wallet::display_wallet(wxWindow* parent, wxFileName& walletfile) : wxALL, // and make border all around 2); } + Bind(wxEVT_CLOSE_WINDOW, &display_wallet::OnClose, this); this->SetSize(this->GetParent()->GetClientSize()); singletonFrame->m_LastUsedSqlite.Assign(walletfile); + + wxMenu* menuFile{ singletonFrame->GetMenuBar()->GetMenu(0) }; + m_menuitem_close.Insert(menuFile, 1, "close", "test"); } display_wallet::~display_wallet() { + assert(true); +} + +void display_wallet::close_menu_event_handler(wxCommandEvent& event) { + wxMessageDialog dlg(this, event.GetString(), wsz_error, wxICON_ERROR); + Close(true); +} + +void display_wallet::OnClose(wxCloseEvent& event) { + // This event gives you the opportunity to clean up anything that needs explicit cleanup, albeit if you have done your work right nothing should need explicit cleanup, + // and to object to the closing in a "file not saved" type situation. + // https://docs.wxwidgets.org/trunk/classwx_close_event.html + DestroyChildren(); + Destroy(); //Default handler will destroy the window. This is our handler for the user calling close, + // replacing the default handler.' + if (singletonFrame->m_panel ==this)singletonFrame->m_panel = nullptr; } \ No newline at end of file diff --git a/display_wallet.h b/display_wallet.h index d3ded93..dbc8e6e 100644 --- a/display_wallet.h +++ b/display_wallet.h @@ -5,8 +5,13 @@ public: display_wallet(wxWindow*, wxFileName&); ~display_wallet(); private: + typedef MenuLink MenuLink; std::unique_ptr m_db; ristretto255::CMasterSecret m_MasterSecret; wxBoxSizer* m_lSizer; wxBoxSizer* m_rSizer; + void close_menu_event_handler(wxCommandEvent&); + // MenuLink m_close(display_wallet::close); + MenuLink m_menuitem_close; + void OnClose(wxCloseEvent& event); }; diff --git a/frame.cpp b/frame.cpp index 7b63c41..0524e63 100644 --- a/frame.cpp +++ b/frame.cpp @@ -4,6 +4,8 @@ // frame // ---------------------------------------------------------------------------- +Frame* singletonFrame{nullptr}; + void Frame::RestorePositionFromConfig(const wxSize& bestSize) { // SetPath() understands ".." but you should probably never use it. singletonApp->pConfig->SetPath(_T("/MainFrame")); wxPoint scr{ wxSystemSettings::GetMetric(wxSYS_SCREEN_X), wxSystemSettings::GetMetric(wxSYS_SCREEN_Y) }; @@ -116,7 +118,6 @@ try { SetIcon(wxICON(AAArho)); //Does not appear to do anything. Maybe it does something in Unix. //wxICON is a namestring on windows, and a symbol on Unix Bind(wxEVT_CLOSE_WINDOW, &Frame::OnClose, this); - Bind(wxEVT_CLOSE_WINDOW, &Frame::OnClose, this); wxMenu* menuFile = new wxMenu; menuFile->Append(wxID_NEW, menu_strings[0].tail[0][0], menu_strings[0].tail[0][1]); @@ -129,31 +130,27 @@ try { menuFile->Bind(wxEVT_MENU, &Frame::OnFileOpen, this, wxID_OPEN); menuFile->Append(wxID_DELETE, menu_strings[0].tail[3][0], menu_strings[0].tail[3][1] + m_LastUsedSqlite.GetFullPath()); + wxLogMessage(m_LastUsedSqlite.GetFullPath()+" wallet path"); menuFile->Bind(wxEVT_MENU, &Frame::OnDelete, this, wxID_DELETE); - - menuFile->AppendSeparator(); - menuFile->Append(myID_DELETECONFIG, menu_strings[0].tail[4][0], menu_strings[0].tail[4][1] + m_LastUsedSqlite.GetFullPath()); menuFile->Bind(wxEVT_MENU, &Frame::OnDeleteConfiguration, this, myID_DELETECONFIG); - + menuFile->Append(myID_MYEXIT,"my exit, testing destruction"); + menuFile->Bind(wxEVT_MENU, &Frame::OnMyCloseMpanel, this, myID_MYEXIT); + menuFile->Append(wxID_EXIT); + menuFile->Bind(wxEVT_MENU, &Frame::OnExit, this, wxID_EXIT); + wxMenu* menuHelp = new wxMenu; menuHelp->Append(wxID_ABOUT); menuHelp->Bind(wxEVT_MENU, &Frame::OnAbout, this, wxID_ABOUT); - menuHelp->Append(myID_ADD_SUBWINDOW, _T("insert new window"), _T("insert")); - menuHelp->Bind(wxEVT_MENU, &Frame::OnAddSubwindow, this, myID_ADD_SUBWINDOW); - menu_OnDeleteSubwindow.Append(menuHelp,this, _T("delete first subwindow"), _T("delete")); - menuHelp->Append(myID_DELETE_LAST_SUBWINDOW, _T("delete last subwindow"), _T("delete")); - menuHelp->Bind(wxEVT_MENU, &Frame::OnDeleteLastSubwindow, this, myID_DELETE_LAST_SUBWINDOW); -// menu_OnFirstUse.Append(menuHelp, this, _T("New wallet"), _T("add new wallet")); wxMenuBar* menuBar = new wxMenuBar; menuBar->Append(menuFile, menu_strings[0].head); menuBar->Append(new wxMenu, menu_strings[1].head); menuBar->Append(menuHelp, menu_strings[2].head); SetMenuBar(menuBar); CreateStatusBar(); + menuBar->EnableTop(1, false); // child controls m_LastUsedSqlite.Assign(singletonApp->pConfig->Read(_T("/Wallet/LastUsed"), _T(""))); - wxString debug_data{ m_LastUsedSqlite.GetFullPath() }; if (!m_LastUsedSqlite.IsOk() || !m_LastUsedSqlite.HasName() || !m_LastUsedSqlite.HasExt()) { m_panel = new welcome_to_rhocoin(this); //Owner is "this", via the base class wxFrame. m_panel is a // non owning pointer in the derived class that duplicates the owning pointer in the base class. @@ -166,14 +163,25 @@ try { SetClientSize(GetClientSize()); } catch (const std::exception& e) { - // cannot throw when no window is available. Construction of the base frame has to be completed, come what may. + // cannot throw when no window is available. Construction of the base frame has to be completed, + // come what may. // if an exception propagated from the constructor of the derived frame, it would destruct the base frame // and chaos would ensue as a windowing program attempts to handle an error with no main window. // so exceptions in the constructor of the main frame have to be caught and not rethrown. queue_error_message(e.what()); } } +void Frame::OnMyCloseMpanel(wxCommandEvent& event) { + if (m_panel) { + m_panel->Close(true); + } +} + void Frame::OnExit(wxCommandEvent& event) { + if (m_panel) { + m_panel->Close(true); + m_panel = nullptr; + } Close(true); } @@ -181,14 +189,15 @@ void Frame::OnClose(wxCloseEvent& event) { // This event gives you the opportunity to clean up anything that needs explicit cleanup, albeit if you have done your work right nothing should need explicit cleanup, // and to object to the closing in a "file not saved" type situation. // https://docs.wxwidgets.org/trunk/classwx_close_event.html - if (sqlite3_shutdown())wxMessageBox(_T(R"|(Sqlite3 shutdown error)|"), _T("Error"), wxICON_ERROR); + if (sqlite3_shutdown())wxMessageBox(_T(R"|(Sqlite3 shutdown error)|"), wsz_error, wxICON_ERROR); + DestroyChildren(); Destroy(); //Default handler will destroy the window. This is our handler for the user calling close, replacing the default handler. } void Frame::OnAbout(wxCommandEvent& event) { - wxMessageBox("This is a wxWidgets' Config sample", - "About sample code", wxOK | wxICON_INFORMATION); + wxMessageBox(szAboutWallet, + szAboutTitle, wxOK | wxICON_INFORMATION); } void Frame::OnDeleteConfiguration(wxCommandEvent&) @@ -213,45 +222,6 @@ void Frame::OnDeleteConfiguration(wxCommandEvent&) } } - -void Frame::OnAddSubwindow(wxCommandEvent& WXUNUSED(event)) { - wxBoxSizer* sizer(static_cast(m_panel->GetSizer())); - sizer->Prepend(new wxStaticText(m_panel, myID_TESTWINDOW, _T("test"))); - sizer->Layout(); -} - -void Frame::OnDeleteSubwindow(wxCommandEvent& WXUNUSED(event)) { - auto sizer(m_panel->GetSizer()); - int item_number(0); - if (sizer->GetItemCount()) { - wxSizerItem* t1 = sizer->GetItem(item_number); - if (t1) { - auto t2 = t1->GetWindow(); - if (t2) { - sizer->Detach(t2); - t2->Destroy(); - sizer->Layout(); - } - } - } -} - -void Frame::OnDeleteLastSubwindow(wxCommandEvent& WXUNUSED(event)) { - auto sizer(m_panel->GetSizer()); - int item_number(sizer->GetItemCount()-1); - if (item_number >= 0) { - wxSizerItem* t1 = sizer->GetItem(item_number); - if (t1) { - auto t2 = t1->GetWindow(); - if (t2) { - sizer->Detach(t2); - t2->Destroy(); - sizer->Layout(); - } - } - } -} - using ro::bin2hex, ro::to_base64_string; void Frame::NewWalletNewSecret(wxCommandEvent&) { @@ -439,4 +409,4 @@ Frame::~Frame(){ if (pConfig == nullptr)return; StorePositionToConfig(); pConfig->Write(_T("/Wallet/LastUsed"), m_LastUsedSqlite.GetFullPath()); -} \ No newline at end of file +} diff --git a/frame.h b/frame.h index 6a173d7..ab56433 100644 --- a/frame.h +++ b/frame.h @@ -1,37 +1,47 @@ #pragma once -template +template // This class exists to record the needed to unbind a drop down menu action and delete // the corresponding item from the drop down menu when the handler is destroyed. // (Because the handler is a method of an object that is about to be destroyed.) // Also avoids the need for manually creating a new windowid to link each additional bind // to each menu item, thus avoids the likelihood of mismatching binds and menu entries. class MenuLink { - void (handler_class::* m_method)(wxCommandEvent&); + typedef void (T::* method_handler)(wxCommandEvent&); + // (thing.*p)(args) is how you use a pointer to method + T* m_handler = nullptr; + method_handler m_method; int m_winid; - handler_class* m_handler = nullptr; - wxMenu* m_menu =nullptr; - wxMenuItem* m_menuItem = nullptr;; + wxMenu* m_menu = nullptr; + wxMenuItem* m_menuItem = nullptr; public: - MenuLink( - void (handler_class::* method)(wxCommandEvent&)) : m_method{ method }, m_winid{ wxWindow::NewControlId()} {} - MenuLink( - void (handler_class::* method)(wxCommandEvent&), MyIDs winid) : m_method{ method }, m_winid{ winid } {} + MenuLink() = delete; + MenuLink(const MenuLink&) = default; + MenuLink(const MenuLink&&) = delete; + MenuLink& operator=(const MenuLink&) = delete; + MenuLink& operator=(MenuLink&) = delete; + MenuLink(T* handler, method_handler method) : + m_handler(handler), m_method{ method }, m_winid{ wxWindow::NewControlId() }{} + MenuLink(T* handler, method_handler method, MyIDs winid) : + m_handler(handler), m_method{ method }, m_winid{ winid } {} ~MenuLink() { if (m_menu != nullptr) { m_menu->Unbind(wxEVT_MENU, m_method, m_handler, m_winid); m_menu->Destroy(m_menuItem); } } - auto Append( + wxMenuItem* Insert( wxMenu* menu, - handler_class* handler, - const wxString& item = wxEmptyString, - const wxString& helpString = wxEmptyString + size_t pos, + const wxString& item, + const wxString& help = wxEmptyString ) { - m_menu = menu; - m_handler = handler; - m_menuItem = menu->Append(m_winid, item, helpString); - menu->Bind(wxEVT_MENU, m_method, handler, m_winid); + if (m_menu == nullptr) m_menu = menu; + else { + assert(false); + throw MyException("Reinsertion of menu item"); + } + m_menuItem = menu->Insert(pos, m_winid, item, help); + menu->Bind(wxEVT_MENU, m_method, m_handler, m_winid); return m_menuItem; } void queue_event() { @@ -39,7 +49,10 @@ public: auto event = new wxCommandEvent(wxEVT_MENU, m_winid); wxQueueEvent(m_menu, event); } - else throw MyException("Event sent to uninitialized Menu item"); + else { + assert(false); + throw MyException("Event sent to uninitialized Menu item"); + } } }; @@ -51,28 +64,26 @@ public: Frame(wxString); ~Frame(); wxFileName m_LastUsedSqlite; + wxPanel* m_panel{nullptr}; //The once current child panel. private: typedef MenuLink MenuLink; - wxPanel* m_panel; //The once current child panel. void StorePositionToConfig(void); void RestorePositionFromConfig(const wxSize&); void OnExit(wxCommandEvent&); void OnClose(wxCloseEvent&); void OnAbout(wxCommandEvent&); void OnDeleteConfiguration(wxCommandEvent&); + void OnMyCloseMpanel(wxCommandEvent&); + public: void OnSaveNew(wxCommandEvent&); void NewWalletNewSecret(wxCommandEvent&); void RecreateWalletFromExistingSecret(wxCommandEvent&); void OnFileOpen(wxCommandEvent&); + private: void OnDelete(wxCommandEvent&); void OnMenuOpen(wxMenuEvent&); - void OnDeleteSubwindow(wxCommandEvent&); - MenuLink menu_OnDeleteSubwindow = - MenuLink(&Frame::OnDeleteSubwindow); - void OnDeleteLastSubwindow(wxCommandEvent&); - void OnAddSubwindow(wxCommandEvent&); public: void OnFirstUse(wxCommandEvent&); @@ -80,4 +91,6 @@ public: // MenuLink menu_OnFirstUse = // MenuLink(&Frame::OnFirstUse, myID_WELCOME_TO_ROCOIN); }; -inline Frame* singletonFrame(nullptr); + +extern Frame* singletonFrame; + diff --git a/localization.cpp b/localization.cpp index d27c84b..62db207 100644 --- a/localization.cpp +++ b/localization.cpp @@ -105,6 +105,10 @@ const char sz_existing_wallet[] {R"|(existing wallet)|"}; const char sz_text_buffer_overflow[]{R"|(conversion to base64 would overflow text buffer)|"}; const char sz_unknown_error[]{ R"|(unknown error.)|"}; +const char szAboutWallet[]{ R"|(A completely useless wallet +that is not even in a fit state for anyone else to work on)|" }; +const char szAboutTitle[]{ R"|(About Wallet)|" }; + //Error message strings const wchar_t wsz_error[] { L"Error" }; const wchar_t wsz_operation[] { L"Operation aborted.\n" }; diff --git a/localization.h b/localization.h index 0445c05..0606243 100644 --- a/localization.h +++ b/localization.h @@ -43,7 +43,10 @@ extern const char sz_existing_secret[]; extern const char sz_open_existing_wallet[]; extern const char sz_existing_wallet[]; extern const char sz_text_buffer_overflow[]; -extern const char sz_unknown_error[]; +extern const char sz_unknown_error[]; + +extern const char szAboutWallet[]; +extern const char szAboutTitle[]; //Error message strings extern const wchar_t wsz_error[]; diff --git a/ristretto255.cpp b/ristretto255.cpp index 0f71085..0a3c2e6 100644 --- a/ristretto255.cpp +++ b/ristretto255.cpp @@ -27,19 +27,6 @@ namespace ristretto255 { bool scalar::constant_time_required{ true }; bool point::constant_time_required{ true }; -/* constexpr scalar::scalar(intmax_t i) { - if (i >= 0) { - auto k{ intmax_t(i) }; - for (auto& j : blob) { j = k; k = k >> 8; } - } - else { - std::array absdata; - auto k{ uintmax_t(-i) }; - for (auto& j : absdata) { j = k; k = k >> 8; } - crypto_core_ristretto255_scalar_negate(&blob[0], &absdata[0]); - } - } - */ point point::operator*(const scalar &sclr) const& noexcept { point me; auto i{ crypto_scalarmult_ristretto255(&me.blob[0], &sclr.blob[0], &blob[0]) }; diff --git a/stdafx.h b/stdafx.h index 7ae2498..7da2cf4 100644 --- a/stdafx.h +++ b/stdafx.h @@ -94,12 +94,13 @@ inline wxString _wx(const char* sz) { return wxString::FromUTF8Unchecked(sz); } namespace testbed { extern void testbed(); } enum MyIDs { myID_DELETECONFIG = wxID_HIGHEST + 1, myID_ERRORMESSAGE, myID_Hello, - myID_DELETE_LAST_SUBWINDOW, myID_ADD_SUBWINDOW, myID_MAINFRAME, - myID_MAINFRAME_PANEL, myID_TESTWINDOW, myID_WELCOME_TO_ROCOIN, myID_WALLET_UI + myID_MAINFRAME, + myID_MAINFRAME_PANEL, myID_TESTWINDOW, myID_WELCOME_TO_ROCOIN, myID_WALLET_UI, + mID_CLOSE_WALLET, myID_MYEXIT }; +#include "localization.h" #include "db_accessors.h" #include "app.h" +#include "frame.h" #include "welcome_to_rhocoin.h" #include "display_wallet.h" -#include "frame.h" -#include "localization.h" diff --git a/testbed.cpp b/testbed.cpp index 8b542a9..c6dc1b6 100644 --- a/testbed.cpp +++ b/testbed.cpp @@ -48,5 +48,6 @@ If using a dialog, exceptions within the dialog will result in an error message */ void testbed() { +// queue_error_message("hello world"); } } diff --git a/unit_test.cpp b/unit_test.cpp index 31d139a..8edc6a9 100644 --- a/unit_test.cpp +++ b/unit_test.cpp @@ -342,6 +342,7 @@ static bool TestErrorDialog(void) { ILogMessage("\t\tposting delayed error message\n\t\tas if inside an exception handler or destructor"); auto event = new wxCommandEvent(wxEVT_MENU, myID_ERRORMESSAGE); wxQueueEvent(singletonFrame->GetMenuBar(), event); +// wxQueueEvent(singletonApp, event); unit_test_action = &Waiting_for_dummy_error_message; return true; } diff --git a/welcome_to_rhocoin.cpp b/welcome_to_rhocoin.cpp index c92d6ed..449c39d 100644 --- a/welcome_to_rhocoin.cpp +++ b/welcome_to_rhocoin.cpp @@ -135,6 +135,7 @@ welcome_to_rhocoin::welcome_to_rhocoin( sizer->Add(sizerRow, 40, wxEXPAND | wxALL, 2); btn_default->SetDefault(); SetSizer(sizer); + Bind(wxEVT_CLOSE_WINDOW, &welcome_to_rhocoin::OnClose, this); assert(singletonWelcome == nullptr); singletonWelcome = this; } @@ -143,3 +144,11 @@ welcome_to_rhocoin::~welcome_to_rhocoin() { assert(singletonWelcome ==this); singletonWelcome = nullptr; } + +void welcome_to_rhocoin::OnClose(wxCloseEvent& event) { + // This event gives you the opportunity to clean up anything that needs explicit cleanup, albeit if you have done your work right nothing should need explicit cleanup, + // and to object to the closing in a "file not saved" type situation. + // https://docs.wxwidgets.org/trunk/classwx_close_event.html + DestroyChildren(); + Destroy(); //Default handler will destroy the window. This is our handler for the user calling close, replacing the default handler. +} diff --git a/welcome_to_rhocoin.h b/welcome_to_rhocoin.h index 99e3fba..1189470 100644 --- a/welcome_to_rhocoin.h +++ b/welcome_to_rhocoin.h @@ -9,6 +9,8 @@ public: ~welcome_to_rhocoin(); wxButton* AddButton(wxString, void(Frame::*)(wxCommandEvent&)); wxButton* AddButton(const char sz[], void(Frame::*)(wxCommandEvent&)); +private: + void OnClose(wxCloseEvent& event); }; extern welcome_to_rhocoin* singletonWelcome;