From 6ca1a1d6799474f8ca977b93ab630af7ace879c2 Mon Sep 17 00:00:00 2001 From: Victorio Nascimento <155357371+Vic-Nas@users.noreply.github.com> Date: Mon, 27 Jul 2026 16:45:28 -0400 Subject: Add Linux GUI installer via Wine (#3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Linux GUI installer via Wine * Fix launcher creation and add BTF_RELAY env var support * Pool server, Linux GUI, unified binary, README update * Root Makefile: make linux / make windows, cleaner README * Remove headless.cpp * Fix XPM color count mismatch causing toolbar image errors on Linux * XPM icons: same code on Windows and Linux, no ifdefs around image loading * Fix GTK icon crash and Linux printf format * btfrv: 10s socket timeout on relay connects * Faster peer discovery: more dials per pass, shorter backoff and sleep * Parallel btf peer connections * Fix GetMyExternalIP - was disabled, now uses modern IP echo services * Fix tunnel disconnect on idle and restore external IP detection * Filter stale Nostr descriptors * Sort peers by freshness, fresh first * Pool: add .btf Stratum listener — miners connect via rendezvous, no port forwarding needed * btf pool: self-replacing listeners, one per relay, no queuing between miners * Mining modes: solo/operator/participant — pool server on-demand, participant Stratum client * Status bar: show external IP and .btf address * README: clean rewrite, concept-first, minimal * make linux produces AppImage * make linux produces AppImage * Pool dashboard: connect instructions, tabs, share bars * Perf fixes: GetMyExternalIP threaded, btf listener counted * Perf fixes: GetMyExternalIP threaded, btf listener counted * Fix pool payouts: defer until coinbase maturity * Pool: clean mode switching, IP warning * Pool: clean mode switching * Fix gPoolRunning: remove static * AppImage: use real icon from bitcoin.ico * Fix exit crash; Mining menu * Fix exit crash; Mining menu * Fix exit crash; Mining menu * Fix exit crash; Mining menu * Fix exit crash; Mining menu * Windows build: use mingw32-make * Windows build: simpler make invocation * Add deps-windows target * Windows build fixes * Windows build fixes * Windows makefile: fix obj dir * Windows: output to repo root * Windows: bundle DLLs into zip * Replace wxWidgets with ImGui+GLFW: same build on Linux and Windows * Fix %I64d that slipped back through rebase (main.h, net.h) * MinGW: add _mkdir shim for non-MSVC Windows; fix %I64d * Fix gPoolRunning extern outside ifndef _WIN32 * Remove -lboost_system: boost is header-only in this codebase * Status bar: copy buttons for IP and .btf address * Windows: add app icon via windres, strip wx stuff from rc file * Clean GUI: single Options menu item, bigger font, better spacing, cleaner options dialog; update README * GUI: embed Roboto font at 16px for clear readability on all platforms * Windows: windres depends on obj dir target * Fix balance hidden off-screen: put on own line below address bar * Windows: inline mkdir in every rule, remove dir target that confused make * Windows: move all target to top so it's the default rule * Fix pool server not starting: always start when operator selected, re-sync dialog state on open * Write debug.log to data directory (AppData/Roaming/Bitflash on Windows) * Participant miner: use wallet address as username so payouts go to wallet * Add .gitattributes to lock LF line endings, prevent CRLF drift * Refactor pool mining to btf-only transport * Persist pool settings and startup wiring * Prune stale peers and expose pool queries * Fix build regressions and add CLI mode/arg parity * Fix rpc miner stats declaration order * Centralize pool runtime extern declarations * Separate operator/participant dashboards and restore peer stats * Add live telemetry strip and clearer per-mode runtime metrics * Reduce mining dashboard clutter and remove manual pool entry * Count only authorized pool miners * Seed initial pool job on startup * Use a real share target for pool work * Switch pool accounting to round-based shares * Fix nostr pool announcer stats call sites * Fix pool stats definition order * Improve pool worker status display * Add mutex include for participant status * Replace ImClamp in dashboard layout * Clarify participant work status * Log participant status transitions * Reduce peer discovery log noise * Add participant status badge * Track participant auth acknowledgements * Log and validate pool job delivery --------- Co-authored-by: Bitflash Pool Dev --- src/ui.cpp | 3269 ------------------------------------------------------------ 1 file changed, 3269 deletions(-) delete mode 100644 src/ui.cpp (limited to 'src/ui.cpp') diff --git a/src/ui.cpp b/src/ui.cpp deleted file mode 100644 index 311a78e..0000000 --- a/src/ui.cpp +++ /dev/null @@ -1,3269 +0,0 @@ -// Copyright (c) 2009 Satoshi Nakamoto -// Distributed under the MIT/X11 software license, see the accompanying -// file license.txt or http://www.opensource.org/licenses/mit-license.php. - -#include "headers.h" -#ifdef _MSC_VER -#include -#endif - - - -DEFINE_EVENT_TYPE(wxEVT_CROSSTHREADCALL) - -// wx3 is Unicode: conversion bridges for the C functions inherited from 2009 -static inline bool ParseMoney(const wxString& str, int64& nRet) -{ - return ParseMoney(std::string(str.mb_str()).c_str(), nRet); -} -DEFINE_EVENT_TYPE(wxEVT_REPLY1) -DEFINE_EVENT_TYPE(wxEVT_REPLY2) -DEFINE_EVENT_TYPE(wxEVT_REPLY3) -DEFINE_EVENT_TYPE(wxEVT_TABLEADDED) -DEFINE_EVENT_TYPE(wxEVT_TABLEUPDATED) -DEFINE_EVENT_TYPE(wxEVT_TABLEDELETED) - -CMainFrame* pframeMain = NULL; -map mapAddressBook; - - -void ThreadRequestProductDetails(void* parg); -void ThreadRandSendTest(void* parg); -bool fRandSendTest = false; -void RandSend(); - - - - - - -////////////////////////////////////////////////////////////////////////////// -// -// Util -// - -void HandleCtrlA(wxKeyEvent& event) -{ - // Ctrl-a select all - wxTextCtrl* textCtrl = (wxTextCtrl*)event.GetEventObject(); - if (event.GetModifiers() == wxMOD_CONTROL && event.GetKeyCode() == 'A') - textCtrl->SetSelection(-1, -1); - event.Skip(); -} - -bool Is24HourTime() -{ - //char pszHourFormat[256]; - //pszHourFormat[0] = '\0'; - //GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ITIME, pszHourFormat, 256); - //return (pszHourFormat[0] != '0'); - return true; -} - -string DateStr(int64 nTime) -{ - return (string)wxDateTime((time_t)nTime).FormatDate(); -} - -string DateTimeStr(int64 nTime) -{ - wxDateTime datetime((time_t)nTime); - if (Is24HourTime()) - return (string)datetime.Format("%x %H:%M"); - else - return (string)datetime.Format("%x ") + itostr((datetime.GetHour() + 11) % 12 + 1) + (string)datetime.Format(":%M %p"); -} - -wxString GetItemText(wxListCtrl* listCtrl, int nIndex, int nColumn) -{ - // Helper to simplify access to listctrl - wxListItem item; - item.m_itemId = nIndex; - item.m_col = nColumn; - item.m_mask = wxLIST_MASK_TEXT; - if (!listCtrl->GetItem(item)) - return ""; - return item.GetText(); -} - -int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1) -{ - int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0); - listCtrl->SetItem(nIndex, 1, str1); - return nIndex; -} - -int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4) -{ - int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0); - listCtrl->SetItem(nIndex, 1, str1); - listCtrl->SetItem(nIndex, 2, str2); - listCtrl->SetItem(nIndex, 3, str3); - listCtrl->SetItem(nIndex, 4, str4); - return nIndex; -} - -int InsertLine(wxListCtrl* listCtrl, void* pdata, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4) -{ - int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0); - listCtrl->SetItemPtrData(nIndex, (wxUIntPtr)pdata); - listCtrl->SetItem(nIndex, 1, str1); - listCtrl->SetItem(nIndex, 2, str2); - listCtrl->SetItem(nIndex, 3, str3); - listCtrl->SetItem(nIndex, 4, str4); - return nIndex; -} - -void SetSelection(wxListCtrl* listCtrl, int nIndex) -{ - int nSize = listCtrl->GetItemCount(); - long nState = (wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED); - for (int i = 0; i < nSize; i++) - listCtrl->SetItemState(i, (i == nIndex ? nState : 0), nState); -} - -int GetSelection(wxListCtrl* listCtrl) -{ - int nSize = listCtrl->GetItemCount(); - for (int i = 0; i < nSize; i++) - if (listCtrl->GetItemState(i, wxLIST_STATE_FOCUSED)) - return i; - return -1; -} - - -string HtmlEscape(const char* psz, bool fMultiLine=false) -{ - int len = 0; - for (const char* p = psz; *p; p++) - { - if (*p == '<') len += 4; - else if (*p == '>') len += 4; - else if (*p == '&') len += 5; - else if (*p == '"') len += 6; - else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') len += 6; - else if (*p == '\n' && fMultiLine) len += 5; - else - len++; - } - string str; - str.reserve(len); - for (const char* p = psz; *p; p++) - { - if (*p == '<') str += "<"; - else if (*p == '>') str += ">"; - else if (*p == '&') str += "&"; - else if (*p == '"') str += """; - else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') str += " "; - else if (*p == '\n' && fMultiLine) str += "
\n"; - else - str += *p; - } - return str; -} - -string HtmlEscape(const string& str, bool fMultiLine=false) -{ - return HtmlEscape(str.c_str(), fMultiLine); -} - -void AddToMyProducts(CProduct product) -{ - CProduct& productInsert = mapMyProducts[product.GetHash()]; - productInsert = product; - InsertLine(pframeMain->m_listCtrlProductsSent, &productInsert, - product.mapValue["category"], - product.mapValue["title"].substr(0, 100), - product.mapValue["description"].substr(0, 100), - product.mapValue["price"], - ""); -} - - - - - - -////////////////////////////////////////////////////////////////////////////// -// -// Custom events -// - -set setCallbackAvailable; -CCriticalSection cs_setCallbackAvailable; - -void AddCallbackAvailable(void* p) -{ - CRITICAL_BLOCK(cs_setCallbackAvailable) - setCallbackAvailable.insert(p); -} - -void RemoveCallbackAvailable(void* p) -{ - CRITICAL_BLOCK(cs_setCallbackAvailable) - setCallbackAvailable.erase(p); -} - -bool IsCallbackAvailable(void* p) -{ - CRITICAL_BLOCK(cs_setCallbackAvailable) - return setCallbackAvailable.count(p); - return false; -} - -template -void AddPendingCustomEvent(wxEvtHandler* pevthandler, int nEventID, const T pbeginIn, const T pendIn) -{ - if (!pevthandler) - return; - - const char* pbegin = (pendIn != pbeginIn) ? (const char*)&pbeginIn[0] : NULL; - const char* pend = pbegin + (pendIn - pbeginIn) * sizeof(pbeginIn[0]); - wxCommandEvent event(nEventID); - // wxString in wx3 is Unicode and does not carry raw bytes; - // the serialized data travels in a buffer that the receiver frees - event.SetClientData(new std::string(pbegin, pend)); - - pevthandler->AddPendingEvent(event); -} - -template -void AddPendingCustomEvent(wxEvtHandler* pevthandler, int nEventID, const T& obj) -{ - CDataStream ss; - ss << obj; - AddPendingCustomEvent(pevthandler, nEventID, ss.begin(), ss.end()); -} - -void AddPendingReplyEvent1(void* pevthandler, CDataStream& vRecv) -{ - if (IsCallbackAvailable(pevthandler)) - AddPendingCustomEvent((wxEvtHandler*)pevthandler, wxEVT_REPLY1, vRecv.begin(), vRecv.end()); -} - -void AddPendingReplyEvent2(void* pevthandler, CDataStream& vRecv) -{ - if (IsCallbackAvailable(pevthandler)) - AddPendingCustomEvent((wxEvtHandler*)pevthandler, wxEVT_REPLY2, vRecv.begin(), vRecv.end()); -} - -void AddPendingReplyEvent3(void* pevthandler, CDataStream& vRecv) -{ - if (IsCallbackAvailable(pevthandler)) - AddPendingCustomEvent((wxEvtHandler*)pevthandler, wxEVT_REPLY3, vRecv.begin(), vRecv.end()); -} - -CDataStream GetStreamFromEvent(const wxCommandEvent& event) -{ - std::string* pstrData = (std::string*)event.GetClientData(); - if (pstrData == NULL) - return CDataStream(SER_NETWORK); - CDataStream ss(pstrData->data(), pstrData->data() + pstrData->size(), SER_NETWORK); - delete pstrData; - ((wxCommandEvent&)event).SetClientData(NULL); - return ss; -} - - - - - - - -////////////////////////////////////////////////////////////////////////////// -// -// CMainFrame -// - -CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent) -{ - Connect(wxEVT_CROSSTHREADCALL, wxCommandEventHandler(CMainFrame::OnCrossThreadCall), NULL, this); - - // Init - fRefreshListCtrl = false; - fRefreshListCtrlRunning = false; - fOnSetFocusAddress = false; - pindexBestLast = NULL; - m_choiceFilter->SetSelection(0); - m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " "); - m_listCtrl->SetFocus(); - SetIcon(wxICON(bitcoin)); - m_menuOptions->Check(wxID_OPTIONSGENERATEBITCOINS, fGenerateBitcoins); - - // Init toolbar with transparency masked bitmaps - m_toolBar->ClearTools(); - - //// shouldn't have to do mask separately anymore, bitmap alpha support added in wx 2.8.9, - wxBitmap bmpSend(wxT("send20"), wxBITMAP_TYPE_RESOURCE); - bmpSend.SetMask(new wxMask(wxBitmap(wxT("send20mask"), wxBITMAP_TYPE_RESOURCE))); - m_toolBar->AddTool(wxID_BUTTONSEND, wxT("&Send Coins"), bmpSend, wxNullBitmap, wxITEM_NORMAL, wxEmptyString, wxEmptyString); - - wxBitmap bmpAddressBook(wxT("addressbook20"), wxBITMAP_TYPE_RESOURCE); - bmpAddressBook.SetMask(new wxMask(wxBitmap(wxT("addressbook20mask"), wxBITMAP_TYPE_RESOURCE))); - m_toolBar->AddTool(wxID_BUTTONRECEIVE, wxT("&Address Book"), bmpAddressBook, wxNullBitmap, wxITEM_NORMAL, wxEmptyString, wxEmptyString); - - m_toolBar->Realize(); - - // Init column headers - int nDateWidth = DateTimeStr(1229413914).size() * 6 + 8; - m_listCtrl->InsertColumn(0, "", wxLIST_FORMAT_LEFT, 0); - m_listCtrl->InsertColumn(1, "", wxLIST_FORMAT_LEFT, 0); - m_listCtrl->InsertColumn(2, "Status", wxLIST_FORMAT_LEFT, 90); - m_listCtrl->InsertColumn(3, "Date", wxLIST_FORMAT_LEFT, nDateWidth); - m_listCtrl->InsertColumn(4, "Description", wxLIST_FORMAT_LEFT, 409 - nDateWidth); - m_listCtrl->InsertColumn(5, "Debit", wxLIST_FORMAT_RIGHT, 79); - m_listCtrl->InsertColumn(6, "Credit", wxLIST_FORMAT_RIGHT, 79); - - //m_listCtrlProductsSent->InsertColumn(0, "Category", wxLIST_FORMAT_LEFT, 100); - //m_listCtrlProductsSent->InsertColumn(1, "Title", wxLIST_FORMAT_LEFT, 100); - //m_listCtrlProductsSent->InsertColumn(2, "Description", wxLIST_FORMAT_LEFT, 100); - //m_listCtrlProductsSent->InsertColumn(3, "Price", wxLIST_FORMAT_LEFT, 100); - //m_listCtrlProductsSent->InsertColumn(4, "", wxLIST_FORMAT_LEFT, 100); - - //m_listCtrlOrdersSent->InsertColumn(0, "Time", wxLIST_FORMAT_LEFT, 100); - //m_listCtrlOrdersSent->InsertColumn(1, "Price", wxLIST_FORMAT_LEFT, 100); - //m_listCtrlOrdersSent->InsertColumn(2, "", wxLIST_FORMAT_LEFT, 100); - //m_listCtrlOrdersSent->InsertColumn(3, "", wxLIST_FORMAT_LEFT, 100); - //m_listCtrlOrdersSent->InsertColumn(4, "", wxLIST_FORMAT_LEFT, 100); - - //m_listCtrlOrdersReceived->InsertColumn(0, "Time", wxLIST_FORMAT_LEFT, 100); - //m_listCtrlOrdersReceived->InsertColumn(1, "Price", wxLIST_FORMAT_LEFT, 100); - //m_listCtrlOrdersReceived->InsertColumn(2, "Payment Status", wxLIST_FORMAT_LEFT, 100); - //m_listCtrlOrdersReceived->InsertColumn(3, "", wxLIST_FORMAT_LEFT, 100); - //m_listCtrlOrdersReceived->InsertColumn(4, "", wxLIST_FORMAT_LEFT, 100); - - // Init status bar - int pnWidths[3] = { -100, 81, 286 }; - m_statusBar->SetFieldsCount(3, pnWidths); - - // Fill your address text box - vector vchPubKey; - if (CWalletDB("r").ReadDefaultKey(vchPubKey)) - m_textCtrlAddress->SetValue(PubKeyToAddress(vchPubKey)); - - // Fill listctrl with wallet transactions - RefreshListCtrl(); -} - -CMainFrame::~CMainFrame() -{ - pframeMain = NULL; -} - -void Shutdown(void* parg) -{ - static CCriticalSection cs_Shutdown; - CRITICAL_BLOCK(cs_Shutdown) - { - fShutdown = true; - nTransactionsUpdated++; - DBFlush(false); - StopNode(); - DBFlush(true); - - printf("Bitcoin exiting\n"); - exit(0); - } -} - -void CMainFrame::OnClose(wxCloseEvent& event) -{ - Destroy(); - _beginthread(Shutdown, 0, NULL); -} - -void CMainFrame::OnMouseEvents(wxMouseEvent& event) -{ - RandAddSeed(); - RAND_add(&event.m_x, sizeof(event.m_x), 0.25); - RAND_add(&event.m_y, sizeof(event.m_y), 0.25); -} - -void CMainFrame::OnListColBeginDrag(wxListEvent& event) -{ - // Hidden columns not resizeable - if (event.GetColumn() <= 1 && !fDebug) - event.Veto(); -} - -void CMainFrame::InsertLine(bool fNew, int nIndex, uint256 hashKey, string strSort, const wxString& str2, const wxString& str3, const wxString& str4, const wxString& str5, const wxString& str6) -{ - string str0 = strSort; - long nData = *(long*)&hashKey; - - if (fNew) - { - nIndex = m_listCtrl->InsertItem(0, str0); - } - else - { - if (nIndex == -1) - { - // Find item - while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1) - if (GetItemText(m_listCtrl, nIndex, 1) == hashKey.ToString()) - break; - if (nIndex == -1) - { - printf("CMainFrame::InsertLine : Couldn't find item to be updated\n"); - return; - } - } - - // If sort key changed, must delete and reinsert to make it relocate - if (GetItemText(m_listCtrl, nIndex, 0) != str0) - { - m_listCtrl->DeleteItem(nIndex); - nIndex = m_listCtrl->InsertItem(0, str0); - } - } - - m_listCtrl->SetItem(nIndex, 1, hashKey.ToString()); - m_listCtrl->SetItem(nIndex, 2, str2); - m_listCtrl->SetItem(nIndex, 3, str3); - m_listCtrl->SetItem(nIndex, 4, str4); - m_listCtrl->SetItem(nIndex, 5, str5); - m_listCtrl->SetItem(nIndex, 6, str6); - m_listCtrl->SetItemData(nIndex, nData); -} - -string FormatTxStatus(const CWalletTx& wtx) -{ - // Status - int nDepth = wtx.GetDepthInMainChain(); - if (!wtx.IsFinal()) - return strprintf("Open for %d blocks", nBestHeight - wtx.nLockTime); - else if (nDepth < 6) - return strprintf("%d/unconfirmed", nDepth); - else - return strprintf("%d blocks", nDepth); -} - -void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) -{ - int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime(); - int64 nCredit = wtx.GetCredit(); - int64 nDebit = wtx.GetDebit(); - int64 nNet = nCredit - nDebit; - uint256 hash = wtx.GetHash(); - string strStatus = FormatTxStatus(wtx); - map mapValue = wtx.mapValue; - - // Find the block the tx is in - CBlockIndex* pindex = NULL; - map::iterator mi = mapBlockIndex.find(wtx.hashBlock); - if (mi != mapBlockIndex.end()) - pindex = (*mi).second; - - // Sort order, unrecorded transactions sort to the top - string strSort = strprintf("%010d-%01d-%010u", - (pindex ? pindex->nHeight : INT_MAX), - (wtx.IsCoinBase() ? 1 : 0), - wtx.nTimeReceived); - - // Insert line - if (nNet > 0 || wtx.IsCoinBase()) - { - // - // Credit - // - string strDescription; - - if (wtx.IsCoinBase()) - { - // Coinbase - strDescription = "Generated"; - if (nCredit == 0) - { - int64 nUnmatured = 0; - foreach(const CTxOut& txout, wtx.vout) - nUnmatured += txout.GetCredit(); - if (wtx.IsInMainChain()) - strDescription += strprintf(" (%s matures in %d blocks)", FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity()); - else - strDescription += " (not accepted)"; - } - } - else if (!mapValue["from"].empty() || !mapValue["message"].empty()) - { - // Online transaction - if (!mapValue["from"].empty()) - strDescription += "From: " + mapValue["from"]; - if (!mapValue["message"].empty()) - { - if (!strDescription.empty()) - strDescription += " - "; - strDescription += mapValue["message"]; - } - } - else - { - // Offline transaction - foreach(const CTxOut& txout, wtx.vout) - { - if (txout.IsMine()) - { - vector vchPubKey; - if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey)) - { - string strAddress = PubKeyToAddress(vchPubKey); - if (mapAddressBook.count(strAddress)) - { - strDescription += "Received with: "; - if (!mapAddressBook[strAddress].empty()) - strDescription += mapAddressBook[strAddress] + " "; - strDescription += strAddress; - } - } - break; - } - } - } - - string strDescription2; - foreach(int c, strDescription) - if (c >= ' ') - strDescription2 += c; - - InsertLine(fNew, nIndex, hash, strSort, - strStatus, - nTime ? DateTimeStr(nTime) : "", - strDescription2, - "", - FormatMoney(nNet, true)); - } - else - { - bool fAllFromMe = true; - foreach(const CTxIn& txin, wtx.vin) - fAllFromMe = fAllFromMe && txin.IsMine(); - - bool fAllToMe = true; - foreach(const CTxOut& txout, wtx.vout) - fAllToMe = fAllToMe && txout.IsMine(); - - if (fAllFromMe && fAllToMe) - { - // Payment to self - int64 nValue = wtx.vout[0].nValue; - InsertLine(fNew, nIndex, hash, strSort, - strStatus, - nTime ? DateTimeStr(nTime) : "", - "Payment to yourself", - FormatMoney(nNet - nValue, true), - FormatMoney(nValue, true)); - } - else if (fAllFromMe) - { - // - // Debit - // - int64 nTxFee = nDebit - wtx.GetValueOut(); - for (int nOut = 0; nOut < wtx.vout.size(); nOut++) - { - const CTxOut& txout = wtx.vout[nOut]; - if (txout.IsMine()) - continue; - - string strAddress; - if (!mapValue["to"].empty()) - { - // Online transaction - strAddress = mapValue["to"]; - } - else - { - // Offline transaction - uint160 hash160; - if (ExtractHash160(txout.scriptPubKey, hash160)) - strAddress = Hash160ToAddress(hash160); - } - - string strDescription = "To: "; - if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty()) - strDescription += mapAddressBook[strAddress] + " "; - strDescription += strAddress; - if (!mapValue["message"].empty()) - { - if (!strDescription.empty()) - strDescription += " - "; - strDescription += mapValue["message"]; - } - - string strDescription2; - foreach(int c, strDescription) - if (c >= ' ') - strDescription2 += c; - - int64 nValue = txout.nValue; - if (nOut == 0 && nTxFee > 0) - nValue += nTxFee; - - InsertLine(fNew, nIndex, hash, strprintf("%s-%d", strSort.c_str(), nOut), - strStatus, - nTime ? DateTimeStr(nTime) : "", - strDescription2, - FormatMoney(-nValue, true), - ""); - } - } - else - { - // - // Mixed debit transaction, can't break down payees - // - bool fAllMine = true; - foreach(const CTxOut& txout, wtx.vout) - fAllMine = fAllMine && txout.IsMine(); - foreach(const CTxIn& txin, wtx.vin) - fAllMine = fAllMine && txin.IsMine(); - - InsertLine(fNew, nIndex, hash, strSort, - strStatus, - nTime ? DateTimeStr(nTime) : "", - "", - FormatMoney(nNet, true), - ""); - } - } -} - -void CMainFrame::RefreshStatus() -{ - static int nLastTop; - int nTop = m_listCtrl->GetTopItem(); - if (nTop == nLastTop && pindexBestLast == pindexBest) - return; - - TRY_CRITICAL_BLOCK(cs_mapWallet) - { - int nStart = nTop; - int nEnd = min(nStart + 100, m_listCtrl->GetItemCount()); - if (pindexBestLast == pindexBest) - { - if (nStart >= nLastTop && nStart < nLastTop + 100) - nStart = nLastTop + 100; - if (nEnd >= nLastTop && nEnd < nLastTop + 100) - nEnd = nLastTop; - } - nLastTop = nTop; - pindexBestLast = pindexBest; - - for (int nIndex = nStart; nIndex < nEnd; nIndex++) - { - uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1)); - map::iterator mi = mapWallet.find(hash); - if (mi == mapWallet.end()) - { - printf("CMainFrame::RefreshStatus() : tx not found in mapWallet\n"); - continue; - } - const CWalletTx& wtx = (*mi).second; - if (wtx.IsCoinBase() || wtx.GetTxTime() != wtx.nTimeDisplayed) - InsertTransaction(wtx, false, nIndex); - else - m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx)); - } - } -} - -void CMainFrame::RefreshListCtrl() -{ - fRefreshListCtrl = true; - ::wxWakeUpIdle(); -} - -void CMainFrame::OnIdle(wxIdleEvent& event) -{ - if (fRefreshListCtrl) - { - // Collect list of wallet transactions and sort newest first - bool fEntered = false; - vector > vSorted; - TRY_CRITICAL_BLOCK(cs_mapWallet) - { - printf("RefreshListCtrl starting\n"); - fEntered = true; - fRefreshListCtrl = false; - vWalletUpdated.clear(); - - // Do the newest transactions first - vSorted.reserve(mapWallet.size()); - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) - { - const CWalletTx& wtx = (*it).second; - unsigned int nTime = UINT_MAX - wtx.GetTxTime(); - vSorted.push_back(make_pair(nTime, (*it).first)); - } - m_listCtrl->DeleteAllItems(); - } - if (!fEntered) - return; - - sort(vSorted.begin(), vSorted.end()); - - // Fill list control - for (int i = 0; i < vSorted.size();) - { - if (fShutdown) - return; - bool fEntered = false; - TRY_CRITICAL_BLOCK(cs_mapWallet) - { - fEntered = true; - uint256& hash = vSorted[i++].second; - map::iterator mi = mapWallet.find(hash); - if (mi != mapWallet.end()) - InsertTransaction((*mi).second, true); - } - if (!fEntered || i == 100 || i % 500 == 0) - wxYield(); - } - - printf("RefreshListCtrl done\n"); - } - else - { - // Check for time updates - static int64 nLastTime; - if (GetTime() > nLastTime + 30) - { - TRY_CRITICAL_BLOCK(cs_mapWallet) - { - nLastTime = GetTime(); - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) - { - CWalletTx& wtx = (*it).second; - if (wtx.nTimeDisplayed && wtx.nTimeDisplayed != wtx.GetTxTime()) - InsertTransaction(wtx, false); - } - } - } - } -} - -void CMainFrame::OnPaint(wxPaintEvent& event) -{ - event.Skip(); -} - -void CMainFrame::OnPaintListCtrl(wxPaintEvent& event) -{ - // Update listctrl contents - if (!vWalletUpdated.empty()) - { - TRY_CRITICAL_BLOCK(cs_mapWallet) - { - pair item; - foreach(item, vWalletUpdated) - { - bool fNew = item.second; - map::iterator mi = mapWallet.find(item.first); - if (mi != mapWallet.end()) - { - printf("vWalletUpdated: %s %s\n", (*mi).second.GetHash().ToString().substr(0,6).c_str(), fNew ? "new" : ""); - InsertTransaction((*mi).second, fNew); - } - } - m_listCtrl->ScrollList(0, INT_MAX); - vWalletUpdated.clear(); - } - } - - // Update status column of visible items only - RefreshStatus(); - - // Update status bar - string strGen = ""; - if (fGenerateBitcoins) - strGen = " Generating"; - if (fGenerateBitcoins && vNodes.empty()) - strGen = "(not connected)"; - m_statusBar->SetStatusText(strGen, 1); - - string strStatus = strprintf(" %d connections %d blocks %d transactions", vNodes.size(), nBestHeight + 1, m_listCtrl->GetItemCount()); - m_statusBar->SetStatusText(strStatus, 2); - - // Balance total - TRY_CRITICAL_BLOCK(cs_mapWallet) - m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " "); - - m_listCtrl->OnPaint(event); -} - -void CrossThreadCall(wxCommandEvent& event) -{ - if (pframeMain) - pframeMain->GetEventHandler()->AddPendingEvent(event); -} - -void CrossThreadCall(int nID, void* pdata) -{ - wxCommandEvent event; - event.SetInt(nID); - event.SetClientData(pdata); - if (pframeMain) - pframeMain->GetEventHandler()->AddPendingEvent(event); -} - -void CMainFrame::OnCrossThreadCall(wxCommandEvent& event) -{ - void* pdata = event.GetClientData(); - switch (event.GetInt()) - { - case UICALL_ADDORDER: - { - break; - } - - case UICALL_UPDATEORDER: - { - break; - } - } -} - -void CMainFrame::OnMenuFileExit(wxCommandEvent& event) -{ - Close(true); -} - -void CMainFrame::OnMenuOptionsGenerate(wxCommandEvent& event) -{ - fGenerateBitcoins = event.IsChecked(); - nTransactionsUpdated++; - CWalletDB().WriteSetting("fGenerateBitcoins", fGenerateBitcoins); - - if (fGenerateBitcoins) - if (_beginthread(ThreadBitcoinMiner, 0, NULL) == -1) - printf("Error: _beginthread(ThreadBitcoinMiner) failed\n"); - - Refresh(); - Update(); -} - -void CMainFrame::OnMenuOptionsOptions(wxCommandEvent& event) -{ - COptionsDialog dialog(this); - dialog.ShowModal(); -} - -void CMainFrame::OnMenuHelpAbout(wxCommandEvent& event) -{ - CAboutDialog dialog(this); - dialog.ShowModal(); -} - -void CMainFrame::OnButtonSend(wxCommandEvent& event) -{ - /// debug test - if (fRandSendTest) - { - RandSend(); - return; - } - - // Toolbar: Send - CSendDialog dialog(this); - dialog.ShowModal(); -} - -void CMainFrame::OnButtonAddressBook(wxCommandEvent& event) -{ - // Toolbar: Address Book - CAddressBookDialog dialogAddr(this, "", false); - if (dialogAddr.ShowModal() == 2) - { - // Send - CSendDialog dialogSend(this, dialogAddr.GetAddress()); - dialogSend.ShowModal(); - } -} - -void CMainFrame::OnSetFocusAddress(wxFocusEvent& event) -{ - // Automatically select-all when entering window - m_textCtrlAddress->SetSelection(-1, -1); - fOnSetFocusAddress = true; - event.Skip(); -} - -void CMainFrame::OnMouseEventsAddress(wxMouseEvent& event) -{ - if (fOnSetFocusAddress) - m_textCtrlAddress->SetSelection(-1, -1); - fOnSetFocusAddress = false; - event.Skip(); -} - -void CMainFrame::OnButtonCopy(wxCommandEvent& event) -{ - // Copy address box to clipboard - if (wxTheClipboard->Open()) - { - wxTheClipboard->SetData(new wxTextDataObject(m_textCtrlAddress->GetValue())); - wxTheClipboard->Close(); - } -} - -void CMainFrame::OnButtonChange(wxCommandEvent& event) -{ - CYourAddressDialog dialog(this, string(m_textCtrlAddress->GetValue())); - if (!dialog.ShowModal()) - return; - string strAddress = (string)dialog.GetAddress(); - if (strAddress != m_textCtrlAddress->GetValue()) - { - uint160 hash160; - if (!AddressToHash160(strAddress, hash160)) - return; - if (!mapPubKeys.count(hash160)) - return; - CWalletDB().WriteDefaultKey(mapPubKeys[hash160]); - m_textCtrlAddress->SetValue(strAddress); - } -} - -void CMainFrame::OnListItemActivatedAllTransactions(wxListEvent& event) -{ - uint256 hash((string)GetItemText(m_listCtrl, event.GetIndex(), 1)); - CWalletTx wtx; - CRITICAL_BLOCK(cs_mapWallet) - { - map::iterator mi = mapWallet.find(hash); - if (mi == mapWallet.end()) - { - printf("CMainFrame::OnListItemActivatedAllTransactions() : tx not found in mapWallet\n"); - return; - } - wtx = (*mi).second; - } - CTxDetailsDialog dialog(this, wtx); - dialog.ShowModal(); - //CTxDetailsDialog* pdialog = new CTxDetailsDialog(this, wtx); - //pdialog->Show(); -} - -void CMainFrame::OnListItemActivatedProductsSent(wxListEvent& event) -{ - CProduct& product = *(CProduct*)event.GetItem().GetData(); - CEditProductDialog* pdialog = new CEditProductDialog(this); - pdialog->SetProduct(product); - pdialog->Show(); -} - -void CMainFrame::OnListItemActivatedOrdersSent(wxListEvent& event) -{ - CWalletTx& order = *(CWalletTx*)event.GetItem().GetData(); - CViewOrderDialog* pdialog = new CViewOrderDialog(this, order, false); - pdialog->Show(); -} - -void CMainFrame::OnListItemActivatedOrdersReceived(wxListEvent& event) -{ - CWalletTx& order = *(CWalletTx*)event.GetItem().GetData(); - CViewOrderDialog* pdialog = new CViewOrderDialog(this, order, true); - pdialog->Show(); -} - - - - - - - -////////////////////////////////////////////////////////////////////////////// -// -// CTxDetailsDialog -// - -CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetailsDialogBase(parent) -{ - string strHTML; - strHTML.reserve(4000); - - int64 nTime = wtx.GetTxTime(); - int64 nCredit = wtx.GetCredit(); - int64 nDebit = wtx.GetDebit(); - int64 nNet = nCredit - nDebit; - - - - - strHTML += "Status: " + FormatTxStatus(wtx) + "
"; - strHTML += "Date: " + (nTime ? DateTimeStr(nTime) : "") + "
"; - - - // - // From - // - if (wtx.IsCoinBase()) - { - strHTML += "Source: Generated
"; - } - else if (!wtx.mapValue["from"].empty()) - { - // Online transaction - if (!wtx.mapValue["from"].empty()) - strHTML += "From: " + HtmlEscape(wtx.mapValue["from"]) + "
"; - } - else - { - // Offline transaction - foreach(const CTxOut& txout, wtx.vout) - { - if (txout.IsMine()) - { - vector vchPubKey; - if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey)) - { - string strAddress = PubKeyToAddress(vchPubKey); - if (mapAddressBook.count(strAddress)) - { - strHTML += "Received with: "; - if (!mapAddressBook[strAddress].empty()) - strHTML += mapAddressBook[strAddress] + " "; - strHTML += HtmlEscape(strAddress); - strHTML += "
"; - } - } - break; - } - } - } - - - // - // To - // - string strAddress; - if (!wtx.mapValue["to"].empty()) - { - // Online transaction - strAddress = wtx.mapValue["to"]; - strHTML += "To: "; - if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty()) - strHTML += mapAddressBook[strAddress] + " "; - strHTML += HtmlEscape(strAddress) + "
"; - } - - - // - // Amount - // - if (wtx.IsCoinBase() && nCredit == 0) - { - // - // Coinbase - // - int64 nUnmatured = 0; - foreach(const CTxOut& txout, wtx.vout) - nUnmatured += txout.GetCredit(); - if (wtx.IsInMainChain()) - strHTML += strprintf("Credit: (%s matures in %d blocks)
", FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity()); - else - strHTML += "Credit: (not accepted)
"; - } - else if (nNet > 0) - { - // - // Credit - // - strHTML += "Credit: " + FormatMoney(nNet) + "
"; - } - else - { - bool fAllFromMe = true; - foreach(const CTxIn& txin, wtx.vin) - fAllFromMe = fAllFromMe && txin.IsMine(); - - bool fAllToMe = true; - foreach(const CTxOut& txout, wtx.vout) - fAllToMe = fAllToMe && txout.IsMine(); - - if (fAllFromMe) - { - // - // Debit - // - foreach(const CTxOut& txout, wtx.vout) - { - if (txout.IsMine()) - continue; - - string strAddress; - if (!wtx.mapValue["to"].empty()) - { - // Online transaction - strAddress = wtx.mapValue["to"]; - } - else - { - // Offline transaction - uint160 hash160; - if (ExtractHash160(txout.scriptPubKey, hash160)) - strAddress = Hash160ToAddress(hash160); - } - - strHTML += "Debit: " + FormatMoney(-txout.nValue) + "    "; - strHTML += "(to "; - if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty()) - strHTML += mapAddressBook[strAddress] + " "; - strHTML += strAddress; - strHTML += ")
"; - } - - if (fAllToMe) - { - // Payment to self - int64 nValue = wtx.vout[0].nValue; - strHTML += "Debit: " + FormatMoney(-nValue) + "
"; - strHTML += "Credit: " + FormatMoney(nValue) + "
"; - } - - int64 nTxFee = nDebit - wtx.GetValueOut(); - if (nTxFee > 0) - strHTML += "Transaction fee: " + FormatMoney(-nTxFee) + "
"; - } - else - { - // - // Mixed debit transaction - // - foreach(const CTxIn& txin, wtx.vin) - if (txin.IsMine()) - strHTML += "Debit: " + FormatMoney(-txin.GetDebit()) + "
"; - foreach(const CTxOut& txout, wtx.vout) - if (txout.IsMine()) - strHTML += "Credit: " + FormatMoney(txout.GetCredit()) + "
"; - } - } - - strHTML += "Net amount: " + FormatMoney(nNet, true) + "
"; - - - // - // Message - // - if (!wtx.mapValue["message"].empty()) - strHTML += "
Message:
" + HtmlEscape(wtx.mapValue["message"], true) + "
"; - - - // - // Debug view - // - if (fDebug) - { - strHTML += "

debug print

"; - foreach(const CTxIn& txin, wtx.vin) - if (txin.IsMine()) - strHTML += "Debit: " + FormatMoney(-txin.GetDebit()) + "
"; - foreach(const CTxOut& txout, wtx.vout) - if (txout.IsMine()) - strHTML += "Credit: " + FormatMoney(txout.GetCredit()) + "
"; - - strHTML += "Inputs:
"; - CRITICAL_BLOCK(cs_mapWallet) - { - foreach(const CTxIn& txin, wtx.vin) - { - COutPoint prevout = txin.prevout; - map::iterator mi = mapWallet.find(prevout.hash); - if (mi != mapWallet.end()) - { - const CWalletTx& prev = (*mi).second; - if (prevout.n < prev.vout.size()) - { - strHTML += HtmlEscape(prev.ToString(), true); - strHTML += "    " + FormatTxStatus(prev) + ", "; - strHTML = strHTML + "IsMine=" + (prev.vout[prevout.n].IsMine() ? "true" : "false") + "
"; - } - } - } - } - - strHTML += "


Transaction:
"; - strHTML += HtmlEscape(wtx.ToString(), true); - } - - - string(strHTML.begin(), strHTML.end()).swap(strHTML); - m_htmlWin->SetPage(strHTML); - m_buttonOK->SetFocus(); -} - -void CTxDetailsDialog::OnButtonOK(wxCommandEvent& event) -{ - EndModal(true); // wx3: modal dialogs must EndModal, not Close() - //Destroy(); -} - - - - - -////////////////////////////////////////////////////////////////////////////// -// -// COptionsDialog -// - -COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent) -{ - m_textCtrlTransactionFee->SetValue(FormatMoney(nTransactionFee)); - m_buttonOK->SetFocus(); -} - -void COptionsDialog::OnKillFocusTransactionFee(wxFocusEvent& event) -{ - int64 nTmp = nTransactionFee; - ParseMoney(m_textCtrlTransactionFee->GetValue(), nTmp); - m_textCtrlTransactionFee->SetValue(FormatMoney(nTmp)); -} - -void COptionsDialog::OnButtonOK(wxCommandEvent& event) -{ - // nTransactionFee - int64 nPrevTransactionFee = nTransactionFee; - if (ParseMoney(m_textCtrlTransactionFee->GetValue(), nTransactionFee) && nTransactionFee != nPrevTransactionFee) - CWalletDB().WriteSetting("nTransactionFee", nTransactionFee); - - EndModal(true); // wx3: modal dialogs must EndModal, not Close() -} - -void COptionsDialog::OnButtonCancel(wxCommandEvent& event) -{ - EndModal(false); // wx3: modal dialogs must EndModal, not Close() -} - - - - - - -////////////////////////////////////////////////////////////////////////////// -// -// CAboutDialog -// - -CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent) -{ - m_staticTextVersion->SetLabel(strprintf("version 0.%d.%d Alpha", VERSION/100, VERSION%100)); - - // (wx3 is natively Unicode; the wx2.8 UTF-8 workaround is no longer needed) -} - -void CAboutDialog::OnButtonOK(wxCommandEvent& event) -{ - EndModal(true); // wx3: modal dialogs must EndModal, not Close() -} - - - - - - -////////////////////////////////////////////////////////////////////////////// -// -// CSendDialog -// - -CSendDialog::CSendDialog(wxWindow* parent, const wxString& strAddress) : CSendDialogBase(parent) -{ - // Init - m_textCtrlAddress->SetValue(strAddress); - m_choiceTransferType->SetSelection(0); - m_bitmapCheckMark->Show(false); - //// todo: should add a display of your balance for convenience - - // Set Icon - wxBitmap bmpSend(wxT("send16"), wxBITMAP_TYPE_RESOURCE); - bmpSend.SetMask(new wxMask(wxBitmap(wxT("send16masknoshadow"), wxBITMAP_TYPE_RESOURCE))); - wxIcon iconSend; - iconSend.CopyFromBitmap(bmpSend); - SetIcon(iconSend); - - wxCommandEvent event; - OnTextAddress(event); - - // Fixup the tab order - m_buttonPaste->MoveAfterInTabOrder(m_buttonCancel); - m_buttonAddress->MoveAfterInTabOrder(m_buttonPaste); - this->Layout(); -} - -void CSendDialog::OnTextAddress(wxCommandEvent& event) -{ - // Check mark - bool fBitcoinAddress = IsValidBitcoinAddress(m_textCtrlAddress->GetValue()); - m_bitmapCheckMark->Show(fBitcoinAddress); - - // Grey out message if bitcoin address - bool fEnable = !fBitcoinAddress; - m_staticTextFrom->Enable(fEnable); - m_textCtrlFrom->Enable(fEnable); - m_staticTextMessage->Enable(fEnable); - m_textCtrlMessage->Enable(fEnable); - m_textCtrlMessage->SetBackgroundColour(wxSystemSettings::GetColour(fEnable ? wxSYS_COLOUR_WINDOW : wxSYS_COLOUR_BTNFACE)); -} - -void CSendDialog::OnKillFocusAmount(wxFocusEvent& event) -{ - // Reformat the amount - if (m_textCtrlAmount->GetValue().Trim().empty()) - return; - int64 nTmp; - if (ParseMoney(m_textCtrlAmount->GetValue(), nTmp)) - m_textCtrlAmount->SetValue(FormatMoney(nTmp)); -} - -void CSendDialog::OnButtonAddressBook(wxCommandEvent& event) -{ - // Open address book - CAddressBookDialog dialog(this, m_textCtrlAddress->GetValue(), true); - if (dialog.ShowModal()) - m_textCtrlAddress->SetValue(dialog.GetAddress()); -} - -void CSendDialog::OnButtonPaste(wxCommandEvent& event) -{ - // Copy clipboard to address box - if (wxTheClipboard->Open()) - { - if (wxTheClipboard->IsSupported(wxDF_TEXT)) - { - wxTextDataObject data; - wxTheClipboard->GetData(data); - m_textCtrlAddress->SetValue(data.GetText()); - } - wxTheClipboard->Close(); - } -} - -void CSendDialog::OnButtonSend(wxCommandEvent& event) -{ - CWalletTx wtx; - string strAddress = (string)m_textCtrlAddress->GetValue(); - - // Parse amount - int64 nValue = 0; - if (!ParseMoney(m_textCtrlAmount->GetValue(), nValue) || nValue <= 0) - { - wxMessageBox("Error in amount "); - return; - } - if (nValue > GetBalance()) - { - wxMessageBox("Amount exceeds your balance "); - return; - } - if (nValue + nTransactionFee > GetBalance()) - { - wxMessageBox(string("Total exceeds your balance when the ") + FormatMoney(nTransactionFee) + " transaction fee is included "); - return; - } - - // Parse bitcoin address - uint160 hash160; - bool fBitcoinAddress = AddressToHash160(strAddress, hash160); - - if (fBitcoinAddress) - { - // Send to bitcoin address - CScript scriptPubKey; - scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG; - - if (!SendMoney(scriptPubKey, nValue, wtx)) - return; - - wxMessageBox("Payment sent ", "Sending..."); - } - else - { - // Parse IP address - CAddress addr(strAddress.c_str()); - if (addr.ip == 0) - { - wxMessageBox("Invalid address "); - return; - } - - // Message - wtx.mapValue["to"] = strAddress; - wtx.mapValue["from"] = m_textCtrlFrom->GetValue(); - wtx.mapValue["message"] = m_textCtrlMessage->GetValue(); - - // Send to IP address - CSendingDialog* pdialog = new CSendingDialog(this, addr, nValue, wtx); - if (!pdialog->ShowModal()) - return; - } - - if (!mapAddressBook.count(strAddress)) - SetAddressBookName(strAddress, ""); - - EndModal(true); -} - -void CSendDialog::OnButtonCancel(wxCommandEvent& event) -{ - // Cancel - EndModal(false); -} - - - - - - -////////////////////////////////////////////////////////////////////////////// -// -// CSendingDialog -// - -CSendingDialog::CSendingDialog(wxWindow* parent, const CAddress& addrIn, int64 nPriceIn, const CWalletTx& wtxIn) : CSendingDialogBase(NULL) // we have to give null so parent can't destroy us -{ - addr = addrIn; - nPrice = nPriceIn; - wtx = wtxIn; - start = wxDateTime::UNow(); - strStatus = ""; - fCanCancel = true; - fAbort = false; - fSuccess = false; - fUIDone = false; - fWorkDone = false; - - SetTitle(strprintf("Sending %s to %s...", FormatMoney(nPrice).c_str(), wtx.mapValue["to"].c_str())); - m_textCtrlStatus->SetValue(""); - - _beginthread(SendingDialogStartTransfer, 0, this); -} - -CSendingDialog::~CSendingDialog() -{ - printf("~CSendingDialog()\n"); -} - -void CSendingDialog::Close() -{ - // Last one out turn out the lights. - // fWorkDone signals that work side is done and UI thread should call destroy. - // fUIDone signals that UI window has closed and work thread should call destroy. - // This allows the window to disappear and end modality when cancelled - // without making the user wait for ConnectNode to return. The dialog object - // hangs around in the background until the work thread exits. - if (IsModal()) - EndModal(fSuccess); - else - Show(false); - if (fWorkDone) - Destroy(); - else - fUIDone = true; -} - -void CSendingDialog::OnClose(wxCloseEvent& event) -{ - if (!event.CanVeto() || fWorkDone || fAbort || !fCanCancel) - { - Close(); - } - else - { - event.Veto(); - wxCommandEvent cmdevent; - OnButtonCancel(cmdevent); - } -} - -void CSendingDialog::OnButtonOK(wxCommandEvent& event) -{ - if (fWorkDone) - Close(); -} - -void CSendingDialog::OnButtonCancel(wxCommandEvent& event) -{ - if (fCanCancel) - fAbort = true; -} - -void CSendingDialog::OnPaint(wxPaintEvent& event) -{ - if (strStatus.size() > 130) - m_textCtrlStatus->SetValue(string("\n") + strStatus); - else - m_textCtrlStatus->SetValue(string("\n\n") + strStatus); - m_staticTextSending->SetFocus(); - if (!fCanCancel) - m_buttonCancel->Enable(false); - if (fWorkDone) - { - m_buttonOK->Enable(true); - m_buttonOK->SetFocus(); - m_buttonCancel->Enable(false); - } - if (fAbort && fCanCancel && IsShown()) - { - strStatus = "CANCELLED"; - m_buttonOK->Enable(true); - m_buttonOK->SetFocus(); - m_buttonCancel->Enable(false); - m_buttonCancel->SetLabel("Cancelled"); - Close(); - wxMessageBox("Transfer cancelled ", "Sending...", wxOK, this); - } - event.Skip(); - - /// debug test - if (fRandSendTest && fWorkDone && fSuccess) - { - Close(); - Sleep(1000); - RandSend(); - } -} - - -// -// Everything from here on is not in the UI thread and must only communicate -// with the rest of the dialog through variables and calling repaint. -// - -void CSendingDialog::Repaint() -{ - // Called from worker threads: repaint only on the GUI thread - if (wxTheApp) - wxTheApp->CallAfter([this] { Refresh(); }); -} - -bool CSendingDialog::Status() -{ - if (fUIDone) - { - Destroy(); - return false; - } - if (fAbort && fCanCancel) - { - strStatus = "CANCELLED"; - Repaint(); - fWorkDone = true; - return false; - } - return true; -} - -bool CSendingDialog::Status(const string& str) -{ - if (!Status()) - return false; - strStatus = str; - Repaint(); - return true; -} - -bool CSendingDialog::Error(const string& str) -{ - fCanCancel = false; - fWorkDone = true; - Status(string("Error: ") + str); - return false; -} - -void SendingDialogStartTransfer(void* parg) -{ - ((CSendingDialog*)parg)->StartTransfer(); -} - -void CSendingDialog::StartTransfer() -{ - // Make sure we have enough money - if (nPrice + nTransactionFee > GetBalance()) - { - Error("You don't have enough money"); - return; - } - - // We may have connected already for product details - if (!Status("Connecting...")) - return; - CNode* pnode = ConnectNode(addr, 5 * 60); - if (!pnode) - { - Error("Unable to connect"); - return; - } - - // Send order to seller, with response going to OnReply2 via event handler - if (!Status("Requesting public key...")) - return; - pnode->PushRequest("checkorder", wtx, SendingDialogOnReply2, this); -} - -void SendingDialogOnReply2(void* parg, CDataStream& vRecv) -{ - ((CSendingDialog*)parg)->OnReply2(vRecv); -} - -void CSendingDialog::OnReply2(CDataStream& vRecv) -{ - if (!Status("Received public key...")) - return; - - CScript scriptPubKey; - int nRet; - try - { - vRecv >> nRet; - if (nRet > 0) - { - string strMessage; - vRecv >> strMessage; - Error("Transfer was not accepted"); - //// todo: enlarge the window and enable a hidden white box to put seller's message - return; - } - vRecv >> scriptPubKey; - } - catch (...) - { - //// what do we want to do about this? - Error("Invalid response received"); - return; - } - - // Should already be connected - CNode* pnode = ConnectNode(addr, 5 * 60); - if (!pnode) - { - Error("Lost connection"); - return; - } - - // Pause to give the user a chance to cancel - while (wxDateTime::UNow() < start + wxTimeSpan(0, 0, 0, 2 * 1000)) - { - Sleep(200); - if (!Status()) - return; - } - - CRITICAL_BLOCK(cs_main) - { - // Pay - if (!Status("Creating transaction...")) - return; - if (nPrice + nTransactionFee > GetBalance()) - { - Error("You don't have enough money"); - return; - } - int64 nFeeRequired; - if (!CreateTransaction(scriptPubKey, nPrice, wtx, nFeeRequired)) - { - if (nPrice + nFeeRequired > GetBalance()) - Error(strprintf("This is an oversized transaction that requires a transaction fee of %s", FormatMoney(nFeeRequired).c_str())); - else - Error("Transaction creation failed"); - return; - } - - // Last chance to cancel - Sleep(50); - if (!Status()) - return; - fCanCancel = false; - if (fAbort) - { - fCanCancel = true; - if (!Status()) - return; - fCanCancel = false; - } - if (!Status("Sending payment...")) - return; - - // Commit - if (!CommitTransactionSpent(wtx)) - { - Error("Error finalizing payment"); - return; - } - - // Send payment tx to seller, with response going to OnReply3 via event handler - pnode->PushRequest("submitorder", wtx, SendingDialogOnReply3, this); - - // Accept and broadcast transaction - if (!wtx.AcceptTransaction()) - printf("ERROR: CSendingDialog : wtxNew.AcceptTransaction() %s failed\n", wtx.GetHash().ToString().c_str()); - wtx.RelayWalletTransaction(); - - Status("Waiting for confirmation..."); - MainFrameRepaint(); - } -} - -void SendingDialogOnReply3(void* parg, CDataStream& vRecv) -{ - ((CSendingDialog*)parg)->OnReply3(vRecv); -} - -void CSendingDialog::OnReply3(CDataStream& vRecv) -{ - int nRet; - try - { - vRecv >> nRet; - if (nRet > 0) - { - Error("The payment was sent, but the recipient was unable to verify it.\n" - "The transaction is recorded and will credit to the recipient if it is valid,\n" - "but without comment information."); - return; - } - } - catch (...) - { - //// what do we want to do about this? - Error("Payment was sent, but an invalid response was received"); - return; - } - - fSuccess = true; - fWorkDone = true; - Status("Payment completed"); -} - - - - - - -////////////////////////////////////////////////////////////////////////////// -// -// CYourAddressDialog -// - -CYourAddressDialog::CYourAddressDialog(wxWindow* parent, const string& strInitSelected) : CYourAddressDialogBase(parent) -{ - // Init column headers - m_listCtrl->InsertColumn(0, "Name", wxLIST_FORMAT_LEFT, 200); - m_listCtrl->InsertColumn(1, "Bitflash Address", wxLIST_FORMAT_LEFT, 350); - m_listCtrl->SetFocus(); - - // Fill listctrl with address book data - CRITICAL_BLOCK(cs_mapKeys) - { - foreach(const PAIRTYPE(string, string)& item, mapAddressBook) - { - string strAddress = item.first; - string strName = item.second; - uint160 hash160; - bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160)); - if (fMine) - { - int nIndex = InsertLine(m_listCtrl, strName, strAddress); - if (strAddress == strInitSelected) - m_listCtrl->SetItemState(nIndex, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED); - } - } - } -} - -wxString CYourAddressDialog::GetAddress() -{ - int nIndex = GetSelection(m_listCtrl); - if (nIndex == -1) - return ""; - return GetItemText(m_listCtrl, nIndex, 1); -} - -void CYourAddressDialog::OnListEndLabelEdit(wxListEvent& event) -{ - // Update address book with edited name - if (event.IsEditCancelled()) - return; - string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1); - SetAddressBookName(strAddress, string(event.GetText())); - pframeMain->RefreshListCtrl(); -} - -void CYourAddressDialog::OnListItemSelected(wxListEvent& event) -{ -} - -void CYourAddressDialog::OnListItemActivated(wxListEvent& event) -{ - // Doubleclick returns selection - EndModal(true); -} - -void CYourAddressDialog::OnButtonRename(wxCommandEvent& event) -{ - // Ask new name - int nIndex = GetSelection(m_listCtrl); - if (nIndex == -1) - return; - string strName = (string)m_listCtrl->GetItemText(nIndex); - string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1); - CGetTextFromUserDialog dialog(this, "Rename Bitflash Address", "New Name", strName); - if (!dialog.ShowModal()) - return; - strName = dialog.GetValue(); - - // Change name - SetAddressBookName(strAddress, strName); - m_listCtrl->SetItemText(nIndex, strName); - pframeMain->RefreshListCtrl(); -} - -void CYourAddressDialog::OnButtonNew(wxCommandEvent& event) -{ - // Ask name - CGetTextFromUserDialog dialog(this, "New Bitflash Address", "Name", ""); - if (!dialog.ShowModal()) - return; - string strName = dialog.GetValue(); - - // Generate new key - string strAddress = PubKeyToAddress(GenerateNewKey()); - SetAddressBookName(strAddress, strName); - - // Add to list and select it - int nIndex = InsertLine(m_listCtrl, strName, strAddress); - SetSelection(m_listCtrl, nIndex); - m_listCtrl->SetFocus(); -} - -void CYourAddressDialog::OnButtonCopy(wxCommandEvent& event) -{ - // Copy address box to clipboard - if (wxTheClipboard->Open()) - { - wxTheClipboard->SetData(new wxTextDataObject(GetAddress())); - wxTheClipboard->Close(); - } -} - -void CYourAddressDialog::OnButtonOK(wxCommandEvent& event) -{ - // OK - EndModal(true); -} - -void CYourAddressDialog::OnButtonCancel(wxCommandEvent& event) -{ - // Cancel - EndModal(false); -} - -void CYourAddressDialog::OnClose(wxCloseEvent& event) -{ - // Close - EndModal(false); -} - - - - - - -////////////////////////////////////////////////////////////////////////////// -// -// CAddressBookDialog -// - -CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInitSelected, bool fSendingIn) : CAddressBookDialogBase(parent) -{ - fSending = fSendingIn; - if (!fSending) - m_buttonCancel->Show(false); - - // Init column headers - m_listCtrl->InsertColumn(0, "Name", wxLIST_FORMAT_LEFT, 200); - m_listCtrl->InsertColumn(1, "Address", wxLIST_FORMAT_LEFT, 350); - m_listCtrl->SetFocus(); - - // Set Icon - wxBitmap bmpAddressBook(wxT("addressbook16"), wxBITMAP_TYPE_RESOURCE); - bmpAddressBook.SetMask(new wxMask(wxBitmap(wxT("addressbook16mask"), wxBITMAP_TYPE_RESOURCE))); - wxIcon iconAddressBook; - iconAddressBook.CopyFromBitmap(bmpAddressBook); - SetIcon(iconAddressBook); - - // Fill listctrl with address book data - CRITICAL_BLOCK(cs_mapKeys) - { - foreach(const PAIRTYPE(string, string)& item, mapAddressBook) - { - string strAddress = item.first; - string strName = item.second; - uint160 hash160; - bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160)); - if (!fMine) - { - int nIndex = InsertLine(m_listCtrl, strName, strAddress); - if (strAddress == strInitSelected) - m_listCtrl->SetItemState(nIndex, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED); - } - } - } -} - -wxString CAddressBookDialog::GetAddress() -{ - int nIndex = GetSelection(m_listCtrl); - if (nIndex == -1) - return ""; - return GetItemText(m_listCtrl, nIndex, 1); -} - -void CAddressBookDialog::OnListEndLabelEdit(wxListEvent& event) -{ - // Update address book with edited name - if (event.IsEditCancelled()) - return; - string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1); - SetAddressBookName(strAddress, string(event.GetText())); - pframeMain->RefreshListCtrl(); -} - -void CAddressBookDialog::OnListItemSelected(wxListEvent& event) -{ -} - -void CAddressBookDialog::OnListItemActivated(wxListEvent& event) -{ - if (fSending) - { - // Doubleclick returns selection - EndModal(GetAddress() != "" ? 2 : 0); - } - else - { - // Doubleclick edits item - wxCommandEvent event; - OnButtonEdit(event); - } -} - -void CAddressBookDialog::OnButtonEdit(wxCommandEvent& event) -{ - // Ask new name - int nIndex = GetSelection(m_listCtrl); - if (nIndex == -1) - return; - string strName = (string)m_listCtrl->GetItemText(nIndex); - string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1); - string strAddressOrg = strAddress; - CGetTextFromUserDialog dialog(this, "Edit Address", "Name", strName, "Address", strAddress); - if (!dialog.ShowModal()) - return; - strName = dialog.GetValue1(); - strAddress = dialog.GetValue2(); - - // Change name - if (strAddress != strAddressOrg) - CWalletDB().EraseName(strAddressOrg); - SetAddressBookName(strAddress, strName); - m_listCtrl->SetItem(nIndex, 1, strAddress); - m_listCtrl->SetItemText(nIndex, strName); - pframeMain->RefreshListCtrl(); -} - -void CAddressBookDialog::OnButtonNew(wxCommandEvent& event) -{ - // Ask name - CGetTextFromUserDialog dialog(this, "New Address", "Name", "", "Address", ""); - if (!dialog.ShowModal()) - return; - string strName = dialog.GetValue1(); - string strAddress = dialog.GetValue2(); - - // Add to list and select it - SetAddressBookName(strAddress, strName); - int nIndex = InsertLine(m_listCtrl, strName, strAddress); - SetSelection(m_listCtrl, nIndex); - m_listCtrl->SetFocus(); -} - -void CAddressBookDialog::OnButtonDelete(wxCommandEvent& event) -{ - for (int nIndex = m_listCtrl->GetItemCount()-1; nIndex >= 0; nIndex--) - { - if (m_listCtrl->GetItemState(nIndex, wxLIST_STATE_SELECTED)) - { - string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1); - CWalletDB().EraseName(strAddress); - m_listCtrl->DeleteItem(nIndex); - } - } - pframeMain->RefreshListCtrl(); -} - -void CAddressBookDialog::OnButtonCopy(wxCommandEvent& event) -{ - // Copy address box to clipboard - if (wxTheClipboard->Open()) - { - wxTheClipboard->SetData(new wxTextDataObject(GetAddress())); - wxTheClipboard->Close(); - } -} - -void CAddressBookDialog::OnButtonOK(wxCommandEvent& event) -{ - // OK - EndModal(GetAddress() != "" ? 1 : 0); -} - -void CAddressBookDialog::OnButtonCancel(wxCommandEvent& event) -{ - // Cancel - EndModal(0); -} - -void CAddressBookDialog::OnClose(wxCloseEvent& event) -{ - // Close - EndModal(0); -} - - - - - - -////////////////////////////////////////////////////////////////////////////// -// -// CProductsDialog -// - -bool CompareIntStringPairBestFirst(const pair& item1, const pair& item2) -{ - return (item1.first > item2.first); -} - -CProductsDialog::CProductsDialog(wxWindow* parent) : CProductsDialogBase(parent) -{ - // Init column headers - m_listCtrl->InsertColumn(0, "Title", wxLIST_FORMAT_LEFT, 200); - m_listCtrl->InsertColumn(1, "Price", wxLIST_FORMAT_LEFT, 80); - m_listCtrl->InsertColumn(2, "Seller", wxLIST_FORMAT_LEFT, 80); - m_listCtrl->InsertColumn(3, "Stars", wxLIST_FORMAT_LEFT, 50); - m_listCtrl->InsertColumn(4, "Power", wxLIST_FORMAT_LEFT, 50); - - // Tally top categories - map mapTopCategories; - CRITICAL_BLOCK(cs_mapProducts) - for (map::iterator mi = mapProducts.begin(); mi != mapProducts.end(); ++mi) - mapTopCategories[(*mi).second.mapValue["category"]]++; - - // Sort top categories - vector > vTopCategories; - for (map::iterator mi = mapTopCategories.begin(); mi != mapTopCategories.end(); ++mi) - vTopCategories.push_back(make_pair((*mi).second, (*mi).first)); - sort(vTopCategories.begin(), vTopCategories.end(), CompareIntStringPairBestFirst); - - // Fill categories combo box - int nLimit = 250; - for (vector >::iterator it = vTopCategories.begin(); it != vTopCategories.end() && nLimit-- > 0; ++it) - m_comboBoxCategory->Append((*it).second); - - // Fill window with initial search - //wxCommandEvent event; - //OnButtonSearch(event); -} - -void CProductsDialog::OnCombobox(wxCommandEvent& event) -{ - OnButtonSearch(event); -} - -bool CompareProductsBestFirst(const CProduct* p1, const CProduct* p2) -{ - return (p1->nAtoms > p2->nAtoms); -} - -void CProductsDialog::OnButtonSearch(wxCommandEvent& event) -{ - string strCategory = (string)m_comboBoxCategory->GetValue(); - string strSearch = (string)m_textCtrlSearch->GetValue(); - - // Search products - vector vProductsFound; - CRITICAL_BLOCK(cs_mapProducts) - { - for (map::iterator mi = mapProducts.begin(); mi != mapProducts.end(); ++mi) - { - CProduct& product = (*mi).second; - if (product.mapValue["category"].find(strCategory) != -1) - { - if (product.mapValue["title"].find(strSearch) != -1 || - product.mapValue["description"].find(strSearch) != -1 || - product.mapValue["seller"].find(strSearch) != -1) - { - vProductsFound.push_back(&product); - } - } - } - } - - // Sort - sort(vProductsFound.begin(), vProductsFound.end(), CompareProductsBestFirst); - - // Display - foreach(CProduct* pproduct, vProductsFound) - { - InsertLine(m_listCtrl, - pproduct->mapValue["title"], - pproduct->mapValue["price"], - pproduct->mapValue["seller"], - pproduct->mapValue["stars"], - itostr(pproduct->nAtoms)); - } -} - -void CProductsDialog::OnListItemActivated(wxListEvent& event) -{ - // Doubleclick opens product - CViewProductDialog* pdialog = new CViewProductDialog(this, m_vProduct[event.GetIndex()]); - pdialog->Show(); -} - - - - - - - -////////////////////////////////////////////////////////////////////////////// -// -// CEditProductDialog -// - -CEditProductDialog::CEditProductDialog(wxWindow* parent) : CEditProductDialogBase(parent) -{ - m_textCtrlLabel[0 ] = m_textCtrlLabel0; - m_textCtrlLabel[1 ] = m_textCtrlLabel1; - m_textCtrlLabel[2 ] = m_textCtrlLabel2; - m_textCtrlLabel[3 ] = m_textCtrlLabel3; - m_textCtrlLabel[4 ] = m_textCtrlLabel4; - m_textCtrlLabel[5 ] = m_textCtrlLabel5; - m_textCtrlLabel[6 ] = m_textCtrlLabel6; - m_textCtrlLabel[7 ] = m_textCtrlLabel7; - m_textCtrlLabel[8 ] = m_textCtrlLabel8; - m_textCtrlLabel[9 ] = m_textCtrlLabel9; - m_textCtrlLabel[10] = m_textCtrlLabel10; - m_textCtrlLabel[11] = m_textCtrlLabel11; - m_textCtrlLabel[12] = m_textCtrlLabel12; - m_textCtrlLabel[13] = m_textCtrlLabel13; - m_textCtrlLabel[14] = m_textCtrlLabel14; - m_textCtrlLabel[15] = m_textCtrlLabel15; - m_textCtrlLabel[16] = m_textCtrlLabel16; - m_textCtrlLabel[17] = m_textCtrlLabel17; - m_textCtrlLabel[18] = m_textCtrlLabel18; - m_textCtrlLabel[19] = m_textCtrlLabel19; - - m_textCtrlField[0 ] = m_textCtrlField0; - m_textCtrlField[1 ] = m_textCtrlField1; - m_textCtrlField[2 ] = m_textCtrlField2; - m_textCtrlField[3 ] = m_textCtrlField3; - m_textCtrlField[4 ] = m_textCtrlField4; - m_textCtrlField[5 ] = m_textCtrlField5; - m_textCtrlField[6 ] = m_textCtrlField6; - m_textCtrlField[7 ] = m_textCtrlField7; - m_textCtrlField[8 ] = m_textCtrlField8; - m_textCtrlField[9 ] = m_textCtrlField9; - m_textCtrlField[10] = m_textCtrlField10; - m_textCtrlField[11] = m_textCtrlField11; - m_textCtrlField[12] = m_textCtrlField12; - m_textCtrlField[13] = m_textCtrlField13; - m_textCtrlField[14] = m_textCtrlField14; - m_textCtrlField[15] = m_textCtrlField15; - m_textCtrlField[16] = m_textCtrlField16; - m_textCtrlField[17] = m_textCtrlField17; - m_textCtrlField[18] = m_textCtrlField18; - m_textCtrlField[19] = m_textCtrlField19; - - m_buttonDel[0 ] = m_buttonDel0; - m_buttonDel[1 ] = m_buttonDel1; - m_buttonDel[2 ] = m_buttonDel2; - m_buttonDel[3 ] = m_buttonDel3; - m_buttonDel[4 ] = m_buttonDel4; - m_buttonDel[5 ] = m_buttonDel5; - m_buttonDel[6 ] = m_buttonDel6; - m_buttonDel[7 ] = m_buttonDel7; - m_buttonDel[8 ] = m_buttonDel8; - m_buttonDel[9 ] = m_buttonDel9; - m_buttonDel[10] = m_buttonDel10; - m_buttonDel[11] = m_buttonDel11; - m_buttonDel[12] = m_buttonDel12; - m_buttonDel[13] = m_buttonDel13; - m_buttonDel[14] = m_buttonDel14; - m_buttonDel[15] = m_buttonDel15; - m_buttonDel[16] = m_buttonDel16; - m_buttonDel[17] = m_buttonDel17; - m_buttonDel[18] = m_buttonDel18; - m_buttonDel[19] = m_buttonDel19; - - for (int i = 1; i < FIELDS_MAX; i++) - ShowLine(i, false); - - LayoutAll(); -} - -void CEditProductDialog::LayoutAll() -{ - m_scrolledWindow->Layout(); - m_scrolledWindow->GetSizer()->Fit(m_scrolledWindow); - this->Layout(); -} - -void CEditProductDialog::ShowLine(int i, bool fShow) -{ - m_textCtrlLabel[i]->Show(fShow); - m_textCtrlField[i]->Show(fShow); - m_buttonDel[i]->Show(fShow); -} - -void CEditProductDialog::OnButtonDel0(wxCommandEvent& event) { OnButtonDel(event, 0); } -void CEditProductDialog::OnButtonDel1(wxCommandEvent& event) { OnButtonDel(event, 1); } -void CEditProductDialog::OnButtonDel2(wxCommandEvent& event) { OnButtonDel(event, 2); } -void CEditProductDialog::OnButtonDel3(wxCommandEvent& event) { OnButtonDel(event, 3); } -void CEditProductDialog::OnButtonDel4(wxCommandEvent& event) { OnButtonDel(event, 4); } -void CEditProductDialog::OnButtonDel5(wxCommandEvent& event) { OnButtonDel(event, 5); } -void CEditProductDialog::OnButtonDel6(wxCommandEvent& event) { OnButtonDel(event, 6); } -void CEditProductDialog::OnButtonDel7(wxCommandEvent& event) { OnButtonDel(event, 7); } -void CEditProductDialog::OnButtonDel8(wxCommandEvent& event) { OnButtonDel(event, 8); } -void CEditProductDialog::OnButtonDel9(wxCommandEvent& event) { OnButtonDel(event, 9); } -void CEditProductDialog::OnButtonDel10(wxCommandEvent& event) { OnButtonDel(event, 10); } -void CEditProductDialog::OnButtonDel11(wxCommandEvent& event) { OnButtonDel(event, 11); } -void CEditProductDialog::OnButtonDel12(wxCommandEvent& event) { OnButtonDel(event, 12); } -void CEditProductDialog::OnButtonDel13(wxCommandEvent& event) { OnButtonDel(event, 13); } -void CEditProductDialog::OnButtonDel14(wxCommandEvent& event) { OnButtonDel(event, 14); } -void CEditProductDialog::OnButtonDel15(wxCommandEvent& event) { OnButtonDel(event, 15); } -void CEditProductDialog::OnButtonDel16(wxCommandEvent& event) { OnButtonDel(event, 16); } -void CEditProductDialog::OnButtonDel17(wxCommandEvent& event) { OnButtonDel(event, 17); } -void CEditProductDialog::OnButtonDel18(wxCommandEvent& event) { OnButtonDel(event, 18); } -void CEditProductDialog::OnButtonDel19(wxCommandEvent& event) { OnButtonDel(event, 19); } - -void CEditProductDialog::OnButtonDel(wxCommandEvent& event, int n) -{ - Freeze(); - int x, y; - m_scrolledWindow->GetViewStart(&x, &y); - int i; - for (i = n; i < FIELDS_MAX-1; i++) - { - m_textCtrlLabel[i]->SetValue(m_textCtrlLabel[i+1]->GetValue()); - m_textCtrlField[i]->SetValue(m_textCtrlField[i+1]->GetValue()); - if (!m_buttonDel[i+1]->IsShown()) - break; - } - m_textCtrlLabel[i]->SetValue(""); - m_textCtrlField[i]->SetValue(""); - ShowLine(i, false); - m_buttonAddField->Enable(true); - LayoutAll(); - m_scrolledWindow->Scroll(0, y); - Thaw(); -} - -void CEditProductDialog::OnButtonAddField(wxCommandEvent& event) -{ - for (int i = 0; i < FIELDS_MAX; i++) - { - if (!m_buttonDel[i]->IsShown()) - { - Freeze(); - ShowLine(i, true); - if (i == FIELDS_MAX-1) - m_buttonAddField->Enable(false); - LayoutAll(); - m_scrolledWindow->Scroll(0, 99999); - Thaw(); - break; - } - } -} - -void CEditProductDialog::OnButtonSend(wxCommandEvent& event) -{ - CProduct product; - GetProduct(product); - - // Sign the detailed product - product.vchPubKeyFrom = keyUser.GetPubKey(); - if (!keyUser.Sign(product.GetSigHash(), product.vchSig)) - { - wxMessageBox("Error digitally signing the product "); - return; - } - - // Save detailed product - AddToMyProducts(product); - - // Strip down to summary product - product.mapDetails.clear(); - product.vOrderForm.clear(); - - // Sign the summary product - if (!keyUser.Sign(product.GetSigHash(), product.vchSig)) - { - wxMessageBox("Error digitally signing the product "); - return; - } - - // Verify - if (!product.CheckProduct()) - { - wxMessageBox("Errors found in product "); - return; - } - - // Broadcast - AdvertStartPublish(pnodeLocalHost, MSG_PRODUCT, 0, product); - - Destroy(); -} - -void CEditProductDialog::OnButtonPreview(wxCommandEvent& event) -{ - CProduct product; - GetProduct(product); - CViewProductDialog* pdialog = new CViewProductDialog(this, product); - pdialog->Show(); -} - -void CEditProductDialog::OnButtonCancel(wxCommandEvent& event) -{ - Destroy(); -} - -void CEditProductDialog::SetProduct(const CProduct& productIn) -{ - CProduct product = productIn; - - m_comboBoxCategory->SetValue(product.mapValue["category"]); - m_textCtrlTitle->SetValue(product.mapValue["title"]); - m_textCtrlPrice->SetValue(product.mapValue["price"]); - m_textCtrlDescription->SetValue(product.mapValue["description"]); - m_textCtrlInstructions->SetValue(product.mapValue["instructions"]); - - for (int i = 0; i < FIELDS_MAX; i++) - { - bool fUsed = i < product.vOrderForm.size(); - m_buttonDel[i]->Show(fUsed); - m_textCtrlLabel[i]->Show(fUsed); - m_textCtrlField[i]->Show(fUsed); - if (!fUsed) - continue; - - m_textCtrlLabel[i]->SetValue(product.vOrderForm[i].first); - string strControl = product.vOrderForm[i].second; - if (strControl.substr(0, 5) == "text=") - m_textCtrlField[i]->SetValue(""); - else if (strControl.substr(0, 7) == "choice=") - m_textCtrlField[i]->SetValue(strControl.substr(7)); - else - m_textCtrlField[i]->SetValue(strControl); - } -} - -void CEditProductDialog::GetProduct(CProduct& product) -{ - // map mapValue; - // vector > vOrderForm; - - product.mapValue["category"] = m_comboBoxCategory->GetValue().Trim(); - product.mapValue["title"] = m_textCtrlTitle->GetValue().Trim(); - product.mapValue["price"] = m_textCtrlPrice->GetValue().Trim(); - product.mapValue["description"] = m_textCtrlDescription->GetValue().Trim(); - product.mapValue["instructions"] = m_textCtrlInstructions->GetValue().Trim(); - - for (int i = 0; i < FIELDS_MAX; i++) - { - if (m_buttonDel[i]->IsShown()) - { - string strLabel = (string)m_textCtrlLabel[i]->GetValue().Trim(); - string strControl = (string)m_textCtrlField[i]->GetValue(); - if (strControl.empty()) - strControl = "text="; - else - strControl = "choice=" + strControl; - product.vOrderForm.push_back(make_pair(strLabel, strControl)); - } - } -} - - - - - - - -////////////////////////////////////////////////////////////////////////////// -// -// CViewProductDialog -// - -CViewProductDialog::CViewProductDialog(wxWindow* parent, const CProduct& productIn) : CViewProductDialogBase(parent) -{ - Connect(wxEVT_REPLY1, wxCommandEventHandler(CViewProductDialog::OnReply1), NULL, this); - AddCallbackAvailable(GetEventHandler()); - - // Fill display with product summary while waiting for details - product = productIn; - UpdateProductDisplay(false); - - m_buttonBack->Enable(false); - m_buttonNext->Enable(!product.vOrderForm.empty()); - m_htmlWinReviews->Show(true); - m_scrolledWindow->Show(false); - this->Layout(); - - // Request details from seller - _beginthread(ThreadRequestProductDetails, 0, new pair(product, GetEventHandler())); -} - -CViewProductDialog::~CViewProductDialog() -{ - RemoveCallbackAvailable(GetEventHandler()); -} - -void ThreadRequestProductDetails(void* parg) -{ - // Extract parameters - pair* pitem = (pair*)parg; - CProduct product = pitem->first; - wxEvtHandler* pevthandler = pitem->second; - delete pitem; - - // Connect to seller - CNode* pnode = ConnectNode(product.addr, 5 * 60); - if (!pnode) - { - CDataStream ssEmpty; - AddPendingReplyEvent1(pevthandler, ssEmpty); - return; - } - - // Request detailed product, with response going to OnReply1 via dialog's event handler - pnode->PushRequest("getdetails", product.GetHash(), AddPendingReplyEvent1, (void*)pevthandler); -} - -void CViewProductDialog::OnReply1(wxCommandEvent& event) -{ - CDataStream ss = GetStreamFromEvent(event); - if (ss.empty()) - { - product.mapValue["description"] = "-- CAN'T CONNECT TO SELLER --\n"; - UpdateProductDisplay(true); - return; - } - - int nRet; - CProduct product2; - try - { - ss >> nRet; - if (nRet > 0) - throw false; - ss >> product2; - if (product2.GetHash() != product.GetHash()) - throw false; - if (!product2.CheckSignature()) - throw false; - } - catch (...) - { - product.mapValue["description"] = "-- INVALID RESPONSE --\n"; - UpdateProductDisplay(true); - return; - } - - product = product2; - UpdateProductDisplay(true); -} - -bool CompareReviewsBestFirst(const CReview* p1, const CReview* p2) -{ - return (p1->nAtoms > p2->nAtoms); -} - -void CViewProductDialog::UpdateProductDisplay(bool fDetails) -{ - // Product and reviews - string strHTML; - strHTML.reserve(4000); - strHTML += "\n" - "\n" - "\n" - "\n" - "\n"; - strHTML += "Category: " + HtmlEscape(product.mapValue["category"]) + "
\n"; - strHTML += "Title: " + HtmlEscape(product.mapValue["title"]) + "
\n"; - strHTML += "Price: " + HtmlEscape(product.mapValue["price"]) + "
\n"; - - if (!fDetails) - strHTML += "Loading details...
\n
\n"; - else - strHTML += HtmlEscape(product.mapValue["description"], true) + "
\n
\n"; - - strHTML += "Reviews:
\n
\n"; - - if (!product.vchPubKeyFrom.empty()) - { - CReviewDB reviewdb("r"); - - // Get reviews - vector vReviews; - reviewdb.ReadReviews(product.GetUserHash(), vReviews); - - // Get reviewer's number of atoms - vector vSortedReviews; - vSortedReviews.reserve(vReviews.size()); - for (vector::reverse_iterator it = vReviews.rbegin(); it != vReviews.rend(); ++it) - { - CReview& review = *it; - CUser user; - reviewdb.ReadUser(review.GetUserHash(), user); - review.nAtoms = user.GetAtomCount(); - vSortedReviews.push_back(&review); - } - - reviewdb.Close(); - - // Sort - stable_sort(vSortedReviews.begin(), vSortedReviews.end(), CompareReviewsBestFirst); - - // Format reviews - foreach(CReview* preview, vSortedReviews) - { - CReview& review = *preview; - int nStars = atoi(review.mapValue["stars"].c_str()); - if (nStars < 1 || nStars > 5) - continue; - - strHTML += "" + itostr(nStars) + (nStars == 1 ? " star" : " stars") + ""; - strHTML += "     "; - strHTML += DateStr(atoi64(review.mapValue["date"])) + "
\n"; - strHTML += HtmlEscape(review.mapValue["review"], true); - strHTML += "
\n
\n"; - } - } - - strHTML += "\n\n"; - - // Shrink capacity to fit - string(strHTML.begin(), strHTML.end()).swap(strHTML); - - m_htmlWinReviews->SetPage(strHTML); - - ///// need to find some other indicator to use so can allow empty order form - if (product.vOrderForm.empty()) - return; - - // Order form - m_staticTextInstructions->SetLabel(product.mapValue["instructions"]); - for (int i = 0; i < FIELDS_MAX; i++) - { - m_staticTextLabel[i] = NULL; - m_textCtrlField[i] = NULL; - m_choiceField[i] = NULL; - } - - // Construct flexgridsizer - wxBoxSizer* bSizer21 = (wxBoxSizer*)m_scrolledWindow->GetSizer(); - wxFlexGridSizer* fgSizer; - fgSizer = new wxFlexGridSizer(0, 2, 0, 0); - fgSizer->AddGrowableCol(1); - fgSizer->SetFlexibleDirection(wxBOTH); - fgSizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); - - // Construct order form fields - wxWindow* windowLast = NULL; - for (int i = 0; i < product.vOrderForm.size(); i++) - { - string strLabel = product.vOrderForm[i].first; - string strControl = product.vOrderForm[i].second; - - if (strLabel.size() < 20) - strLabel.insert(strLabel.begin(), 20 - strLabel.size(), ' '); - - m_staticTextLabel[i] = new wxStaticText(m_scrolledWindow, wxID_ANY, strLabel, wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); - m_staticTextLabel[i]->Wrap(-1); - fgSizer->Add(m_staticTextLabel[i], 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5); - - if (strControl.substr(0, 5) == "text=") - { - m_textCtrlField[i] = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); - fgSizer->Add(m_textCtrlField[i], 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5); - windowLast = m_textCtrlField[i]; - } - else if (strControl.substr(0, 7) == "choice=") - { - vector vChoices; - ParseString(strControl.substr(7), ',', vChoices); - - wxArrayString arraystring; - foreach(const string& str, vChoices) - arraystring.Add(str); - - m_choiceField[i] = new wxChoice(m_scrolledWindow, wxID_ANY, wxDefaultPosition, wxDefaultSize, arraystring, 0); - fgSizer->Add(m_choiceField[i], 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); - windowLast = m_choiceField[i]; - } - else - { - m_textCtrlField[i] = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); - fgSizer->Add(m_textCtrlField[i], 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5); - m_staticTextLabel[i]->Show(false); - m_textCtrlField[i]->Show(false); - } - } - - // Insert after instructions and before submit/cancel buttons - bSizer21->Insert(2, fgSizer, 0, wxEXPAND|wxRIGHT|wxLEFT, 5); - m_scrolledWindow->Layout(); - bSizer21->Fit(m_scrolledWindow); - this->Layout(); - - // Fixup the tab order - m_buttonSubmitForm->MoveAfterInTabOrder(windowLast); - m_buttonCancelForm->MoveAfterInTabOrder(m_buttonSubmitForm); - //m_buttonBack->MoveAfterInTabOrder(m_buttonCancelForm); - //m_buttonNext->MoveAfterInTabOrder(m_buttonBack); - //m_buttonCancel->MoveAfterInTabOrder(m_buttonNext); - this->Layout(); -} - -void CViewProductDialog::GetOrder(CWalletTx& wtx) -{ - wtx.SetNull(); - for (int i = 0; i < product.vOrderForm.size(); i++) - { - string strValue; - if (m_textCtrlField[i]) - strValue = m_textCtrlField[i]->GetValue().Trim(); - else - strValue = m_choiceField[i]->GetStringSelection(); - wtx.vOrderForm.push_back(make_pair(m_staticTextLabel[i]->GetLabel(), strValue)); - } -} - -void CViewProductDialog::OnButtonSubmitForm(wxCommandEvent& event) -{ - m_buttonSubmitForm->Enable(false); - m_buttonCancelForm->Enable(false); - - CWalletTx wtx; - GetOrder(wtx); - - CSendingDialog* pdialog = new CSendingDialog(this, product.addr, atoi64(product.mapValue["price"]), wtx); - if (!pdialog->ShowModal()) - { - m_buttonSubmitForm->Enable(true); - m_buttonCancelForm->Enable(true); - return; - } -} - -void CViewProductDialog::OnButtonCancelForm(wxCommandEvent& event) -{ - Destroy(); -} - -void CViewProductDialog::OnButtonBack(wxCommandEvent& event) -{ - Freeze(); - m_htmlWinReviews->Show(true); - m_scrolledWindow->Show(false); - m_buttonBack->Enable(false); - m_buttonNext->Enable(!product.vOrderForm.empty()); - this->Layout(); - Thaw(); -} - -void CViewProductDialog::OnButtonNext(wxCommandEvent& event) -{ - if (!product.vOrderForm.empty()) - { - Freeze(); - m_htmlWinReviews->Show(false); - m_scrolledWindow->Show(true); - m_buttonBack->Enable(true); - m_buttonNext->Enable(false); - this->Layout(); - Thaw(); - } -} - -void CViewProductDialog::OnButtonCancel(wxCommandEvent& event) -{ - Destroy(); -} - - - - - - - -////////////////////////////////////////////////////////////////////////////// -// -// CViewOrderDialog -// - -CViewOrderDialog::CViewOrderDialog(wxWindow* parent, CWalletTx order, bool fReceived) : CViewOrderDialogBase(parent) -{ - int64 nPrice = (fReceived ? order.GetCredit() : order.GetDebit()); - - string strHTML; - strHTML.reserve(4000); - strHTML += "\n" - "\n" - "\n" - "\n" - "\n"; - strHTML += "Time: " + HtmlEscape(DateTimeStr(order.nTimeReceived)) + "
\n"; - strHTML += "Price: " + HtmlEscape(FormatMoney(nPrice)) + "
\n"; - strHTML += "Status: " + HtmlEscape(FormatTxStatus(order)) + "
\n"; - - strHTML += "\n"; - for (int i = 0; i < order.vOrderForm.size(); i++) - { - strHTML += " "; - strHTML += "\n"; - } - strHTML += "
" + HtmlEscape(order.vOrderForm[i].first) + ":" + HtmlEscape(order.vOrderForm[i].second) + "
\n"; - - strHTML += "\n\n"; - - // Shrink capacity to fit - // (strings are ref counted, so it may live on in SetPage) - string(strHTML.begin(), strHTML.end()).swap(strHTML); - - m_htmlWin->SetPage(strHTML); -} - -void CViewOrderDialog::OnButtonOK(wxCommandEvent& event) -{ - Destroy(); -} - - - - - - - -////////////////////////////////////////////////////////////////////////////// -// -// CEditReviewDialog -// - -CEditReviewDialog::CEditReviewDialog(wxWindow* parent) : CEditReviewDialogBase(parent) -{ -} - -void CEditReviewDialog::OnButtonSubmit(wxCommandEvent& event) -{ - if (m_choiceStars->GetSelection() == -1) - { - wxMessageBox("Please select a rating "); - return; - } - - CReview review; - GetReview(review); - - // Sign the review - review.vchPubKeyFrom = keyUser.GetPubKey(); - if (!keyUser.Sign(review.GetSigHash(), review.vchSig)) - { - wxMessageBox("Unable to digitally sign the review "); - return; - } - - // Broadcast - if (!review.AcceptReview()) - { - wxMessageBox("Save failed "); - return; - } - RelayMessage(CInv(MSG_REVIEW, review.GetHash()), review); - - Destroy(); -} - -void CEditReviewDialog::OnButtonCancel(wxCommandEvent& event) -{ - Destroy(); -} - -void CEditReviewDialog::GetReview(CReview& review) -{ - review.mapValue["time"] = i64tostr(GetAdjustedTime()); - review.mapValue["stars"] = itostr(m_choiceStars->GetSelection()+1); - review.mapValue["review"] = m_textCtrlReview->GetValue(); -} - - - - - - - - - - - - -////////////////////////////////////////////////////////////////////////////// -// -// CMyApp -// - -// Define a new application -class CMyApp: public wxApp -{ - public: - CMyApp(){}; - ~CMyApp(){}; - bool OnInit(); - bool OnInit2(); - int OnExit(); - - // The MSYS2 release wxWidgets DLLs ship with asserts enabled. Log any - // assertion to debug.log instead of showing a modal "Debug Alert" popup, - // so the packaged build runs cleanly by double-click. - virtual void OnAssertFailure(const wxChar* file, int line, const wxChar* func, - const wxChar* cond, const wxChar* msg) - { - printf("wxAssert: %s(%d) %s: %s %s\n", - (const char*)wxString(file).mb_str(), line, - (const char*)wxString(func).mb_str(), - (const char*)wxString(cond).mb_str(), - (const char*)wxString(msg).mb_str()); - } - - // 2nd-level exception handling: we get all the exceptions occurring in any - // event handler here - virtual bool OnExceptionInMainLoop(); - - // 3rd, and final, level exception handling: whenever an unhandled - // exception is caught, this function is called - virtual void OnUnhandledException(); - - // and now for something different: this function is called in case of a - // crash (e.g. dereferencing null pointer, division by 0, ...) - virtual void OnFatalException(); -}; - -IMPLEMENT_APP(CMyApp) - -bool CMyApp::OnInit() -{ - // The 2009 wxFormBuilder layout mixes wxEXPAND with alignment flags, which - // modern wxWidgets flags as an assertion. Disable those sizer consistency - // checks globally so no "Debug Alert" popup ever blocks the UI. - wxSizerFlags::DisableConsistencyChecks(); - try - { - return OnInit2(); - } - catch (std::exception& e) { - PrintException(&e, "OnInit()"); - } catch (...) { - PrintException(NULL, "OnInit()"); - } - return false; -} - -map ParseParameters(int argc, char* argv[]) -{ - map mapArgs; - for (int i = 0; i < argc; i++) - { - char psz[10000]; - strcpy(psz, argv[i]); - char* pszValue = ""; - if (strchr(psz, '=')) - { - pszValue = strchr(psz, '='); - *pszValue++ = '\0'; - } - strlwr(psz); - if (psz[0] == '-') - psz[0] = '/'; - mapArgs[psz] = pszValue; - } - return mapArgs; -} - -bool CMyApp::OnInit2() -{ -#ifdef _MSC_VER - // Turn off microsoft heap dump noise for now - _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); - _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0)); -#endif - - //// debug print - printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); - printf("Bitcoin CMyApp::OnInit()\n"); - - // - // Parameters (parsed before the lock so /datadir and /port feed the mutex) - // - wxImage::AddHandler(new wxPNGHandler); - map mapArgs = ParseParameters(argc, argv); - - if (mapArgs.count("/datadir")) - strSetDataDir = mapArgs["/datadir"]; - - if (mapArgs.count("/port")) - nListenPort = htons(atoi(mapArgs["/port"].c_str())); - - // - // Limit to single instance per user/datadir - // The mutex includes the datadir to allow multiple nodes on one machine. - // - const char* pszHomePath = getenv("HOMEPATH"); - wxString strMutexName = wxString("Bitflash.") + (pszHomePath ? pszHomePath : "default") + "." + strSetDataDir.c_str(); - for (int i = 0; i < strMutexName.size(); i++) - if (!isalnum(strMutexName[i])) - strMutexName[i] = '.'; - wxSingleInstanceChecker* psingleinstancechecker = new wxSingleInstanceChecker(strMutexName); - if (psingleinstancechecker->IsAnotherRunning()) - { - printf("Existing instance found\n"); - unsigned int nStart = GetTime(); - loop - { - // Show the previous instance and exit - HWND hwndPrev = FindWindow("wxWindowClassNR", "Bitflash"); - if (hwndPrev) - { - if (IsIconic(hwndPrev)) - ShowWindow(hwndPrev, SW_RESTORE); - SetForegroundWindow(hwndPrev); - return false; - } - - if (GetTime() > nStart + 60) - return false; - - // Resume this instance if the other exits - delete psingleinstancechecker; - Sleep(1000); - psingleinstancechecker = new wxSingleInstanceChecker(strMutexName); - if (!psingleinstancechecker->IsAnotherRunning()) - break; - } - } - - if (mapArgs.count("/proxy")) - addrProxy = CAddress(mapArgs["/proxy"].c_str()); - - // Rendezvous meeting relay override: replace the seed list with a single - // relay (default keeps the built-in seed list with failover). - if (mapArgs.count("/rvrelay")) - vBtfMeetingRelays = { mapArgs["/rvrelay"] }; - - // Announce a relay you run so other nodes discover it automatically. - if (mapArgs.count("/announcerelay")) - strBtfAnnounceRelay = mapArgs["/announcerelay"]; - - // Keep an anonymous outbound connection to a specific .btf peer. - if (mapArgs.count("/connectbtf")) - strBtfConnect = mapArgs["/connectbtf"]; - - if (mapArgs.count("/debug")) - fDebug = true; - - if (mapArgs.count("/dropmessages")) - { - nDropMessagesTest = atoi(mapArgs["/dropmessages"]); - if (nDropMessagesTest == 0) - nDropMessagesTest = 20; - } - - if (mapArgs.count("/loadblockindextest")) - { - CTxDB txdb("r"); - txdb.LoadBlockIndex(); - PrintBlockTree(); - ExitProcess(0); - } - - // - // Load data files - // - string strErrors; - int64 nStart, nEnd; - - printf("Loading addresses...\n"); - QueryPerformanceCounter((LARGE_INTEGER*)&nStart); - if (!LoadAddresses()) - strErrors += "Error loading addr.dat \n"; - QueryPerformanceCounter((LARGE_INTEGER*)&nEnd); - printf(" addresses %20I64d\n", nEnd - nStart); - - printf("Loading block index...\n"); - QueryPerformanceCounter((LARGE_INTEGER*)&nStart); - if (!LoadBlockIndex()) - strErrors += "Error loading blkindex.dat \n"; - QueryPerformanceCounter((LARGE_INTEGER*)&nEnd); - printf(" block index %20I64d\n", nEnd - nStart); - - printf("Loading wallet...\n"); - QueryPerformanceCounter((LARGE_INTEGER*)&nStart); - if (!LoadWallet()) - strErrors += "Error loading wallet.dat \n"; - QueryPerformanceCounter((LARGE_INTEGER*)&nEnd); - printf(" wallet %20I64d\n", nEnd - nStart); - - printf("Done loading\n"); - - //// debug print - printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size()); - printf("nBestHeight = %d\n", nBestHeight); - printf("mapKeys.size() = %d\n", mapKeys.size()); - printf("mapPubKeys.size() = %d\n", mapPubKeys.size()); - printf("mapWallet.size() = %d\n", mapWallet.size()); - printf("mapAddressBook.size() = %d\n", mapAddressBook.size()); - - if (!strErrors.empty()) - { - wxMessageBox(strErrors); - OnExit(); - return false; - } - - // Add wallet transactions that aren't already in a block to mapTransactions - ReacceptWalletTransactions(); - - // - // Parameters - // - if (mapArgs.count("/printblockindex") || mapArgs.count("/printblocktree")) - { - PrintBlockTree(); - OnExit(); - return false; - } - - if (mapArgs.count("/solomine")) - fSoloMineTest = true; - - if (mapArgs.count("/gen")) - { - if (mapArgs["/gen"].empty()) - fGenerateBitcoins = true; - else - fGenerateBitcoins = atoi(mapArgs["/gen"].c_str()); - } - - // - // Create the main frame window - // - { - pframeMain = new CMainFrame(NULL); - pframeMain->Show(); - - if (!StartNode(strErrors)) - wxMessageBox(strErrors); - - if (fGenerateBitcoins) - if (_beginthread(ThreadBitcoinMiner, 0, NULL) == -1) - printf("Error: _beginthread(ThreadBitcoinMiner) failed\n"); - - // - // Tests - // - if (argc >= 2 && wxString(argv[1]).CmpNoCase("/send") == 0) - { - int64 nValue = 1; - if (argc >= 3) - ParseMoney(argv[2], nValue); - - string strAddress; - if (argc >= 4) - strAddress = argv[3]; - CAddress addr(strAddress.c_str()); - - CWalletTx wtx; - wtx.mapValue["to"] = strAddress; - wtx.mapValue["from"] = addrLocalHost.ToString(); - wtx.mapValue["message"] = "command line send"; - - // Send to IP address - CSendingDialog* pdialog = new CSendingDialog(pframeMain, addr, nValue, wtx); - if (!pdialog->ShowModal()) - return false; - } - - if (mapArgs.count("/randsendtest")) - { - if (!mapArgs["/randsendtest"].empty()) - _beginthread(ThreadRandSendTest, 0, new string(mapArgs["/randsendtest"])); - else - fRandSendTest = true; - fDebug = true; - } - } - - return true; -} - -int CMyApp::OnExit() -{ - Shutdown(NULL); - return wxApp::OnExit(); -} - -bool CMyApp::OnExceptionInMainLoop() -{ - try - { - throw; - } - catch (std::exception& e) - { - PrintException(&e, "CMyApp::OnExceptionInMainLoop()"); - wxLogWarning(_T("Exception %s %s"), typeid(e).name(), e.what()); - Sleep(1000); - throw; - } - catch (...) - { - PrintException(NULL, "CMyApp::OnExceptionInMainLoop()"); - wxLogWarning(_T("Unknown exception")); - Sleep(1000); - throw; - } - - return true; -} - -void CMyApp::OnUnhandledException() -{ - // this shows how we may let some exception propagate uncaught - try - { - throw; - } - catch (std::exception& e) - { - PrintException(&e, "CMyApp::OnUnhandledException()"); - wxLogWarning(_T("Exception %s %s"), typeid(e).name(), e.what()); - Sleep(1000); - throw; - } - catch (...) - { - PrintException(NULL, "CMyApp::OnUnhandledException()"); - wxLogWarning(_T("Unknown exception")); - Sleep(1000); - throw; - } -} - -void CMyApp::OnFatalException() -{ - wxMessageBox("Program has crashed and will terminate. ", "", wxOK | wxICON_ERROR); -} - - - -void MainFrameRepaint() -{ - if (pframeMain) - { - printf("MainFrameRepaint()\n"); - // Called from worker threads: repaint only on the GUI thread - wxTheApp->CallAfter([] { if (pframeMain) pframeMain->Refresh(); }); - } -} - - - - - - - -// randsendtest to bitcoin address -void ThreadRandSendTest(void* parg) -{ - string strAddress = *(string*)parg; - uint160 hash160; - if (!AddressToHash160(strAddress, hash160)) - { - wxMessageBox(strprintf("ThreadRandSendTest: Bitcoin address '%s' not valid ", strAddress.c_str())); - return; - } - - loop - { - Sleep(GetRand(30) * 1000 + 100); - - // Message - CWalletTx wtx; - wtx.mapValue["to"] = strAddress; - wtx.mapValue["from"] = addrLocalHost.ToString(); - static int nRep; - wtx.mapValue["message"] = strprintf("randsendtest %d\n", ++nRep); - - // Value - int64 nValue = (GetRand(9) + 1) * 100 * CENT; - if (GetBalance() < nValue) - { - wxMessageBox("Out of money "); - return; - } - nValue += (nRep % 100) * CENT; - - // Send to bitcoin address - CScript scriptPubKey; - scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG; - - if (!SendMoney(scriptPubKey, nValue, wtx)) - return; - } -} - - -// randsendtest to any connected node -void RandSend() -{ - CWalletTx wtx; - - while (vNodes.empty()) - Sleep(1000); - CAddress addr; - CRITICAL_BLOCK(cs_vNodes) - addr = vNodes[GetRand(vNodes.size())]->addr; - - // Message - wtx.mapValue["to"] = addr.ToString(); - wtx.mapValue["from"] = addrLocalHost.ToString(); - static int nRep; - wtx.mapValue["message"] = strprintf("randsendtest %d\n", ++nRep); - - // Value - int64 nValue = (GetRand(999) + 1) * CENT; - if (GetBalance() < nValue) - { - wxMessageBox("Out of money "); - return; - } - - // Send to IP address - CSendingDialog* pdialog = new CSendingDialog(pframeMain, addr, nValue, wtx); - if (!pdialog->Show()) - wxMessageBox("ShowModal Failed "); -} -- cgit v1.2.3