Merge remote-tracking branch 'origin/master' into docs
This commit is contained in:
commit
0a0255a9f7
@ -150,6 +150,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="../src/app.cpp" />
|
<ClCompile Include="../src/app.cpp" />
|
||||||
<ClCompile Include="../src/display_wallet.cpp" />
|
<ClCompile Include="../src/display_wallet.cpp" />
|
||||||
|
<ClCompile Include="../src/db_accessors.cpp" />
|
||||||
<ClCompile Include="../src/frame.cpp" />
|
<ClCompile Include="../src/frame.cpp" />
|
||||||
<ClCompile Include="../src/ILog.cpp" />
|
<ClCompile Include="../src/ILog.cpp" />
|
||||||
<ClCompile Include="../src/ISqlit3Impl.cpp">
|
<ClCompile Include="../src/ISqlit3Impl.cpp">
|
||||||
|
@ -1,13 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "ILog.h"
|
#include "ILog.h"
|
||||||
// this is pure virtual interface base class between sqlite3, which speaks only C and utf8 char[]
|
// this is an interface base class between sqlite3, which speaks only C and utf8 char[]
|
||||||
// and wxWidgets which speaks only C++ and unicode strings.
|
// and wxWidgets which speaks only C++ and unicode strings.
|
||||||
|
|
||||||
// Usage: Call the factory function std::shared_ptr<ISqlite3> sqlite3_open(const char *) to get a shared
|
|
||||||
// pointer to the // Sqlite3 database object. Then call the factory function
|
|
||||||
// sqlite3_prepare(std::shared_ptr<ISqlite3>, const char *) to get a unique pointer to
|
|
||||||
// a compiled SQL statement
|
|
||||||
|
|
||||||
// Its primary purpose is to avoid code that needs both the wxWidgets header files,
|
// Its primary purpose is to avoid code that needs both the wxWidgets header files,
|
||||||
// and the sqlite3.h header file.
|
// and the sqlite3.h header file.
|
||||||
//
|
//
|
||||||
@ -25,8 +20,6 @@
|
|||||||
// substantially more difficult in C++14, because one is effectively rolling one's own
|
// substantially more difficult in C++14, because one is effectively rolling one's own
|
||||||
// unique pointer.
|
// unique pointer.
|
||||||
//
|
//
|
||||||
// It is therefore easier to implement a pure virtual base class with a virtual destructor and
|
|
||||||
// factory function that returns a smart pointer to a member of the derived implementation
|
|
||||||
//
|
//
|
||||||
/* This code is at a low level abstraction, because it provides low level C++ interface to inherently low level C
|
/* This code is at a low level abstraction, because it provides low level C++ interface to inherently low level C
|
||||||
It is intended to be wrapped in higher level code that does not know about the nuts and bolts of sqlite3, but which supports throwing, templated functions, and all that.*/
|
It is intended to be wrapped in higher level code that does not know about the nuts and bolts of sqlite3, but which supports throwing, templated functions, and all that.*/
|
||||||
|
45
src/db_accessors.cpp
Normal file
45
src/db_accessors.cpp
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
namespace ro {
|
||||||
|
static constexpr char SrcFilename[]{ "src/db_accessors.cpp" };
|
||||||
|
|
||||||
|
dbconnect::dbconnect(const wxFileName& filename) {
|
||||||
|
if (!filename.IsOk() || !filename.HasName() || !filename.HasExt()) throw
|
||||||
|
MyException("unexpected file name", __LINE__, __func__, SrcFilename);
|
||||||
|
if (!filename.FileExists())throw MyException(
|
||||||
|
std::string(filename.GetFullPath().ToUTF8()) + " does not exist.",
|
||||||
|
__LINE__, __func__, SrcFilename);
|
||||||
|
this->reset(Sqlite3_open(filename.GetFullPath().ToUTF8()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// move constructor
|
||||||
|
dbconnect::dbconnect(dbconnect&& p) noexcept :std::unique_ptr<ISqlite3>(p.release()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move assignment
|
||||||
|
dbconnect& dbconnect::operator=(dbconnect&& p) noexcept {
|
||||||
|
std::unique_ptr<ISqlite3>::reset(p.release());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
sql::sql(const std::unique_ptr<ISqlite3>& p, const char* sz) :
|
||||||
|
std::unique_ptr<Icompiled_sql>(sqlite3_prepare(p.get(), sz)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// move constructor
|
||||||
|
sql::sql(sql&& p) noexcept :std::unique_ptr<Icompiled_sql>(p.release()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move assignment
|
||||||
|
sql& sql::operator=(sql&& p) noexcept {
|
||||||
|
std::unique_ptr<Icompiled_sql>::reset(p.release());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
sql::sql(Icompiled_sql* p) :
|
||||||
|
std::unique_ptr<Icompiled_sql>(p) {
|
||||||
|
}
|
||||||
|
|
||||||
|
sql::sql(std::unique_ptr<Icompiled_sql>&& p) :
|
||||||
|
std::unique_ptr<Icompiled_sql>(p.release()) {
|
||||||
|
}
|
||||||
|
}
|
@ -15,26 +15,42 @@ namespace ro {
|
|||||||
|
|
||||||
static_assert(is_sqlite3_field_type<int>::value);
|
static_assert(is_sqlite3_field_type<int>::value);
|
||||||
|
|
||||||
|
//Owns a database connection and closes it when it is deconstructed
|
||||||
|
//Has move semantics
|
||||||
|
struct dbconnect : std::unique_ptr<ISqlite3> {
|
||||||
|
dbconnect(const wxFileName&); //And here we wrap our Cish implementation in C++ish implementation
|
||||||
|
dbconnect() = delete;
|
||||||
|
~dbconnect() = default; //Our base class takes care of it
|
||||||
|
// copy constructor
|
||||||
|
dbconnect(const dbconnect& a) = delete; //Move semantics
|
||||||
|
// move constructor
|
||||||
|
dbconnect(dbconnect&& p) noexcept;
|
||||||
|
// copy assignment
|
||||||
|
dbconnect& operator=(const dbconnect) = delete; //Move semantics
|
||||||
|
// Move assignment
|
||||||
|
dbconnect& operator=(dbconnect&& p) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
//Owns a compiled sql statement and destroys it when it is deconstructed.
|
//Owns a compiled sql statement and destroys it when it is deconstructed.
|
||||||
//Has move semantics.
|
//Has move semantics.
|
||||||
class sql : public std::unique_ptr<Icompiled_sql> {
|
class sql : public std::unique_ptr<Icompiled_sql> {
|
||||||
public:
|
public:
|
||||||
class monostate {};
|
class monostate {};
|
||||||
|
sql() = delete;
|
||||||
sql(ISqlite3* p, const char* sz) :std::unique_ptr<Icompiled_sql>(sqlite3_prepare(p, sz)) {}
|
sql(ISqlite3* p, const char* sz) :std::unique_ptr<Icompiled_sql>(sqlite3_prepare(p, sz)) {}
|
||||||
sql(const std::unique_ptr<ISqlite3>& p, const char* sz) :std::unique_ptr<Icompiled_sql>(sqlite3_prepare(p.get(), sz)) {}
|
sql(const std::unique_ptr<ISqlite3>& p, const char* sz);
|
||||||
// copy constructor
|
// copy constructor
|
||||||
sql(const sql& a) = delete;
|
sql(const sql& a) = delete;
|
||||||
// move constructor
|
// move constructor
|
||||||
sql(sql&& p) noexcept :std::unique_ptr<Icompiled_sql>(p.release()) { }
|
sql(sql&& p) noexcept;
|
||||||
// copy assignment
|
// copy assignment
|
||||||
sql& operator=(const sql) = delete;
|
sql& operator=(const sql) = delete;
|
||||||
// Move assignment
|
// Move assignment
|
||||||
sql& operator=(sql&& p) noexcept {
|
sql& operator=(sql&& p) noexcept;
|
||||||
std::unique_ptr<Icompiled_sql>::reset(p.release());
|
sql(Icompiled_sql* p);
|
||||||
}
|
sql(std::unique_ptr<Icompiled_sql>&& p);
|
||||||
sql(Icompiled_sql* p) :std::unique_ptr<Icompiled_sql>(p) {}
|
|
||||||
sql(std::unique_ptr<Icompiled_sql>&& p) :std::unique_ptr<Icompiled_sql>(p.release()) { }
|
|
||||||
~sql() = default;
|
~sql() = default;
|
||||||
|
|
||||||
template <typename T>auto column(int i) const {
|
template <typename T>auto column(int i) const {
|
||||||
if constexpr (ro::blob_type<T>) {
|
if constexpr (ro::blob_type<T>) {
|
||||||
auto st = (*this)->Isqlite3_column_blob(i);
|
auto st = (*this)->Isqlite3_column_blob(i);
|
||||||
@ -180,45 +196,13 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class sql_insert_name {
|
class sql_insert_name {
|
||||||
ro::sql csql_begin;
|
|
||||||
ro::sql csql_into_names;
|
ro::sql csql_into_names;
|
||||||
ro::sql csql_namekey_into_keys;
|
|
||||||
ro::sql csql_commit;
|
|
||||||
ro::sql csql_rollback;
|
|
||||||
public:
|
public:
|
||||||
sql_insert_name(ISqlite3* p) :
|
sql_insert_name(ISqlite3* p) :
|
||||||
csql_begin(p, R"|(BEGIN IMMEDIATE;)|"),
|
csql_into_names(p, R"|(INSERT OR FAIL INTO "UserZookoIDs" VALUES(?1, ?2);)|"){}
|
||||||
csql_into_names(p, R"|(INSERT OR FAIL INTO "Names" VALUES(NULL, ?1);)|"),
|
|
||||||
csql_namekey_into_keys(p, R"|(INSERT OR FAIL INTO "Keys" VALUES(NULL, ?1, last_insert_rowid(), 1);)|"),
|
|
||||||
/* NULL triggers special nonstandard Sqlite behavior to autogenerate a unique ROWID
|
|
||||||
Because we explicitly make the ROWID a named field in the table to avoid too much
|
|
||||||
non standard SQlite behavior, we must explicitly provide a placeholder in the INSERT
|
|
||||||
statement. So at least we only get special SQlite3 behavior when we deliberately
|
|
||||||
invoke it. */
|
|
||||||
csql_commit(p, R"|(COMMIT;)|"),
|
|
||||||
csql_rollback(p, R"|(ROLLBACK;)|")
|
|
||||||
{}
|
|
||||||
sql_insert_name(const std::unique_ptr<ISqlite3>& p) : sql_insert_name(p.get()) {}
|
sql_insert_name(const std::unique_ptr<ISqlite3>& p) : sql_insert_name(p.get()) {}
|
||||||
void operator()(const char* psz, const ristretto255::point& pt) {
|
void operator()(const char* psz, const ristretto255::point& pt) {
|
||||||
csql_begin.do_one();
|
csql_into_names.do_one(psz,pt);
|
||||||
try {
|
|
||||||
csql_into_names.do_one(psz);
|
|
||||||
csql_namekey_into_keys.do_one(pt);
|
|
||||||
}
|
|
||||||
catch (const MyException& e) {
|
|
||||||
csql_rollback.do_one();
|
|
||||||
if (e.what_num() == 19) {
|
|
||||||
throw MyException("Name already in database");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (const std::exception &) {
|
|
||||||
csql_rollback.do_one();
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
csql_commit.do_one();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -234,7 +218,5 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
constexpr auto WALLET_FILE_IDENTIFIER (0x56d34bc5a655dd1fi64);
|
constexpr auto WALLET_FILE_IDENTIFIER (0x56d34bc5a655dd1fi64);
|
||||||
constexpr auto WALLET_FILE_SCHEMA_VERSION_0_0(1);
|
constexpr auto WALLET_FILE_SCHEMA_VERSION_0_0(1);
|
||||||
|
@ -1,75 +1,32 @@
|
|||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
using ro::base58;
|
using ro::base58;
|
||||||
static constexpr char SrcFilename[]{ "src/display_wallet.cpp" };
|
static constexpr char SrcFilename[]{ "src/display_wallet.cpp" };
|
||||||
|
|
||||||
display_wallet::display_wallet(wxWindow* parent, wxFileName& walletfile) :
|
display_wallet::display_wallet(wxWindow* parent, wxFileName& walletfile) :
|
||||||
wxPanel(parent, myID_WALLET_UI, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, wxT("Wallet")),
|
wxPanel(parent, myID_WALLET_UI, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, wxT("Wallet")),
|
||||||
m_db(nullptr), m_DisplayWalletEditMenu(1)
|
m_db(walletfile), m_DisplayWalletEditMenu(1),
|
||||||
|
m_read_names_and_keys(m_db, R"|(SELECT * FROM "UserZookoIDs"; )|"),
|
||||||
|
m_read_from_misc(m_db),
|
||||||
|
m_insert_name(m_db),
|
||||||
|
m_find_position(m_db, R"|( SELECT COUNT(*) FROM UserZookoIDs
|
||||||
|
WHERE LOWER("name")<LOWER(?1) OR (LOWER("name")=LOWER(?1) AND "name"<?1);)|")
|
||||||
{
|
{
|
||||||
wxLogMessage(wxT("Loading %s"), walletfile.GetFullPath());
|
wxLogMessage(wxT("Loading %s"), walletfile.GetFullPath());
|
||||||
try {
|
try {
|
||||||
if (!walletfile.IsOk() || !walletfile.HasName() || !walletfile.HasExt()) throw MyException("unexpected file name", __LINE__, __func__, SrcFilename);
|
if (!m_read_from_misc(1) || m_read_from_misc.value<int64_t>() != WALLET_FILE_IDENTIFIER)throw MyException(sz_unrecognizable_wallet_file_format);
|
||||||
if (!walletfile.FileExists())throw MyException(
|
if (!m_read_from_misc(2) || m_read_from_misc.value<int64_t>() != WALLET_FILE_SCHEMA_VERSION_0_0 || !m_read_from_misc(4))throw MyException(sz_unrecognized_wallet_schema);
|
||||||
walletfile.GetFullPath().append(" does not exist.").ToUTF8(),
|
m_MasterSecret= *(m_read_from_misc.value<ristretto255::scalar>());
|
||||||
__LINE__, __func__, SrcFilename);
|
|
||||||
m_db.reset(Sqlite3_open(walletfile.GetFullPath().ToUTF8()));
|
|
||||||
m_read_from_misc.reset(new sql_read_from_misc(m_db));
|
|
||||||
m_read_names_and_keys.reset(new ro::sql(m_db,
|
|
||||||
R"|(SELECT "Names".name AS name, "Keys".pubkey AS pubkey FROM "Names" INNER JOIN "Keys" )|"
|
|
||||||
R"|(ON "Names"."ROWID"="Keys".id AND "Keys".use=1 ORDER BY LOWER(name), name COLLATE BINARY;)|"));
|
|
||||||
if (!(*m_read_from_misc)(1) || m_read_from_misc->value<int64_t>() != WALLET_FILE_IDENTIFIER)throw MyException(sz_unrecognizable_wallet_file_format);
|
|
||||||
if (!(*m_read_from_misc)(2) || m_read_from_misc->value<int64_t>() != WALLET_FILE_SCHEMA_VERSION_0_0 || !(*m_read_from_misc)(4))throw MyException(sz_unrecognized_wallet_schema);
|
|
||||||
m_MasterSecret= *(m_read_from_misc->value<ristretto255::scalar>());
|
|
||||||
ILogMessage(std::format("\t\tmaster secret: #{}", ro::base58(m_MasterSecret).operator const char* ()).c_str());
|
ILogMessage(std::format("\t\tmaster secret: #{}", ro::base58(m_MasterSecret).operator const char* ()).c_str());
|
||||||
if(!m_MasterSecret.valid()) throw MyException(sz_cold_wallets_not_yet_implemented, __LINE__, __func__, SrcFilename);
|
if(!m_MasterSecret.valid()) throw MyException(sz_cold_wallets_not_yet_implemented, __LINE__, __func__, SrcFilename);
|
||||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
m_lSizer = new wxBoxSizer(wxVERTICAL);
|
m_lSizer = new wxBoxSizer(wxVERTICAL);
|
||||||
m_rSizer = new wxBoxSizer(wxVERTICAL);
|
m_rSizer = new wxBoxSizer(wxVERTICAL);
|
||||||
sizer->Add(m_lSizer, 0, wxGROW, 4);
|
sizer->Add(m_lSizer, 0, 0, 4);
|
||||||
sizer->Add(m_rSizer, 50, wxGROW, 4);
|
sizer->Add(m_rSizer, 50, 0, 4);
|
||||||
SetSizer(sizer);
|
SetSizer(sizer);
|
||||||
try {
|
refresh_from_database();
|
||||||
while (m_read_names_and_keys->step() == Icompiled_sql::ROW) {
|
|
||||||
std::string name = m_read_names_and_keys->column<const char*>(0);
|
|
||||||
auto pubkey = *(m_read_names_and_keys->column<ristretto255::point>(1));
|
|
||||||
if (m_MasterSecret(name).timesBase() != pubkey)throw MyException(std::string(sz_public_key_of) + name + sz_fails_to_correspond);
|
|
||||||
m_lSizer->Add(
|
|
||||||
new wxStaticText(
|
|
||||||
this,
|
|
||||||
wxID_ANY,
|
|
||||||
name,
|
|
||||||
wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT | wxST_ELLIPSIZE_END
|
|
||||||
),
|
|
||||||
10,
|
|
||||||
wxEXPAND | // make horizontally stretchable
|
|
||||||
wxALL, // and make border all around
|
|
||||||
2);
|
|
||||||
m_rSizer->Add(
|
|
||||||
new wxStaticText(
|
|
||||||
this,
|
|
||||||
wxID_ANY,
|
|
||||||
"#" + base58(pubkey).operator std::string(),
|
|
||||||
wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT | wxST_ELLIPSIZE_END
|
|
||||||
),
|
|
||||||
10,
|
|
||||||
wxEXPAND | // make horizontally stretchable
|
|
||||||
wxALL, // and make border all around
|
|
||||||
2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (const MyException& e) {
|
|
||||||
throw MyException(e, __LINE__, __func__, SrcFilename);
|
|
||||||
// sql exceptions tend to be unintelligible and excessively generic
|
|
||||||
// because unclear what statement provoked them.
|
|
||||||
}
|
|
||||||
catch (const std::exception& e) {
|
|
||||||
throw MyException(e, __LINE__, __func__, SrcFilename);
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
szError = sz_unknown_error;
|
|
||||||
throw MyException(sz_unknown_error, __LINE__, __func__, SrcFilename);
|
|
||||||
}
|
|
||||||
Bind(wxEVT_CLOSE_WINDOW, &display_wallet::OnClose, this);
|
|
||||||
this->SetSize(this->GetParent()->GetClientSize());
|
this->SetSize(this->GetParent()->GetClientSize());
|
||||||
|
Bind(wxEVT_CLOSE_WINDOW, &display_wallet::OnClose, this);
|
||||||
singletonFrame->m_LastUsedWallet.Assign(walletfile);
|
singletonFrame->m_LastUsedWallet.Assign(walletfile);
|
||||||
|
|
||||||
m_DisplayWalletEditMenu.Menu->Append(
|
m_DisplayWalletEditMenu.Menu->Append(
|
||||||
@ -93,8 +50,6 @@ display_wallet::display_wallet(wxWindow* parent, wxFileName& walletfile) :
|
|||||||
szError = sz_unknown_error;
|
szError = sz_unknown_error;
|
||||||
throw MyException(sz_unknown_error, __LINE__, __func__, SrcFilename);
|
throw MyException(sz_unknown_error, __LINE__, __func__, SrcFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
display_wallet::~display_wallet() {
|
display_wallet::~display_wallet() {
|
||||||
@ -104,6 +59,39 @@ void display_wallet::close_menu_event_handler(wxCommandEvent& event) {
|
|||||||
Close(true);
|
Close(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct display_wallet::cleanup {
|
||||||
|
cleanup() = delete;
|
||||||
|
// copy constructor
|
||||||
|
cleanup(const cleanup& a) = delete;
|
||||||
|
// move constructor
|
||||||
|
cleanup(cleanup&& p) = delete;
|
||||||
|
// copy assignment
|
||||||
|
cleanup& operator=(cleanup) = delete;
|
||||||
|
// Move assignment
|
||||||
|
cleanup& operator=(cleanup&&) = delete;
|
||||||
|
display_wallet* m_win;
|
||||||
|
wxSizer* sizer;
|
||||||
|
wxSize dirty_area;
|
||||||
|
cleanup(display_wallet* win) :
|
||||||
|
m_win(win),
|
||||||
|
sizer(win->GetSizer()),
|
||||||
|
dirty_area(sizer->ComputeFittingClientSize(singletonFrame))
|
||||||
|
{
|
||||||
|
assert(sizer);
|
||||||
|
}
|
||||||
|
~cleanup() {
|
||||||
|
auto desired_size = sizer->ComputeFittingClientSize(singletonFrame);
|
||||||
|
dirty_area.IncTo(desired_size);
|
||||||
|
//singletonFrame->SetMinClientSize(desired_size);
|
||||||
|
auto clientSize = singletonFrame->GetClientSize();
|
||||||
|
desired_size.IncTo(clientSize);
|
||||||
|
if (desired_size.GetHeight() > clientSize.GetHeight()
|
||||||
|
|| desired_size.GetWidth() > clientSize.GetWidth()
|
||||||
|
)singletonFrame->SetClientSize(desired_size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void display_wallet::add_name_event_handler(wxCommandEvent& event) {
|
void display_wallet::add_name_event_handler(wxCommandEvent& event) {
|
||||||
wxTextEntryDialog dialog(this,
|
wxTextEntryDialog dialog(this,
|
||||||
R"("A Zooko name has a human readable name,
|
R"("A Zooko name has a human readable name,
|
||||||
@ -114,13 +102,37 @@ and a public key defined by the name and the wallet master secret)",
|
|||||||
if (dialog.ShowModal() == wxID_OK)
|
if (dialog.ShowModal() == wxID_OK)
|
||||||
{
|
{
|
||||||
std::string zookoNickname(dialog.GetValue().ToUTF8());
|
std::string zookoNickname(dialog.GetValue().ToUTF8());
|
||||||
sql_insert_name insert_name(m_db);
|
|
||||||
auto zookoNickname_psz = zookoNickname.c_str();
|
auto zookoNickname_psz = zookoNickname.c_str();
|
||||||
insert_name(
|
auto pubkey = m_MasterSecret(zookoNickname_psz).timesBase();
|
||||||
|
m_insert_name(
|
||||||
zookoNickname_psz,
|
zookoNickname_psz,
|
||||||
m_MasterSecret(zookoNickname_psz).timesBase()
|
pubkey
|
||||||
);
|
);
|
||||||
|
m_find_position.read_one(zookoNickname_psz);
|
||||||
|
auto position = m_find_position.column<int64_t>(0);
|
||||||
|
cleanup cln(this);
|
||||||
|
m_lSizer->Insert(position,
|
||||||
|
new wxStaticText(
|
||||||
|
this,
|
||||||
|
wxID_ANY,
|
||||||
|
zookoNickname_psz,
|
||||||
|
wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT | wxEXPAND | wxFIXED_MINSIZE | wxST_ELLIPSIZE_END
|
||||||
|
),
|
||||||
|
10,
|
||||||
|
wxALL, // and make border all around
|
||||||
|
2);
|
||||||
|
m_rSizer->Insert(position,
|
||||||
|
new wxStaticText(
|
||||||
|
this,
|
||||||
|
wxID_ANY,
|
||||||
|
"#" + base58(pubkey).operator std::string(),
|
||||||
|
wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT | wxEXPAND | wxFIXED_MINSIZE | wxST_ELLIPSIZE_END
|
||||||
|
),
|
||||||
|
10,
|
||||||
|
wxALL, // and make border all around
|
||||||
|
2);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -134,3 +146,47 @@ void display_wallet::OnClose(wxCloseEvent& event) {
|
|||||||
if (singletonFrame->m_panel ==this)singletonFrame->m_panel = nullptr;
|
if (singletonFrame->m_panel ==this)singletonFrame->m_panel = nullptr;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void display_wallet::refresh_from_database() {
|
||||||
|
cleanup cln(this);
|
||||||
|
try {
|
||||||
|
m_read_names_and_keys.reset();
|
||||||
|
while (m_read_names_and_keys.step() == Icompiled_sql::ROW) {
|
||||||
|
std::string name = m_read_names_and_keys.column<const char*>(0);
|
||||||
|
auto pubkey = *(m_read_names_and_keys.column<ristretto255::point>(1));
|
||||||
|
if (m_MasterSecret(name).timesBase() != pubkey)throw MyException(std::string(sz_public_key_of) + name + sz_fails_to_correspond);
|
||||||
|
m_lSizer->Add(
|
||||||
|
new wxStaticText(
|
||||||
|
this,
|
||||||
|
wxID_ANY,
|
||||||
|
name,
|
||||||
|
wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT | wxEXPAND| wxFIXED_MINSIZE| wxST_ELLIPSIZE_END
|
||||||
|
),
|
||||||
|
10,
|
||||||
|
wxALL, // and make border all around
|
||||||
|
2);
|
||||||
|
m_rSizer->Add(
|
||||||
|
new wxStaticText(
|
||||||
|
this,
|
||||||
|
wxID_ANY,
|
||||||
|
"#" + base58(pubkey).operator std::string(),
|
||||||
|
wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT | wxEXPAND | wxFIXED_MINSIZE | wxST_ELLIPSIZE_END
|
||||||
|
),
|
||||||
|
10,
|
||||||
|
wxALL, // and make border all around
|
||||||
|
2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const MyException& e) {
|
||||||
|
throw MyException(e, __LINE__, __func__, SrcFilename);
|
||||||
|
// sql exceptions tend to be unintelligible and excessively generic
|
||||||
|
// because unclear what statement provoked them.
|
||||||
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
throw MyException(e, __LINE__, __func__, SrcFilename);
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
szError = sz_unknown_error;
|
||||||
|
throw MyException(sz_unknown_error, __LINE__, __func__, SrcFilename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,10 +5,14 @@ public:
|
|||||||
display_wallet(wxWindow*, wxFileName&);
|
display_wallet(wxWindow*, wxFileName&);
|
||||||
~display_wallet();
|
~display_wallet();
|
||||||
private:
|
private:
|
||||||
|
struct cleanup;
|
||||||
typedef MenuLink<display_wallet> MenuLink;
|
typedef MenuLink<display_wallet> MenuLink;
|
||||||
std::unique_ptr<ISqlite3> m_db;
|
ro::dbconnect m_db;
|
||||||
std::unique_ptr <sql_read_from_misc> m_read_from_misc;
|
sql_read_from_misc m_read_from_misc;
|
||||||
std::unique_ptr <ro::sql> m_read_names_and_keys;
|
ro::sql m_read_names_and_keys;
|
||||||
|
sql_insert_name m_insert_name;
|
||||||
|
ro::sql m_find_position;
|
||||||
|
|
||||||
ristretto255::CMasterSecret m_MasterSecret;
|
ristretto255::CMasterSecret m_MasterSecret;
|
||||||
wxBoxSizer* m_lSizer;
|
wxBoxSizer* m_lSizer;
|
||||||
wxBoxSizer* m_rSizer;
|
wxBoxSizer* m_rSizer;
|
||||||
@ -16,4 +20,5 @@ private:
|
|||||||
void add_name_event_handler(wxCommandEvent&);
|
void add_name_event_handler(wxCommandEvent&);
|
||||||
void OnClose(wxCloseEvent& event);
|
void OnClose(wxCloseEvent& event);
|
||||||
wxMenuTracker m_DisplayWalletEditMenu;
|
wxMenuTracker m_DisplayWalletEditMenu;
|
||||||
|
void refresh_from_database();
|
||||||
};
|
};
|
||||||
|
@ -10,27 +10,50 @@ wxMenuTracker::wxMenuTracker(const int i) : Menu(new wxMenu), MenuPosition(i) {}
|
|||||||
wxMenu* wxMenuTracker::InitialAndFinal[]{ nullptr, new wxMenu, nullptr };
|
wxMenu* wxMenuTracker::InitialAndFinal[]{ nullptr, new wxMenu, nullptr };
|
||||||
|
|
||||||
void wxMenuTracker::Replace() {
|
void wxMenuTracker::Replace() {
|
||||||
singletonFrame->GetMenuBar()->Replace(
|
auto menuBar = singletonFrame->GetMenuBar();
|
||||||
MenuPosition,
|
if ((menuBar->GetMenu(MenuPosition) != Menu)) {
|
||||||
Menu,
|
menuBar->Replace(
|
||||||
menu_strings[MenuPosition].head
|
MenuPosition,
|
||||||
);
|
Menu,
|
||||||
singletonFrame->GetMenuBar()->EnableTop(MenuPosition, true); //enable edit menu.
|
menu_strings[MenuPosition].head
|
||||||
|
);
|
||||||
|
menuBar->EnableTop(MenuPosition, true); //enable edit menu.
|
||||||
|
}
|
||||||
};
|
};
|
||||||
wxMenuTracker::~wxMenuTracker() {
|
wxMenuTracker::~wxMenuTracker() {
|
||||||
auto menu_bar = singletonFrame->GetMenuBar();
|
auto menuBar = singletonFrame->GetMenuBar();
|
||||||
if (menu_bar->GetMenu(MenuPosition) == Menu) {
|
if (menuBar->GetMenu(MenuPosition) == Menu) {
|
||||||
assert(InitialAndFinal[MenuPosition]);
|
assert(InitialAndFinal[MenuPosition]);
|
||||||
menu_bar->Replace(
|
menuBar->Replace(
|
||||||
MenuPosition,
|
MenuPosition,
|
||||||
InitialAndFinal[MenuPosition],
|
InitialAndFinal[MenuPosition],
|
||||||
menu_strings[MenuPosition].head
|
menu_strings[MenuPosition].head
|
||||||
);
|
);
|
||||||
menu_bar->EnableTop(MenuPosition, false);
|
menuBar->EnableTop(MenuPosition, false);
|
||||||
delete Menu;
|
delete Menu;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void wxMenuTracker::check_dynamic_menus_absent() {
|
||||||
|
if constexpr (debug_mode) {
|
||||||
|
// Check that the values of all replaceable menus
|
||||||
|
// are at their default values as if the window handling them
|
||||||
|
// had just been destroyed and not yet replaced.
|
||||||
|
auto menuBar = singletonFrame->GetMenuBar();
|
||||||
|
for (int i = 0; i < std::size(InitialAndFinal); i++) {
|
||||||
|
assert(
|
||||||
|
!InitialAndFinal[i]
|
||||||
|
||
|
||||||
|
(
|
||||||
|
InitialAndFinal[i] == menuBar->GetMenu(i)
|
||||||
|
&&
|
||||||
|
!menuBar->IsEnabledTop(i)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// frame
|
// frame
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -199,21 +222,10 @@ Frame::Frame(const wxString& wxs)
|
|||||||
SetMenuBar(menuBar);
|
SetMenuBar(menuBar);
|
||||||
menuBar->EnableTop(1, false); //disable edit menu.
|
menuBar->EnableTop(1, false); //disable edit menu.
|
||||||
if constexpr (debug_mode) {
|
if constexpr (debug_mode) {
|
||||||
// Check that the initial values of all replaceable menus
|
wxMenuTracker::check_dynamic_menus_absent();
|
||||||
// are at their default values as if the window handling them
|
// Because the initial values of the dynamic menus are not being deleted by the child windows
|
||||||
// had just been destroyed and not yet replaced.
|
// that own the modified windows, they need to be the same as the final values,
|
||||||
for (int i = 0; i < std::size(wxMenuTracker::InitialAndFinal); i++) {
|
// which is to say, the values in wxMenuTracker::InitialAndFinal[]
|
||||||
assert(
|
|
||||||
!wxMenuTracker::InitialAndFinal[i]
|
|
||||||
||
|
|
||||||
(
|
|
||||||
wxMenuTracker::InitialAndFinal[i] == menuBar->GetMenu(i)
|
|
||||||
&&
|
|
||||||
!menuBar->IsEnabledTop(i)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
CreateStatusBar();
|
CreateStatusBar();
|
||||||
// child controls
|
// child controls
|
||||||
@ -374,17 +386,16 @@ SELECT
|
|||||||
"Keys".pubkey AS pubkey
|
"Keys".pubkey AS pubkey
|
||||||
FROM "Names" INNER JOIN "Keys"
|
FROM "Names" INNER JOIN "Keys"
|
||||||
ON "Names"."ROWID"="Keys"."id" AND "Keys"."use"=1
|
ON "Names"."ROWID"="Keys"."id" AND "Keys"."use"=1
|
||||||
ORDER BY LOWER("name"), "name"
|
ORDER BY LOWER("name"), "name" COLLATE BINARY;
|
||||||
COLLATE BINARY;
|
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
|
||||||
BEGIN IMMEDIATE TRANSACTION;
|
BEGIN IMMEDIATE TRANSACTION;
|
||||||
CREATE TRIGGER InsertUserZookoID INSTEAD OF INSERT ON UserZookoIDs FOR EACH ROW BEGIN
|
CREATE TRIGGER InsertUserZookoID INSTEAD OF INSERT ON UserZookoIDs FOR EACH ROW BEGIN
|
||||||
INSERT OR FAIL INTO "Names" VALUES(
|
INSERT OR ROLLBACK INTO "Names" VALUES(
|
||||||
NULL,
|
NULL,
|
||||||
NEW."name"
|
NEW."name"
|
||||||
);
|
);
|
||||||
INSERT OR FAIL INTO "Keys" VALUES(
|
INSERT OR ROLLBACK INTO "Keys" VALUES(
|
||||||
NULL,
|
NULL,
|
||||||
NEW."pubkey",
|
NEW."pubkey",
|
||||||
last_insert_rowid(),
|
last_insert_rowid(),
|
||||||
@ -555,7 +566,6 @@ void Frame::OnMenuOpen(wxMenuEvent& evt) {
|
|||||||
|
|
||||||
Frame::~Frame() {
|
Frame::~Frame() {
|
||||||
assert(singletonFrame == this);
|
assert(singletonFrame == this);
|
||||||
singletonFrame = nullptr;
|
|
||||||
wxConfigBase& Config = singletonApp->m_Config;
|
wxConfigBase& Config = singletonApp->m_Config;
|
||||||
StorePositionToConfig();
|
StorePositionToConfig();
|
||||||
Config.SetPath(wxT("/TipOfTheDay"));
|
Config.SetPath(wxT("/TipOfTheDay"));
|
||||||
@ -567,21 +577,7 @@ Frame::~Frame() {
|
|||||||
Config.SetPath(wxT("/"));
|
Config.SetPath(wxT("/"));
|
||||||
Config.Flush();
|
Config.Flush();
|
||||||
if constexpr (debug_mode) {
|
if constexpr (debug_mode) {
|
||||||
// Check that the final values of all replaceable menus
|
wxMenuTracker::check_dynamic_menus_absent();
|
||||||
// are at what they should be because the window handling
|
|
||||||
// them should have been destroyed.
|
|
||||||
auto menuBar = this->GetMenuBar();
|
|
||||||
for (int i = 0; i < std::size(wxMenuTracker::InitialAndFinal); i++) {
|
|
||||||
assert(
|
|
||||||
!wxMenuTracker::InitialAndFinal[i]
|
|
||||||
||
|
|
||||||
(
|
|
||||||
wxMenuTracker::InitialAndFinal[i] == menuBar->GetMenu(i)
|
|
||||||
&&
|
|
||||||
!menuBar->IsEnabledTop(i)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
singletonFrame = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ struct wxMenuTracker {
|
|||||||
// the frame initializer. In the debug build, congruence between the menu bar
|
// the frame initializer. In the debug build, congruence between the menu bar
|
||||||
// and InitialAndFinal should be checked with assert.
|
// and InitialAndFinal should be checked with assert.
|
||||||
static wxMenu* InitialAndFinal[3];
|
static wxMenu* InitialAndFinal[3];
|
||||||
|
static void check_dynamic_menus_absent();
|
||||||
wxMenuTracker(wxMenuTracker&&) = delete; // Move constructor
|
wxMenuTracker(wxMenuTracker&&) = delete; // Move constructor
|
||||||
wxMenuTracker(const wxMenuTracker&) = delete; // Copy constructor
|
wxMenuTracker(const wxMenuTracker&) = delete; // Copy constructor
|
||||||
wxMenuTracker& operator=(wxMenuTracker&&) = delete; // Move assignment.
|
wxMenuTracker& operator=(wxMenuTracker&&) = delete; // Move assignment.
|
||||||
|
@ -138,6 +138,7 @@ welcome_to_rhocoin::welcome_to_rhocoin(
|
|||||||
Bind(wxEVT_CLOSE_WINDOW, &welcome_to_rhocoin::OnClose, this);
|
Bind(wxEVT_CLOSE_WINDOW, &welcome_to_rhocoin::OnClose, this);
|
||||||
assert(singletonWelcome == nullptr);
|
assert(singletonWelcome == nullptr);
|
||||||
singletonWelcome = this;
|
singletonWelcome = this;
|
||||||
|
singletonFrame->SetMinClientSize(sizer->ComputeFittingClientSize(singletonFrame));
|
||||||
}
|
}
|
||||||
|
|
||||||
welcome_to_rhocoin::~welcome_to_rhocoin() {
|
welcome_to_rhocoin::~welcome_to_rhocoin() {
|
||||||
|
Loading…
Reference in New Issue
Block a user