1 // Copyright (c) 2009 Satoshi Nakamoto
\r
2 // Distributed under the MIT/X11 software license, see the accompanying
\r
3 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
\r
10 void ThreadRequestProductDetails(void* parg);
\r
11 void ThreadRandSendTest(void* parg);
\r
12 bool GetStartOnSystemStartup();
\r
13 void SetStartOnSystemStartup(bool fAutoStart);
\r
17 DEFINE_EVENT_TYPE(wxEVT_CROSSTHREADCALL)
\r
18 DEFINE_EVENT_TYPE(wxEVT_REPLY1)
\r
19 DEFINE_EVENT_TYPE(wxEVT_REPLY2)
\r
20 DEFINE_EVENT_TYPE(wxEVT_REPLY3)
\r
21 DEFINE_EVENT_TYPE(wxEVT_TABLEADDED)
\r
22 DEFINE_EVENT_TYPE(wxEVT_TABLEUPDATED)
\r
23 DEFINE_EVENT_TYPE(wxEVT_TABLEDELETED)
\r
25 CMainFrame* pframeMain = NULL;
\r
26 CMyTaskBarIcon* ptaskbaricon = NULL;
\r
27 map<string, string> mapAddressBook;
\r
28 map<string, string> mapArgs;
\r
29 bool fRandSendTest = false;
\r
31 extern int g_isPainting;
\r
34 int fShowGenerated = true;
\r
35 int fMinimizeToTray = true;
\r
36 int fMinimizeOnClose = true;
\r
44 //////////////////////////////////////////////////////////////////////////////
\r
49 void HandleCtrlA(wxKeyEvent& event)
\r
51 // Ctrl-a select all
\r
52 wxTextCtrl* textCtrl = (wxTextCtrl*)event.GetEventObject();
\r
53 if (event.GetModifiers() == wxMOD_CONTROL && event.GetKeyCode() == 'A')
\r
54 textCtrl->SetSelection(-1, -1);
\r
60 //char pszHourFormat[256];
\r
61 //pszHourFormat[0] = '\0';
\r
62 //GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ITIME, pszHourFormat, 256);
\r
63 //return (pszHourFormat[0] != '0');
\r
67 string DateStr(int64 nTime)
\r
69 return (string)wxDateTime((time_t)nTime).FormatDate();
\r
72 string DateTimeStr(int64 nTime)
\r
74 wxDateTime datetime((time_t)nTime);
\r
76 return (string)datetime.Format("%x %H:%M");
\r
78 return (string)datetime.Format("%x ") + itostr((datetime.GetHour() + 11) % 12 + 1) + (string)datetime.Format(":%M %p");
\r
81 wxString GetItemText(wxListCtrl* listCtrl, int nIndex, int nColumn)
\r
83 // Helper to simplify access to listctrl
\r
85 item.m_itemId = nIndex;
\r
86 item.m_col = nColumn;
\r
87 item.m_mask = wxLIST_MASK_TEXT;
\r
88 if (!listCtrl->GetItem(item))
\r
90 return item.GetText();
\r
93 int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1)
\r
95 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
\r
96 listCtrl->SetItem(nIndex, 1, str1);
\r
100 int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
\r
102 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
\r
103 listCtrl->SetItem(nIndex, 1, str1);
\r
104 listCtrl->SetItem(nIndex, 2, str2);
\r
105 listCtrl->SetItem(nIndex, 3, str3);
\r
106 listCtrl->SetItem(nIndex, 4, str4);
\r
110 int InsertLine(wxListCtrl* listCtrl, void* pdata, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
\r
112 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
\r
113 listCtrl->SetItemPtrData(nIndex, (wxUIntPtr)pdata);
\r
114 listCtrl->SetItem(nIndex, 1, str1);
\r
115 listCtrl->SetItem(nIndex, 2, str2);
\r
116 listCtrl->SetItem(nIndex, 3, str3);
\r
117 listCtrl->SetItem(nIndex, 4, str4);
\r
121 void SetSelection(wxListCtrl* listCtrl, int nIndex)
\r
123 int nSize = listCtrl->GetItemCount();
\r
124 long nState = (wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
\r
125 for (int i = 0; i < nSize; i++)
\r
126 listCtrl->SetItemState(i, (i == nIndex ? nState : 0), nState);
\r
129 int GetSelection(wxListCtrl* listCtrl)
\r
131 int nSize = listCtrl->GetItemCount();
\r
132 for (int i = 0; i < nSize; i++)
\r
133 if (listCtrl->GetItemState(i, wxLIST_STATE_FOCUSED))
\r
139 string HtmlEscape(const char* psz, bool fMultiLine=false)
\r
142 for (const char* p = psz; *p; p++)
\r
144 if (*p == '<') len += 4;
\r
145 else if (*p == '>') len += 4;
\r
146 else if (*p == '&') len += 5;
\r
147 else if (*p == '"') len += 6;
\r
148 else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') len += 6;
\r
149 else if (*p == '\n' && fMultiLine) len += 5;
\r
155 for (const char* p = psz; *p; p++)
\r
157 if (*p == '<') str += "<";
\r
158 else if (*p == '>') str += ">";
\r
159 else if (*p == '&') str += "&";
\r
160 else if (*p == '"') str += """;
\r
161 else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') str += " ";
\r
162 else if (*p == '\n' && fMultiLine) str += "<br>\n";
\r
169 string HtmlEscape(const string& str, bool fMultiLine=false)
\r
171 return HtmlEscape(str.c_str(), fMultiLine);
\r
174 void AddToMyProducts(CProduct product)
\r
176 CProduct& productInsert = mapMyProducts[product.GetHash()];
\r
177 productInsert = product;
\r
178 InsertLine(pframeMain->m_listCtrlProductsSent, &productInsert,
\r
179 product.mapValue["category"],
\r
180 product.mapValue["title"].substr(0, 100),
\r
181 product.mapValue["description"].substr(0, 100),
\r
182 product.mapValue["price"],
\r
191 //////////////////////////////////////////////////////////////////////////////
\r
196 set<void*> setCallbackAvailable;
\r
197 CCriticalSection cs_setCallbackAvailable;
\r
199 void AddCallbackAvailable(void* p)
\r
201 CRITICAL_BLOCK(cs_setCallbackAvailable)
\r
202 setCallbackAvailable.insert(p);
\r
205 void RemoveCallbackAvailable(void* p)
\r
207 CRITICAL_BLOCK(cs_setCallbackAvailable)
\r
208 setCallbackAvailable.erase(p);
\r
211 bool IsCallbackAvailable(void* p)
\r
213 CRITICAL_BLOCK(cs_setCallbackAvailable)
\r
214 return setCallbackAvailable.count(p);
\r
218 template<typename T>
\r
219 void AddPendingCustomEvent(wxEvtHandler* pevthandler, int nEventID, const T pbeginIn, const T pendIn)
\r
224 const char* pbegin = (pendIn != pbeginIn) ? &pbeginIn[0] : NULL;
\r
225 const char* pend = pbegin + (pendIn - pbeginIn) * sizeof(pbeginIn[0]);
\r
226 wxCommandEvent event(nEventID);
\r
227 wxString strData(wxChar(0), (pend - pbegin) / sizeof(wxChar) + 1);
\r
228 memcpy(&strData[0], pbegin, pend - pbegin);
\r
229 event.SetString(strData);
\r
230 event.SetInt(pend - pbegin);
\r
232 pevthandler->AddPendingEvent(event);
\r
236 void AddPendingCustomEvent(wxEvtHandler* pevthandler, int nEventID, const T& obj)
\r
240 AddPendingCustomEvent(pevthandler, nEventID, ss.begin(), ss.end());
\r
243 void AddPendingReplyEvent1(void* pevthandler, CDataStream& vRecv)
\r
245 if (IsCallbackAvailable(pevthandler))
\r
246 AddPendingCustomEvent((wxEvtHandler*)pevthandler, wxEVT_REPLY1, vRecv.begin(), vRecv.end());
\r
249 void AddPendingReplyEvent2(void* pevthandler, CDataStream& vRecv)
\r
251 if (IsCallbackAvailable(pevthandler))
\r
252 AddPendingCustomEvent((wxEvtHandler*)pevthandler, wxEVT_REPLY2, vRecv.begin(), vRecv.end());
\r
255 void AddPendingReplyEvent3(void* pevthandler, CDataStream& vRecv)
\r
257 if (IsCallbackAvailable(pevthandler))
\r
258 AddPendingCustomEvent((wxEvtHandler*)pevthandler, wxEVT_REPLY3, vRecv.begin(), vRecv.end());
\r
261 CDataStream GetStreamFromEvent(const wxCommandEvent& event)
\r
263 wxString strData = event.GetString();
\r
264 return CDataStream(strData.begin(), strData.begin() + event.GetInt(), SER_NETWORK);
\r
273 //////////////////////////////////////////////////////////////////////////////
\r
278 CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent)
\r
280 Connect(wxEVT_CROSSTHREADCALL, wxCommandEventHandler(CMainFrame::OnCrossThreadCall), NULL, this);
\r
283 fRefreshListCtrl = false;
\r
284 fRefreshListCtrlRunning = false;
\r
285 fOnSetFocusAddress = false;
\r
286 pindexBestLast = NULL;
\r
287 m_choiceFilter->SetSelection(0);
\r
288 m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " ");
\r
289 m_listCtrl->SetFocus();
\r
290 SetIcon(wxICON(bitcoin));
\r
291 ptaskbaricon = new CMyTaskBarIcon();
\r
293 // Init toolbar with transparency masked bitmaps
\r
294 m_toolBar->ClearTools();
\r
296 //// shouldn't have to do mask separately anymore, bitmap alpha support added in wx 2.8.9,
\r
297 wxBitmap bmpSend(wxT("send20"), wxBITMAP_TYPE_RESOURCE);
\r
298 bmpSend.SetMask(new wxMask(wxBitmap(wxT("send20mask"), wxBITMAP_TYPE_RESOURCE)));
\r
299 m_toolBar->AddTool(wxID_BUTTONSEND, wxT("&Send Coins"), bmpSend, wxNullBitmap, wxITEM_NORMAL, wxEmptyString, wxEmptyString);
\r
301 wxBitmap bmpAddressBook(wxT("addressbook20"), wxBITMAP_TYPE_RESOURCE);
\r
302 bmpAddressBook.SetMask(new wxMask(wxBitmap(wxT("addressbook20mask"), wxBITMAP_TYPE_RESOURCE)));
\r
303 m_toolBar->AddTool(wxID_BUTTONRECEIVE, wxT("&Address Book"), bmpAddressBook, wxNullBitmap, wxITEM_NORMAL, wxEmptyString, wxEmptyString);
\r
305 m_toolBar->Realize();
\r
307 // Init column headers
\r
308 int nDateWidth = DateTimeStr(1229413914).size() * 6 + 8;
\r
309 if (!strstr(DateTimeStr(1229413914).c_str(), "2008"))
\r
311 m_listCtrl->InsertColumn(0, "", wxLIST_FORMAT_LEFT, 0);
\r
312 m_listCtrl->InsertColumn(1, "", wxLIST_FORMAT_LEFT, 0);
\r
313 m_listCtrl->InsertColumn(2, "Status", wxLIST_FORMAT_LEFT, 90);
\r
314 m_listCtrl->InsertColumn(3, "Date", wxLIST_FORMAT_LEFT, nDateWidth);
\r
315 m_listCtrl->InsertColumn(4, "Description", wxLIST_FORMAT_LEFT, 409 - nDateWidth);
\r
316 m_listCtrl->InsertColumn(5, "Debit", wxLIST_FORMAT_RIGHT, 79);
\r
317 m_listCtrl->InsertColumn(6, "Credit", wxLIST_FORMAT_RIGHT, 79);
\r
319 //m_listCtrlProductsSent->InsertColumn(0, "Category", wxLIST_FORMAT_LEFT, 100);
\r
320 //m_listCtrlProductsSent->InsertColumn(1, "Title", wxLIST_FORMAT_LEFT, 100);
\r
321 //m_listCtrlProductsSent->InsertColumn(2, "Description", wxLIST_FORMAT_LEFT, 100);
\r
322 //m_listCtrlProductsSent->InsertColumn(3, "Price", wxLIST_FORMAT_LEFT, 100);
\r
323 //m_listCtrlProductsSent->InsertColumn(4, "", wxLIST_FORMAT_LEFT, 100);
\r
325 //m_listCtrlOrdersSent->InsertColumn(0, "Time", wxLIST_FORMAT_LEFT, 100);
\r
326 //m_listCtrlOrdersSent->InsertColumn(1, "Price", wxLIST_FORMAT_LEFT, 100);
\r
327 //m_listCtrlOrdersSent->InsertColumn(2, "", wxLIST_FORMAT_LEFT, 100);
\r
328 //m_listCtrlOrdersSent->InsertColumn(3, "", wxLIST_FORMAT_LEFT, 100);
\r
329 //m_listCtrlOrdersSent->InsertColumn(4, "", wxLIST_FORMAT_LEFT, 100);
\r
331 //m_listCtrlOrdersReceived->InsertColumn(0, "Time", wxLIST_FORMAT_LEFT, 100);
\r
332 //m_listCtrlOrdersReceived->InsertColumn(1, "Price", wxLIST_FORMAT_LEFT, 100);
\r
333 //m_listCtrlOrdersReceived->InsertColumn(2, "Payment Status", wxLIST_FORMAT_LEFT, 100);
\r
334 //m_listCtrlOrdersReceived->InsertColumn(3, "", wxLIST_FORMAT_LEFT, 100);
\r
335 //m_listCtrlOrdersReceived->InsertColumn(4, "", wxLIST_FORMAT_LEFT, 100);
\r
338 int pnWidths[3] = { -100, 88, 290 };
\r
339 m_statusBar->SetFieldsCount(3, pnWidths);
\r
341 // Fill your address text box
\r
342 vector<unsigned char> vchPubKey;
\r
343 if (CWalletDB("r").ReadDefaultKey(vchPubKey))
\r
344 m_textCtrlAddress->SetValue(PubKeyToAddress(vchPubKey));
\r
346 // Fill listctrl with wallet transactions
\r
350 CMainFrame::~CMainFrame()
\r
353 delete ptaskbaricon;
\r
354 ptaskbaricon = NULL;
\r
357 void Shutdown(void* parg)
\r
359 static CCriticalSection cs_Shutdown;
\r
360 CRITICAL_BLOCK(cs_Shutdown)
\r
363 nTransactionsUpdated++;
\r
368 printf("Bitcoin exiting\n");
\r
373 void CMainFrame::OnClose(wxCloseEvent& event)
\r
375 if (fMinimizeToTray && fMinimizeOnClose && event.CanVeto() && !IsIconized())
\r
377 // Divert close to minimize
\r
384 _beginthread(Shutdown, 0, NULL);
\r
388 void CMainFrame::OnIconize(wxIconizeEvent& event)
\r
390 // Hide the task bar button when minimized.
\r
391 // Event is sent when the frame is minimized or restored.
\r
392 Show(!fMinimizeToTray || !event.Iconized());
\r
395 void CMainFrame::OnMouseEvents(wxMouseEvent& event)
\r
398 RAND_add(&event.m_x, sizeof(event.m_x), 0.25);
\r
399 RAND_add(&event.m_y, sizeof(event.m_y), 0.25);
\r
402 void CMainFrame::OnListColBeginDrag(wxListEvent& event)
\r
404 // Hidden columns not resizeable
\r
405 if (event.GetColumn() <= 1 && !fDebug)
\r
409 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)
\r
411 string str0 = strSort;
\r
412 long nData = *(long*)&hashKey;
\r
415 if (!fNew && nIndex == -1)
\r
417 while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)
\r
418 if (GetItemText(m_listCtrl, nIndex, 1) == hashKey.ToString())
\r
422 // fNew is for blind insert, only use if you're sure it's new
\r
423 if (fNew || nIndex == -1)
\r
425 nIndex = m_listCtrl->InsertItem(0, str0);
\r
429 // If sort key changed, must delete and reinsert to make it relocate
\r
430 if (GetItemText(m_listCtrl, nIndex, 0) != str0)
\r
432 m_listCtrl->DeleteItem(nIndex);
\r
433 nIndex = m_listCtrl->InsertItem(0, str0);
\r
437 m_listCtrl->SetItem(nIndex, 1, hashKey.ToString());
\r
438 m_listCtrl->SetItem(nIndex, 2, str2);
\r
439 m_listCtrl->SetItem(nIndex, 3, str3);
\r
440 m_listCtrl->SetItem(nIndex, 4, str4);
\r
441 m_listCtrl->SetItem(nIndex, 5, str5);
\r
442 m_listCtrl->SetItem(nIndex, 6, str6);
\r
443 m_listCtrl->SetItemData(nIndex, nData);
\r
446 bool CMainFrame::DeleteLine(uint256 hashKey)
\r
448 long nData = *(long*)&hashKey;
\r
452 while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)
\r
453 if (GetItemText(m_listCtrl, nIndex, 1) == hashKey.ToString())
\r
457 m_listCtrl->DeleteItem(nIndex);
\r
459 return nIndex != -1;
\r
462 string FormatTxStatus(const CWalletTx& wtx)
\r
465 int nDepth = wtx.GetDepthInMainChain();
\r
466 if (!wtx.IsFinal())
\r
468 if (wtx.nLockTime < 500000000)
\r
469 return strprintf("Open for %d blocks", nBestHeight - wtx.nLockTime);
\r
471 return strprintf("Open until %s", DateTimeStr(wtx.nLockTime).c_str());
\r
473 else if (nDepth < 6)
\r
474 return strprintf("%d/unconfirmed", nDepth);
\r
476 return strprintf("%d blocks", nDepth);
\r
479 string SingleLine(const string& strIn)
\r
482 bool fOneSpace = false;
\r
483 foreach(int c, strIn)
\r
491 if (fOneSpace && !strOut.empty())
\r
500 void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
\r
502 int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime();
\r
503 int64 nCredit = wtx.GetCredit();
\r
504 int64 nDebit = wtx.GetDebit();
\r
505 int64 nNet = nCredit - nDebit;
\r
506 uint256 hash = wtx.GetHash();
\r
507 string strStatus = FormatTxStatus(wtx);
\r
508 map<string, string> mapValue = wtx.mapValue;
\r
511 if (wtx.IsCoinBase())
\r
513 // View->Show Generated
\r
514 if (!fShowGenerated)
\r
517 // Don't show generated coin until confirmed by at least one block after it
\r
518 // so we don't get the user's hopes up until it looks like it's probably accepted.
\r
520 // It is not an error when generated blocks are not accepted. By design,
\r
521 // some percentage of blocks, like 10% or more, will end up not accepted.
\r
522 // This is the normal mechanism by which the network copes with latency.
\r
524 // We display regular transactions right away before any confirmation
\r
525 // because they can always get into some block eventually. Generated coins
\r
526 // are special because if their block is not accepted, they are not valid.
\r
528 if (wtx.GetDepthInMainChain() < 2)
\r
530 // In case it was previously displayed
\r
536 // Find the block the tx is in
\r
537 CBlockIndex* pindex = NULL;
\r
538 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(wtx.hashBlock);
\r
539 if (mi != mapBlockIndex.end())
\r
540 pindex = (*mi).second;
\r
542 // Sort order, unrecorded transactions sort to the top
\r
543 string strSort = strprintf("%010d-%01d-%010u",
\r
544 (pindex ? pindex->nHeight : INT_MAX),
\r
545 (wtx.IsCoinBase() ? 1 : 0),
\r
546 wtx.nTimeReceived);
\r
549 if (nNet > 0 || wtx.IsCoinBase())
\r
554 string strDescription;
\r
556 if (wtx.IsCoinBase())
\r
559 strDescription = "Generated";
\r
562 int64 nUnmatured = 0;
\r
563 foreach(const CTxOut& txout, wtx.vout)
\r
564 nUnmatured += txout.GetCredit();
\r
565 if (wtx.IsInMainChain())
\r
566 strDescription += strprintf(" (%s matures in %d more blocks)", FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
\r
568 strDescription += " (not accepted)";
\r
571 else if (!mapValue["from"].empty() || !mapValue["message"].empty())
\r
573 // Online transaction
\r
574 if (!mapValue["from"].empty())
\r
575 strDescription += "From: " + mapValue["from"];
\r
576 if (!mapValue["message"].empty())
\r
578 if (!strDescription.empty())
\r
579 strDescription += " - ";
\r
580 strDescription += mapValue["message"];
\r
585 // Offline transaction
\r
586 foreach(const CTxOut& txout, wtx.vout)
\r
588 if (txout.IsMine())
\r
590 vector<unsigned char> vchPubKey;
\r
591 if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
\r
593 string strAddress = PubKeyToAddress(vchPubKey);
\r
594 if (mapAddressBook.count(strAddress))
\r
596 //strDescription += "Received payment to ";
\r
597 //strDescription += "Received with address ";
\r
598 strDescription += "From: unknown, To: ";
\r
599 strDescription += strAddress;
\r
600 /// The labeling feature is just too confusing, so I hid it
\r
601 /// by putting it at the end where it runs off the screen.
\r
602 /// It can still be seen by widening the column, or in the
\r
603 /// details dialog.
\r
604 if (!mapAddressBook[strAddress].empty())
\r
605 strDescription += " (" + mapAddressBook[strAddress] + ")";
\r
613 InsertLine(fNew, nIndex, hash, strSort,
\r
615 nTime ? DateTimeStr(nTime) : "",
\r
616 SingleLine(strDescription),
\r
618 FormatMoney(nNet, true));
\r
622 bool fAllFromMe = true;
\r
623 foreach(const CTxIn& txin, wtx.vin)
\r
624 fAllFromMe = fAllFromMe && txin.IsMine();
\r
626 bool fAllToMe = true;
\r
627 foreach(const CTxOut& txout, wtx.vout)
\r
628 fAllToMe = fAllToMe && txout.IsMine();
\r
630 if (fAllFromMe && fAllToMe)
\r
633 int64 nValue = wtx.vout[0].nValue;
\r
634 InsertLine(fNew, nIndex, hash, strSort,
\r
636 nTime ? DateTimeStr(nTime) : "",
\r
637 "Payment to yourself",
\r
638 FormatMoney(nNet - nValue, true),
\r
639 FormatMoney(nValue, true));
\r
641 else if (fAllFromMe)
\r
646 int64 nTxFee = nDebit - wtx.GetValueOut();
\r
647 for (int nOut = 0; nOut < wtx.vout.size(); nOut++)
\r
649 const CTxOut& txout = wtx.vout[nOut];
\r
650 if (txout.IsMine())
\r
654 if (!mapValue["to"].empty())
\r
656 // Online transaction
\r
657 strAddress = mapValue["to"];
\r
661 // Offline transaction
\r
663 if (ExtractHash160(txout.scriptPubKey, hash160))
\r
664 strAddress = Hash160ToAddress(hash160);
\r
667 string strDescription = "To: ";
\r
668 if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
\r
669 strDescription += mapAddressBook[strAddress] + " ";
\r
670 strDescription += strAddress;
\r
671 if (!mapValue["message"].empty())
\r
673 if (!strDescription.empty())
\r
674 strDescription += " - ";
\r
675 strDescription += mapValue["message"];
\r
678 int64 nValue = txout.nValue;
\r
679 if (nOut == 0 && nTxFee > 0)
\r
682 InsertLine(fNew, nIndex, hash, strprintf("%s-%d", strSort.c_str(), nOut),
\r
684 nTime ? DateTimeStr(nTime) : "",
\r
685 SingleLine(strDescription),
\r
686 FormatMoney(-nValue, true),
\r
693 // Mixed debit transaction, can't break down payees
\r
695 bool fAllMine = true;
\r
696 foreach(const CTxOut& txout, wtx.vout)
\r
697 fAllMine = fAllMine && txout.IsMine();
\r
698 foreach(const CTxIn& txin, wtx.vin)
\r
699 fAllMine = fAllMine && txin.IsMine();
\r
701 InsertLine(fNew, nIndex, hash, strSort,
\r
703 nTime ? DateTimeStr(nTime) : "",
\r
705 FormatMoney(nNet, true),
\r
711 void CMainFrame::RefreshStatus()
\r
713 static int nLastTop;
\r
714 int nTop = m_listCtrl->GetTopItem();
\r
715 if (nTop == nLastTop && pindexBestLast == pindexBest)
\r
718 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
721 int nEnd = min(nStart + 100, m_listCtrl->GetItemCount());
\r
722 if (pindexBestLast == pindexBest)
\r
724 if (nStart >= nLastTop && nStart < nLastTop + 100)
\r
725 nStart = nLastTop + 100;
\r
726 if (nEnd >= nLastTop && nEnd < nLastTop + 100)
\r
730 pindexBestLast = pindexBest;
\r
732 for (int nIndex = nStart; nIndex < nEnd; nIndex++)
\r
734 uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1));
\r
735 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
\r
736 if (mi == mapWallet.end())
\r
738 printf("CMainFrame::RefreshStatus() : tx not found in mapWallet\n");
\r
741 const CWalletTx& wtx = (*mi).second;
\r
742 if (wtx.IsCoinBase() || wtx.GetTxTime() != wtx.nTimeDisplayed)
\r
743 InsertTransaction(wtx, false, nIndex);
\r
745 m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx));
\r
750 void CMainFrame::RefreshListCtrl()
\r
752 fRefreshListCtrl = true;
\r
756 void CMainFrame::OnIdle(wxIdleEvent& event)
\r
758 if (fRefreshListCtrl)
\r
760 // Collect list of wallet transactions and sort newest first
\r
761 bool fEntered = false;
\r
762 vector<pair<unsigned int, uint256> > vSorted;
\r
763 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
765 printf("RefreshListCtrl starting\n");
\r
767 fRefreshListCtrl = false;
\r
768 vWalletUpdated.clear();
\r
770 // Do the newest transactions first
\r
771 vSorted.reserve(mapWallet.size());
\r
772 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
\r
774 const CWalletTx& wtx = (*it).second;
\r
775 unsigned int nTime = UINT_MAX - wtx.GetTxTime();
\r
776 vSorted.push_back(make_pair(nTime, (*it).first));
\r
778 m_listCtrl->DeleteAllItems();
\r
783 sort(vSorted.begin(), vSorted.end());
\r
785 // Fill list control
\r
786 for (int i = 0; i < vSorted.size();)
\r
790 bool fEntered = false;
\r
791 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
794 uint256& hash = vSorted[i++].second;
\r
795 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
\r
796 if (mi != mapWallet.end())
\r
797 InsertTransaction((*mi).second, true);
\r
799 if (!fEntered || i == 100 || i % 500 == 0)
\r
803 printf("RefreshListCtrl done\n");
\r
807 // Check for time updates
\r
808 static int64 nLastTime;
\r
809 if (GetTime() > nLastTime + 30)
\r
811 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
813 nLastTime = GetTime();
\r
814 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
\r
816 CWalletTx& wtx = (*it).second;
\r
817 if (wtx.nTimeDisplayed && wtx.nTimeDisplayed != wtx.GetTxTime())
\r
818 InsertTransaction(wtx, false);
\r
825 void CMainFrame::OnPaint(wxPaintEvent& event)
\r
830 void DelayedRepaint(void* parg)
\r
832 static bool fOneThread;
\r
837 MainFrameRepaint();
\r
838 fOneThread = false;
\r
841 void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
\r
843 // Update listctrl contents
\r
844 if (!vWalletUpdated.empty())
\r
846 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
848 foreach(uint256 hash, vWalletUpdated)
\r
850 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
\r
851 if (mi != mapWallet.end())
\r
852 InsertTransaction((*mi).second, false);
\r
854 m_listCtrl->ScrollList(0, INT_MAX);
\r
855 vWalletUpdated.clear();
\r
859 // Update status column of visible items only
\r
862 // Update status bar
\r
863 string strGen = "";
\r
864 if (fGenerateBitcoins)
\r
865 strGen = " Generating";
\r
866 if (fGenerateBitcoins && vNodes.empty())
\r
867 strGen = "(not connected)";
\r
868 m_statusBar->SetStatusText(strGen, 1);
\r
870 string strStatus = strprintf(" %d connections %d blocks %d transactions", vNodes.size(), nBestHeight + 1, m_listCtrl->GetItemCount());
\r
871 m_statusBar->SetStatusText(strStatus, 2);
\r
874 bool fRefreshed = false;
\r
875 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
877 m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " ");
\r
881 // mapWallet was locked, try again later
\r
882 if (!vWalletUpdated.empty() || !fRefreshed)
\r
883 _beginthread(DelayedRepaint, 0, NULL);
\r
885 m_listCtrl->OnPaint(event);
\r
888 void CrossThreadCall(wxCommandEvent& event)
\r
891 pframeMain->GetEventHandler()->AddPendingEvent(event);
\r
894 void CrossThreadCall(int nID, void* pdata)
\r
896 wxCommandEvent event;
\r
898 event.SetClientData(pdata);
\r
900 pframeMain->GetEventHandler()->AddPendingEvent(event);
\r
903 void CMainFrame::OnCrossThreadCall(wxCommandEvent& event)
\r
905 void* pdata = event.GetClientData();
\r
906 switch (event.GetInt())
\r
908 case UICALL_ADDORDER:
\r
913 case UICALL_UPDATEORDER:
\r
920 void CMainFrame::OnMenuFileExit(wxCommandEvent& event)
\r
926 void CMainFrame::OnMenuViewShowGenerated(wxCommandEvent& event)
\r
928 // View->Show Generated
\r
929 fShowGenerated = event.IsChecked();
\r
930 CWalletDB().WriteSetting("fShowGenerated", fShowGenerated);
\r
934 void CMainFrame::OnUpdateUIViewShowGenerated(wxUpdateUIEvent& event)
\r
936 event.Check(fShowGenerated);
\r
939 void CMainFrame::OnMenuOptionsGenerate(wxCommandEvent& event)
\r
941 // Options->Generate Coins
\r
942 GenerateBitcoins(event.IsChecked());
\r
945 void CMainFrame::OnUpdateUIOptionsGenerate(wxUpdateUIEvent& event)
\r
947 event.Check(fGenerateBitcoins);
\r
950 void CMainFrame::OnMenuOptionsChangeYourAddress(wxCommandEvent& event)
\r
952 // Options->Change Your Address
\r
953 OnButtonChange(event);
\r
956 void CMainFrame::OnMenuOptionsOptions(wxCommandEvent& event)
\r
958 // Options->Options
\r
959 COptionsDialog dialog(this);
\r
960 dialog.ShowModal();
\r
963 void CMainFrame::OnMenuHelpAbout(wxCommandEvent& event)
\r
966 CAboutDialog dialog(this);
\r
967 dialog.ShowModal();
\r
970 void CMainFrame::OnButtonSend(wxCommandEvent& event)
\r
980 CSendDialog dialog(this);
\r
981 dialog.ShowModal();
\r
984 void CMainFrame::OnButtonAddressBook(wxCommandEvent& event)
\r
986 // Toolbar: Address Book
\r
987 CAddressBookDialog dialogAddr(this, "", false);
\r
988 if (dialogAddr.ShowModal() == 2)
\r
991 CSendDialog dialogSend(this, dialogAddr.GetAddress());
\r
992 dialogSend.ShowModal();
\r
996 void CMainFrame::OnSetFocusAddress(wxFocusEvent& event)
\r
998 // Automatically select-all when entering window
\r
999 m_textCtrlAddress->SetSelection(-1, -1);
\r
1000 fOnSetFocusAddress = true;
\r
1004 void CMainFrame::OnMouseEventsAddress(wxMouseEvent& event)
\r
1006 if (fOnSetFocusAddress)
\r
1007 m_textCtrlAddress->SetSelection(-1, -1);
\r
1008 fOnSetFocusAddress = false;
\r
1012 void CMainFrame::OnButtonCopy(wxCommandEvent& event)
\r
1014 // Copy address box to clipboard
\r
1015 if (wxTheClipboard->Open())
\r
1017 wxTheClipboard->SetData(new wxTextDataObject(m_textCtrlAddress->GetValue()));
\r
1018 wxTheClipboard->Close();
\r
1022 void CMainFrame::OnButtonChange(wxCommandEvent& event)
\r
1024 CYourAddressDialog dialog(this, string(m_textCtrlAddress->GetValue()));
\r
1025 if (!dialog.ShowModal())
\r
1027 string strAddress = (string)dialog.GetAddress();
\r
1028 if (strAddress != m_textCtrlAddress->GetValue())
\r
1031 if (!AddressToHash160(strAddress, hash160))
\r
1033 if (!mapPubKeys.count(hash160))
\r
1035 CWalletDB().WriteDefaultKey(mapPubKeys[hash160]);
\r
1036 m_textCtrlAddress->SetValue(strAddress);
\r
1040 void CMainFrame::OnListItemActivatedAllTransactions(wxListEvent& event)
\r
1042 uint256 hash((string)GetItemText(m_listCtrl, event.GetIndex(), 1));
\r
1044 CRITICAL_BLOCK(cs_mapWallet)
\r
1046 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
\r
1047 if (mi == mapWallet.end())
\r
1049 printf("CMainFrame::OnListItemActivatedAllTransactions() : tx not found in mapWallet\n");
\r
1052 wtx = (*mi).second;
\r
1054 CTxDetailsDialog dialog(this, wtx);
\r
1055 dialog.ShowModal();
\r
1056 //CTxDetailsDialog* pdialog = new CTxDetailsDialog(this, wtx);
\r
1057 //pdialog->Show();
\r
1060 void CMainFrame::OnListItemActivatedProductsSent(wxListEvent& event)
\r
1062 CProduct& product = *(CProduct*)event.GetItem().GetData();
\r
1063 CEditProductDialog* pdialog = new CEditProductDialog(this);
\r
1064 pdialog->SetProduct(product);
\r
1068 void CMainFrame::OnListItemActivatedOrdersSent(wxListEvent& event)
\r
1070 CWalletTx& order = *(CWalletTx*)event.GetItem().GetData();
\r
1071 CViewOrderDialog* pdialog = new CViewOrderDialog(this, order, false);
\r
1075 void CMainFrame::OnListItemActivatedOrdersReceived(wxListEvent& event)
\r
1077 CWalletTx& order = *(CWalletTx*)event.GetItem().GetData();
\r
1078 CViewOrderDialog* pdialog = new CViewOrderDialog(this, order, true);
\r
1088 //////////////////////////////////////////////////////////////////////////////
\r
1090 // CTxDetailsDialog
\r
1093 CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetailsDialogBase(parent)
\r
1096 strHTML.reserve(4000);
\r
1097 strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
\r
1099 int64 nTime = wtx.GetTxTime();
\r
1100 int64 nCredit = wtx.GetCredit();
\r
1101 int64 nDebit = wtx.GetDebit();
\r
1102 int64 nNet = nCredit - nDebit;
\r
1106 strHTML += "<b>Status:</b> " + FormatTxStatus(wtx) + "<br>";
\r
1107 strHTML += "<b>Date:</b> " + (nTime ? DateTimeStr(nTime) : "") + "<br>";
\r
1113 if (wtx.IsCoinBase())
\r
1115 strHTML += "<b>Source:</b> Generated<br>";
\r
1117 else if (!wtx.mapValue["from"].empty())
\r
1119 // Online transaction
\r
1120 if (!wtx.mapValue["from"].empty())
\r
1121 strHTML += "<b>From:</b> " + HtmlEscape(wtx.mapValue["from"]) + "<br>";
\r
1125 // Offline transaction
\r
1129 foreach(const CTxOut& txout, wtx.vout)
\r
1131 if (txout.IsMine())
\r
1133 vector<unsigned char> vchPubKey;
\r
1134 if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
\r
1136 string strAddress = PubKeyToAddress(vchPubKey);
\r
1137 if (mapAddressBook.count(strAddress))
\r
1139 strHTML += "<b>From:</b> unknown<br>";
\r
1140 strHTML += "<b>To:</b> ";
\r
1141 strHTML += HtmlEscape(strAddress);
\r
1142 if (!mapAddressBook[strAddress].empty())
\r
1143 strHTML += " (yours, label: " + mapAddressBook[strAddress] + ")";
\r
1145 strHTML += " (yours)";
\r
1146 strHTML += "<br>";
\r
1159 string strAddress;
\r
1160 if (!wtx.mapValue["to"].empty())
\r
1162 // Online transaction
\r
1163 strAddress = wtx.mapValue["to"];
\r
1164 strHTML += "<b>To:</b> ";
\r
1165 if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
\r
1166 strHTML += mapAddressBook[strAddress] + " ";
\r
1167 strHTML += HtmlEscape(strAddress) + "<br>";
\r
1174 if (wtx.IsCoinBase() && nCredit == 0)
\r
1179 int64 nUnmatured = 0;
\r
1180 foreach(const CTxOut& txout, wtx.vout)
\r
1181 nUnmatured += txout.GetCredit();
\r
1182 if (wtx.IsInMainChain())
\r
1183 strHTML += strprintf("<b>Credit:</b> (%s matures in %d more blocks)<br>", FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
\r
1185 strHTML += "<b>Credit:</b> (not accepted)<br>";
\r
1187 else if (nNet > 0)
\r
1192 strHTML += "<b>Credit:</b> " + FormatMoney(nNet) + "<br>";
\r
1196 bool fAllFromMe = true;
\r
1197 foreach(const CTxIn& txin, wtx.vin)
\r
1198 fAllFromMe = fAllFromMe && txin.IsMine();
\r
1200 bool fAllToMe = true;
\r
1201 foreach(const CTxOut& txout, wtx.vout)
\r
1202 fAllToMe = fAllToMe && txout.IsMine();
\r
1209 foreach(const CTxOut& txout, wtx.vout)
\r
1211 if (txout.IsMine())
\r
1214 if (wtx.mapValue["to"].empty())
\r
1216 // Offline transaction
\r
1218 if (ExtractHash160(txout.scriptPubKey, hash160))
\r
1220 string strAddress = Hash160ToAddress(hash160);
\r
1221 strHTML += "<b>To:</b> ";
\r
1222 if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
\r
1223 strHTML += mapAddressBook[strAddress] + " ";
\r
1224 strHTML += strAddress;
\r
1225 strHTML += "<br>";
\r
1229 strHTML += "<b>Debit:</b> " + FormatMoney(-txout.nValue) + "<br>";
\r
1234 // Payment to self
\r
1235 int64 nValue = wtx.vout[0].nValue;
\r
1236 strHTML += "<b>Debit:</b> " + FormatMoney(-nValue) + "<br>";
\r
1237 strHTML += "<b>Credit:</b> " + FormatMoney(nValue) + "<br>";
\r
1240 int64 nTxFee = nDebit - wtx.GetValueOut();
\r
1242 strHTML += "<b>Transaction fee:</b> " + FormatMoney(-nTxFee) + "<br>";
\r
1247 // Mixed debit transaction
\r
1249 foreach(const CTxIn& txin, wtx.vin)
\r
1250 if (txin.IsMine())
\r
1251 strHTML += "<b>Debit:</b> " + FormatMoney(-txin.GetDebit()) + "<br>";
\r
1252 foreach(const CTxOut& txout, wtx.vout)
\r
1253 if (txout.IsMine())
\r
1254 strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";
\r
1258 strHTML += "<b>Net amount:</b> " + FormatMoney(nNet, true) + "<br>";
\r
1264 if (!wtx.mapValue["message"].empty())
\r
1265 strHTML += "<br><b>Message:</b><br>" + HtmlEscape(wtx.mapValue["message"], true) + "<br>";
\r
1267 if (wtx.IsCoinBase())
\r
1268 strHTML += "<br>Generated coins must wait 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, it will change to \"not accepted\" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.<br>";
\r
1276 strHTML += "<hr><br>debug print<br><br>";
\r
1277 foreach(const CTxIn& txin, wtx.vin)
\r
1278 if (txin.IsMine())
\r
1279 strHTML += "<b>Debit:</b> " + FormatMoney(-txin.GetDebit()) + "<br>";
\r
1280 foreach(const CTxOut& txout, wtx.vout)
\r
1281 if (txout.IsMine())
\r
1282 strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";
\r
1284 strHTML += "<b>Inputs:</b><br>";
\r
1285 CRITICAL_BLOCK(cs_mapWallet)
\r
1287 foreach(const CTxIn& txin, wtx.vin)
\r
1289 COutPoint prevout = txin.prevout;
\r
1290 map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
\r
1291 if (mi != mapWallet.end())
\r
1293 const CWalletTx& prev = (*mi).second;
\r
1294 if (prevout.n < prev.vout.size())
\r
1296 strHTML += HtmlEscape(prev.ToString(), true);
\r
1297 strHTML += " " + FormatTxStatus(prev) + ", ";
\r
1298 strHTML = strHTML + "IsMine=" + (prev.vout[prevout.n].IsMine() ? "true" : "false") + "<br>";
\r
1304 strHTML += "<br><hr><br><b>Transaction:</b><br>";
\r
1305 strHTML += HtmlEscape(wtx.ToString(), true);
\r
1310 strHTML += "</font></html>";
\r
1311 string(strHTML.begin(), strHTML.end()).swap(strHTML);
\r
1312 m_htmlWin->SetPage(strHTML);
\r
1313 m_buttonOK->SetFocus();
\r
1316 void CTxDetailsDialog::OnButtonOK(wxCommandEvent& event)
\r
1326 //////////////////////////////////////////////////////////////////////////////
\r
1331 COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent)
\r
1333 // Set up list box of page choices
\r
1334 m_listBox->Append("Main");
\r
1335 //m_listBox->Append("Test 2");
\r
1336 m_listBox->SetSelection(0);
\r
1340 m_textCtrlTransactionFee->SetValue(FormatMoney(nTransactionFee));
\r
1341 m_checkBoxLimitProcessors->SetValue(fLimitProcessors);
\r
1342 m_spinCtrlLimitProcessors->Enable(fLimitProcessors);
\r
1343 m_spinCtrlLimitProcessors->SetValue(nLimitProcessors);
\r
1344 int nProcessors = atoi(getenv("NUMBER_OF_PROCESSORS"));
\r
1345 if (nProcessors < 1)
\r
1346 nProcessors = 999;
\r
1347 m_spinCtrlLimitProcessors->SetRange(1, nProcessors);
\r
1348 m_checkBoxStartOnSystemStartup->SetValue(fTmpStartOnSystemStartup = GetStartOnSystemStartup());
\r
1349 m_checkBoxMinimizeToTray->SetValue(fMinimizeToTray);
\r
1350 m_checkBoxMinimizeOnClose->Enable(fMinimizeToTray);
\r
1351 m_checkBoxMinimizeOnClose->SetValue(fMinimizeToTray && fMinimizeOnClose);
\r
1352 fTmpMinimizeOnClose = fMinimizeOnClose;
\r
1353 m_buttonOK->SetFocus();
\r
1356 void COptionsDialog::SelectPage(int nPage)
\r
1358 m_panelMain->Show(nPage == 0);
\r
1359 m_panelTest2->Show(nPage == 1);
\r
1361 m_scrolledWindow->Layout();
\r
1362 m_scrolledWindow->SetScrollbars(0, 0, 0, 0, 0, 0);
\r
1365 void COptionsDialog::OnListBox(wxCommandEvent& event)
\r
1367 SelectPage(event.GetSelection());
\r
1370 void COptionsDialog::OnKillFocusTransactionFee(wxFocusEvent& event)
\r
1372 int64 nTmp = nTransactionFee;
\r
1373 ParseMoney(m_textCtrlTransactionFee->GetValue(), nTmp);
\r
1374 m_textCtrlTransactionFee->SetValue(FormatMoney(nTmp));
\r
1377 void COptionsDialog::OnCheckBoxLimitProcessors(wxCommandEvent& event)
\r
1379 m_spinCtrlLimitProcessors->Enable(event.IsChecked());
\r
1382 void COptionsDialog::OnCheckBoxMinimizeToTray(wxCommandEvent& event)
\r
1384 m_checkBoxMinimizeOnClose->Enable(event.IsChecked());
\r
1386 // Save the value in fTmpMinimizeOnClose so we can
\r
1387 // show the checkbox unchecked when its parent is unchecked
\r
1388 if (event.IsChecked())
\r
1389 m_checkBoxMinimizeOnClose->SetValue(fTmpMinimizeOnClose);
\r
1392 fTmpMinimizeOnClose = m_checkBoxMinimizeOnClose->GetValue();
\r
1393 m_checkBoxMinimizeOnClose->SetValue(false);
\r
1398 void COptionsDialog::OnButtonOK(wxCommandEvent& event)
\r
1400 OnButtonApply(event);
\r
1404 void COptionsDialog::OnButtonCancel(wxCommandEvent& event)
\r
1409 void COptionsDialog::OnButtonApply(wxCommandEvent& event)
\r
1411 CWalletDB walletdb;
\r
1413 int64 nPrevTransactionFee = nTransactionFee;
\r
1414 if (ParseMoney(m_textCtrlTransactionFee->GetValue(), nTransactionFee) && nTransactionFee != nPrevTransactionFee)
\r
1415 walletdb.WriteSetting("nTransactionFee", nTransactionFee);
\r
1417 int nPrevMaxProc = (fLimitProcessors ? nLimitProcessors : INT_MAX);
\r
1418 if (fLimitProcessors != m_checkBoxLimitProcessors->GetValue())
\r
1420 fLimitProcessors = m_checkBoxLimitProcessors->GetValue();
\r
1421 walletdb.WriteSetting("fLimitProcessors", fLimitProcessors);
\r
1423 if (nLimitProcessors != m_spinCtrlLimitProcessors->GetValue())
\r
1425 nLimitProcessors = m_spinCtrlLimitProcessors->GetValue();
\r
1426 walletdb.WriteSetting("nLimitProcessors", nLimitProcessors);
\r
1428 if (fGenerateBitcoins && (fLimitProcessors ? nLimitProcessors : INT_MAX) > nPrevMaxProc)
\r
1429 GenerateBitcoins(fGenerateBitcoins);
\r
1431 if (fTmpStartOnSystemStartup != m_checkBoxStartOnSystemStartup->GetValue())
\r
1433 fTmpStartOnSystemStartup = m_checkBoxStartOnSystemStartup->GetValue();
\r
1434 SetStartOnSystemStartup(fTmpStartOnSystemStartup);
\r
1437 if (fMinimizeToTray != m_checkBoxMinimizeToTray->GetValue())
\r
1439 fMinimizeToTray = m_checkBoxMinimizeToTray->GetValue();
\r
1440 walletdb.WriteSetting("fMinimizeToTray", fMinimizeToTray);
\r
1441 ptaskbaricon->Show(fMinimizeToTray);
\r
1444 if (fMinimizeOnClose != (fMinimizeToTray ? m_checkBoxMinimizeOnClose->GetValue() : fTmpMinimizeOnClose))
\r
1446 fMinimizeOnClose = (fMinimizeToTray ? m_checkBoxMinimizeOnClose->GetValue() : fTmpMinimizeOnClose);
\r
1447 walletdb.WriteSetting("fMinimizeOnClose", fMinimizeOnClose);
\r
1456 //////////////////////////////////////////////////////////////////////////////
\r
1461 CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent)
\r
1463 m_staticTextVersion->SetLabel(strprintf("version 0.%d.%d Beta", VERSION/100, VERSION%100));
\r
1465 // Workaround until upgrade to wxWidgets supporting UTF-8
\r
1466 wxString str = m_staticTextMain->GetLabel();
\r
1467 if (str.Find('Â') != wxNOT_FOUND)
\r
1468 str.Remove(str.Find('Â'), 1);
\r
1469 m_staticTextMain->SetLabel(str);
\r
1472 void CAboutDialog::OnButtonOK(wxCommandEvent& event)
\r
1482 //////////////////////////////////////////////////////////////////////////////
\r
1487 CSendDialog::CSendDialog(wxWindow* parent, const wxString& strAddress) : CSendDialogBase(parent)
\r
1490 m_textCtrlAddress->SetValue(strAddress);
\r
1491 m_choiceTransferType->SetSelection(0);
\r
1492 m_bitmapCheckMark->Show(false);
\r
1493 fEnabledPrev = true;
\r
1494 //// todo: should add a display of your balance for convenience
\r
1497 wxBitmap bmpSend(wxT("send16"), wxBITMAP_TYPE_RESOURCE);
\r
1498 bmpSend.SetMask(new wxMask(wxBitmap(wxT("send16masknoshadow"), wxBITMAP_TYPE_RESOURCE)));
\r
1500 iconSend.CopyFromBitmap(bmpSend);
\r
1501 SetIcon(iconSend);
\r
1503 wxCommandEvent event;
\r
1504 OnTextAddress(event);
\r
1506 // Fixup the tab order
\r
1507 m_buttonPaste->MoveAfterInTabOrder(m_buttonCancel);
\r
1508 m_buttonAddress->MoveAfterInTabOrder(m_buttonPaste);
\r
1512 void CSendDialog::OnTextAddress(wxCommandEvent& event)
\r
1515 bool fBitcoinAddress = IsValidBitcoinAddress(m_textCtrlAddress->GetValue());
\r
1516 m_bitmapCheckMark->Show(fBitcoinAddress);
\r
1518 // Grey out message if bitcoin address
\r
1519 bool fEnable = !fBitcoinAddress;
\r
1520 m_staticTextFrom->Enable(fEnable);
\r
1521 m_textCtrlFrom->Enable(fEnable);
\r
1522 m_staticTextMessage->Enable(fEnable);
\r
1523 m_textCtrlMessage->Enable(fEnable);
\r
1524 m_textCtrlMessage->SetBackgroundColour(wxSystemSettings::GetColour(fEnable ? wxSYS_COLOUR_WINDOW : wxSYS_COLOUR_BTNFACE));
\r
1525 if (!fEnable && fEnabledPrev)
\r
1527 strFromSave = m_textCtrlFrom->GetValue();
\r
1528 strMessageSave = m_textCtrlMessage->GetValue();
\r
1529 m_textCtrlFrom->SetValue("Will appear as \"From: Unknown\"");
\r
1530 m_textCtrlMessage->SetValue("Can't include a message when sending to a Bitcoin address");
\r
1532 else if (fEnable && !fEnabledPrev)
\r
1534 m_textCtrlFrom->SetValue(strFromSave);
\r
1535 m_textCtrlMessage->SetValue(strMessageSave);
\r
1537 fEnabledPrev = fEnable;
\r
1540 void CSendDialog::OnKillFocusAmount(wxFocusEvent& event)
\r
1542 // Reformat the amount
\r
1543 if (m_textCtrlAmount->GetValue().Trim().empty())
\r
1546 if (ParseMoney(m_textCtrlAmount->GetValue(), nTmp))
\r
1547 m_textCtrlAmount->SetValue(FormatMoney(nTmp));
\r
1550 void CSendDialog::OnButtonAddressBook(wxCommandEvent& event)
\r
1552 // Open address book
\r
1553 CAddressBookDialog dialog(this, m_textCtrlAddress->GetValue(), true);
\r
1554 if (dialog.ShowModal())
\r
1555 m_textCtrlAddress->SetValue(dialog.GetAddress());
\r
1558 void CSendDialog::OnButtonPaste(wxCommandEvent& event)
\r
1560 // Copy clipboard to address box
\r
1561 if (wxTheClipboard->Open())
\r
1563 if (wxTheClipboard->IsSupported(wxDF_TEXT))
\r
1565 wxTextDataObject data;
\r
1566 wxTheClipboard->GetData(data);
\r
1567 m_textCtrlAddress->SetValue(data.GetText());
\r
1569 wxTheClipboard->Close();
\r
1573 void CSendDialog::OnButtonSend(wxCommandEvent& event)
\r
1576 string strAddress = (string)m_textCtrlAddress->GetValue();
\r
1580 if (!ParseMoney(m_textCtrlAmount->GetValue(), nValue) || nValue <= 0)
\r
1582 wxMessageBox("Error in amount ", "Send Coins");
\r
1585 if (nValue > GetBalance())
\r
1587 wxMessageBox("Amount exceeds your balance ", "Send Coins");
\r
1590 if (nValue + nTransactionFee > GetBalance())
\r
1592 wxMessageBox(string("Total exceeds your balance when the ") + FormatMoney(nTransactionFee) + " transaction fee is included ", "Send Coins");
\r
1596 // Parse bitcoin address
\r
1598 bool fBitcoinAddress = AddressToHash160(strAddress, hash160);
\r
1600 if (fBitcoinAddress)
\r
1602 // Send to bitcoin address
\r
1603 CScript scriptPubKey;
\r
1604 scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
\r
1606 if (!SendMoney(scriptPubKey, nValue, wtx))
\r
1609 wxMessageBox("Payment sent ", "Sending...");
\r
1613 // Parse IP address
\r
1614 CAddress addr(strAddress.c_str());
\r
1617 wxMessageBox("Invalid address ", "Send Coins");
\r
1622 wtx.mapValue["to"] = strAddress;
\r
1623 wtx.mapValue["from"] = m_textCtrlFrom->GetValue();
\r
1624 wtx.mapValue["message"] = m_textCtrlMessage->GetValue();
\r
1626 // Send to IP address
\r
1627 CSendingDialog* pdialog = new CSendingDialog(this, addr, nValue, wtx);
\r
1628 if (!pdialog->ShowModal())
\r
1632 if (!mapAddressBook.count(strAddress))
\r
1633 SetAddressBookName(strAddress, "");
\r
1638 void CSendDialog::OnButtonCancel(wxCommandEvent& event)
\r
1649 //////////////////////////////////////////////////////////////////////////////
\r
1654 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
\r
1657 nPrice = nPriceIn;
\r
1659 start = wxDateTime::UNow();
\r
1661 fCanCancel = true;
\r
1665 fWorkDone = false;
\r
1667 SetTitle(strprintf("Sending %s to %s...", FormatMoney(nPrice).c_str(), wtx.mapValue["to"].c_str()));
\r
1668 m_textCtrlStatus->SetValue("");
\r
1670 _beginthread(SendingDialogStartTransfer, 0, this);
\r
1673 CSendingDialog::~CSendingDialog()
\r
1675 printf("~CSendingDialog()\n");
\r
1678 void CSendingDialog::Close()
\r
1680 // Last one out turn out the lights.
\r
1681 // fWorkDone signals that work side is done and UI thread should call destroy.
\r
1682 // fUIDone signals that UI window has closed and work thread should call destroy.
\r
1683 // This allows the window to disappear and end modality when cancelled
\r
1684 // without making the user wait for ConnectNode to return. The dialog object
\r
1685 // hangs around in the background until the work thread exits.
\r
1687 EndModal(fSuccess);
\r
1696 void CSendingDialog::OnClose(wxCloseEvent& event)
\r
1698 if (!event.CanVeto() || fWorkDone || fAbort || !fCanCancel)
\r
1705 wxCommandEvent cmdevent;
\r
1706 OnButtonCancel(cmdevent);
\r
1710 void CSendingDialog::OnButtonOK(wxCommandEvent& event)
\r
1716 void CSendingDialog::OnButtonCancel(wxCommandEvent& event)
\r
1722 void CSendingDialog::OnPaint(wxPaintEvent& event)
\r
1724 if (strStatus.size() > 130)
\r
1725 m_textCtrlStatus->SetValue(string("\n") + strStatus);
\r
1727 m_textCtrlStatus->SetValue(string("\n\n") + strStatus);
\r
1728 m_staticTextSending->SetFocus();
\r
1730 m_buttonCancel->Enable(false);
\r
1733 m_buttonOK->Enable(true);
\r
1734 m_buttonOK->SetFocus();
\r
1735 m_buttonCancel->Enable(false);
\r
1737 if (fAbort && fCanCancel && IsShown())
\r
1739 strStatus = "CANCELLED";
\r
1740 m_buttonOK->Enable(true);
\r
1741 m_buttonOK->SetFocus();
\r
1742 m_buttonCancel->Enable(false);
\r
1743 m_buttonCancel->SetLabel("Cancelled");
\r
1745 wxMessageBox("Transfer cancelled ", "Sending...", wxOK, this);
\r
1750 if (fRandSendTest && fWorkDone && fSuccess)
\r
1760 // Everything from here on is not in the UI thread and must only communicate
\r
1761 // with the rest of the dialog through variables and calling repaint.
\r
1764 void CSendingDialog::Repaint()
\r
1767 wxPaintEvent event;
\r
1768 AddPendingEvent(event);
\r
1771 bool CSendingDialog::Status()
\r
1778 if (fAbort && fCanCancel)
\r
1780 strStatus = "CANCELLED";
\r
1788 bool CSendingDialog::Status(const string& str)
\r
1797 bool CSendingDialog::Error(const string& str)
\r
1799 fCanCancel = false;
\r
1801 Status(string("Error: ") + str);
\r
1805 void SendingDialogStartTransfer(void* parg)
\r
1807 ((CSendingDialog*)parg)->StartTransfer();
\r
1810 void CSendingDialog::StartTransfer()
\r
1812 // Make sure we have enough money
\r
1813 if (nPrice + nTransactionFee > GetBalance())
\r
1815 Error("You don't have enough money");
\r
1819 // We may have connected already for product details
\r
1820 if (!Status("Connecting..."))
\r
1822 CNode* pnode = ConnectNode(addr, 5 * 60);
\r
1825 Error("Unable to connect");
\r
1829 // Send order to seller, with response going to OnReply2 via event handler
\r
1830 if (!Status("Requesting public key..."))
\r
1832 pnode->PushRequest("checkorder", wtx, SendingDialogOnReply2, this);
\r
1835 void SendingDialogOnReply2(void* parg, CDataStream& vRecv)
\r
1837 ((CSendingDialog*)parg)->OnReply2(vRecv);
\r
1840 void CSendingDialog::OnReply2(CDataStream& vRecv)
\r
1842 if (!Status("Received public key..."))
\r
1845 CScript scriptPubKey;
\r
1852 string strMessage;
\r
1853 vRecv >> strMessage;
\r
1854 Error("Transfer was not accepted");
\r
1855 //// todo: enlarge the window and enable a hidden white box to put seller's message
\r
1858 vRecv >> scriptPubKey;
\r
1862 //// what do we want to do about this?
\r
1863 Error("Invalid response received");
\r
1867 // Should already be connected
\r
1868 CNode* pnode = ConnectNode(addr, 5 * 60);
\r
1871 Error("Lost connection");
\r
1875 // Pause to give the user a chance to cancel
\r
1876 while (wxDateTime::UNow() < start + wxTimeSpan(0, 0, 0, 2 * 1000))
\r
1883 CRITICAL_BLOCK(cs_main)
\r
1886 if (!Status("Creating transaction..."))
\r
1888 if (nPrice + nTransactionFee > GetBalance())
\r
1890 Error("You don't have enough money");
\r
1894 int64 nFeeRequired;
\r
1895 if (!CreateTransaction(scriptPubKey, nPrice, wtx, key, nFeeRequired))
\r
1897 if (nPrice + nFeeRequired > GetBalance())
\r
1898 Error(strprintf("This is an oversized transaction that requires a transaction fee of %s", FormatMoney(nFeeRequired).c_str()));
\r
1900 Error("Transaction creation failed");
\r
1904 // Last chance to cancel
\r
1908 fCanCancel = false;
\r
1911 fCanCancel = true;
\r
1914 fCanCancel = false;
\r
1916 if (!Status("Sending payment..."))
\r
1920 if (!CommitTransactionSpent(wtx, key))
\r
1922 Error("Error finalizing payment");
\r
1926 // Send payment tx to seller, with response going to OnReply3 via event handler
\r
1927 pnode->PushRequest("submitorder", wtx, SendingDialogOnReply3, this);
\r
1929 // Accept and broadcast transaction
\r
1930 if (!wtx.AcceptTransaction())
\r
1931 printf("ERROR: CSendingDialog : wtxNew.AcceptTransaction() %s failed\n", wtx.GetHash().ToString().c_str());
\r
1932 wtx.RelayWalletTransaction();
\r
1934 Status("Waiting for confirmation...");
\r
1935 MainFrameRepaint();
\r
1939 void SendingDialogOnReply3(void* parg, CDataStream& vRecv)
\r
1941 ((CSendingDialog*)parg)->OnReply3(vRecv);
\r
1944 void CSendingDialog::OnReply3(CDataStream& vRecv)
\r
1952 Error("The payment was sent, but the recipient was unable to verify it.\n"
\r
1953 "The transaction is recorded and will credit to the recipient if it is valid,\n"
\r
1954 "but without comment information.");
\r
1960 //// what do we want to do about this?
\r
1961 Error("Payment was sent, but an invalid response was received");
\r
1967 Status("Payment completed");
\r
1975 //////////////////////////////////////////////////////////////////////////////
\r
1977 // CYourAddressDialog
\r
1980 CYourAddressDialog::CYourAddressDialog(wxWindow* parent, const string& strInitSelected) : CYourAddressDialogBase(parent)
\r
1982 // Init column headers
\r
1983 m_listCtrl->InsertColumn(0, "Label", wxLIST_FORMAT_LEFT, 200);
\r
1984 m_listCtrl->InsertColumn(1, "Bitcoin Address", wxLIST_FORMAT_LEFT, 350);
\r
1985 m_listCtrl->SetFocus();
\r
1987 // Fill listctrl with address book data
\r
1988 CRITICAL_BLOCK(cs_mapKeys)
\r
1990 foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
\r
1992 string strAddress = item.first;
\r
1993 string strName = item.second;
\r
1995 bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
\r
1998 int nIndex = InsertLine(m_listCtrl, strName, strAddress);
\r
1999 if (strAddress == strInitSelected)
\r
2000 m_listCtrl->SetItemState(nIndex, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
\r
2006 wxString CYourAddressDialog::GetAddress()
\r
2008 int nIndex = GetSelection(m_listCtrl);
\r
2011 return GetItemText(m_listCtrl, nIndex, 1);
\r
2014 void CYourAddressDialog::OnListEndLabelEdit(wxListEvent& event)
\r
2016 // Update address book with edited name
\r
2017 if (event.IsEditCancelled())
\r
2019 string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1);
\r
2020 SetAddressBookName(strAddress, string(event.GetText()));
\r
2021 pframeMain->RefreshListCtrl();
\r
2024 void CYourAddressDialog::OnListItemSelected(wxListEvent& event)
\r
2028 void CYourAddressDialog::OnListItemActivated(wxListEvent& event)
\r
2030 // Doubleclick edits item
\r
2031 wxCommandEvent event2;
\r
2032 OnButtonRename(event2);
\r
2035 void CYourAddressDialog::OnButtonRename(wxCommandEvent& event)
\r
2038 int nIndex = GetSelection(m_listCtrl);
\r
2041 string strName = (string)m_listCtrl->GetItemText(nIndex);
\r
2042 string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
\r
2043 CGetTextFromUserDialog dialog(this, "Edit Address Label", "New Label", strName);
\r
2044 if (!dialog.ShowModal())
\r
2046 strName = dialog.GetValue();
\r
2049 SetAddressBookName(strAddress, strName);
\r
2050 m_listCtrl->SetItemText(nIndex, strName);
\r
2051 pframeMain->RefreshListCtrl();
\r
2054 void CYourAddressDialog::OnButtonNew(wxCommandEvent& event)
\r
2057 CGetTextFromUserDialog dialog(this, "New Bitcoin Address", "Label", "");
\r
2058 if (!dialog.ShowModal())
\r
2060 string strName = dialog.GetValue();
\r
2062 // Generate new key
\r
2063 string strAddress = PubKeyToAddress(GenerateNewKey());
\r
2064 SetAddressBookName(strAddress, strName);
\r
2066 // Add to list and select it
\r
2067 int nIndex = InsertLine(m_listCtrl, strName, strAddress);
\r
2068 SetSelection(m_listCtrl, nIndex);
\r
2069 m_listCtrl->SetFocus();
\r
2072 void CYourAddressDialog::OnButtonCopy(wxCommandEvent& event)
\r
2074 // Copy address box to clipboard
\r
2075 if (wxTheClipboard->Open())
\r
2077 wxTheClipboard->SetData(new wxTextDataObject(GetAddress()));
\r
2078 wxTheClipboard->Close();
\r
2082 void CYourAddressDialog::OnButtonOK(wxCommandEvent& event)
\r
2088 void CYourAddressDialog::OnButtonCancel(wxCommandEvent& event)
\r
2094 void CYourAddressDialog::OnClose(wxCloseEvent& event)
\r
2105 //////////////////////////////////////////////////////////////////////////////
\r
2107 // CAddressBookDialog
\r
2110 CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInitSelected, bool fSendingIn) : CAddressBookDialogBase(parent)
\r
2112 fSending = fSendingIn;
\r
2114 m_buttonCancel->Show(false);
\r
2116 // Init column headers
\r
2117 m_listCtrl->InsertColumn(0, "Name", wxLIST_FORMAT_LEFT, 200);
\r
2118 m_listCtrl->InsertColumn(1, "Address", wxLIST_FORMAT_LEFT, 350);
\r
2119 m_listCtrl->SetFocus();
\r
2122 wxBitmap bmpAddressBook(wxT("addressbook16"), wxBITMAP_TYPE_RESOURCE);
\r
2123 bmpAddressBook.SetMask(new wxMask(wxBitmap(wxT("addressbook16mask"), wxBITMAP_TYPE_RESOURCE)));
\r
2124 wxIcon iconAddressBook;
\r
2125 iconAddressBook.CopyFromBitmap(bmpAddressBook);
\r
2126 SetIcon(iconAddressBook);
\r
2128 // Fill listctrl with address book data
\r
2129 CRITICAL_BLOCK(cs_mapKeys)
\r
2131 foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
\r
2133 string strAddress = item.first;
\r
2134 string strName = item.second;
\r
2136 bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
\r
2139 int nIndex = InsertLine(m_listCtrl, strName, strAddress);
\r
2140 if (strAddress == strInitSelected)
\r
2141 m_listCtrl->SetItemState(nIndex, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
\r
2147 wxString CAddressBookDialog::GetAddress()
\r
2149 int nIndex = GetSelection(m_listCtrl);
\r
2152 return GetItemText(m_listCtrl, nIndex, 1);
\r
2155 void CAddressBookDialog::OnListEndLabelEdit(wxListEvent& event)
\r
2157 // Update address book with edited name
\r
2158 if (event.IsEditCancelled())
\r
2160 string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1);
\r
2161 SetAddressBookName(strAddress, string(event.GetText()));
\r
2162 pframeMain->RefreshListCtrl();
\r
2165 void CAddressBookDialog::OnListItemSelected(wxListEvent& event)
\r
2169 void CAddressBookDialog::OnListItemActivated(wxListEvent& event)
\r
2173 // Doubleclick returns selection
\r
2174 EndModal(GetAddress() != "" ? 2 : 0);
\r
2178 // Doubleclick edits item
\r
2179 wxCommandEvent event2;
\r
2180 OnButtonEdit(event2);
\r
2184 bool CAddressBookDialog::CheckIfMine(const string& strAddress, const string& strTitle)
\r
2187 bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
\r
2189 wxMessageBox("This is one of your own addresses for receiving payments and cannot be entered in the address book. ", strTitle);
\r
2193 void CAddressBookDialog::OnButtonEdit(wxCommandEvent& event)
\r
2196 int nIndex = GetSelection(m_listCtrl);
\r
2199 string strName = (string)m_listCtrl->GetItemText(nIndex);
\r
2200 string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
\r
2201 string strAddressOrg = strAddress;
\r
2204 CGetTextFromUserDialog dialog(this, "Edit Address", "Name", strName, "Address", strAddress);
\r
2205 if (!dialog.ShowModal())
\r
2207 strName = dialog.GetValue1();
\r
2208 strAddress = dialog.GetValue2();
\r
2210 while (CheckIfMine(strAddress, "Edit Address"));
\r
2213 if (strAddress != strAddressOrg)
\r
2214 CWalletDB().EraseName(strAddressOrg);
\r
2215 SetAddressBookName(strAddress, strName);
\r
2216 m_listCtrl->SetItem(nIndex, 1, strAddress);
\r
2217 m_listCtrl->SetItemText(nIndex, strName);
\r
2218 pframeMain->RefreshListCtrl();
\r
2221 void CAddressBookDialog::OnButtonNew(wxCommandEvent& event)
\r
2225 string strAddress;
\r
2228 CGetTextFromUserDialog dialog(this, "New Address", "Name", strName, "Address", strAddress);
\r
2229 if (!dialog.ShowModal())
\r
2231 strName = dialog.GetValue1();
\r
2232 strAddress = dialog.GetValue2();
\r
2234 while (CheckIfMine(strAddress, "New Address"));
\r
2236 // Add to list and select it
\r
2237 SetAddressBookName(strAddress, strName);
\r
2238 int nIndex = InsertLine(m_listCtrl, strName, strAddress);
\r
2239 SetSelection(m_listCtrl, nIndex);
\r
2240 m_listCtrl->SetFocus();
\r
2241 pframeMain->RefreshListCtrl();
\r
2244 void CAddressBookDialog::OnButtonDelete(wxCommandEvent& event)
\r
2246 for (int nIndex = m_listCtrl->GetItemCount()-1; nIndex >= 0; nIndex--)
\r
2248 if (m_listCtrl->GetItemState(nIndex, wxLIST_STATE_SELECTED))
\r
2250 string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
\r
2251 CWalletDB().EraseName(strAddress);
\r
2252 m_listCtrl->DeleteItem(nIndex);
\r
2255 pframeMain->RefreshListCtrl();
\r
2258 void CAddressBookDialog::OnButtonCopy(wxCommandEvent& event)
\r
2260 // Copy address box to clipboard
\r
2261 if (wxTheClipboard->Open())
\r
2263 wxTheClipboard->SetData(new wxTextDataObject(GetAddress()));
\r
2264 wxTheClipboard->Close();
\r
2268 void CAddressBookDialog::OnButtonOK(wxCommandEvent& event)
\r
2271 EndModal(GetAddress() != "" ? 1 : 0);
\r
2274 void CAddressBookDialog::OnButtonCancel(wxCommandEvent& event)
\r
2280 void CAddressBookDialog::OnClose(wxCloseEvent& event)
\r
2291 //////////////////////////////////////////////////////////////////////////////
\r
2293 // CProductsDialog
\r
2296 bool CompareIntStringPairBestFirst(const pair<int, string>& item1, const pair<int, string>& item2)
\r
2298 return (item1.first > item2.first);
\r
2301 CProductsDialog::CProductsDialog(wxWindow* parent) : CProductsDialogBase(parent)
\r
2303 // Init column headers
\r
2304 m_listCtrl->InsertColumn(0, "Title", wxLIST_FORMAT_LEFT, 200);
\r
2305 m_listCtrl->InsertColumn(1, "Price", wxLIST_FORMAT_LEFT, 80);
\r
2306 m_listCtrl->InsertColumn(2, "Seller", wxLIST_FORMAT_LEFT, 80);
\r
2307 m_listCtrl->InsertColumn(3, "Stars", wxLIST_FORMAT_LEFT, 50);
\r
2308 m_listCtrl->InsertColumn(4, "Power", wxLIST_FORMAT_LEFT, 50);
\r
2310 // Tally top categories
\r
2311 map<string, int> mapTopCategories;
\r
2312 CRITICAL_BLOCK(cs_mapProducts)
\r
2313 for (map<uint256, CProduct>::iterator mi = mapProducts.begin(); mi != mapProducts.end(); ++mi)
\r
2314 mapTopCategories[(*mi).second.mapValue["category"]]++;
\r
2316 // Sort top categories
\r
2317 vector<pair<int, string> > vTopCategories;
\r
2318 for (map<string, int>::iterator mi = mapTopCategories.begin(); mi != mapTopCategories.end(); ++mi)
\r
2319 vTopCategories.push_back(make_pair((*mi).second, (*mi).first));
\r
2320 sort(vTopCategories.begin(), vTopCategories.end(), CompareIntStringPairBestFirst);
\r
2322 // Fill categories combo box
\r
2324 for (vector<pair<int, string> >::iterator it = vTopCategories.begin(); it != vTopCategories.end() && nLimit-- > 0; ++it)
\r
2325 m_comboBoxCategory->Append((*it).second);
\r
2327 // Fill window with initial search
\r
2328 //wxCommandEvent event;
\r
2329 //OnButtonSearch(event);
\r
2332 void CProductsDialog::OnCombobox(wxCommandEvent& event)
\r
2334 OnButtonSearch(event);
\r
2337 bool CompareProductsBestFirst(const CProduct* p1, const CProduct* p2)
\r
2339 return (p1->nAtoms > p2->nAtoms);
\r
2342 void CProductsDialog::OnButtonSearch(wxCommandEvent& event)
\r
2344 string strCategory = (string)m_comboBoxCategory->GetValue();
\r
2345 string strSearch = (string)m_textCtrlSearch->GetValue();
\r
2347 // Search products
\r
2348 vector<CProduct*> vProductsFound;
\r
2349 CRITICAL_BLOCK(cs_mapProducts)
\r
2351 for (map<uint256, CProduct>::iterator mi = mapProducts.begin(); mi != mapProducts.end(); ++mi)
\r
2353 CProduct& product = (*mi).second;
\r
2354 if (product.mapValue["category"].find(strCategory) != -1)
\r
2356 if (product.mapValue["title"].find(strSearch) != -1 ||
\r
2357 product.mapValue["description"].find(strSearch) != -1 ||
\r
2358 product.mapValue["seller"].find(strSearch) != -1)
\r
2360 vProductsFound.push_back(&product);
\r
2367 sort(vProductsFound.begin(), vProductsFound.end(), CompareProductsBestFirst);
\r
2370 foreach(CProduct* pproduct, vProductsFound)
\r
2372 InsertLine(m_listCtrl,
\r
2373 pproduct->mapValue["title"],
\r
2374 pproduct->mapValue["price"],
\r
2375 pproduct->mapValue["seller"],
\r
2376 pproduct->mapValue["stars"],
\r
2377 itostr(pproduct->nAtoms));
\r
2381 void CProductsDialog::OnListItemActivated(wxListEvent& event)
\r
2383 // Doubleclick opens product
\r
2384 CViewProductDialog* pdialog = new CViewProductDialog(this, m_vProduct[event.GetIndex()]);
\r
2394 //////////////////////////////////////////////////////////////////////////////
\r
2396 // CEditProductDialog
\r
2399 CEditProductDialog::CEditProductDialog(wxWindow* parent) : CEditProductDialogBase(parent)
\r
2401 m_textCtrlLabel[0 ] = m_textCtrlLabel0;
\r
2402 m_textCtrlLabel[1 ] = m_textCtrlLabel1;
\r
2403 m_textCtrlLabel[2 ] = m_textCtrlLabel2;
\r
2404 m_textCtrlLabel[3 ] = m_textCtrlLabel3;
\r
2405 m_textCtrlLabel[4 ] = m_textCtrlLabel4;
\r
2406 m_textCtrlLabel[5 ] = m_textCtrlLabel5;
\r
2407 m_textCtrlLabel[6 ] = m_textCtrlLabel6;
\r
2408 m_textCtrlLabel[7 ] = m_textCtrlLabel7;
\r
2409 m_textCtrlLabel[8 ] = m_textCtrlLabel8;
\r
2410 m_textCtrlLabel[9 ] = m_textCtrlLabel9;
\r
2411 m_textCtrlLabel[10] = m_textCtrlLabel10;
\r
2412 m_textCtrlLabel[11] = m_textCtrlLabel11;
\r
2413 m_textCtrlLabel[12] = m_textCtrlLabel12;
\r
2414 m_textCtrlLabel[13] = m_textCtrlLabel13;
\r
2415 m_textCtrlLabel[14] = m_textCtrlLabel14;
\r
2416 m_textCtrlLabel[15] = m_textCtrlLabel15;
\r
2417 m_textCtrlLabel[16] = m_textCtrlLabel16;
\r
2418 m_textCtrlLabel[17] = m_textCtrlLabel17;
\r
2419 m_textCtrlLabel[18] = m_textCtrlLabel18;
\r
2420 m_textCtrlLabel[19] = m_textCtrlLabel19;
\r
2422 m_textCtrlField[0 ] = m_textCtrlField0;
\r
2423 m_textCtrlField[1 ] = m_textCtrlField1;
\r
2424 m_textCtrlField[2 ] = m_textCtrlField2;
\r
2425 m_textCtrlField[3 ] = m_textCtrlField3;
\r
2426 m_textCtrlField[4 ] = m_textCtrlField4;
\r
2427 m_textCtrlField[5 ] = m_textCtrlField5;
\r
2428 m_textCtrlField[6 ] = m_textCtrlField6;
\r
2429 m_textCtrlField[7 ] = m_textCtrlField7;
\r
2430 m_textCtrlField[8 ] = m_textCtrlField8;
\r
2431 m_textCtrlField[9 ] = m_textCtrlField9;
\r
2432 m_textCtrlField[10] = m_textCtrlField10;
\r
2433 m_textCtrlField[11] = m_textCtrlField11;
\r
2434 m_textCtrlField[12] = m_textCtrlField12;
\r
2435 m_textCtrlField[13] = m_textCtrlField13;
\r
2436 m_textCtrlField[14] = m_textCtrlField14;
\r
2437 m_textCtrlField[15] = m_textCtrlField15;
\r
2438 m_textCtrlField[16] = m_textCtrlField16;
\r
2439 m_textCtrlField[17] = m_textCtrlField17;
\r
2440 m_textCtrlField[18] = m_textCtrlField18;
\r
2441 m_textCtrlField[19] = m_textCtrlField19;
\r
2443 m_buttonDel[0 ] = m_buttonDel0;
\r
2444 m_buttonDel[1 ] = m_buttonDel1;
\r
2445 m_buttonDel[2 ] = m_buttonDel2;
\r
2446 m_buttonDel[3 ] = m_buttonDel3;
\r
2447 m_buttonDel[4 ] = m_buttonDel4;
\r
2448 m_buttonDel[5 ] = m_buttonDel5;
\r
2449 m_buttonDel[6 ] = m_buttonDel6;
\r
2450 m_buttonDel[7 ] = m_buttonDel7;
\r
2451 m_buttonDel[8 ] = m_buttonDel8;
\r
2452 m_buttonDel[9 ] = m_buttonDel9;
\r
2453 m_buttonDel[10] = m_buttonDel10;
\r
2454 m_buttonDel[11] = m_buttonDel11;
\r
2455 m_buttonDel[12] = m_buttonDel12;
\r
2456 m_buttonDel[13] = m_buttonDel13;
\r
2457 m_buttonDel[14] = m_buttonDel14;
\r
2458 m_buttonDel[15] = m_buttonDel15;
\r
2459 m_buttonDel[16] = m_buttonDel16;
\r
2460 m_buttonDel[17] = m_buttonDel17;
\r
2461 m_buttonDel[18] = m_buttonDel18;
\r
2462 m_buttonDel[19] = m_buttonDel19;
\r
2464 for (int i = 1; i < FIELDS_MAX; i++)
\r
2465 ShowLine(i, false);
\r
2470 void CEditProductDialog::LayoutAll()
\r
2472 m_scrolledWindow->Layout();
\r
2473 m_scrolledWindow->GetSizer()->Fit(m_scrolledWindow);
\r
2477 void CEditProductDialog::ShowLine(int i, bool fShow)
\r
2479 m_textCtrlLabel[i]->Show(fShow);
\r
2480 m_textCtrlField[i]->Show(fShow);
\r
2481 m_buttonDel[i]->Show(fShow);
\r
2484 void CEditProductDialog::OnButtonDel0(wxCommandEvent& event) { OnButtonDel(event, 0); }
\r
2485 void CEditProductDialog::OnButtonDel1(wxCommandEvent& event) { OnButtonDel(event, 1); }
\r
2486 void CEditProductDialog::OnButtonDel2(wxCommandEvent& event) { OnButtonDel(event, 2); }
\r
2487 void CEditProductDialog::OnButtonDel3(wxCommandEvent& event) { OnButtonDel(event, 3); }
\r
2488 void CEditProductDialog::OnButtonDel4(wxCommandEvent& event) { OnButtonDel(event, 4); }
\r
2489 void CEditProductDialog::OnButtonDel5(wxCommandEvent& event) { OnButtonDel(event, 5); }
\r
2490 void CEditProductDialog::OnButtonDel6(wxCommandEvent& event) { OnButtonDel(event, 6); }
\r
2491 void CEditProductDialog::OnButtonDel7(wxCommandEvent& event) { OnButtonDel(event, 7); }
\r
2492 void CEditProductDialog::OnButtonDel8(wxCommandEvent& event) { OnButtonDel(event, 8); }
\r
2493 void CEditProductDialog::OnButtonDel9(wxCommandEvent& event) { OnButtonDel(event, 9); }
\r
2494 void CEditProductDialog::OnButtonDel10(wxCommandEvent& event) { OnButtonDel(event, 10); }
\r
2495 void CEditProductDialog::OnButtonDel11(wxCommandEvent& event) { OnButtonDel(event, 11); }
\r
2496 void CEditProductDialog::OnButtonDel12(wxCommandEvent& event) { OnButtonDel(event, 12); }
\r
2497 void CEditProductDialog::OnButtonDel13(wxCommandEvent& event) { OnButtonDel(event, 13); }
\r
2498 void CEditProductDialog::OnButtonDel14(wxCommandEvent& event) { OnButtonDel(event, 14); }
\r
2499 void CEditProductDialog::OnButtonDel15(wxCommandEvent& event) { OnButtonDel(event, 15); }
\r
2500 void CEditProductDialog::OnButtonDel16(wxCommandEvent& event) { OnButtonDel(event, 16); }
\r
2501 void CEditProductDialog::OnButtonDel17(wxCommandEvent& event) { OnButtonDel(event, 17); }
\r
2502 void CEditProductDialog::OnButtonDel18(wxCommandEvent& event) { OnButtonDel(event, 18); }
\r
2503 void CEditProductDialog::OnButtonDel19(wxCommandEvent& event) { OnButtonDel(event, 19); }
\r
2505 void CEditProductDialog::OnButtonDel(wxCommandEvent& event, int n)
\r
2509 m_scrolledWindow->GetViewStart(&x, &y);
\r
2511 for (i = n; i < FIELDS_MAX-1; i++)
\r
2513 m_textCtrlLabel[i]->SetValue(m_textCtrlLabel[i+1]->GetValue());
\r
2514 m_textCtrlField[i]->SetValue(m_textCtrlField[i+1]->GetValue());
\r
2515 if (!m_buttonDel[i+1]->IsShown())
\r
2518 m_textCtrlLabel[i]->SetValue("");
\r
2519 m_textCtrlField[i]->SetValue("");
\r
2520 ShowLine(i, false);
\r
2521 m_buttonAddField->Enable(true);
\r
2523 m_scrolledWindow->Scroll(0, y);
\r
2527 void CEditProductDialog::OnButtonAddField(wxCommandEvent& event)
\r
2529 for (int i = 0; i < FIELDS_MAX; i++)
\r
2531 if (!m_buttonDel[i]->IsShown())
\r
2534 ShowLine(i, true);
\r
2535 if (i == FIELDS_MAX-1)
\r
2536 m_buttonAddField->Enable(false);
\r
2538 m_scrolledWindow->Scroll(0, 99999);
\r
2545 void CEditProductDialog::OnButtonSend(wxCommandEvent& event)
\r
2548 GetProduct(product);
\r
2550 // Sign the detailed product
\r
2551 product.vchPubKeyFrom = keyUser.GetPubKey();
\r
2552 if (!keyUser.Sign(product.GetSigHash(), product.vchSig))
\r
2554 wxMessageBox("Error digitally signing the product ");
\r
2558 // Save detailed product
\r
2559 AddToMyProducts(product);
\r
2561 // Strip down to summary product
\r
2562 product.mapDetails.clear();
\r
2563 product.vOrderForm.clear();
\r
2565 // Sign the summary product
\r
2566 if (!keyUser.Sign(product.GetSigHash(), product.vchSig))
\r
2568 wxMessageBox("Error digitally signing the product ");
\r
2573 if (!product.CheckProduct())
\r
2575 wxMessageBox("Errors found in product ");
\r
2580 AdvertStartPublish(pnodeLocalHost, MSG_PRODUCT, 0, product);
\r
2585 void CEditProductDialog::OnButtonPreview(wxCommandEvent& event)
\r
2588 GetProduct(product);
\r
2589 CViewProductDialog* pdialog = new CViewProductDialog(this, product);
\r
2593 void CEditProductDialog::OnButtonCancel(wxCommandEvent& event)
\r
2598 void CEditProductDialog::SetProduct(const CProduct& productIn)
\r
2600 CProduct product = productIn;
\r
2602 m_comboBoxCategory->SetValue(product.mapValue["category"]);
\r
2603 m_textCtrlTitle->SetValue(product.mapValue["title"]);
\r
2604 m_textCtrlPrice->SetValue(product.mapValue["price"]);
\r
2605 m_textCtrlDescription->SetValue(product.mapValue["description"]);
\r
2606 m_textCtrlInstructions->SetValue(product.mapValue["instructions"]);
\r
2608 for (int i = 0; i < FIELDS_MAX; i++)
\r
2610 bool fUsed = i < product.vOrderForm.size();
\r
2611 m_buttonDel[i]->Show(fUsed);
\r
2612 m_textCtrlLabel[i]->Show(fUsed);
\r
2613 m_textCtrlField[i]->Show(fUsed);
\r
2617 m_textCtrlLabel[i]->SetValue(product.vOrderForm[i].first);
\r
2618 string strControl = product.vOrderForm[i].second;
\r
2619 if (strControl.substr(0, 5) == "text=")
\r
2620 m_textCtrlField[i]->SetValue("");
\r
2621 else if (strControl.substr(0, 7) == "choice=")
\r
2622 m_textCtrlField[i]->SetValue(strControl.substr(7));
\r
2624 m_textCtrlField[i]->SetValue(strControl);
\r
2628 void CEditProductDialog::GetProduct(CProduct& product)
\r
2630 // map<string, string> mapValue;
\r
2631 // vector<pair<string, string> > vOrderForm;
\r
2633 product.mapValue["category"] = m_comboBoxCategory->GetValue().Trim();
\r
2634 product.mapValue["title"] = m_textCtrlTitle->GetValue().Trim();
\r
2635 product.mapValue["price"] = m_textCtrlPrice->GetValue().Trim();
\r
2636 product.mapValue["description"] = m_textCtrlDescription->GetValue().Trim();
\r
2637 product.mapValue["instructions"] = m_textCtrlInstructions->GetValue().Trim();
\r
2639 for (int i = 0; i < FIELDS_MAX; i++)
\r
2641 if (m_buttonDel[i]->IsShown())
\r
2643 string strLabel = (string)m_textCtrlLabel[i]->GetValue().Trim();
\r
2644 string strControl = (string)m_textCtrlField[i]->GetValue();
\r
2645 if (strControl.empty())
\r
2646 strControl = "text=";
\r
2648 strControl = "choice=" + strControl;
\r
2649 product.vOrderForm.push_back(make_pair(strLabel, strControl));
\r
2660 //////////////////////////////////////////////////////////////////////////////
\r
2662 // CViewProductDialog
\r
2665 CViewProductDialog::CViewProductDialog(wxWindow* parent, const CProduct& productIn) : CViewProductDialogBase(parent)
\r
2667 Connect(wxEVT_REPLY1, wxCommandEventHandler(CViewProductDialog::OnReply1), NULL, this);
\r
2668 AddCallbackAvailable(GetEventHandler());
\r
2670 // Fill display with product summary while waiting for details
\r
2671 product = productIn;
\r
2672 UpdateProductDisplay(false);
\r
2674 m_buttonBack->Enable(false);
\r
2675 m_buttonNext->Enable(!product.vOrderForm.empty());
\r
2676 m_htmlWinReviews->Show(true);
\r
2677 m_scrolledWindow->Show(false);
\r
2680 // Request details from seller
\r
2681 _beginthread(ThreadRequestProductDetails, 0, new pair<CProduct, wxEvtHandler*>(product, GetEventHandler()));
\r
2684 CViewProductDialog::~CViewProductDialog()
\r
2686 RemoveCallbackAvailable(GetEventHandler());
\r
2689 void ThreadRequestProductDetails(void* parg)
\r
2691 // Extract parameters
\r
2692 pair<CProduct, wxEvtHandler*>* pitem = (pair<CProduct, wxEvtHandler*>*)parg;
\r
2693 CProduct product = pitem->first;
\r
2694 wxEvtHandler* pevthandler = pitem->second;
\r
2697 // Connect to seller
\r
2698 CNode* pnode = ConnectNode(product.addr, 5 * 60);
\r
2701 CDataStream ssEmpty;
\r
2702 AddPendingReplyEvent1(pevthandler, ssEmpty);
\r
2706 // Request detailed product, with response going to OnReply1 via dialog's event handler
\r
2707 pnode->PushRequest("getdetails", product.GetHash(), AddPendingReplyEvent1, (void*)pevthandler);
\r
2710 void CViewProductDialog::OnReply1(wxCommandEvent& event)
\r
2712 CDataStream ss = GetStreamFromEvent(event);
\r
2715 product.mapValue["description"] = "-- CAN'T CONNECT TO SELLER --\n";
\r
2716 UpdateProductDisplay(true);
\r
2721 CProduct product2;
\r
2728 if (product2.GetHash() != product.GetHash())
\r
2730 if (!product2.CheckSignature())
\r
2735 product.mapValue["description"] = "-- INVALID RESPONSE --\n";
\r
2736 UpdateProductDisplay(true);
\r
2740 product = product2;
\r
2741 UpdateProductDisplay(true);
\r
2744 bool CompareReviewsBestFirst(const CReview* p1, const CReview* p2)
\r
2746 return (p1->nAtoms > p2->nAtoms);
\r
2749 void CViewProductDialog::UpdateProductDisplay(bool fDetails)
\r
2751 // Product and reviews
\r
2753 strHTML.reserve(4000);
\r
2754 strHTML += "<html>\n"
\r
2756 "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"
\r
2759 strHTML += "<b>Category:</b> " + HtmlEscape(product.mapValue["category"]) + "<br>\n";
\r
2760 strHTML += "<b>Title:</b> " + HtmlEscape(product.mapValue["title"]) + "<br>\n";
\r
2761 strHTML += "<b>Price:</b> " + HtmlEscape(product.mapValue["price"]) + "<br>\n";
\r
2764 strHTML += "<b>Loading details...</b><br>\n<br>\n";
\r
2766 strHTML += HtmlEscape(product.mapValue["description"], true) + "<br>\n<br>\n";
\r
2768 strHTML += "<b>Reviews:</b><br>\n<br>\n";
\r
2770 if (!product.vchPubKeyFrom.empty())
\r
2772 CReviewDB reviewdb("r");
\r
2775 vector<CReview> vReviews;
\r
2776 reviewdb.ReadReviews(product.GetUserHash(), vReviews);
\r
2778 // Get reviewer's number of atoms
\r
2779 vector<CReview*> vSortedReviews;
\r
2780 vSortedReviews.reserve(vReviews.size());
\r
2781 for (vector<CReview>::reverse_iterator it = vReviews.rbegin(); it != vReviews.rend(); ++it)
\r
2783 CReview& review = *it;
\r
2785 reviewdb.ReadUser(review.GetUserHash(), user);
\r
2786 review.nAtoms = user.GetAtomCount();
\r
2787 vSortedReviews.push_back(&review);
\r
2793 stable_sort(vSortedReviews.begin(), vSortedReviews.end(), CompareReviewsBestFirst);
\r
2796 foreach(CReview* preview, vSortedReviews)
\r
2798 CReview& review = *preview;
\r
2799 int nStars = atoi(review.mapValue["stars"].c_str());
\r
2800 if (nStars < 1 || nStars > 5)
\r
2803 strHTML += "<b>" + itostr(nStars) + (nStars == 1 ? " star" : " stars") + "</b>";
\r
2804 strHTML += " ";
\r
2805 strHTML += DateStr(atoi64(review.mapValue["date"])) + "<br>\n";
\r
2806 strHTML += HtmlEscape(review.mapValue["review"], true);
\r
2807 strHTML += "<br>\n<br>\n";
\r
2811 strHTML += "</body>\n</html>\n";
\r
2813 // Shrink capacity to fit
\r
2814 string(strHTML.begin(), strHTML.end()).swap(strHTML);
\r
2816 m_htmlWinReviews->SetPage(strHTML);
\r
2818 ///// need to find some other indicator to use so can allow empty order form
\r
2819 if (product.vOrderForm.empty())
\r
2823 m_staticTextInstructions->SetLabel(product.mapValue["instructions"]);
\r
2824 for (int i = 0; i < FIELDS_MAX; i++)
\r
2826 m_staticTextLabel[i] = NULL;
\r
2827 m_textCtrlField[i] = NULL;
\r
2828 m_choiceField[i] = NULL;
\r
2831 // Construct flexgridsizer
\r
2832 wxBoxSizer* bSizer21 = (wxBoxSizer*)m_scrolledWindow->GetSizer();
\r
2833 wxFlexGridSizer* fgSizer;
\r
2834 fgSizer = new wxFlexGridSizer(0, 2, 0, 0);
\r
2835 fgSizer->AddGrowableCol(1);
\r
2836 fgSizer->SetFlexibleDirection(wxBOTH);
\r
2837 fgSizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
\r
2839 // Construct order form fields
\r
2840 wxWindow* windowLast = NULL;
\r
2841 for (int i = 0; i < product.vOrderForm.size(); i++)
\r
2843 string strLabel = product.vOrderForm[i].first;
\r
2844 string strControl = product.vOrderForm[i].second;
\r
2846 if (strLabel.size() < 20)
\r
2847 strLabel.insert(strLabel.begin(), 20 - strLabel.size(), ' ');
\r
2849 m_staticTextLabel[i] = new wxStaticText(m_scrolledWindow, wxID_ANY, strLabel, wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
\r
2850 m_staticTextLabel[i]->Wrap(-1);
\r
2851 fgSizer->Add(m_staticTextLabel[i], 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5);
\r
2853 if (strControl.substr(0, 5) == "text=")
\r
2855 m_textCtrlField[i] = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0);
\r
2856 fgSizer->Add(m_textCtrlField[i], 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5);
\r
2857 windowLast = m_textCtrlField[i];
\r
2859 else if (strControl.substr(0, 7) == "choice=")
\r
2861 vector<string> vChoices;
\r
2862 ParseString(strControl.substr(7), ',', vChoices);
\r
2864 wxArrayString arraystring;
\r
2865 foreach(const string& str, vChoices)
\r
2866 arraystring.Add(str);
\r
2868 m_choiceField[i] = new wxChoice(m_scrolledWindow, wxID_ANY, wxDefaultPosition, wxDefaultSize, arraystring, 0);
\r
2869 fgSizer->Add(m_choiceField[i], 0, wxALL|wxALIGN_CENTER_VERTICAL, 5);
\r
2870 windowLast = m_choiceField[i];
\r
2874 m_textCtrlField[i] = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0);
\r
2875 fgSizer->Add(m_textCtrlField[i], 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5);
\r
2876 m_staticTextLabel[i]->Show(false);
\r
2877 m_textCtrlField[i]->Show(false);
\r
2881 // Insert after instructions and before submit/cancel buttons
\r
2882 bSizer21->Insert(2, fgSizer, 0, wxEXPAND|wxRIGHT|wxLEFT, 5);
\r
2883 m_scrolledWindow->Layout();
\r
2884 bSizer21->Fit(m_scrolledWindow);
\r
2887 // Fixup the tab order
\r
2888 m_buttonSubmitForm->MoveAfterInTabOrder(windowLast);
\r
2889 m_buttonCancelForm->MoveAfterInTabOrder(m_buttonSubmitForm);
\r
2890 //m_buttonBack->MoveAfterInTabOrder(m_buttonCancelForm);
\r
2891 //m_buttonNext->MoveAfterInTabOrder(m_buttonBack);
\r
2892 //m_buttonCancel->MoveAfterInTabOrder(m_buttonNext);
\r
2896 void CViewProductDialog::GetOrder(CWalletTx& wtx)
\r
2899 for (int i = 0; i < product.vOrderForm.size(); i++)
\r
2902 if (m_textCtrlField[i])
\r
2903 strValue = m_textCtrlField[i]->GetValue().Trim();
\r
2905 strValue = m_choiceField[i]->GetStringSelection();
\r
2906 wtx.vOrderForm.push_back(make_pair(m_staticTextLabel[i]->GetLabel(), strValue));
\r
2910 void CViewProductDialog::OnButtonSubmitForm(wxCommandEvent& event)
\r
2912 m_buttonSubmitForm->Enable(false);
\r
2913 m_buttonCancelForm->Enable(false);
\r
2918 CSendingDialog* pdialog = new CSendingDialog(this, product.addr, atoi64(product.mapValue["price"]), wtx);
\r
2919 if (!pdialog->ShowModal())
\r
2921 m_buttonSubmitForm->Enable(true);
\r
2922 m_buttonCancelForm->Enable(true);
\r
2927 void CViewProductDialog::OnButtonCancelForm(wxCommandEvent& event)
\r
2932 void CViewProductDialog::OnButtonBack(wxCommandEvent& event)
\r
2935 m_htmlWinReviews->Show(true);
\r
2936 m_scrolledWindow->Show(false);
\r
2937 m_buttonBack->Enable(false);
\r
2938 m_buttonNext->Enable(!product.vOrderForm.empty());
\r
2943 void CViewProductDialog::OnButtonNext(wxCommandEvent& event)
\r
2945 if (!product.vOrderForm.empty())
\r
2948 m_htmlWinReviews->Show(false);
\r
2949 m_scrolledWindow->Show(true);
\r
2950 m_buttonBack->Enable(true);
\r
2951 m_buttonNext->Enable(false);
\r
2957 void CViewProductDialog::OnButtonCancel(wxCommandEvent& event)
\r
2968 //////////////////////////////////////////////////////////////////////////////
\r
2970 // CViewOrderDialog
\r
2973 CViewOrderDialog::CViewOrderDialog(wxWindow* parent, CWalletTx order, bool fReceived) : CViewOrderDialogBase(parent)
\r
2975 int64 nPrice = (fReceived ? order.GetCredit() : order.GetDebit());
\r
2978 strHTML.reserve(4000);
\r
2979 strHTML += "<html>\n"
\r
2981 "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"
\r
2984 strHTML += "<b>Time:</b> " + HtmlEscape(DateTimeStr(order.nTimeReceived)) + "<br>\n";
\r
2985 strHTML += "<b>Price:</b> " + HtmlEscape(FormatMoney(nPrice)) + "<br>\n";
\r
2986 strHTML += "<b>Status:</b> " + HtmlEscape(FormatTxStatus(order)) + "<br>\n";
\r
2988 strHTML += "<table>\n";
\r
2989 for (int i = 0; i < order.vOrderForm.size(); i++)
\r
2991 strHTML += " <tr><td><b>" + HtmlEscape(order.vOrderForm[i].first) + ":</b></td>";
\r
2992 strHTML += "<td>" + HtmlEscape(order.vOrderForm[i].second) + "</td></tr>\n";
\r
2994 strHTML += "</table>\n";
\r
2996 strHTML += "</body>\n</html>\n";
\r
2998 // Shrink capacity to fit
\r
2999 // (strings are ref counted, so it may live on in SetPage)
\r
3000 string(strHTML.begin(), strHTML.end()).swap(strHTML);
\r
3002 m_htmlWin->SetPage(strHTML);
\r
3005 void CViewOrderDialog::OnButtonOK(wxCommandEvent& event)
\r
3016 //////////////////////////////////////////////////////////////////////////////
\r
3018 // CEditReviewDialog
\r
3021 CEditReviewDialog::CEditReviewDialog(wxWindow* parent) : CEditReviewDialogBase(parent)
\r
3025 void CEditReviewDialog::OnButtonSubmit(wxCommandEvent& event)
\r
3027 if (m_choiceStars->GetSelection() == -1)
\r
3029 wxMessageBox("Please select a rating ");
\r
3034 GetReview(review);
\r
3036 // Sign the review
\r
3037 review.vchPubKeyFrom = keyUser.GetPubKey();
\r
3038 if (!keyUser.Sign(review.GetSigHash(), review.vchSig))
\r
3040 wxMessageBox("Unable to digitally sign the review ");
\r
3045 if (!review.AcceptReview())
\r
3047 wxMessageBox("Save failed ");
\r
3050 RelayMessage(CInv(MSG_REVIEW, review.GetHash()), review);
\r
3055 void CEditReviewDialog::OnButtonCancel(wxCommandEvent& event)
\r
3060 void CEditReviewDialog::GetReview(CReview& review)
\r
3062 review.mapValue["time"] = i64tostr(GetAdjustedTime());
\r
3063 review.mapValue["stars"] = itostr(m_choiceStars->GetSelection()+1);
\r
3064 review.mapValue["review"] = m_textCtrlReview->GetValue();
\r
3073 //////////////////////////////////////////////////////////////////////////////
\r
3080 ID_TASKBAR_RESTORE = 10001,
\r
3081 ID_TASKBAR_GENERATE,
\r
3085 BEGIN_EVENT_TABLE(CMyTaskBarIcon, wxTaskBarIcon)
\r
3086 EVT_TASKBAR_LEFT_DCLICK(CMyTaskBarIcon::OnLeftButtonDClick)
\r
3087 EVT_MENU(ID_TASKBAR_RESTORE, CMyTaskBarIcon::OnMenuRestore)
\r
3088 EVT_MENU(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnMenuGenerate)
\r
3089 EVT_UPDATE_UI(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnUpdateUIGenerate)
\r
3090 EVT_MENU(ID_TASKBAR_EXIT, CMyTaskBarIcon::OnMenuExit)
\r
3093 void CMyTaskBarIcon::Show(bool fShow)
\r
3097 string strTooltip = "Bitcoin";
\r
3098 if (fGenerateBitcoins)
\r
3099 strTooltip = "Bitcoin - Generating";
\r
3100 if (fGenerateBitcoins && vNodes.empty())
\r
3101 strTooltip = "Bitcoin - (not connected)";
\r
3102 SetIcon(wxICON(bitcoin), strTooltip);
\r
3110 void CMyTaskBarIcon::Hide()
\r
3115 void CMyTaskBarIcon::OnLeftButtonDClick(wxTaskBarIconEvent& event)
\r
3120 void CMyTaskBarIcon::OnMenuRestore(wxCommandEvent& event)
\r
3125 void CMyTaskBarIcon::Restore()
\r
3127 pframeMain->Show();
\r
3128 pframeMain->Iconize(false);
\r
3129 pframeMain->Raise();
\r
3132 void CMyTaskBarIcon::OnMenuGenerate(wxCommandEvent& event)
\r
3134 GenerateBitcoins(event.IsChecked());
\r
3137 void CMyTaskBarIcon::OnUpdateUIGenerate(wxUpdateUIEvent& event)
\r
3139 event.Check(fGenerateBitcoins);
\r
3142 void CMyTaskBarIcon::OnMenuExit(wxCommandEvent& event)
\r
3144 pframeMain->Close(true);
\r
3147 void CMyTaskBarIcon::UpdateTooltip()
\r
3149 if (IsIconInstalled())
\r
3153 wxMenu* CMyTaskBarIcon::CreatePopupMenu()
\r
3155 wxMenu* pmenu = new wxMenu;
\r
3156 pmenu->Append(ID_TASKBAR_RESTORE, "&Open Bitcoin");
\r
3157 pmenu->AppendCheckItem(ID_TASKBAR_GENERATE, "&Generate Coins")->Check(fGenerateBitcoins);
\r
3158 #ifndef __WXMAC_OSX__ // Mac has built-in quit menu
\r
3159 pmenu->AppendSeparator();
\r
3160 pmenu->Append(ID_TASKBAR_EXIT, "E&xit");
\r
3177 //////////////////////////////////////////////////////////////////////////////
\r
3182 // Define a new application
\r
3183 class CMyApp: public wxApp
\r
3192 // 2nd-level exception handling: we get all the exceptions occurring in any
\r
3193 // event handler here
\r
3194 virtual bool OnExceptionInMainLoop();
\r
3196 // 3rd, and final, level exception handling: whenever an unhandled
\r
3197 // exception is caught, this function is called
\r
3198 virtual void OnUnhandledException();
\r
3200 // and now for something different: this function is called in case of a
\r
3201 // crash (e.g. dereferencing null pointer, division by 0, ...)
\r
3202 virtual void OnFatalException();
\r
3205 IMPLEMENT_APP(CMyApp)
\r
3207 bool CMyApp::OnInit()
\r
3213 catch (std::exception& e) {
\r
3214 PrintException(&e, "OnInit()");
\r
3216 PrintException(NULL, "OnInit()");
\r
3221 map<string, string> ParseParameters(int argc, char* argv[])
\r
3223 map<string, string> mapArgs;
\r
3224 for (int i = 0; i < argc; i++)
\r
3227 strcpy(psz, argv[i]);
\r
3228 char* pszValue = "";
\r
3229 if (strchr(psz, '='))
\r
3231 pszValue = strchr(psz, '=');
\r
3232 *pszValue++ = '\0';
\r
3235 if (psz[0] == '-')
\r
3237 mapArgs[psz] = pszValue;
\r
3242 bool CMyApp::OnInit2()
\r
3245 // Turn off microsoft heap dump noise for now
\r
3246 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
\r
3247 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
\r
3249 #ifdef __WXDEBUG__
\r
3250 // Disable malfunctioning wxWidgets debug assertion
\r
3251 g_isPainting = 10000;
\r
3255 printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
\r
3256 printf("Bitcoin version %d, Windows version %08x\n", VERSION, GetVersion());
\r
3259 // Limit to single instance per user
\r
3260 // Required to protect the database files if we're going to keep deleting log.*
\r
3262 wxString strMutexName = wxString("Bitcoin.") + getenv("HOMEPATH");
\r
3263 for (int i = 0; i < strMutexName.size(); i++)
\r
3264 if (!isalnum(strMutexName[i]))
\r
3265 strMutexName[i] = '.';
\r
3266 wxSingleInstanceChecker* psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);
\r
3267 if (psingleinstancechecker->IsAnotherRunning())
\r
3269 printf("Existing instance found\n");
\r
3270 unsigned int nStart = GetTime();
\r
3273 // Show the previous instance and exit
\r
3274 HWND hwndPrev = FindWindow("wxWindowClassNR", "Bitcoin");
\r
3277 if (IsIconic(hwndPrev))
\r
3278 ShowWindow(hwndPrev, SW_RESTORE);
\r
3279 SetForegroundWindow(hwndPrev);
\r
3283 if (GetTime() > nStart + 60)
\r
3286 // Resume this instance if the other exits
\r
3287 delete psingleinstancechecker;
\r
3289 psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);
\r
3290 if (!psingleinstancechecker->IsAnotherRunning())
\r
3298 wxImage::AddHandler(new wxPNGHandler);
\r
3299 mapArgs = ParseParameters(argc, argv);
\r
3301 if (mapArgs.count("/datadir"))
\r
3302 strSetDataDir = mapArgs["/datadir"];
\r
3304 if (mapArgs.count("/proxy"))
\r
3305 addrProxy = CAddress(mapArgs["/proxy"].c_str());
\r
3307 if (mapArgs.count("/debug"))
\r
3310 if (mapArgs.count("/dropmessages"))
\r
3312 nDropMessagesTest = atoi(mapArgs["/dropmessages"]);
\r
3313 if (nDropMessagesTest == 0)
\r
3314 nDropMessagesTest = 20;
\r
3317 if (mapArgs.count("/loadblockindextest"))
\r
3320 txdb.LoadBlockIndex();
\r
3326 // Load data files
\r
3330 int64 nStart, nEnd;
\r
3332 printf("Loading addresses...\n");
\r
3333 QueryPerformanceCounter((LARGE_INTEGER*)&nStart);
\r
3334 if (!LoadAddresses())
\r
3335 strErrors += "Error loading addr.dat \n";
\r
3336 QueryPerformanceCounter((LARGE_INTEGER*)&nEnd);
\r
3337 printf(" addresses %20I64d\n", nEnd - nStart);
\r
3339 printf("Loading block index...\n");
\r
3340 QueryPerformanceCounter((LARGE_INTEGER*)&nStart);
\r
3341 if (!LoadBlockIndex())
\r
3342 strErrors += "Error loading blkindex.dat \n";
\r
3343 QueryPerformanceCounter((LARGE_INTEGER*)&nEnd);
\r
3344 printf(" block index %20I64d\n", nEnd - nStart);
\r
3346 printf("Loading wallet...\n");
\r
3347 QueryPerformanceCounter((LARGE_INTEGER*)&nStart);
\r
3348 if (!LoadWallet(fFirstRun))
\r
3349 strErrors += "Error loading wallet.dat \n";
\r
3350 QueryPerformanceCounter((LARGE_INTEGER*)&nEnd);
\r
3351 printf(" wallet %20I64d\n", nEnd - nStart);
\r
3353 printf("Done loading\n");
\r
3356 printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size());
\r
3357 printf("nBestHeight = %d\n", nBestHeight);
\r
3358 printf("mapKeys.size() = %d\n", mapKeys.size());
\r
3359 printf("mapPubKeys.size() = %d\n", mapPubKeys.size());
\r
3360 printf("mapWallet.size() = %d\n", mapWallet.size());
\r
3361 printf("mapAddressBook.size() = %d\n", mapAddressBook.size());
\r
3363 if (!strErrors.empty())
\r
3365 wxMessageBox(strErrors, "Bitcoin");
\r
3370 // Add wallet transactions that aren't already in a block to mapTransactions
\r
3371 ReacceptWalletTransactions();
\r
3376 if (mapArgs.count("/printblockindex") || mapArgs.count("/printblocktree"))
\r
3383 if (mapArgs.count("/gen"))
\r
3385 if (mapArgs["/gen"].empty())
\r
3386 fGenerateBitcoins = true;
\r
3388 fGenerateBitcoins = atoi(mapArgs["/gen"].c_str());
\r
3392 // Create the main frame window
\r
3394 pframeMain = new CMainFrame(NULL);
\r
3395 if (mapArgs.count("/min"))
\r
3396 pframeMain->Iconize(true);
\r
3397 pframeMain->Show(true); // have to show first to get taskbar button to hide
\r
3398 pframeMain->Show(!fMinimizeToTray || !pframeMain->IsIconized());
\r
3399 ptaskbaricon->Show(fMinimizeToTray);
\r
3401 if (!CheckDiskSpace())
\r
3407 //RandAddSeedPerfmon();
\r
3409 if (!StartNode(strErrors))
\r
3410 wxMessageBox(strErrors, "Bitcoin");
\r
3412 GenerateBitcoins(fGenerateBitcoins);
\r
3415 SetStartOnSystemStartup(true);
\r
3421 if (argc >= 2 && stricmp(argv[1], "/send") == 0)
\r
3425 ParseMoney(argv[2], nValue);
\r
3427 string strAddress;
\r
3429 strAddress = argv[3];
\r
3430 CAddress addr(strAddress.c_str());
\r
3433 wtx.mapValue["to"] = strAddress;
\r
3434 wtx.mapValue["from"] = addrLocalHost.ToString();
\r
3435 wtx.mapValue["message"] = "command line send";
\r
3437 // Send to IP address
\r
3438 CSendingDialog* pdialog = new CSendingDialog(pframeMain, addr, nValue, wtx);
\r
3439 if (!pdialog->ShowModal())
\r
3443 if (mapArgs.count("/randsendtest"))
\r
3445 if (!mapArgs["/randsendtest"].empty())
\r
3446 _beginthread(ThreadRandSendTest, 0, new string(mapArgs["/randsendtest"]));
\r
3448 fRandSendTest = true;
\r
3455 int CMyApp::OnExit()
\r
3458 return wxApp::OnExit();
\r
3461 bool CMyApp::OnExceptionInMainLoop()
\r
3467 catch (std::exception& e)
\r
3469 PrintException(&e, "CMyApp::OnExceptionInMainLoop()");
\r
3470 wxLogWarning("Exception %s %s", typeid(e).name(), e.what());
\r
3476 PrintException(NULL, "CMyApp::OnExceptionInMainLoop()");
\r
3477 wxLogWarning("Unknown exception");
\r
3485 void CMyApp::OnUnhandledException()
\r
3487 // this shows how we may let some exception propagate uncaught
\r
3492 catch (std::exception& e)
\r
3494 PrintException(&e, "CMyApp::OnUnhandledException()");
\r
3495 wxLogWarning("Exception %s %s", typeid(e).name(), e.what());
\r
3501 PrintException(NULL, "CMyApp::OnUnhandledException()");
\r
3502 wxLogWarning("Unknown exception");
\r
3508 void CMyApp::OnFatalException()
\r
3510 wxMessageBox("Program has crashed and will terminate. ", "Bitcoin", wxOK | wxICON_ERROR);
\r
3515 void MainFrameRepaint()
\r
3517 // This is called by network code that shouldn't access pframeMain and ptaskbaricon
\r
3518 // directly because it could still be running after the UI is closed.
\r
3521 printf("MainFrameRepaint()\n");
\r
3522 wxPaintEvent event;
\r
3523 pframeMain->Refresh();
\r
3524 pframeMain->AddPendingEvent(event);
\r
3527 ptaskbaricon->UpdateTooltip();
\r
3532 string StartupShortcutPath()
\r
3534 // Get the startup folder shortcut path
\r
3535 char pszLinkPath[MAX_PATH+100];
\r
3536 pszLinkPath[0] = '\0';
\r
3537 SHGetSpecialFolderPath(0, pszLinkPath, CSIDL_STARTUP, 0);
\r
3538 strcat(pszLinkPath, "\\Bitcoin.lnk");
\r
3539 return pszLinkPath;
\r
3542 bool GetStartOnSystemStartup()
\r
3544 return FileExists(StartupShortcutPath().c_str());
\r
3547 void SetStartOnSystemStartup(bool fAutoStart)
\r
3549 // If the shortcut exists already, remove it for updating
\r
3550 remove(StartupShortcutPath().c_str());
\r
3554 CoInitialize(NULL);
\r
3556 // Get a pointer to the IShellLink interface.
\r
3557 HRESULT hres = NULL;
\r
3558 IShellLink* psl = NULL;
\r
3559 hres = CoCreateInstance(CLSID_ShellLink, NULL,
\r
3560 CLSCTX_INPROC_SERVER, IID_IShellLink,
\r
3561 reinterpret_cast<void**>(&psl));
\r
3563 if (SUCCEEDED(hres))
\r
3565 // Get the current executable path
\r
3566 char pszExePath[MAX_PATH];
\r
3567 GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));
\r
3569 // Set the path to the shortcut target
\r
3570 psl->SetPath(pszExePath);
\r
3571 PathRemoveFileSpec(pszExePath);
\r
3572 psl->SetWorkingDirectory(pszExePath);
\r
3573 psl->SetShowCmd(SW_SHOWMINNOACTIVE);
\r
3575 // Query IShellLink for the IPersistFile interface for
\r
3576 // saving the shortcut in persistent storage.
\r
3577 IPersistFile* ppf = NULL;
\r
3578 hres = psl->QueryInterface(IID_IPersistFile,
\r
3579 reinterpret_cast<void**>(&ppf));
\r
3580 if (SUCCEEDED(hres))
\r
3582 WCHAR pwsz[MAX_PATH];
\r
3583 // Ensure that the string is ANSI.
\r
3584 MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().c_str(), -1, pwsz, MAX_PATH);
\r
3585 // Save the link by calling IPersistFile::Save.
\r
3586 hres = ppf->Save(pwsz, TRUE);
\r
3606 // randsendtest to bitcoin address
\r
3607 void ThreadRandSendTest(void* parg)
\r
3609 string strAddress = *(string*)parg;
\r
3611 if (!AddressToHash160(strAddress, hash160))
\r
3613 wxMessageBox(strprintf("ThreadRandSendTest: Bitcoin address '%s' not valid ", strAddress.c_str()));
\r
3619 Sleep(GetRand(30) * 1000 + 100);
\r
3623 wtx.mapValue["to"] = strAddress;
\r
3624 wtx.mapValue["from"] = addrLocalHost.ToString();
\r
3626 wtx.mapValue["message"] = strprintf("randsendtest %d\n", ++nRep);
\r
3629 int64 nValue = (GetRand(9) + 1) * 100 * CENT;
\r
3630 if (GetBalance() < nValue)
\r
3632 wxMessageBox("Out of money ");
\r
3635 nValue += (nRep % 100) * CENT;
\r
3637 // Send to bitcoin address
\r
3638 CScript scriptPubKey;
\r
3639 scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
\r
3641 if (!SendMoney(scriptPubKey, nValue, wtx))
\r
3647 // randsendtest to any connected node
\r
3652 while (vNodes.empty())
\r
3655 CRITICAL_BLOCK(cs_vNodes)
\r
3656 addr = vNodes[GetRand(vNodes.size())]->addr;
\r
3659 wtx.mapValue["to"] = addr.ToString();
\r
3660 wtx.mapValue["from"] = addrLocalHost.ToString();
\r
3662 wtx.mapValue["message"] = strprintf("randsendtest %d\n", ++nRep);
\r
3665 int64 nValue = (GetRand(999) + 1) * CENT;
\r
3666 if (GetBalance() < nValue)
\r
3668 wxMessageBox("Out of money ");
\r
3672 // Send to IP address
\r
3673 CSendingDialog* pdialog = new CSendingDialog(pframeMain, addr, nValue, wtx);
\r
3674 if (!pdialog->Show())
\r
3675 wxMessageBox("ShowModal Failed ");
\r