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 bool fRandSendTest = false;
\r
30 extern int g_isPainting;
\r
33 int fShowGenerated = true;
\r
34 int fMinimizeToTray = true;
\r
35 int fMinimizeOnClose = true;
\r
43 //////////////////////////////////////////////////////////////////////////////
\r
48 void HandleCtrlA(wxKeyEvent& event)
\r
50 // Ctrl-a select all
\r
51 wxTextCtrl* textCtrl = (wxTextCtrl*)event.GetEventObject();
\r
52 if (event.GetModifiers() == wxMOD_CONTROL && event.GetKeyCode() == 'A')
\r
53 textCtrl->SetSelection(-1, -1);
\r
59 //char pszHourFormat[256];
\r
60 //pszHourFormat[0] = '\0';
\r
61 //GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ITIME, pszHourFormat, 256);
\r
62 //return (pszHourFormat[0] != '0');
\r
66 string DateStr(int64 nTime)
\r
68 return (string)wxDateTime((time_t)nTime).FormatDate();
\r
71 string DateTimeStr(int64 nTime)
\r
73 wxDateTime datetime((time_t)nTime);
\r
75 return (string)datetime.Format("%x %H:%M");
\r
77 return (string)datetime.Format("%x ") + itostr((datetime.GetHour() + 11) % 12 + 1) + (string)datetime.Format(":%M %p");
\r
80 wxString GetItemText(wxListCtrl* listCtrl, int nIndex, int nColumn)
\r
82 // Helper to simplify access to listctrl
\r
84 item.m_itemId = nIndex;
\r
85 item.m_col = nColumn;
\r
86 item.m_mask = wxLIST_MASK_TEXT;
\r
87 if (!listCtrl->GetItem(item))
\r
89 return item.GetText();
\r
92 int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1)
\r
94 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
\r
95 listCtrl->SetItem(nIndex, 1, str1);
\r
99 int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
\r
101 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
\r
102 listCtrl->SetItem(nIndex, 1, str1);
\r
103 listCtrl->SetItem(nIndex, 2, str2);
\r
104 listCtrl->SetItem(nIndex, 3, str3);
\r
105 listCtrl->SetItem(nIndex, 4, str4);
\r
109 int InsertLine(wxListCtrl* listCtrl, void* pdata, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
\r
111 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
\r
112 listCtrl->SetItemPtrData(nIndex, (wxUIntPtr)pdata);
\r
113 listCtrl->SetItem(nIndex, 1, str1);
\r
114 listCtrl->SetItem(nIndex, 2, str2);
\r
115 listCtrl->SetItem(nIndex, 3, str3);
\r
116 listCtrl->SetItem(nIndex, 4, str4);
\r
120 void SetSelection(wxListCtrl* listCtrl, int nIndex)
\r
122 int nSize = listCtrl->GetItemCount();
\r
123 long nState = (wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
\r
124 for (int i = 0; i < nSize; i++)
\r
125 listCtrl->SetItemState(i, (i == nIndex ? nState : 0), nState);
\r
128 int GetSelection(wxListCtrl* listCtrl)
\r
130 int nSize = listCtrl->GetItemCount();
\r
131 for (int i = 0; i < nSize; i++)
\r
132 if (listCtrl->GetItemState(i, wxLIST_STATE_FOCUSED))
\r
138 string HtmlEscape(const char* psz, bool fMultiLine=false)
\r
141 for (const char* p = psz; *p; p++)
\r
143 if (*p == '<') len += 4;
\r
144 else if (*p == '>') len += 4;
\r
145 else if (*p == '&') len += 5;
\r
146 else if (*p == '"') len += 6;
\r
147 else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') len += 6;
\r
148 else if (*p == '\n' && fMultiLine) len += 5;
\r
154 for (const char* p = psz; *p; p++)
\r
156 if (*p == '<') str += "<";
\r
157 else if (*p == '>') str += ">";
\r
158 else if (*p == '&') str += "&";
\r
159 else if (*p == '"') str += """;
\r
160 else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') str += " ";
\r
161 else if (*p == '\n' && fMultiLine) str += "<br>\n";
\r
168 string HtmlEscape(const string& str, bool fMultiLine=false)
\r
170 return HtmlEscape(str.c_str(), fMultiLine);
\r
173 void AddToMyProducts(CProduct product)
\r
175 CProduct& productInsert = mapMyProducts[product.GetHash()];
\r
176 productInsert = product;
\r
177 InsertLine(pframeMain->m_listCtrlProductsSent, &productInsert,
\r
178 product.mapValue["category"],
\r
179 product.mapValue["title"].substr(0, 100),
\r
180 product.mapValue["description"].substr(0, 100),
\r
181 product.mapValue["price"],
\r
190 //////////////////////////////////////////////////////////////////////////////
\r
195 set<void*> setCallbackAvailable;
\r
196 CCriticalSection cs_setCallbackAvailable;
\r
198 void AddCallbackAvailable(void* p)
\r
200 CRITICAL_BLOCK(cs_setCallbackAvailable)
\r
201 setCallbackAvailable.insert(p);
\r
204 void RemoveCallbackAvailable(void* p)
\r
206 CRITICAL_BLOCK(cs_setCallbackAvailable)
\r
207 setCallbackAvailable.erase(p);
\r
210 bool IsCallbackAvailable(void* p)
\r
212 CRITICAL_BLOCK(cs_setCallbackAvailable)
\r
213 return setCallbackAvailable.count(p);
\r
217 template<typename T>
\r
218 void AddPendingCustomEvent(wxEvtHandler* pevthandler, int nEventID, const T pbeginIn, const T pendIn)
\r
223 const char* pbegin = (pendIn != pbeginIn) ? &pbeginIn[0] : NULL;
\r
224 const char* pend = pbegin + (pendIn - pbeginIn) * sizeof(pbeginIn[0]);
\r
225 wxCommandEvent event(nEventID);
\r
226 wxString strData(wxChar(0), (pend - pbegin) / sizeof(wxChar) + 1);
\r
227 memcpy(&strData[0], pbegin, pend - pbegin);
\r
228 event.SetString(strData);
\r
229 event.SetInt(pend - pbegin);
\r
231 pevthandler->AddPendingEvent(event);
\r
235 void AddPendingCustomEvent(wxEvtHandler* pevthandler, int nEventID, const T& obj)
\r
239 AddPendingCustomEvent(pevthandler, nEventID, ss.begin(), ss.end());
\r
242 void AddPendingReplyEvent1(void* pevthandler, CDataStream& vRecv)
\r
244 if (IsCallbackAvailable(pevthandler))
\r
245 AddPendingCustomEvent((wxEvtHandler*)pevthandler, wxEVT_REPLY1, vRecv.begin(), vRecv.end());
\r
248 void AddPendingReplyEvent2(void* pevthandler, CDataStream& vRecv)
\r
250 if (IsCallbackAvailable(pevthandler))
\r
251 AddPendingCustomEvent((wxEvtHandler*)pevthandler, wxEVT_REPLY2, vRecv.begin(), vRecv.end());
\r
254 void AddPendingReplyEvent3(void* pevthandler, CDataStream& vRecv)
\r
256 if (IsCallbackAvailable(pevthandler))
\r
257 AddPendingCustomEvent((wxEvtHandler*)pevthandler, wxEVT_REPLY3, vRecv.begin(), vRecv.end());
\r
260 CDataStream GetStreamFromEvent(const wxCommandEvent& event)
\r
262 wxString strData = event.GetString();
\r
263 const char* pszBegin = strData.c_str();
\r
264 return CDataStream(pszBegin, pszBegin + 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 m_choiceFilter->SetSelection(0);
\r
287 m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " ");
\r
288 m_listCtrl->SetFocus();
\r
289 SetIcon(wxICON(bitcoin));
\r
290 ptaskbaricon = new CMyTaskBarIcon();
\r
292 // Init column headers
\r
293 int nDateWidth = DateTimeStr(1229413914).size() * 6 + 8;
\r
294 if (!strstr(DateTimeStr(1229413914).c_str(), "2008"))
\r
296 m_listCtrl->InsertColumn(0, "", wxLIST_FORMAT_LEFT, 0);
\r
297 m_listCtrl->InsertColumn(1, "", wxLIST_FORMAT_LEFT, 0);
\r
298 m_listCtrl->InsertColumn(2, "Status", wxLIST_FORMAT_LEFT, 90);
\r
299 m_listCtrl->InsertColumn(3, "Date", wxLIST_FORMAT_LEFT, nDateWidth);
\r
300 m_listCtrl->InsertColumn(4, "Description", wxLIST_FORMAT_LEFT, 409 - nDateWidth);
\r
301 m_listCtrl->InsertColumn(5, "Debit", wxLIST_FORMAT_RIGHT, 79);
\r
302 m_listCtrl->InsertColumn(6, "Credit", wxLIST_FORMAT_RIGHT, 79);
\r
304 //m_listCtrlProductsSent->InsertColumn(0, "Category", wxLIST_FORMAT_LEFT, 100);
\r
305 //m_listCtrlProductsSent->InsertColumn(1, "Title", wxLIST_FORMAT_LEFT, 100);
\r
306 //m_listCtrlProductsSent->InsertColumn(2, "Description", wxLIST_FORMAT_LEFT, 100);
\r
307 //m_listCtrlProductsSent->InsertColumn(3, "Price", wxLIST_FORMAT_LEFT, 100);
\r
308 //m_listCtrlProductsSent->InsertColumn(4, "", wxLIST_FORMAT_LEFT, 100);
\r
310 //m_listCtrlOrdersSent->InsertColumn(0, "Time", wxLIST_FORMAT_LEFT, 100);
\r
311 //m_listCtrlOrdersSent->InsertColumn(1, "Price", wxLIST_FORMAT_LEFT, 100);
\r
312 //m_listCtrlOrdersSent->InsertColumn(2, "", wxLIST_FORMAT_LEFT, 100);
\r
313 //m_listCtrlOrdersSent->InsertColumn(3, "", wxLIST_FORMAT_LEFT, 100);
\r
314 //m_listCtrlOrdersSent->InsertColumn(4, "", wxLIST_FORMAT_LEFT, 100);
\r
316 //m_listCtrlOrdersReceived->InsertColumn(0, "Time", wxLIST_FORMAT_LEFT, 100);
\r
317 //m_listCtrlOrdersReceived->InsertColumn(1, "Price", wxLIST_FORMAT_LEFT, 100);
\r
318 //m_listCtrlOrdersReceived->InsertColumn(2, "Payment Status", wxLIST_FORMAT_LEFT, 100);
\r
319 //m_listCtrlOrdersReceived->InsertColumn(3, "", wxLIST_FORMAT_LEFT, 100);
\r
320 //m_listCtrlOrdersReceived->InsertColumn(4, "", wxLIST_FORMAT_LEFT, 100);
\r
323 int pnWidths[3] = { -100, 88, 290 };
\r
324 m_statusBar->SetFieldsCount(3, pnWidths);
\r
326 // Fill your address text box
\r
327 vector<unsigned char> vchPubKey;
\r
328 if (CWalletDB("r").ReadDefaultKey(vchPubKey))
\r
329 m_textCtrlAddress->SetValue(PubKeyToAddress(vchPubKey));
\r
331 // Fill listctrl with wallet transactions
\r
335 CMainFrame::~CMainFrame()
\r
338 delete ptaskbaricon;
\r
339 ptaskbaricon = NULL;
\r
342 void Shutdown(void* parg)
\r
344 static CCriticalSection cs_Shutdown;
\r
345 CRITICAL_BLOCK(cs_Shutdown)
\r
348 nTransactionsUpdated++;
\r
353 printf("Bitcoin exiting\n");
\r
358 void CMainFrame::OnClose(wxCloseEvent& event)
\r
360 if (fMinimizeToTray && fMinimizeOnClose && event.CanVeto() && !IsIconized())
\r
362 // Divert close to minimize
\r
369 _beginthread(Shutdown, 0, NULL);
\r
373 void CMainFrame::OnIconize(wxIconizeEvent& event)
\r
375 // Hide the task bar button when minimized.
\r
376 // Event is sent when the frame is minimized or restored.
\r
377 Show(!fMinimizeToTray || !event.Iconized());
\r
380 void CMainFrame::OnMouseEvents(wxMouseEvent& event)
\r
383 RAND_add(&event.m_x, sizeof(event.m_x), 0.25);
\r
384 RAND_add(&event.m_y, sizeof(event.m_y), 0.25);
\r
387 void CMainFrame::OnListColBeginDrag(wxListEvent& event)
\r
389 // Hidden columns not resizeable
\r
390 if (event.GetColumn() <= 1 && !fDebug)
\r
394 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
396 string str0 = strSort;
\r
397 long nData = *(long*)&hashKey;
\r
400 if (!fNew && nIndex == -1)
\r
402 while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)
\r
403 if (GetItemText(m_listCtrl, nIndex, 1) == hashKey.ToString())
\r
407 // fNew is for blind insert, only use if you're sure it's new
\r
408 if (fNew || nIndex == -1)
\r
410 nIndex = m_listCtrl->InsertItem(0, str0);
\r
414 // If sort key changed, must delete and reinsert to make it relocate
\r
415 if (GetItemText(m_listCtrl, nIndex, 0) != str0)
\r
417 m_listCtrl->DeleteItem(nIndex);
\r
418 nIndex = m_listCtrl->InsertItem(0, str0);
\r
422 m_listCtrl->SetItem(nIndex, 1, hashKey.ToString());
\r
423 m_listCtrl->SetItem(nIndex, 2, str2);
\r
424 m_listCtrl->SetItem(nIndex, 3, str3);
\r
425 m_listCtrl->SetItem(nIndex, 4, str4);
\r
426 m_listCtrl->SetItem(nIndex, 5, str5);
\r
427 m_listCtrl->SetItem(nIndex, 6, str6);
\r
428 m_listCtrl->SetItemData(nIndex, nData);
\r
431 bool CMainFrame::DeleteLine(uint256 hashKey)
\r
433 long nData = *(long*)&hashKey;
\r
437 while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)
\r
438 if (GetItemText(m_listCtrl, nIndex, 1) == hashKey.ToString())
\r
442 m_listCtrl->DeleteItem(nIndex);
\r
444 return nIndex != -1;
\r
447 string FormatTxStatus(const CWalletTx& wtx)
\r
450 int nDepth = wtx.GetDepthInMainChain();
\r
451 if (!wtx.IsFinal())
\r
453 if (wtx.nLockTime < 500000000)
\r
454 return strprintf("Open for %d blocks", nBestHeight - wtx.nLockTime);
\r
456 return strprintf("Open until %s", DateTimeStr(wtx.nLockTime).c_str());
\r
458 else if (nDepth < 6)
\r
459 return strprintf("%d/unconfirmed", nDepth);
\r
461 return strprintf("%d blocks", nDepth);
\r
464 string SingleLine(const string& strIn)
\r
467 bool fOneSpace = false;
\r
468 foreach(int c, strIn)
\r
476 if (fOneSpace && !strOut.empty())
\r
485 bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
\r
487 int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime();
\r
488 int64 nCredit = wtx.GetCredit();
\r
489 int64 nDebit = wtx.GetDebit();
\r
490 int64 nNet = nCredit - nDebit;
\r
491 uint256 hash = wtx.GetHash();
\r
492 string strStatus = FormatTxStatus(wtx);
\r
493 map<string, string> mapValue = wtx.mapValue;
\r
494 wtx.nLinesDisplayed = 1;
\r
495 nListViewUpdated++;
\r
498 if (wtx.IsCoinBase())
\r
500 // Don't show generated coin until confirmed by at least one block after it
\r
501 // so we don't get the user's hopes up until it looks like it's probably accepted.
\r
503 // It is not an error when generated blocks are not accepted. By design,
\r
504 // some percentage of blocks, like 10% or more, will end up not accepted.
\r
505 // This is the normal mechanism by which the network copes with latency.
\r
507 // We display regular transactions right away before any confirmation
\r
508 // because they can always get into some block eventually. Generated coins
\r
509 // are special because if their block is not accepted, they are not valid.
\r
511 if (wtx.GetDepthInMainChain() < 2)
\r
513 wtx.nLinesDisplayed = 0;
\r
517 // View->Show Generated
\r
518 if (!fShowGenerated)
\r
522 // Find the block the tx is in
\r
523 CBlockIndex* pindex = NULL;
\r
524 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(wtx.hashBlock);
\r
525 if (mi != mapBlockIndex.end())
\r
526 pindex = (*mi).second;
\r
528 // Sort order, unrecorded transactions sort to the top
\r
529 string strSort = strprintf("%010d-%01d-%010u",
\r
530 (pindex ? pindex->nHeight : INT_MAX),
\r
531 (wtx.IsCoinBase() ? 1 : 0),
\r
532 wtx.nTimeReceived);
\r
535 if (nNet > 0 || wtx.IsCoinBase())
\r
540 string strDescription;
\r
542 if (wtx.IsCoinBase())
\r
545 strDescription = "Generated";
\r
548 int64 nUnmatured = 0;
\r
549 foreach(const CTxOut& txout, wtx.vout)
\r
550 nUnmatured += txout.GetCredit();
\r
551 if (wtx.IsInMainChain())
\r
552 strDescription += strprintf(" (%s matures in %d more blocks)", FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
\r
554 strDescription += " (not accepted)";
\r
557 else if (!mapValue["from"].empty() || !mapValue["message"].empty())
\r
559 // Online transaction
\r
560 if (!mapValue["from"].empty())
\r
561 strDescription += "From: " + mapValue["from"];
\r
562 if (!mapValue["message"].empty())
\r
564 if (!strDescription.empty())
\r
565 strDescription += " - ";
\r
566 strDescription += mapValue["message"];
\r
571 // Offline transaction
\r
572 foreach(const CTxOut& txout, wtx.vout)
\r
574 if (txout.IsMine())
\r
576 vector<unsigned char> vchPubKey;
\r
577 if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
\r
579 string strAddress = PubKeyToAddress(vchPubKey);
\r
580 if (mapAddressBook.count(strAddress))
\r
582 //strDescription += "Received payment to ";
\r
583 //strDescription += "Received with address ";
\r
584 strDescription += "From: unknown, To: ";
\r
585 strDescription += strAddress;
\r
586 /// The labeling feature is just too confusing, so I hid it
\r
587 /// by putting it at the end where it runs off the screen.
\r
588 /// It can still be seen by widening the column, or in the
\r
589 /// details dialog.
\r
590 if (!mapAddressBook[strAddress].empty())
\r
591 strDescription += " (" + mapAddressBook[strAddress] + ")";
\r
599 InsertLine(fNew, nIndex, hash, strSort,
\r
601 nTime ? DateTimeStr(nTime) : "",
\r
602 SingleLine(strDescription),
\r
604 FormatMoney(nNet, true));
\r
608 bool fAllFromMe = true;
\r
609 foreach(const CTxIn& txin, wtx.vin)
\r
610 fAllFromMe = fAllFromMe && txin.IsMine();
\r
612 bool fAllToMe = true;
\r
613 foreach(const CTxOut& txout, wtx.vout)
\r
614 fAllToMe = fAllToMe && txout.IsMine();
\r
616 if (fAllFromMe && fAllToMe)
\r
619 int64 nValue = wtx.vout[0].nValue;
\r
620 InsertLine(fNew, nIndex, hash, strSort,
\r
622 nTime ? DateTimeStr(nTime) : "",
\r
623 "Payment to yourself",
\r
624 FormatMoney(nNet - nValue, true),
\r
625 FormatMoney(nValue, true));
\r
627 else if (fAllFromMe)
\r
632 int64 nTxFee = nDebit - wtx.GetValueOut();
\r
633 wtx.nLinesDisplayed = 0;
\r
634 for (int nOut = 0; nOut < wtx.vout.size(); nOut++)
\r
636 const CTxOut& txout = wtx.vout[nOut];
\r
637 if (txout.IsMine())
\r
641 if (!mapValue["to"].empty())
\r
643 // Online transaction
\r
644 strAddress = mapValue["to"];
\r
648 // Offline transaction
\r
650 if (ExtractHash160(txout.scriptPubKey, hash160))
\r
651 strAddress = Hash160ToAddress(hash160);
\r
654 string strDescription = "To: ";
\r
655 if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
\r
656 strDescription += mapAddressBook[strAddress] + " ";
\r
657 strDescription += strAddress;
\r
658 if (!mapValue["message"].empty())
\r
660 if (!strDescription.empty())
\r
661 strDescription += " - ";
\r
662 strDescription += mapValue["message"];
\r
665 int64 nValue = txout.nValue;
\r
666 if (nOut == 0 && nTxFee > 0)
\r
669 InsertLine(fNew, nIndex, hash, strprintf("%s-%d", strSort.c_str(), nOut),
\r
671 nTime ? DateTimeStr(nTime) : "",
\r
672 SingleLine(strDescription),
\r
673 FormatMoney(-nValue, true),
\r
675 wtx.nLinesDisplayed++;
\r
681 // Mixed debit transaction, can't break down payees
\r
683 bool fAllMine = true;
\r
684 foreach(const CTxOut& txout, wtx.vout)
\r
685 fAllMine = fAllMine && txout.IsMine();
\r
686 foreach(const CTxIn& txin, wtx.vin)
\r
687 fAllMine = fAllMine && txin.IsMine();
\r
689 InsertLine(fNew, nIndex, hash, strSort,
\r
691 nTime ? DateTimeStr(nTime) : "",
\r
693 FormatMoney(nNet, true),
\r
701 void CMainFrame::RefreshListCtrl()
\r
703 fRefreshListCtrl = true;
\r
707 void CMainFrame::OnIdle(wxIdleEvent& event)
\r
709 if (fRefreshListCtrl)
\r
711 // Collect list of wallet transactions and sort newest first
\r
712 bool fEntered = false;
\r
713 vector<pair<unsigned int, uint256> > vSorted;
\r
714 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
716 printf("RefreshListCtrl starting\n");
\r
718 fRefreshListCtrl = false;
\r
719 vWalletUpdated.clear();
\r
721 // Do the newest transactions first
\r
722 vSorted.reserve(mapWallet.size());
\r
723 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
\r
725 const CWalletTx& wtx = (*it).second;
\r
726 unsigned int nTime = UINT_MAX - wtx.GetTxTime();
\r
727 vSorted.push_back(make_pair(nTime, (*it).first));
\r
729 m_listCtrl->DeleteAllItems();
\r
734 sort(vSorted.begin(), vSorted.end());
\r
736 // Fill list control
\r
737 for (int i = 0; i < vSorted.size();)
\r
741 bool fEntered = false;
\r
742 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
745 uint256& hash = vSorted[i++].second;
\r
746 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
\r
747 if (mi != mapWallet.end())
\r
748 InsertTransaction((*mi).second, true);
\r
750 if (!fEntered || i == 100 || i % 500 == 0)
\r
754 printf("RefreshListCtrl done\n");
\r
756 // Update transaction total display
\r
757 MainFrameRepaint();
\r
761 // Check for time updates
\r
762 static int64 nLastTime;
\r
763 if (GetTime() > nLastTime + 30)
\r
765 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
767 nLastTime = GetTime();
\r
768 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
\r
770 CWalletTx& wtx = (*it).second;
\r
771 if (wtx.nTimeDisplayed && wtx.nTimeDisplayed != wtx.GetTxTime())
\r
772 InsertTransaction(wtx, false);
\r
779 void CMainFrame::RefreshStatusColumn()
\r
781 static int nLastTop;
\r
782 static CBlockIndex* pindexLastBest;
\r
783 static unsigned int nLastRefreshed;
\r
785 int nTop = max((int)m_listCtrl->GetTopItem(), 0);
\r
786 if (nTop == nLastTop && pindexLastBest == pindexBest)
\r
789 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
792 int nEnd = min(nStart + 100, m_listCtrl->GetItemCount());
\r
794 if (pindexLastBest == pindexBest && nLastRefreshed == nListViewUpdated)
\r
796 // If no updates, only need to do the part that moved onto the screen
\r
797 if (nStart >= nLastTop && nStart < nLastTop + 100)
\r
798 nStart = nLastTop + 100;
\r
799 if (nEnd >= nLastTop && nEnd < nLastTop + 100)
\r
803 pindexLastBest = pindexBest;
\r
804 nLastRefreshed = nListViewUpdated;
\r
806 for (int nIndex = nStart; nIndex < min(nEnd, m_listCtrl->GetItemCount()); nIndex++)
\r
808 uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1));
\r
809 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
\r
810 if (mi == mapWallet.end())
\r
812 printf("CMainFrame::RefreshStatusColumn() : tx not found in mapWallet\n");
\r
815 CWalletTx& wtx = (*mi).second;
\r
816 if (wtx.IsCoinBase() || wtx.GetTxTime() != wtx.nTimeDisplayed)
\r
818 if (!InsertTransaction(wtx, false, nIndex))
\r
819 m_listCtrl->DeleteItem(nIndex--);
\r
822 m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx));
\r
827 void CMainFrame::OnPaint(wxPaintEvent& event)
\r
833 unsigned int nNeedRepaint = 0;
\r
834 unsigned int nLastRepaint = 0;
\r
835 int64 nLastRepaintTime = 0;
\r
836 int64 nRepaintInterval = 500;
\r
838 void ThreadDelayedRepaint(void* parg)
\r
842 if (nLastRepaint != nNeedRepaint && GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)
\r
844 nLastRepaint = nNeedRepaint;
\r
847 printf("DelayedRepaint\n");
\r
848 wxPaintEvent event;
\r
849 pframeMain->Refresh();
\r
850 pframeMain->AddPendingEvent(event);
\r
853 Sleep(nRepaintInterval);
\r
857 void MainFrameRepaint()
\r
859 // This is called by network code that shouldn't access pframeMain
\r
860 // directly because it could still be running after the UI is closed.
\r
863 // Don't repaint too often
\r
864 static int64 nLastRepaintRequest;
\r
865 if (GetTimeMillis() - nLastRepaintRequest < 100)
\r
870 nLastRepaintRequest = GetTimeMillis();
\r
872 printf("MainFrameRepaint\n");
\r
873 wxPaintEvent event;
\r
874 pframeMain->Refresh();
\r
875 pframeMain->AddPendingEvent(event);
\r
879 void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
\r
882 ptaskbaricon->UpdateTooltip();
\r
887 static int nTransactionCount;
\r
888 bool fPaintedBalance = false;
\r
889 if (GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)
\r
891 nLastRepaint = nNeedRepaint;
\r
892 nLastRepaintTime = GetTimeMillis();
\r
894 // Update listctrl contents
\r
895 if (!vWalletUpdated.empty())
\r
897 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
900 if (m_listCtrl->GetItemCount())
\r
901 strTop = (string)m_listCtrl->GetItemText(0);
\r
902 foreach(uint256 hash, vWalletUpdated)
\r
904 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
\r
905 if (mi != mapWallet.end())
\r
906 InsertTransaction((*mi).second, false);
\r
908 vWalletUpdated.clear();
\r
909 if (m_listCtrl->GetItemCount() && strTop != (string)m_listCtrl->GetItemText(0))
\r
910 m_listCtrl->ScrollList(0, INT_MAX);
\r
915 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
917 fPaintedBalance = true;
\r
918 m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " ");
\r
920 // Count hidden and multi-line transactions
\r
921 nTransactionCount = 0;
\r
922 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
\r
924 CWalletTx& wtx = (*it).second;
\r
925 nTransactionCount += wtx.nLinesDisplayed;
\r
929 if (!vWalletUpdated.empty() || !fPaintedBalance)
\r
932 // Update status column of visible items only
\r
933 RefreshStatusColumn();
\r
935 // Update status bar
\r
936 string strGen = "";
\r
937 if (fGenerateBitcoins)
\r
938 strGen = " Generating";
\r
939 if (fGenerateBitcoins && vNodes.empty())
\r
940 strGen = "(not connected)";
\r
941 m_statusBar->SetStatusText(strGen, 1);
\r
943 string strStatus = strprintf(" %d connections %d blocks %d transactions", vNodes.size(), nBestHeight + 1, nTransactionCount);
\r
944 m_statusBar->SetStatusText(strStatus, 2);
\r
947 m_listCtrl->OnPaint(event);
\r
952 void CrossThreadCall(wxCommandEvent& event)
\r
955 pframeMain->GetEventHandler()->AddPendingEvent(event);
\r
958 void CrossThreadCall(int nID, void* pdata)
\r
960 wxCommandEvent event;
\r
962 event.SetClientData(pdata);
\r
964 pframeMain->GetEventHandler()->AddPendingEvent(event);
\r
967 void CMainFrame::OnCrossThreadCall(wxCommandEvent& event)
\r
969 void* pdata = event.GetClientData();
\r
970 switch (event.GetInt())
\r
972 case UICALL_ADDORDER:
\r
977 case UICALL_UPDATEORDER:
\r
984 void CMainFrame::OnMenuFileExit(wxCommandEvent& event)
\r
990 void CMainFrame::OnMenuViewShowGenerated(wxCommandEvent& event)
\r
992 // View->Show Generated
\r
993 fShowGenerated = event.IsChecked();
\r
994 CWalletDB().WriteSetting("fShowGenerated", fShowGenerated);
\r
998 void CMainFrame::OnUpdateUIViewShowGenerated(wxUpdateUIEvent& event)
\r
1000 event.Check(fShowGenerated);
\r
1003 void CMainFrame::OnMenuOptionsGenerate(wxCommandEvent& event)
\r
1005 // Options->Generate Coins
\r
1006 GenerateBitcoins(event.IsChecked());
\r
1009 void CMainFrame::OnUpdateUIOptionsGenerate(wxUpdateUIEvent& event)
\r
1011 event.Check(fGenerateBitcoins);
\r
1014 void CMainFrame::OnMenuOptionsChangeYourAddress(wxCommandEvent& event)
\r
1016 // Options->Change Your Address
\r
1017 OnButtonChange(event);
\r
1020 void CMainFrame::OnMenuOptionsOptions(wxCommandEvent& event)
\r
1022 // Options->Options
\r
1023 COptionsDialog dialog(this);
\r
1024 dialog.ShowModal();
\r
1027 void CMainFrame::OnMenuHelpAbout(wxCommandEvent& event)
\r
1030 CAboutDialog dialog(this);
\r
1031 dialog.ShowModal();
\r
1034 void CMainFrame::OnButtonSend(wxCommandEvent& event)
\r
1037 CSendDialog dialog(this);
\r
1038 dialog.ShowModal();
\r
1041 void CMainFrame::OnButtonAddressBook(wxCommandEvent& event)
\r
1043 // Toolbar: Address Book
\r
1044 CAddressBookDialog dialogAddr(this, "", false);
\r
1045 if (dialogAddr.ShowModal() == 2)
\r
1048 CSendDialog dialogSend(this, dialogAddr.GetAddress());
\r
1049 dialogSend.ShowModal();
\r
1053 void CMainFrame::OnSetFocusAddress(wxFocusEvent& event)
\r
1055 // Automatically select-all when entering window
\r
1056 m_textCtrlAddress->SetSelection(-1, -1);
\r
1057 fOnSetFocusAddress = true;
\r
1061 void CMainFrame::OnMouseEventsAddress(wxMouseEvent& event)
\r
1063 if (fOnSetFocusAddress)
\r
1064 m_textCtrlAddress->SetSelection(-1, -1);
\r
1065 fOnSetFocusAddress = false;
\r
1069 void CMainFrame::OnButtonCopy(wxCommandEvent& event)
\r
1071 // Copy address box to clipboard
\r
1072 if (wxTheClipboard->Open())
\r
1074 wxTheClipboard->SetData(new wxTextDataObject(m_textCtrlAddress->GetValue()));
\r
1075 wxTheClipboard->Close();
\r
1079 void CMainFrame::OnButtonChange(wxCommandEvent& event)
\r
1081 CYourAddressDialog dialog(this, string(m_textCtrlAddress->GetValue()));
\r
1082 if (!dialog.ShowModal())
\r
1084 string strAddress = (string)dialog.GetAddress();
\r
1085 if (strAddress != m_textCtrlAddress->GetValue())
\r
1088 if (!AddressToHash160(strAddress, hash160))
\r
1090 if (!mapPubKeys.count(hash160))
\r
1092 CWalletDB().WriteDefaultKey(mapPubKeys[hash160]);
\r
1093 m_textCtrlAddress->SetValue(strAddress);
\r
1097 void CMainFrame::OnListItemActivatedAllTransactions(wxListEvent& event)
\r
1099 uint256 hash((string)GetItemText(m_listCtrl, event.GetIndex(), 1));
\r
1101 CRITICAL_BLOCK(cs_mapWallet)
\r
1103 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
\r
1104 if (mi == mapWallet.end())
\r
1106 printf("CMainFrame::OnListItemActivatedAllTransactions() : tx not found in mapWallet\n");
\r
1109 wtx = (*mi).second;
\r
1111 CTxDetailsDialog dialog(this, wtx);
\r
1112 dialog.ShowModal();
\r
1113 //CTxDetailsDialog* pdialog = new CTxDetailsDialog(this, wtx);
\r
1114 //pdialog->Show();
\r
1117 void CMainFrame::OnListItemActivatedProductsSent(wxListEvent& event)
\r
1119 CProduct& product = *(CProduct*)event.GetItem().GetData();
\r
1120 CEditProductDialog* pdialog = new CEditProductDialog(this);
\r
1121 pdialog->SetProduct(product);
\r
1125 void CMainFrame::OnListItemActivatedOrdersSent(wxListEvent& event)
\r
1127 CWalletTx& order = *(CWalletTx*)event.GetItem().GetData();
\r
1128 CViewOrderDialog* pdialog = new CViewOrderDialog(this, order, false);
\r
1132 void CMainFrame::OnListItemActivatedOrdersReceived(wxListEvent& event)
\r
1134 CWalletTx& order = *(CWalletTx*)event.GetItem().GetData();
\r
1135 CViewOrderDialog* pdialog = new CViewOrderDialog(this, order, true);
\r
1145 //////////////////////////////////////////////////////////////////////////////
\r
1147 // CTxDetailsDialog
\r
1150 CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetailsDialogBase(parent)
\r
1153 strHTML.reserve(4000);
\r
1154 strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
\r
1156 int64 nTime = wtx.GetTxTime();
\r
1157 int64 nCredit = wtx.GetCredit();
\r
1158 int64 nDebit = wtx.GetDebit();
\r
1159 int64 nNet = nCredit - nDebit;
\r
1163 strHTML += "<b>Status:</b> " + FormatTxStatus(wtx) + "<br>";
\r
1164 strHTML += "<b>Date:</b> " + (nTime ? DateTimeStr(nTime) : "") + "<br>";
\r
1170 if (wtx.IsCoinBase())
\r
1172 strHTML += "<b>Source:</b> Generated<br>";
\r
1174 else if (!wtx.mapValue["from"].empty())
\r
1176 // Online transaction
\r
1177 if (!wtx.mapValue["from"].empty())
\r
1178 strHTML += "<b>From:</b> " + HtmlEscape(wtx.mapValue["from"]) + "<br>";
\r
1182 // Offline transaction
\r
1186 foreach(const CTxOut& txout, wtx.vout)
\r
1188 if (txout.IsMine())
\r
1190 vector<unsigned char> vchPubKey;
\r
1191 if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
\r
1193 string strAddress = PubKeyToAddress(vchPubKey);
\r
1194 if (mapAddressBook.count(strAddress))
\r
1196 strHTML += "<b>From:</b> unknown<br>";
\r
1197 strHTML += "<b>To:</b> ";
\r
1198 strHTML += HtmlEscape(strAddress);
\r
1199 if (!mapAddressBook[strAddress].empty())
\r
1200 strHTML += " (yours, label: " + mapAddressBook[strAddress] + ")";
\r
1202 strHTML += " (yours)";
\r
1203 strHTML += "<br>";
\r
1216 string strAddress;
\r
1217 if (!wtx.mapValue["to"].empty())
\r
1219 // Online transaction
\r
1220 strAddress = wtx.mapValue["to"];
\r
1221 strHTML += "<b>To:</b> ";
\r
1222 if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
\r
1223 strHTML += mapAddressBook[strAddress] + " ";
\r
1224 strHTML += HtmlEscape(strAddress) + "<br>";
\r
1231 if (wtx.IsCoinBase() && nCredit == 0)
\r
1236 int64 nUnmatured = 0;
\r
1237 foreach(const CTxOut& txout, wtx.vout)
\r
1238 nUnmatured += txout.GetCredit();
\r
1239 if (wtx.IsInMainChain())
\r
1240 strHTML += strprintf("<b>Credit:</b> (%s matures in %d more blocks)<br>", FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
\r
1242 strHTML += "<b>Credit:</b> (not accepted)<br>";
\r
1244 else if (nNet > 0)
\r
1249 strHTML += "<b>Credit:</b> " + FormatMoney(nNet) + "<br>";
\r
1253 bool fAllFromMe = true;
\r
1254 foreach(const CTxIn& txin, wtx.vin)
\r
1255 fAllFromMe = fAllFromMe && txin.IsMine();
\r
1257 bool fAllToMe = true;
\r
1258 foreach(const CTxOut& txout, wtx.vout)
\r
1259 fAllToMe = fAllToMe && txout.IsMine();
\r
1266 foreach(const CTxOut& txout, wtx.vout)
\r
1268 if (txout.IsMine())
\r
1271 if (wtx.mapValue["to"].empty())
\r
1273 // Offline transaction
\r
1275 if (ExtractHash160(txout.scriptPubKey, hash160))
\r
1277 string strAddress = Hash160ToAddress(hash160);
\r
1278 strHTML += "<b>To:</b> ";
\r
1279 if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
\r
1280 strHTML += mapAddressBook[strAddress] + " ";
\r
1281 strHTML += strAddress;
\r
1282 strHTML += "<br>";
\r
1286 strHTML += "<b>Debit:</b> " + FormatMoney(-txout.nValue) + "<br>";
\r
1291 // Payment to self
\r
1292 int64 nValue = wtx.vout[0].nValue;
\r
1293 strHTML += "<b>Debit:</b> " + FormatMoney(-nValue) + "<br>";
\r
1294 strHTML += "<b>Credit:</b> " + FormatMoney(nValue) + "<br>";
\r
1297 int64 nTxFee = nDebit - wtx.GetValueOut();
\r
1299 strHTML += "<b>Transaction fee:</b> " + FormatMoney(-nTxFee) + "<br>";
\r
1304 // Mixed debit transaction
\r
1306 foreach(const CTxIn& txin, wtx.vin)
\r
1307 if (txin.IsMine())
\r
1308 strHTML += "<b>Debit:</b> " + FormatMoney(-txin.GetDebit()) + "<br>";
\r
1309 foreach(const CTxOut& txout, wtx.vout)
\r
1310 if (txout.IsMine())
\r
1311 strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";
\r
1315 strHTML += "<b>Net amount:</b> " + FormatMoney(nNet, true) + "<br>";
\r
1321 if (!wtx.mapValue["message"].empty())
\r
1322 strHTML += "<br><b>Message:</b><br>" + HtmlEscape(wtx.mapValue["message"], true) + "<br>";
\r
1324 if (wtx.IsCoinBase())
\r
1325 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
1333 strHTML += "<hr><br>debug print<br><br>";
\r
1334 foreach(const CTxIn& txin, wtx.vin)
\r
1335 if (txin.IsMine())
\r
1336 strHTML += "<b>Debit:</b> " + FormatMoney(-txin.GetDebit()) + "<br>";
\r
1337 foreach(const CTxOut& txout, wtx.vout)
\r
1338 if (txout.IsMine())
\r
1339 strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";
\r
1341 strHTML += "<b>Inputs:</b><br>";
\r
1342 CRITICAL_BLOCK(cs_mapWallet)
\r
1344 foreach(const CTxIn& txin, wtx.vin)
\r
1346 COutPoint prevout = txin.prevout;
\r
1347 map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
\r
1348 if (mi != mapWallet.end())
\r
1350 const CWalletTx& prev = (*mi).second;
\r
1351 if (prevout.n < prev.vout.size())
\r
1353 strHTML += HtmlEscape(prev.ToString(), true);
\r
1354 strHTML += " " + FormatTxStatus(prev) + ", ";
\r
1355 strHTML = strHTML + "IsMine=" + (prev.vout[prevout.n].IsMine() ? "true" : "false") + "<br>";
\r
1361 strHTML += "<br><hr><br><b>Transaction:</b><br>";
\r
1362 strHTML += HtmlEscape(wtx.ToString(), true);
\r
1367 strHTML += "</font></html>";
\r
1368 string(strHTML.begin(), strHTML.end()).swap(strHTML);
\r
1369 m_htmlWin->SetPage(strHTML);
\r
1370 m_buttonOK->SetFocus();
\r
1373 void CTxDetailsDialog::OnButtonOK(wxCommandEvent& event)
\r
1383 //////////////////////////////////////////////////////////////////////////////
\r
1388 COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent)
\r
1390 // Set up list box of page choices
\r
1391 m_listBox->Append("Main");
\r
1392 //m_listBox->Append("Test 2");
\r
1393 m_listBox->SetSelection(0);
\r
1397 m_textCtrlTransactionFee->SetValue(FormatMoney(nTransactionFee));
\r
1398 m_checkBoxLimitProcessors->SetValue(fLimitProcessors);
\r
1399 m_spinCtrlLimitProcessors->Enable(fLimitProcessors);
\r
1400 m_spinCtrlLimitProcessors->SetValue(nLimitProcessors);
\r
1401 int nProcessors = wxThread::GetCPUCount();
\r
1402 if (nProcessors < 1)
\r
1403 nProcessors = 999;
\r
1404 m_spinCtrlLimitProcessors->SetRange(1, nProcessors);
\r
1405 m_checkBoxStartOnSystemStartup->SetValue(fTmpStartOnSystemStartup = GetStartOnSystemStartup());
\r
1406 m_checkBoxMinimizeToTray->SetValue(fMinimizeToTray);
\r
1407 m_checkBoxMinimizeOnClose->Enable(fMinimizeToTray);
\r
1408 m_checkBoxMinimizeOnClose->SetValue(fMinimizeToTray && fMinimizeOnClose);
\r
1409 fTmpMinimizeOnClose = fMinimizeOnClose;
\r
1410 m_checkBoxUseProxy->SetValue(fUseProxy);
\r
1411 m_textCtrlProxyIP->Enable(fUseProxy);
\r
1412 m_textCtrlProxyPort->Enable(fUseProxy);
\r
1413 m_staticTextProxyIP->Enable(fUseProxy);
\r
1414 m_staticTextProxyPort->Enable(fUseProxy);
\r
1415 m_textCtrlProxyIP->SetValue(addrProxy.ToStringIP());
\r
1416 m_textCtrlProxyPort->SetValue(addrProxy.ToStringPort());
\r
1418 m_buttonOK->SetFocus();
\r
1421 void COptionsDialog::SelectPage(int nPage)
\r
1423 m_panelMain->Show(nPage == 0);
\r
1424 m_panelTest2->Show(nPage == 1);
\r
1426 m_scrolledWindow->Layout();
\r
1427 m_scrolledWindow->SetScrollbars(0, 0, 0, 0, 0, 0);
\r
1430 void COptionsDialog::OnListBox(wxCommandEvent& event)
\r
1432 SelectPage(event.GetSelection());
\r
1435 void COptionsDialog::OnKillFocusTransactionFee(wxFocusEvent& event)
\r
1437 int64 nTmp = nTransactionFee;
\r
1438 ParseMoney(m_textCtrlTransactionFee->GetValue(), nTmp);
\r
1439 m_textCtrlTransactionFee->SetValue(FormatMoney(nTmp));
\r
1442 void COptionsDialog::OnCheckBoxLimitProcessors(wxCommandEvent& event)
\r
1444 m_spinCtrlLimitProcessors->Enable(event.IsChecked());
\r
1447 void COptionsDialog::OnCheckBoxMinimizeToTray(wxCommandEvent& event)
\r
1449 m_checkBoxMinimizeOnClose->Enable(event.IsChecked());
\r
1451 // Save the value in fTmpMinimizeOnClose so we can
\r
1452 // show the checkbox unchecked when its parent is unchecked
\r
1453 if (event.IsChecked())
\r
1454 m_checkBoxMinimizeOnClose->SetValue(fTmpMinimizeOnClose);
\r
1457 fTmpMinimizeOnClose = m_checkBoxMinimizeOnClose->GetValue();
\r
1458 m_checkBoxMinimizeOnClose->SetValue(false);
\r
1463 void COptionsDialog::OnCheckBoxUseProxy(wxCommandEvent& event)
\r
1465 m_textCtrlProxyIP->Enable(event.IsChecked());
\r
1466 m_textCtrlProxyPort->Enable(event.IsChecked());
\r
1467 m_staticTextProxyIP->Enable(event.IsChecked());
\r
1468 m_staticTextProxyPort->Enable(event.IsChecked());
\r
1471 CAddress COptionsDialog::GetProxyAddr()
\r
1473 // Be careful about byte order, addr.ip and addr.port are big endian
\r
1474 CAddress addr(m_textCtrlProxyIP->GetValue() + ":" + m_textCtrlProxyPort->GetValue());
\r
1475 if (addr.ip == INADDR_NONE)
\r
1476 addr.ip = addrProxy.ip;
\r
1477 int nPort = atoi(m_textCtrlProxyPort->GetValue());
\r
1478 addr.port = htons(nPort);
\r
1479 if (nPort <= 0 || nPort > USHRT_MAX)
\r
1480 addr.port = addrProxy.port;
\r
1484 void COptionsDialog::OnKillFocusProxy(wxFocusEvent& event)
\r
1486 m_textCtrlProxyIP->SetValue(GetProxyAddr().ToStringIP());
\r
1487 m_textCtrlProxyPort->SetValue(GetProxyAddr().ToStringPort());
\r
1491 void COptionsDialog::OnButtonOK(wxCommandEvent& event)
\r
1493 OnButtonApply(event);
\r
1497 void COptionsDialog::OnButtonCancel(wxCommandEvent& event)
\r
1502 void COptionsDialog::OnButtonApply(wxCommandEvent& event)
\r
1504 CWalletDB walletdb;
\r
1506 int64 nPrevTransactionFee = nTransactionFee;
\r
1507 if (ParseMoney(m_textCtrlTransactionFee->GetValue(), nTransactionFee) && nTransactionFee != nPrevTransactionFee)
\r
1508 walletdb.WriteSetting("nTransactionFee", nTransactionFee);
\r
1510 int nPrevMaxProc = (fLimitProcessors ? nLimitProcessors : INT_MAX);
\r
1511 if (fLimitProcessors != m_checkBoxLimitProcessors->GetValue())
\r
1513 fLimitProcessors = m_checkBoxLimitProcessors->GetValue();
\r
1514 walletdb.WriteSetting("fLimitProcessors", fLimitProcessors);
\r
1516 if (nLimitProcessors != m_spinCtrlLimitProcessors->GetValue())
\r
1518 nLimitProcessors = m_spinCtrlLimitProcessors->GetValue();
\r
1519 walletdb.WriteSetting("nLimitProcessors", nLimitProcessors);
\r
1521 if (fGenerateBitcoins && (fLimitProcessors ? nLimitProcessors : INT_MAX) > nPrevMaxProc)
\r
1522 GenerateBitcoins(fGenerateBitcoins);
\r
1524 if (fTmpStartOnSystemStartup != m_checkBoxStartOnSystemStartup->GetValue())
\r
1526 fTmpStartOnSystemStartup = m_checkBoxStartOnSystemStartup->GetValue();
\r
1527 SetStartOnSystemStartup(fTmpStartOnSystemStartup);
\r
1530 if (fMinimizeToTray != m_checkBoxMinimizeToTray->GetValue())
\r
1532 fMinimizeToTray = m_checkBoxMinimizeToTray->GetValue();
\r
1533 walletdb.WriteSetting("fMinimizeToTray", fMinimizeToTray);
\r
1534 ptaskbaricon->Show(fMinimizeToTray);
\r
1537 if (fMinimizeOnClose != (fMinimizeToTray ? m_checkBoxMinimizeOnClose->GetValue() : fTmpMinimizeOnClose))
\r
1539 fMinimizeOnClose = (fMinimizeToTray ? m_checkBoxMinimizeOnClose->GetValue() : fTmpMinimizeOnClose);
\r
1540 walletdb.WriteSetting("fMinimizeOnClose", fMinimizeOnClose);
\r
1543 fUseProxy = m_checkBoxUseProxy->GetValue();
\r
1544 walletdb.WriteSetting("fUseProxy", fUseProxy);
\r
1546 addrProxy = GetProxyAddr();
\r
1547 walletdb.WriteSetting("addrProxy", addrProxy);
\r
1555 //////////////////////////////////////////////////////////////////////////////
\r
1560 CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent)
\r
1562 m_staticTextVersion->SetLabel(strprintf("version 0.%d.%d Beta", VERSION/100, VERSION%100));
\r
1564 // Workaround until upgrade to wxWidgets supporting UTF-8
\r
1565 wxString str = m_staticTextMain->GetLabel();
\r
1566 if (str.Find('Â') != wxNOT_FOUND)
\r
1567 str.Remove(str.Find('Â'), 1);
\r
1568 m_staticTextMain->SetLabel(str);
\r
1571 void CAboutDialog::OnButtonOK(wxCommandEvent& event)
\r
1581 //////////////////////////////////////////////////////////////////////////////
\r
1586 CSendDialog::CSendDialog(wxWindow* parent, const wxString& strAddress) : CSendDialogBase(parent)
\r
1589 m_textCtrlAddress->SetValue(strAddress);
\r
1590 m_choiceTransferType->SetSelection(0);
\r
1591 m_bitmapCheckMark->Show(false);
\r
1592 fEnabledPrev = true;
\r
1593 //// todo: should add a display of your balance for convenience
\r
1597 iconSend.CopyFromBitmap(wxBitmap(send16noshadow_xpm));
\r
1598 SetIcon(iconSend);
\r
1600 wxCommandEvent event;
\r
1601 OnTextAddress(event);
\r
1603 // Fixup the tab order
\r
1604 m_buttonPaste->MoveAfterInTabOrder(m_buttonCancel);
\r
1605 m_buttonAddress->MoveAfterInTabOrder(m_buttonPaste);
\r
1609 void CSendDialog::OnTextAddress(wxCommandEvent& event)
\r
1612 bool fBitcoinAddress = IsValidBitcoinAddress(m_textCtrlAddress->GetValue());
\r
1613 m_bitmapCheckMark->Show(fBitcoinAddress);
\r
1615 // Grey out message if bitcoin address
\r
1616 bool fEnable = !fBitcoinAddress;
\r
1617 m_staticTextFrom->Enable(fEnable);
\r
1618 m_textCtrlFrom->Enable(fEnable);
\r
1619 m_staticTextMessage->Enable(fEnable);
\r
1620 m_textCtrlMessage->Enable(fEnable);
\r
1621 m_textCtrlMessage->SetBackgroundColour(wxSystemSettings::GetColour(fEnable ? wxSYS_COLOUR_WINDOW : wxSYS_COLOUR_BTNFACE));
\r
1622 if (!fEnable && fEnabledPrev)
\r
1624 strFromSave = m_textCtrlFrom->GetValue();
\r
1625 strMessageSave = m_textCtrlMessage->GetValue();
\r
1626 m_textCtrlFrom->SetValue("Will appear as \"From: Unknown\"");
\r
1627 m_textCtrlMessage->SetValue("Can't include a message when sending to a Bitcoin address");
\r
1629 else if (fEnable && !fEnabledPrev)
\r
1631 m_textCtrlFrom->SetValue(strFromSave);
\r
1632 m_textCtrlMessage->SetValue(strMessageSave);
\r
1634 fEnabledPrev = fEnable;
\r
1637 void CSendDialog::OnKillFocusAmount(wxFocusEvent& event)
\r
1639 // Reformat the amount
\r
1640 if (m_textCtrlAmount->GetValue().Trim().empty())
\r
1643 if (ParseMoney(m_textCtrlAmount->GetValue(), nTmp))
\r
1644 m_textCtrlAmount->SetValue(FormatMoney(nTmp));
\r
1647 void CSendDialog::OnButtonAddressBook(wxCommandEvent& event)
\r
1649 // Open address book
\r
1650 CAddressBookDialog dialog(this, m_textCtrlAddress->GetValue(), true);
\r
1651 if (dialog.ShowModal())
\r
1652 m_textCtrlAddress->SetValue(dialog.GetAddress());
\r
1655 void CSendDialog::OnButtonPaste(wxCommandEvent& event)
\r
1657 // Copy clipboard to address box
\r
1658 if (wxTheClipboard->Open())
\r
1660 if (wxTheClipboard->IsSupported(wxDF_TEXT))
\r
1662 wxTextDataObject data;
\r
1663 wxTheClipboard->GetData(data);
\r
1664 m_textCtrlAddress->SetValue(data.GetText());
\r
1666 wxTheClipboard->Close();
\r
1670 void CSendDialog::OnButtonSend(wxCommandEvent& event)
\r
1673 string strAddress = (string)m_textCtrlAddress->GetValue();
\r
1677 if (!ParseMoney(m_textCtrlAmount->GetValue(), nValue) || nValue <= 0)
\r
1679 wxMessageBox("Error in amount ", "Send Coins");
\r
1682 if (nValue > GetBalance())
\r
1684 wxMessageBox("Amount exceeds your balance ", "Send Coins");
\r
1687 if (nValue + nTransactionFee > GetBalance())
\r
1689 wxMessageBox(string("Total exceeds your balance when the ") + FormatMoney(nTransactionFee) + " transaction fee is included ", "Send Coins");
\r
1693 // Parse bitcoin address
\r
1695 bool fBitcoinAddress = AddressToHash160(strAddress, hash160);
\r
1697 if (fBitcoinAddress)
\r
1699 // Send to bitcoin address
\r
1700 CScript scriptPubKey;
\r
1701 scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
\r
1703 if (!SendMoney(scriptPubKey, nValue, wtx))
\r
1706 wxMessageBox("Payment sent ", "Sending...");
\r
1710 // Parse IP address
\r
1711 CAddress addr(strAddress);
\r
1712 if (!addr.IsValid())
\r
1714 wxMessageBox("Invalid address ", "Send Coins");
\r
1719 wtx.mapValue["to"] = strAddress;
\r
1720 wtx.mapValue["from"] = m_textCtrlFrom->GetValue();
\r
1721 wtx.mapValue["message"] = m_textCtrlMessage->GetValue();
\r
1723 // Send to IP address
\r
1724 CSendingDialog* pdialog = new CSendingDialog(this, addr, nValue, wtx);
\r
1725 if (!pdialog->ShowModal())
\r
1729 if (!mapAddressBook.count(strAddress))
\r
1730 SetAddressBookName(strAddress, "");
\r
1735 void CSendDialog::OnButtonCancel(wxCommandEvent& event)
\r
1746 //////////////////////////////////////////////////////////////////////////////
\r
1751 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
1754 nPrice = nPriceIn;
\r
1756 start = wxDateTime::UNow();
\r
1757 memset(pszStatus, 0, sizeof(pszStatus));
\r
1758 fCanCancel = true;
\r
1762 fWorkDone = false;
\r
1764 SetTitle(strprintf("Sending %s to %s...", FormatMoney(nPrice).c_str(), wtx.mapValue["to"].c_str()));
\r
1765 m_textCtrlStatus->SetValue("");
\r
1767 _beginthread(SendingDialogStartTransfer, 0, this);
\r
1770 CSendingDialog::~CSendingDialog()
\r
1772 printf("~CSendingDialog()\n");
\r
1775 void CSendingDialog::Close()
\r
1777 // Last one out turn out the lights.
\r
1778 // fWorkDone signals that work side is done and UI thread should call destroy.
\r
1779 // fUIDone signals that UI window has closed and work thread should call destroy.
\r
1780 // This allows the window to disappear and end modality when cancelled
\r
1781 // without making the user wait for ConnectNode to return. The dialog object
\r
1782 // hangs around in the background until the work thread exits.
\r
1784 EndModal(fSuccess);
\r
1793 void CSendingDialog::OnClose(wxCloseEvent& event)
\r
1795 if (!event.CanVeto() || fWorkDone || fAbort || !fCanCancel)
\r
1802 wxCommandEvent cmdevent;
\r
1803 OnButtonCancel(cmdevent);
\r
1807 void CSendingDialog::OnButtonOK(wxCommandEvent& event)
\r
1813 void CSendingDialog::OnButtonCancel(wxCommandEvent& event)
\r
1819 void CSendingDialog::OnPaint(wxPaintEvent& event)
\r
1821 if (strlen(pszStatus) > 130)
\r
1822 m_textCtrlStatus->SetValue(string("\n") + pszStatus);
\r
1824 m_textCtrlStatus->SetValue(string("\n\n") + pszStatus);
\r
1825 m_staticTextSending->SetFocus();
\r
1827 m_buttonCancel->Enable(false);
\r
1830 m_buttonOK->Enable(true);
\r
1831 m_buttonOK->SetFocus();
\r
1832 m_buttonCancel->Enable(false);
\r
1834 if (fAbort && fCanCancel && IsShown())
\r
1836 strcpy(pszStatus, "CANCELLED");
\r
1837 m_buttonOK->Enable(true);
\r
1838 m_buttonOK->SetFocus();
\r
1839 m_buttonCancel->Enable(false);
\r
1840 m_buttonCancel->SetLabel("Cancelled");
\r
1842 wxMessageBox("Transfer cancelled ", "Sending...", wxOK, this);
\r
1849 // Everything from here on is not in the UI thread and must only communicate
\r
1850 // with the rest of the dialog through variables and calling repaint.
\r
1853 void CSendingDialog::Repaint()
\r
1856 wxPaintEvent event;
\r
1857 AddPendingEvent(event);
\r
1860 bool CSendingDialog::Status()
\r
1867 if (fAbort && fCanCancel)
\r
1869 memset(pszStatus, 0, 10);
\r
1870 strcpy(pszStatus, "CANCELLED");
\r
1878 bool CSendingDialog::Status(const string& str)
\r
1883 // This can be read by the UI thread at any time,
\r
1884 // so copy in a way that can be read cleanly at all times.
\r
1885 memset(pszStatus, 0, min(str.size()+1, sizeof(pszStatus)));
\r
1886 strlcpy(pszStatus, str.c_str(), sizeof(pszStatus));
\r
1892 bool CSendingDialog::Error(const string& str)
\r
1894 fCanCancel = false;
\r
1896 Status(string("Error: ") + str);
\r
1900 void SendingDialogStartTransfer(void* parg)
\r
1902 ((CSendingDialog*)parg)->StartTransfer();
\r
1905 void CSendingDialog::StartTransfer()
\r
1907 // Make sure we have enough money
\r
1908 if (nPrice + nTransactionFee > GetBalance())
\r
1910 Error("You don't have enough money");
\r
1914 // We may have connected already for product details
\r
1915 if (!Status("Connecting..."))
\r
1917 CNode* pnode = ConnectNode(addr, 5 * 60);
\r
1920 Error("Unable to connect");
\r
1924 // Send order to seller, with response going to OnReply2 via event handler
\r
1925 if (!Status("Requesting public key..."))
\r
1927 pnode->PushRequest("checkorder", wtx, SendingDialogOnReply2, this);
\r
1930 void SendingDialogOnReply2(void* parg, CDataStream& vRecv)
\r
1932 ((CSendingDialog*)parg)->OnReply2(vRecv);
\r
1935 void CSendingDialog::OnReply2(CDataStream& vRecv)
\r
1937 if (!Status("Received public key..."))
\r
1940 CScript scriptPubKey;
\r
1947 string strMessage;
\r
1948 vRecv >> strMessage;
\r
1949 Error("Transfer was not accepted");
\r
1950 //// todo: enlarge the window and enable a hidden white box to put seller's message
\r
1953 vRecv >> scriptPubKey;
\r
1957 //// what do we want to do about this?
\r
1958 Error("Invalid response received");
\r
1962 // Should already be connected
\r
1963 CNode* pnode = ConnectNode(addr, 5 * 60);
\r
1966 Error("Lost connection");
\r
1970 // Pause to give the user a chance to cancel
\r
1971 while (wxDateTime::UNow() < start + wxTimeSpan(0, 0, 0, 2 * 1000))
\r
1978 CRITICAL_BLOCK(cs_main)
\r
1981 if (!Status("Creating transaction..."))
\r
1983 if (nPrice + nTransactionFee > GetBalance())
\r
1985 Error("You don't have enough money");
\r
1989 int64 nFeeRequired;
\r
1990 if (!CreateTransaction(scriptPubKey, nPrice, wtx, key, nFeeRequired))
\r
1992 if (nPrice + nFeeRequired > GetBalance())
\r
1993 Error(strprintf("This is an oversized transaction that requires a transaction fee of %s", FormatMoney(nFeeRequired).c_str()));
\r
1995 Error("Transaction creation failed");
\r
1999 // Last chance to cancel
\r
2003 fCanCancel = false;
\r
2006 fCanCancel = true;
\r
2009 fCanCancel = false;
\r
2011 if (!Status("Sending payment..."))
\r
2015 if (!CommitTransactionSpent(wtx, key))
\r
2017 Error("Error finalizing payment");
\r
2021 // Send payment tx to seller, with response going to OnReply3 via event handler
\r
2022 pnode->PushRequest("submitorder", wtx, SendingDialogOnReply3, this);
\r
2024 // Accept and broadcast transaction
\r
2025 if (!wtx.AcceptTransaction())
\r
2026 printf("ERROR: CSendingDialog : wtxNew.AcceptTransaction() %s failed\n", wtx.GetHash().ToString().c_str());
\r
2027 wtx.RelayWalletTransaction();
\r
2029 Status("Waiting for confirmation...");
\r
2030 MainFrameRepaint();
\r
2034 void SendingDialogOnReply3(void* parg, CDataStream& vRecv)
\r
2036 ((CSendingDialog*)parg)->OnReply3(vRecv);
\r
2039 void CSendingDialog::OnReply3(CDataStream& vRecv)
\r
2047 Error("The payment was sent, but the recipient was unable to verify it.\n"
\r
2048 "The transaction is recorded and will credit to the recipient,\n"
\r
2049 "but the comment information will be blank.");
\r
2055 //// what do we want to do about this?
\r
2056 Error("Payment was sent, but an invalid response was received");
\r
2062 Status("Payment completed");
\r
2070 //////////////////////////////////////////////////////////////////////////////
\r
2072 // CYourAddressDialog
\r
2075 CYourAddressDialog::CYourAddressDialog(wxWindow* parent, const string& strInitSelected) : CYourAddressDialogBase(parent)
\r
2077 // Init column headers
\r
2078 m_listCtrl->InsertColumn(0, "Label", wxLIST_FORMAT_LEFT, 200);
\r
2079 m_listCtrl->InsertColumn(1, "Bitcoin Address", wxLIST_FORMAT_LEFT, 350);
\r
2080 m_listCtrl->SetFocus();
\r
2082 // Fill listctrl with address book data
\r
2083 CRITICAL_BLOCK(cs_mapKeys)
\r
2085 foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
\r
2087 string strAddress = item.first;
\r
2088 string strName = item.second;
\r
2090 bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
\r
2093 int nIndex = InsertLine(m_listCtrl, strName, strAddress);
\r
2094 if (strAddress == strInitSelected)
\r
2095 m_listCtrl->SetItemState(nIndex, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
\r
2101 wxString CYourAddressDialog::GetAddress()
\r
2103 int nIndex = GetSelection(m_listCtrl);
\r
2106 return GetItemText(m_listCtrl, nIndex, 1);
\r
2109 void CYourAddressDialog::OnListEndLabelEdit(wxListEvent& event)
\r
2111 // Update address book with edited name
\r
2112 if (event.IsEditCancelled())
\r
2114 string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1);
\r
2115 SetAddressBookName(strAddress, string(event.GetText()));
\r
2116 pframeMain->RefreshListCtrl();
\r
2119 void CYourAddressDialog::OnListItemSelected(wxListEvent& event)
\r
2123 void CYourAddressDialog::OnListItemActivated(wxListEvent& event)
\r
2125 // Doubleclick edits item
\r
2126 wxCommandEvent event2;
\r
2127 OnButtonRename(event2);
\r
2130 void CYourAddressDialog::OnButtonRename(wxCommandEvent& event)
\r
2133 int nIndex = GetSelection(m_listCtrl);
\r
2136 string strName = (string)m_listCtrl->GetItemText(nIndex);
\r
2137 string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
\r
2138 CGetTextFromUserDialog dialog(this, "Edit Address Label", "New Label", strName);
\r
2139 if (!dialog.ShowModal())
\r
2141 strName = dialog.GetValue();
\r
2144 SetAddressBookName(strAddress, strName);
\r
2145 m_listCtrl->SetItemText(nIndex, strName);
\r
2146 pframeMain->RefreshListCtrl();
\r
2149 void CYourAddressDialog::OnButtonNew(wxCommandEvent& event)
\r
2152 CGetTextFromUserDialog dialog(this, "New Bitcoin Address", "Label", "");
\r
2153 if (!dialog.ShowModal())
\r
2155 string strName = dialog.GetValue();
\r
2157 // Generate new key
\r
2158 string strAddress = PubKeyToAddress(GenerateNewKey());
\r
2159 SetAddressBookName(strAddress, strName);
\r
2161 // Add to list and select it
\r
2162 int nIndex = InsertLine(m_listCtrl, strName, strAddress);
\r
2163 SetSelection(m_listCtrl, nIndex);
\r
2164 m_listCtrl->SetFocus();
\r
2167 void CYourAddressDialog::OnButtonCopy(wxCommandEvent& event)
\r
2169 // Copy address box to clipboard
\r
2170 if (wxTheClipboard->Open())
\r
2172 wxTheClipboard->SetData(new wxTextDataObject(GetAddress()));
\r
2173 wxTheClipboard->Close();
\r
2177 void CYourAddressDialog::OnButtonOK(wxCommandEvent& event)
\r
2183 void CYourAddressDialog::OnButtonCancel(wxCommandEvent& event)
\r
2189 void CYourAddressDialog::OnClose(wxCloseEvent& event)
\r
2200 //////////////////////////////////////////////////////////////////////////////
\r
2202 // CAddressBookDialog
\r
2205 CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInitSelected, bool fSendingIn) : CAddressBookDialogBase(parent)
\r
2207 fSending = fSendingIn;
\r
2209 m_buttonCancel->Show(false);
\r
2211 // Init column headers
\r
2212 m_listCtrl->InsertColumn(0, "Name", wxLIST_FORMAT_LEFT, 200);
\r
2213 m_listCtrl->InsertColumn(1, "Address", wxLIST_FORMAT_LEFT, 350);
\r
2214 m_listCtrl->SetFocus();
\r
2217 wxIcon iconAddressBook;
\r
2218 iconAddressBook.CopyFromBitmap(wxBitmap(addressbook16_xpm));
\r
2219 SetIcon(iconAddressBook);
\r
2221 // Fill listctrl with address book data
\r
2222 CRITICAL_BLOCK(cs_mapKeys)
\r
2224 foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
\r
2226 string strAddress = item.first;
\r
2227 string strName = item.second;
\r
2229 bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
\r
2232 int nIndex = InsertLine(m_listCtrl, strName, strAddress);
\r
2233 if (strAddress == strInitSelected)
\r
2234 m_listCtrl->SetItemState(nIndex, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
\r
2240 wxString CAddressBookDialog::GetAddress()
\r
2242 int nIndex = GetSelection(m_listCtrl);
\r
2245 return GetItemText(m_listCtrl, nIndex, 1);
\r
2248 void CAddressBookDialog::OnListEndLabelEdit(wxListEvent& event)
\r
2250 // Update address book with edited name
\r
2251 if (event.IsEditCancelled())
\r
2253 string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1);
\r
2254 SetAddressBookName(strAddress, string(event.GetText()));
\r
2255 pframeMain->RefreshListCtrl();
\r
2258 void CAddressBookDialog::OnListItemSelected(wxListEvent& event)
\r
2262 void CAddressBookDialog::OnListItemActivated(wxListEvent& event)
\r
2266 // Doubleclick returns selection
\r
2267 EndModal(GetAddress() != "" ? 2 : 0);
\r
2271 // Doubleclick edits item
\r
2272 wxCommandEvent event2;
\r
2273 OnButtonEdit(event2);
\r
2277 bool CAddressBookDialog::CheckIfMine(const string& strAddress, const string& strTitle)
\r
2280 bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
\r
2282 wxMessageBox("This is one of your own addresses for receiving payments and cannot be entered in the address book. ", strTitle);
\r
2286 void CAddressBookDialog::OnButtonEdit(wxCommandEvent& event)
\r
2289 int nIndex = GetSelection(m_listCtrl);
\r
2292 string strName = (string)m_listCtrl->GetItemText(nIndex);
\r
2293 string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
\r
2294 string strAddressOrg = strAddress;
\r
2297 CGetTextFromUserDialog dialog(this, "Edit Address", "Name", strName, "Address", strAddress);
\r
2298 if (!dialog.ShowModal())
\r
2300 strName = dialog.GetValue1();
\r
2301 strAddress = dialog.GetValue2();
\r
2303 while (CheckIfMine(strAddress, "Edit Address"));
\r
2306 if (strAddress != strAddressOrg)
\r
2307 CWalletDB().EraseName(strAddressOrg);
\r
2308 SetAddressBookName(strAddress, strName);
\r
2309 m_listCtrl->SetItem(nIndex, 1, strAddress);
\r
2310 m_listCtrl->SetItemText(nIndex, strName);
\r
2311 pframeMain->RefreshListCtrl();
\r
2314 void CAddressBookDialog::OnButtonNew(wxCommandEvent& event)
\r
2318 string strAddress;
\r
2321 CGetTextFromUserDialog dialog(this, "New Address", "Name", strName, "Address", strAddress);
\r
2322 if (!dialog.ShowModal())
\r
2324 strName = dialog.GetValue1();
\r
2325 strAddress = dialog.GetValue2();
\r
2327 while (CheckIfMine(strAddress, "New Address"));
\r
2329 // Add to list and select it
\r
2330 SetAddressBookName(strAddress, strName);
\r
2331 int nIndex = InsertLine(m_listCtrl, strName, strAddress);
\r
2332 SetSelection(m_listCtrl, nIndex);
\r
2333 m_listCtrl->SetFocus();
\r
2334 pframeMain->RefreshListCtrl();
\r
2337 void CAddressBookDialog::OnButtonDelete(wxCommandEvent& event)
\r
2339 for (int nIndex = m_listCtrl->GetItemCount()-1; nIndex >= 0; nIndex--)
\r
2341 if (m_listCtrl->GetItemState(nIndex, wxLIST_STATE_SELECTED))
\r
2343 string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
\r
2344 CWalletDB().EraseName(strAddress);
\r
2345 m_listCtrl->DeleteItem(nIndex);
\r
2348 pframeMain->RefreshListCtrl();
\r
2351 void CAddressBookDialog::OnButtonCopy(wxCommandEvent& event)
\r
2353 // Copy address box to clipboard
\r
2354 if (wxTheClipboard->Open())
\r
2356 wxTheClipboard->SetData(new wxTextDataObject(GetAddress()));
\r
2357 wxTheClipboard->Close();
\r
2361 void CAddressBookDialog::OnButtonOK(wxCommandEvent& event)
\r
2364 EndModal(GetAddress() != "" ? 1 : 0);
\r
2367 void CAddressBookDialog::OnButtonCancel(wxCommandEvent& event)
\r
2373 void CAddressBookDialog::OnClose(wxCloseEvent& event)
\r
2384 //////////////////////////////////////////////////////////////////////////////
\r
2386 // CProductsDialog
\r
2389 bool CompareIntStringPairBestFirst(const pair<int, string>& item1, const pair<int, string>& item2)
\r
2391 return (item1.first > item2.first);
\r
2394 CProductsDialog::CProductsDialog(wxWindow* parent) : CProductsDialogBase(parent)
\r
2396 // Init column headers
\r
2397 m_listCtrl->InsertColumn(0, "Title", wxLIST_FORMAT_LEFT, 200);
\r
2398 m_listCtrl->InsertColumn(1, "Price", wxLIST_FORMAT_LEFT, 80);
\r
2399 m_listCtrl->InsertColumn(2, "Seller", wxLIST_FORMAT_LEFT, 80);
\r
2400 m_listCtrl->InsertColumn(3, "Stars", wxLIST_FORMAT_LEFT, 50);
\r
2401 m_listCtrl->InsertColumn(4, "Power", wxLIST_FORMAT_LEFT, 50);
\r
2403 // Tally top categories
\r
2404 map<string, int> mapTopCategories;
\r
2405 CRITICAL_BLOCK(cs_mapProducts)
\r
2406 for (map<uint256, CProduct>::iterator mi = mapProducts.begin(); mi != mapProducts.end(); ++mi)
\r
2407 mapTopCategories[(*mi).second.mapValue["category"]]++;
\r
2409 // Sort top categories
\r
2410 vector<pair<int, string> > vTopCategories;
\r
2411 for (map<string, int>::iterator mi = mapTopCategories.begin(); mi != mapTopCategories.end(); ++mi)
\r
2412 vTopCategories.push_back(make_pair((*mi).second, (*mi).first));
\r
2413 sort(vTopCategories.begin(), vTopCategories.end(), CompareIntStringPairBestFirst);
\r
2415 // Fill categories combo box
\r
2417 for (vector<pair<int, string> >::iterator it = vTopCategories.begin(); it != vTopCategories.end() && nLimit-- > 0; ++it)
\r
2418 m_comboBoxCategory->Append((*it).second);
\r
2420 // Fill window with initial search
\r
2421 //wxCommandEvent event;
\r
2422 //OnButtonSearch(event);
\r
2425 void CProductsDialog::OnCombobox(wxCommandEvent& event)
\r
2427 OnButtonSearch(event);
\r
2430 bool CompareProductsBestFirst(const CProduct* p1, const CProduct* p2)
\r
2432 return (p1->nAtoms > p2->nAtoms);
\r
2435 void CProductsDialog::OnButtonSearch(wxCommandEvent& event)
\r
2437 string strCategory = (string)m_comboBoxCategory->GetValue();
\r
2438 string strSearch = (string)m_textCtrlSearch->GetValue();
\r
2440 // Search products
\r
2441 vector<CProduct*> vProductsFound;
\r
2442 CRITICAL_BLOCK(cs_mapProducts)
\r
2444 for (map<uint256, CProduct>::iterator mi = mapProducts.begin(); mi != mapProducts.end(); ++mi)
\r
2446 CProduct& product = (*mi).second;
\r
2447 if (product.mapValue["category"].find(strCategory) != -1)
\r
2449 if (product.mapValue["title"].find(strSearch) != -1 ||
\r
2450 product.mapValue["description"].find(strSearch) != -1 ||
\r
2451 product.mapValue["seller"].find(strSearch) != -1)
\r
2453 vProductsFound.push_back(&product);
\r
2460 sort(vProductsFound.begin(), vProductsFound.end(), CompareProductsBestFirst);
\r
2463 foreach(CProduct* pproduct, vProductsFound)
\r
2465 InsertLine(m_listCtrl,
\r
2466 pproduct->mapValue["title"],
\r
2467 pproduct->mapValue["price"],
\r
2468 pproduct->mapValue["seller"],
\r
2469 pproduct->mapValue["stars"],
\r
2470 itostr(pproduct->nAtoms));
\r
2474 void CProductsDialog::OnListItemActivated(wxListEvent& event)
\r
2476 // Doubleclick opens product
\r
2477 CViewProductDialog* pdialog = new CViewProductDialog(this, m_vProduct[event.GetIndex()]);
\r
2487 //////////////////////////////////////////////////////////////////////////////
\r
2489 // CEditProductDialog
\r
2492 CEditProductDialog::CEditProductDialog(wxWindow* parent) : CEditProductDialogBase(parent)
\r
2494 m_textCtrlLabel[0 ] = m_textCtrlLabel0;
\r
2495 m_textCtrlLabel[1 ] = m_textCtrlLabel1;
\r
2496 m_textCtrlLabel[2 ] = m_textCtrlLabel2;
\r
2497 m_textCtrlLabel[3 ] = m_textCtrlLabel3;
\r
2498 m_textCtrlLabel[4 ] = m_textCtrlLabel4;
\r
2499 m_textCtrlLabel[5 ] = m_textCtrlLabel5;
\r
2500 m_textCtrlLabel[6 ] = m_textCtrlLabel6;
\r
2501 m_textCtrlLabel[7 ] = m_textCtrlLabel7;
\r
2502 m_textCtrlLabel[8 ] = m_textCtrlLabel8;
\r
2503 m_textCtrlLabel[9 ] = m_textCtrlLabel9;
\r
2504 m_textCtrlLabel[10] = m_textCtrlLabel10;
\r
2505 m_textCtrlLabel[11] = m_textCtrlLabel11;
\r
2506 m_textCtrlLabel[12] = m_textCtrlLabel12;
\r
2507 m_textCtrlLabel[13] = m_textCtrlLabel13;
\r
2508 m_textCtrlLabel[14] = m_textCtrlLabel14;
\r
2509 m_textCtrlLabel[15] = m_textCtrlLabel15;
\r
2510 m_textCtrlLabel[16] = m_textCtrlLabel16;
\r
2511 m_textCtrlLabel[17] = m_textCtrlLabel17;
\r
2512 m_textCtrlLabel[18] = m_textCtrlLabel18;
\r
2513 m_textCtrlLabel[19] = m_textCtrlLabel19;
\r
2515 m_textCtrlField[0 ] = m_textCtrlField0;
\r
2516 m_textCtrlField[1 ] = m_textCtrlField1;
\r
2517 m_textCtrlField[2 ] = m_textCtrlField2;
\r
2518 m_textCtrlField[3 ] = m_textCtrlField3;
\r
2519 m_textCtrlField[4 ] = m_textCtrlField4;
\r
2520 m_textCtrlField[5 ] = m_textCtrlField5;
\r
2521 m_textCtrlField[6 ] = m_textCtrlField6;
\r
2522 m_textCtrlField[7 ] = m_textCtrlField7;
\r
2523 m_textCtrlField[8 ] = m_textCtrlField8;
\r
2524 m_textCtrlField[9 ] = m_textCtrlField9;
\r
2525 m_textCtrlField[10] = m_textCtrlField10;
\r
2526 m_textCtrlField[11] = m_textCtrlField11;
\r
2527 m_textCtrlField[12] = m_textCtrlField12;
\r
2528 m_textCtrlField[13] = m_textCtrlField13;
\r
2529 m_textCtrlField[14] = m_textCtrlField14;
\r
2530 m_textCtrlField[15] = m_textCtrlField15;
\r
2531 m_textCtrlField[16] = m_textCtrlField16;
\r
2532 m_textCtrlField[17] = m_textCtrlField17;
\r
2533 m_textCtrlField[18] = m_textCtrlField18;
\r
2534 m_textCtrlField[19] = m_textCtrlField19;
\r
2536 m_buttonDel[0 ] = m_buttonDel0;
\r
2537 m_buttonDel[1 ] = m_buttonDel1;
\r
2538 m_buttonDel[2 ] = m_buttonDel2;
\r
2539 m_buttonDel[3 ] = m_buttonDel3;
\r
2540 m_buttonDel[4 ] = m_buttonDel4;
\r
2541 m_buttonDel[5 ] = m_buttonDel5;
\r
2542 m_buttonDel[6 ] = m_buttonDel6;
\r
2543 m_buttonDel[7 ] = m_buttonDel7;
\r
2544 m_buttonDel[8 ] = m_buttonDel8;
\r
2545 m_buttonDel[9 ] = m_buttonDel9;
\r
2546 m_buttonDel[10] = m_buttonDel10;
\r
2547 m_buttonDel[11] = m_buttonDel11;
\r
2548 m_buttonDel[12] = m_buttonDel12;
\r
2549 m_buttonDel[13] = m_buttonDel13;
\r
2550 m_buttonDel[14] = m_buttonDel14;
\r
2551 m_buttonDel[15] = m_buttonDel15;
\r
2552 m_buttonDel[16] = m_buttonDel16;
\r
2553 m_buttonDel[17] = m_buttonDel17;
\r
2554 m_buttonDel[18] = m_buttonDel18;
\r
2555 m_buttonDel[19] = m_buttonDel19;
\r
2557 for (int i = 1; i < FIELDS_MAX; i++)
\r
2558 ShowLine(i, false);
\r
2563 void CEditProductDialog::LayoutAll()
\r
2565 m_scrolledWindow->Layout();
\r
2566 m_scrolledWindow->GetSizer()->Fit(m_scrolledWindow);
\r
2570 void CEditProductDialog::ShowLine(int i, bool fShow)
\r
2572 m_textCtrlLabel[i]->Show(fShow);
\r
2573 m_textCtrlField[i]->Show(fShow);
\r
2574 m_buttonDel[i]->Show(fShow);
\r
2577 void CEditProductDialog::OnButtonDel0(wxCommandEvent& event) { OnButtonDel(event, 0); }
\r
2578 void CEditProductDialog::OnButtonDel1(wxCommandEvent& event) { OnButtonDel(event, 1); }
\r
2579 void CEditProductDialog::OnButtonDel2(wxCommandEvent& event) { OnButtonDel(event, 2); }
\r
2580 void CEditProductDialog::OnButtonDel3(wxCommandEvent& event) { OnButtonDel(event, 3); }
\r
2581 void CEditProductDialog::OnButtonDel4(wxCommandEvent& event) { OnButtonDel(event, 4); }
\r
2582 void CEditProductDialog::OnButtonDel5(wxCommandEvent& event) { OnButtonDel(event, 5); }
\r
2583 void CEditProductDialog::OnButtonDel6(wxCommandEvent& event) { OnButtonDel(event, 6); }
\r
2584 void CEditProductDialog::OnButtonDel7(wxCommandEvent& event) { OnButtonDel(event, 7); }
\r
2585 void CEditProductDialog::OnButtonDel8(wxCommandEvent& event) { OnButtonDel(event, 8); }
\r
2586 void CEditProductDialog::OnButtonDel9(wxCommandEvent& event) { OnButtonDel(event, 9); }
\r
2587 void CEditProductDialog::OnButtonDel10(wxCommandEvent& event) { OnButtonDel(event, 10); }
\r
2588 void CEditProductDialog::OnButtonDel11(wxCommandEvent& event) { OnButtonDel(event, 11); }
\r
2589 void CEditProductDialog::OnButtonDel12(wxCommandEvent& event) { OnButtonDel(event, 12); }
\r
2590 void CEditProductDialog::OnButtonDel13(wxCommandEvent& event) { OnButtonDel(event, 13); }
\r
2591 void CEditProductDialog::OnButtonDel14(wxCommandEvent& event) { OnButtonDel(event, 14); }
\r
2592 void CEditProductDialog::OnButtonDel15(wxCommandEvent& event) { OnButtonDel(event, 15); }
\r
2593 void CEditProductDialog::OnButtonDel16(wxCommandEvent& event) { OnButtonDel(event, 16); }
\r
2594 void CEditProductDialog::OnButtonDel17(wxCommandEvent& event) { OnButtonDel(event, 17); }
\r
2595 void CEditProductDialog::OnButtonDel18(wxCommandEvent& event) { OnButtonDel(event, 18); }
\r
2596 void CEditProductDialog::OnButtonDel19(wxCommandEvent& event) { OnButtonDel(event, 19); }
\r
2598 void CEditProductDialog::OnButtonDel(wxCommandEvent& event, int n)
\r
2602 m_scrolledWindow->GetViewStart(&x, &y);
\r
2604 for (i = n; i < FIELDS_MAX-1; i++)
\r
2606 m_textCtrlLabel[i]->SetValue(m_textCtrlLabel[i+1]->GetValue());
\r
2607 m_textCtrlField[i]->SetValue(m_textCtrlField[i+1]->GetValue());
\r
2608 if (!m_buttonDel[i+1]->IsShown())
\r
2611 m_textCtrlLabel[i]->SetValue("");
\r
2612 m_textCtrlField[i]->SetValue("");
\r
2613 ShowLine(i, false);
\r
2614 m_buttonAddField->Enable(true);
\r
2616 m_scrolledWindow->Scroll(0, y);
\r
2620 void CEditProductDialog::OnButtonAddField(wxCommandEvent& event)
\r
2622 for (int i = 0; i < FIELDS_MAX; i++)
\r
2624 if (!m_buttonDel[i]->IsShown())
\r
2627 ShowLine(i, true);
\r
2628 if (i == FIELDS_MAX-1)
\r
2629 m_buttonAddField->Enable(false);
\r
2631 m_scrolledWindow->Scroll(0, 99999);
\r
2638 void CEditProductDialog::OnButtonSend(wxCommandEvent& event)
\r
2641 GetProduct(product);
\r
2643 // Sign the detailed product
\r
2644 product.vchPubKeyFrom = keyUser.GetPubKey();
\r
2645 if (!keyUser.Sign(product.GetSigHash(), product.vchSig))
\r
2647 wxMessageBox("Error digitally signing the product ");
\r
2651 // Save detailed product
\r
2652 AddToMyProducts(product);
\r
2654 // Strip down to summary product
\r
2655 product.mapDetails.clear();
\r
2656 product.vOrderForm.clear();
\r
2658 // Sign the summary product
\r
2659 if (!keyUser.Sign(product.GetSigHash(), product.vchSig))
\r
2661 wxMessageBox("Error digitally signing the product ");
\r
2666 if (!product.CheckProduct())
\r
2668 wxMessageBox("Errors found in product ");
\r
2673 AdvertStartPublish(pnodeLocalHost, MSG_PRODUCT, 0, product);
\r
2678 void CEditProductDialog::OnButtonPreview(wxCommandEvent& event)
\r
2681 GetProduct(product);
\r
2682 CViewProductDialog* pdialog = new CViewProductDialog(this, product);
\r
2686 void CEditProductDialog::OnButtonCancel(wxCommandEvent& event)
\r
2691 void CEditProductDialog::SetProduct(const CProduct& productIn)
\r
2693 CProduct product = productIn;
\r
2695 m_comboBoxCategory->SetValue(product.mapValue["category"]);
\r
2696 m_textCtrlTitle->SetValue(product.mapValue["title"]);
\r
2697 m_textCtrlPrice->SetValue(product.mapValue["price"]);
\r
2698 m_textCtrlDescription->SetValue(product.mapValue["description"]);
\r
2699 m_textCtrlInstructions->SetValue(product.mapValue["instructions"]);
\r
2701 for (int i = 0; i < FIELDS_MAX; i++)
\r
2703 bool fUsed = i < product.vOrderForm.size();
\r
2704 m_buttonDel[i]->Show(fUsed);
\r
2705 m_textCtrlLabel[i]->Show(fUsed);
\r
2706 m_textCtrlField[i]->Show(fUsed);
\r
2710 m_textCtrlLabel[i]->SetValue(product.vOrderForm[i].first);
\r
2711 string strControl = product.vOrderForm[i].second;
\r
2712 if (strControl.substr(0, 5) == "text=")
\r
2713 m_textCtrlField[i]->SetValue("");
\r
2714 else if (strControl.substr(0, 7) == "choice=")
\r
2715 m_textCtrlField[i]->SetValue(strControl.substr(7));
\r
2717 m_textCtrlField[i]->SetValue(strControl);
\r
2721 void CEditProductDialog::GetProduct(CProduct& product)
\r
2723 // map<string, string> mapValue;
\r
2724 // vector<pair<string, string> > vOrderForm;
\r
2726 product.mapValue["category"] = m_comboBoxCategory->GetValue().Trim();
\r
2727 product.mapValue["title"] = m_textCtrlTitle->GetValue().Trim();
\r
2728 product.mapValue["price"] = m_textCtrlPrice->GetValue().Trim();
\r
2729 product.mapValue["description"] = m_textCtrlDescription->GetValue().Trim();
\r
2730 product.mapValue["instructions"] = m_textCtrlInstructions->GetValue().Trim();
\r
2732 for (int i = 0; i < FIELDS_MAX; i++)
\r
2734 if (m_buttonDel[i]->IsShown())
\r
2736 string strLabel = (string)m_textCtrlLabel[i]->GetValue().Trim();
\r
2737 string strControl = (string)m_textCtrlField[i]->GetValue();
\r
2738 if (strControl.empty())
\r
2739 strControl = "text=";
\r
2741 strControl = "choice=" + strControl;
\r
2742 product.vOrderForm.push_back(make_pair(strLabel, strControl));
\r
2753 //////////////////////////////////////////////////////////////////////////////
\r
2755 // CViewProductDialog
\r
2758 CViewProductDialog::CViewProductDialog(wxWindow* parent, const CProduct& productIn) : CViewProductDialogBase(parent)
\r
2760 Connect(wxEVT_REPLY1, wxCommandEventHandler(CViewProductDialog::OnReply1), NULL, this);
\r
2761 AddCallbackAvailable(GetEventHandler());
\r
2763 // Fill display with product summary while waiting for details
\r
2764 product = productIn;
\r
2765 UpdateProductDisplay(false);
\r
2767 m_buttonBack->Enable(false);
\r
2768 m_buttonNext->Enable(!product.vOrderForm.empty());
\r
2769 m_htmlWinReviews->Show(true);
\r
2770 m_scrolledWindow->Show(false);
\r
2773 // Request details from seller
\r
2774 _beginthread(ThreadRequestProductDetails, 0, new pair<CProduct, wxEvtHandler*>(product, GetEventHandler()));
\r
2777 CViewProductDialog::~CViewProductDialog()
\r
2779 RemoveCallbackAvailable(GetEventHandler());
\r
2782 void ThreadRequestProductDetails(void* parg)
\r
2784 // Extract parameters
\r
2785 pair<CProduct, wxEvtHandler*>* pitem = (pair<CProduct, wxEvtHandler*>*)parg;
\r
2786 CProduct product = pitem->first;
\r
2787 wxEvtHandler* pevthandler = pitem->second;
\r
2790 // Connect to seller
\r
2791 CNode* pnode = ConnectNode(product.addr, 5 * 60);
\r
2794 CDataStream ssEmpty;
\r
2795 AddPendingReplyEvent1(pevthandler, ssEmpty);
\r
2799 // Request detailed product, with response going to OnReply1 via dialog's event handler
\r
2800 pnode->PushRequest("getdetails", product.GetHash(), AddPendingReplyEvent1, (void*)pevthandler);
\r
2803 void CViewProductDialog::OnReply1(wxCommandEvent& event)
\r
2805 CDataStream ss = GetStreamFromEvent(event);
\r
2808 product.mapValue["description"] = "-- CAN'T CONNECT TO SELLER --\n";
\r
2809 UpdateProductDisplay(true);
\r
2814 CProduct product2;
\r
2821 if (product2.GetHash() != product.GetHash())
\r
2823 if (!product2.CheckSignature())
\r
2828 product.mapValue["description"] = "-- INVALID RESPONSE --\n";
\r
2829 UpdateProductDisplay(true);
\r
2833 product = product2;
\r
2834 UpdateProductDisplay(true);
\r
2837 bool CompareReviewsBestFirst(const CReview* p1, const CReview* p2)
\r
2839 return (p1->nAtoms > p2->nAtoms);
\r
2842 void CViewProductDialog::UpdateProductDisplay(bool fDetails)
\r
2844 // Product and reviews
\r
2846 strHTML.reserve(4000);
\r
2847 strHTML += "<html>\n"
\r
2849 "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"
\r
2852 strHTML += "<b>Category:</b> " + HtmlEscape(product.mapValue["category"]) + "<br>\n";
\r
2853 strHTML += "<b>Title:</b> " + HtmlEscape(product.mapValue["title"]) + "<br>\n";
\r
2854 strHTML += "<b>Price:</b> " + HtmlEscape(product.mapValue["price"]) + "<br>\n";
\r
2857 strHTML += "<b>Loading details...</b><br>\n<br>\n";
\r
2859 strHTML += HtmlEscape(product.mapValue["description"], true) + "<br>\n<br>\n";
\r
2861 strHTML += "<b>Reviews:</b><br>\n<br>\n";
\r
2863 if (!product.vchPubKeyFrom.empty())
\r
2865 CReviewDB reviewdb("r");
\r
2868 vector<CReview> vReviews;
\r
2869 reviewdb.ReadReviews(product.GetUserHash(), vReviews);
\r
2871 // Get reviewer's number of atoms
\r
2872 vector<CReview*> vSortedReviews;
\r
2873 vSortedReviews.reserve(vReviews.size());
\r
2874 for (vector<CReview>::reverse_iterator it = vReviews.rbegin(); it != vReviews.rend(); ++it)
\r
2876 CReview& review = *it;
\r
2878 reviewdb.ReadUser(review.GetUserHash(), user);
\r
2879 review.nAtoms = user.GetAtomCount();
\r
2880 vSortedReviews.push_back(&review);
\r
2886 stable_sort(vSortedReviews.begin(), vSortedReviews.end(), CompareReviewsBestFirst);
\r
2889 foreach(CReview* preview, vSortedReviews)
\r
2891 CReview& review = *preview;
\r
2892 int nStars = atoi(review.mapValue["stars"].c_str());
\r
2893 if (nStars < 1 || nStars > 5)
\r
2896 strHTML += "<b>" + itostr(nStars) + (nStars == 1 ? " star" : " stars") + "</b>";
\r
2897 strHTML += " ";
\r
2898 strHTML += DateStr(atoi64(review.mapValue["date"])) + "<br>\n";
\r
2899 strHTML += HtmlEscape(review.mapValue["review"], true);
\r
2900 strHTML += "<br>\n<br>\n";
\r
2904 strHTML += "</body>\n</html>\n";
\r
2906 // Shrink capacity to fit
\r
2907 string(strHTML.begin(), strHTML.end()).swap(strHTML);
\r
2909 m_htmlWinReviews->SetPage(strHTML);
\r
2911 ///// need to find some other indicator to use so can allow empty order form
\r
2912 if (product.vOrderForm.empty())
\r
2916 m_staticTextInstructions->SetLabel(product.mapValue["instructions"]);
\r
2917 for (int i = 0; i < FIELDS_MAX; i++)
\r
2919 m_staticTextLabel[i] = NULL;
\r
2920 m_textCtrlField[i] = NULL;
\r
2921 m_choiceField[i] = NULL;
\r
2924 // Construct flexgridsizer
\r
2925 wxBoxSizer* bSizer21 = (wxBoxSizer*)m_scrolledWindow->GetSizer();
\r
2926 wxFlexGridSizer* fgSizer;
\r
2927 fgSizer = new wxFlexGridSizer(0, 2, 0, 0);
\r
2928 fgSizer->AddGrowableCol(1);
\r
2929 fgSizer->SetFlexibleDirection(wxBOTH);
\r
2930 fgSizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
\r
2932 // Construct order form fields
\r
2933 wxWindow* windowLast = NULL;
\r
2934 for (int i = 0; i < product.vOrderForm.size(); i++)
\r
2936 string strLabel = product.vOrderForm[i].first;
\r
2937 string strControl = product.vOrderForm[i].second;
\r
2939 if (strLabel.size() < 20)
\r
2940 strLabel.insert(strLabel.begin(), 20 - strLabel.size(), ' ');
\r
2942 m_staticTextLabel[i] = new wxStaticText(m_scrolledWindow, wxID_ANY, strLabel, wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
\r
2943 m_staticTextLabel[i]->Wrap(-1);
\r
2944 fgSizer->Add(m_staticTextLabel[i], 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5);
\r
2946 if (strControl.substr(0, 5) == "text=")
\r
2948 m_textCtrlField[i] = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0);
\r
2949 fgSizer->Add(m_textCtrlField[i], 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5);
\r
2950 windowLast = m_textCtrlField[i];
\r
2952 else if (strControl.substr(0, 7) == "choice=")
\r
2954 vector<string> vChoices;
\r
2955 ParseString(strControl.substr(7), ',', vChoices);
\r
2957 wxArrayString arraystring;
\r
2958 foreach(const string& str, vChoices)
\r
2959 arraystring.Add(str);
\r
2961 m_choiceField[i] = new wxChoice(m_scrolledWindow, wxID_ANY, wxDefaultPosition, wxDefaultSize, arraystring, 0);
\r
2962 fgSizer->Add(m_choiceField[i], 0, wxALL|wxALIGN_CENTER_VERTICAL, 5);
\r
2963 windowLast = m_choiceField[i];
\r
2967 m_textCtrlField[i] = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0);
\r
2968 fgSizer->Add(m_textCtrlField[i], 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5);
\r
2969 m_staticTextLabel[i]->Show(false);
\r
2970 m_textCtrlField[i]->Show(false);
\r
2974 // Insert after instructions and before submit/cancel buttons
\r
2975 bSizer21->Insert(2, fgSizer, 0, wxEXPAND|wxRIGHT|wxLEFT, 5);
\r
2976 m_scrolledWindow->Layout();
\r
2977 bSizer21->Fit(m_scrolledWindow);
\r
2980 // Fixup the tab order
\r
2981 m_buttonSubmitForm->MoveAfterInTabOrder(windowLast);
\r
2982 m_buttonCancelForm->MoveAfterInTabOrder(m_buttonSubmitForm);
\r
2983 //m_buttonBack->MoveAfterInTabOrder(m_buttonCancelForm);
\r
2984 //m_buttonNext->MoveAfterInTabOrder(m_buttonBack);
\r
2985 //m_buttonCancel->MoveAfterInTabOrder(m_buttonNext);
\r
2989 void CViewProductDialog::GetOrder(CWalletTx& wtx)
\r
2992 for (int i = 0; i < product.vOrderForm.size(); i++)
\r
2995 if (m_textCtrlField[i])
\r
2996 strValue = m_textCtrlField[i]->GetValue().Trim();
\r
2998 strValue = m_choiceField[i]->GetStringSelection();
\r
2999 wtx.vOrderForm.push_back(make_pair(m_staticTextLabel[i]->GetLabel(), strValue));
\r
3003 void CViewProductDialog::OnButtonSubmitForm(wxCommandEvent& event)
\r
3005 m_buttonSubmitForm->Enable(false);
\r
3006 m_buttonCancelForm->Enable(false);
\r
3011 CSendingDialog* pdialog = new CSendingDialog(this, product.addr, atoi64(product.mapValue["price"]), wtx);
\r
3012 if (!pdialog->ShowModal())
\r
3014 m_buttonSubmitForm->Enable(true);
\r
3015 m_buttonCancelForm->Enable(true);
\r
3020 void CViewProductDialog::OnButtonCancelForm(wxCommandEvent& event)
\r
3025 void CViewProductDialog::OnButtonBack(wxCommandEvent& event)
\r
3028 m_htmlWinReviews->Show(true);
\r
3029 m_scrolledWindow->Show(false);
\r
3030 m_buttonBack->Enable(false);
\r
3031 m_buttonNext->Enable(!product.vOrderForm.empty());
\r
3036 void CViewProductDialog::OnButtonNext(wxCommandEvent& event)
\r
3038 if (!product.vOrderForm.empty())
\r
3041 m_htmlWinReviews->Show(false);
\r
3042 m_scrolledWindow->Show(true);
\r
3043 m_buttonBack->Enable(true);
\r
3044 m_buttonNext->Enable(false);
\r
3050 void CViewProductDialog::OnButtonCancel(wxCommandEvent& event)
\r
3061 //////////////////////////////////////////////////////////////////////////////
\r
3063 // CViewOrderDialog
\r
3066 CViewOrderDialog::CViewOrderDialog(wxWindow* parent, CWalletTx order, bool fReceived) : CViewOrderDialogBase(parent)
\r
3068 int64 nPrice = (fReceived ? order.GetCredit() : order.GetDebit());
\r
3071 strHTML.reserve(4000);
\r
3072 strHTML += "<html>\n"
\r
3074 "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"
\r
3077 strHTML += "<b>Time:</b> " + HtmlEscape(DateTimeStr(order.nTimeReceived)) + "<br>\n";
\r
3078 strHTML += "<b>Price:</b> " + HtmlEscape(FormatMoney(nPrice)) + "<br>\n";
\r
3079 strHTML += "<b>Status:</b> " + HtmlEscape(FormatTxStatus(order)) + "<br>\n";
\r
3081 strHTML += "<table>\n";
\r
3082 for (int i = 0; i < order.vOrderForm.size(); i++)
\r
3084 strHTML += " <tr><td><b>" + HtmlEscape(order.vOrderForm[i].first) + ":</b></td>";
\r
3085 strHTML += "<td>" + HtmlEscape(order.vOrderForm[i].second) + "</td></tr>\n";
\r
3087 strHTML += "</table>\n";
\r
3089 strHTML += "</body>\n</html>\n";
\r
3091 // Shrink capacity to fit
\r
3092 // (strings are ref counted, so it may live on in SetPage)
\r
3093 string(strHTML.begin(), strHTML.end()).swap(strHTML);
\r
3095 m_htmlWin->SetPage(strHTML);
\r
3098 void CViewOrderDialog::OnButtonOK(wxCommandEvent& event)
\r
3109 //////////////////////////////////////////////////////////////////////////////
\r
3111 // CEditReviewDialog
\r
3114 CEditReviewDialog::CEditReviewDialog(wxWindow* parent) : CEditReviewDialogBase(parent)
\r
3118 void CEditReviewDialog::OnButtonSubmit(wxCommandEvent& event)
\r
3120 if (m_choiceStars->GetSelection() == -1)
\r
3122 wxMessageBox("Please select a rating ");
\r
3127 GetReview(review);
\r
3129 // Sign the review
\r
3130 review.vchPubKeyFrom = keyUser.GetPubKey();
\r
3131 if (!keyUser.Sign(review.GetSigHash(), review.vchSig))
\r
3133 wxMessageBox("Unable to digitally sign the review ");
\r
3138 if (!review.AcceptReview())
\r
3140 wxMessageBox("Save failed ");
\r
3143 RelayMessage(CInv(MSG_REVIEW, review.GetHash()), review);
\r
3148 void CEditReviewDialog::OnButtonCancel(wxCommandEvent& event)
\r
3153 void CEditReviewDialog::GetReview(CReview& review)
\r
3155 review.mapValue["time"] = i64tostr(GetAdjustedTime());
\r
3156 review.mapValue["stars"] = itostr(m_choiceStars->GetSelection()+1);
\r
3157 review.mapValue["review"] = m_textCtrlReview->GetValue();
\r
3166 //////////////////////////////////////////////////////////////////////////////
\r
3173 ID_TASKBAR_RESTORE = 10001,
\r
3174 ID_TASKBAR_GENERATE,
\r
3178 BEGIN_EVENT_TABLE(CMyTaskBarIcon, wxTaskBarIcon)
\r
3179 EVT_TASKBAR_LEFT_DCLICK(CMyTaskBarIcon::OnLeftButtonDClick)
\r
3180 EVT_MENU(ID_TASKBAR_RESTORE, CMyTaskBarIcon::OnMenuRestore)
\r
3181 EVT_MENU(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnMenuGenerate)
\r
3182 EVT_UPDATE_UI(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnUpdateUIGenerate)
\r
3183 EVT_MENU(ID_TASKBAR_EXIT, CMyTaskBarIcon::OnMenuExit)
\r
3186 void CMyTaskBarIcon::Show(bool fShow)
\r
3188 static char pszPrevTip[200];
\r
3191 string strTooltip = "Bitcoin";
\r
3192 if (fGenerateBitcoins)
\r
3193 strTooltip = "Bitcoin - Generating";
\r
3194 if (fGenerateBitcoins && vNodes.empty())
\r
3195 strTooltip = "Bitcoin - (not connected)";
\r
3197 // Optimization, only update when changed, using char array to be reentrant
\r
3198 if (strncmp(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip)-1) != 0)
\r
3200 strlcpy(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip));
\r
3201 SetIcon(wxICON(bitcoin), strTooltip);
\r
3206 strlcpy(pszPrevTip, "", sizeof(pszPrevTip));
\r
3211 void CMyTaskBarIcon::Hide()
\r
3216 void CMyTaskBarIcon::OnLeftButtonDClick(wxTaskBarIconEvent& event)
\r
3221 void CMyTaskBarIcon::OnMenuRestore(wxCommandEvent& event)
\r
3226 void CMyTaskBarIcon::Restore()
\r
3228 pframeMain->Show();
\r
3229 pframeMain->Iconize(false);
\r
3230 pframeMain->Raise();
\r
3233 void CMyTaskBarIcon::OnMenuGenerate(wxCommandEvent& event)
\r
3235 GenerateBitcoins(event.IsChecked());
\r
3238 void CMyTaskBarIcon::OnUpdateUIGenerate(wxUpdateUIEvent& event)
\r
3240 event.Check(fGenerateBitcoins);
\r
3243 void CMyTaskBarIcon::OnMenuExit(wxCommandEvent& event)
\r
3245 pframeMain->Close(true);
\r
3248 void CMyTaskBarIcon::UpdateTooltip()
\r
3250 if (IsIconInstalled())
\r
3254 wxMenu* CMyTaskBarIcon::CreatePopupMenu()
\r
3256 wxMenu* pmenu = new wxMenu;
\r
3257 pmenu->Append(ID_TASKBAR_RESTORE, "&Open Bitcoin");
\r
3258 pmenu->AppendCheckItem(ID_TASKBAR_GENERATE, "&Generate Coins")->Check(fGenerateBitcoins);
\r
3259 #ifndef __WXMAC_OSX__ // Mac has built-in quit menu
\r
3260 pmenu->AppendSeparator();
\r
3261 pmenu->Append(ID_TASKBAR_EXIT, "E&xit");
\r
3278 //////////////////////////////////////////////////////////////////////////////
\r
3283 // Define a new application
\r
3284 class CMyApp: public wxApp
\r
3293 // 2nd-level exception handling: we get all the exceptions occurring in any
\r
3294 // event handler here
\r
3295 virtual bool OnExceptionInMainLoop();
\r
3297 // 3rd, and final, level exception handling: whenever an unhandled
\r
3298 // exception is caught, this function is called
\r
3299 virtual void OnUnhandledException();
\r
3301 // and now for something different: this function is called in case of a
\r
3302 // crash (e.g. dereferencing null pointer, division by 0, ...)
\r
3303 virtual void OnFatalException();
\r
3306 IMPLEMENT_APP(CMyApp)
\r
3308 bool CMyApp::OnInit()
\r
3314 catch (std::exception& e) {
\r
3315 PrintException(&e, "OnInit()");
\r
3317 PrintException(NULL, "OnInit()");
\r
3322 bool CMyApp::OnInit2()
\r
3325 // Turn off microsoft heap dump noise for now
\r
3326 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
\r
3327 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
\r
3329 #if defined(__WXMSW__) && defined(__WXDEBUG__)
\r
3330 // Disable malfunctioning wxWidgets debug assertion
\r
3331 g_isPainting = 10000;
\r
3333 wxImage::AddHandler(new wxPNGHandler);
\r
3334 SetAppName("Bitcoin");
\r
3336 ParseParameters(argc, argv);
\r
3337 if (mapArgs.count("-?") || mapArgs.count("--help"))
\r
3340 "Usage: bitcoin [options]\t\t\t\t\t\t\n"
\r
3342 " -gen\t\t Generate coins\n"
\r
3343 " -gen=0\t\t Don't generate coins\n"
\r
3344 " -min\t\t Start minimized\n"
\r
3345 " -datadir=<dir>\t Specify data directory\n"
\r
3346 " -proxy=<ip:port>\t Connect through socks4 proxy\n"
\r
3347 " -addnode=<ip>\t Add a node to connect to\n"
\r
3348 " -connect=<ip>\t Connect only to the specified node\n"
\r
3349 " -?\t\t This help message\n";
\r
3350 wxMessageBox(strUsage, "Bitcoin", wxOK);
\r
3355 // Limit to single instance per user
\r
3356 // Required to protect the database files if we're going to keep deleting log.*
\r
3358 wxString strMutexName = wxString("Bitcoin.") + getenv("HOMEPATH");
\r
3359 for (int i = 0; i < strMutexName.size(); i++)
\r
3360 if (!isalnum(strMutexName[i]))
\r
3361 strMutexName[i] = '.';
\r
3362 wxSingleInstanceChecker* psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);
\r
3363 if (psingleinstancechecker->IsAnotherRunning())
\r
3365 printf("Existing instance found\n");
\r
3366 unsigned int nStart = GetTime();
\r
3369 // TODO: find out how to do this in Linux, or replace with wxWidgets commands
\r
3371 // Show the previous instance and exit
\r
3372 HWND hwndPrev = FindWindow("wxWindowClassNR", "Bitcoin");
\r
3375 if (IsIconic(hwndPrev))
\r
3376 ShowWindow(hwndPrev, SW_RESTORE);
\r
3377 SetForegroundWindow(hwndPrev);
\r
3382 if (GetTime() > nStart + 60)
\r
3385 // Resume this instance if the other exits
\r
3386 delete psingleinstancechecker;
\r
3388 psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);
\r
3389 if (!psingleinstancechecker->IsAnotherRunning())
\r
3397 if (mapArgs.count("-datadir"))
\r
3398 strlcpy(pszSetDataDir, mapArgs["-datadir"].c_str(), sizeof(pszSetDataDir));
\r
3400 if (mapArgs.count("-debug"))
\r
3403 if (mapArgs.count("-printtodebugger"))
\r
3404 fPrintToDebugger = true;
\r
3406 printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
\r
3407 printf("Bitcoin version %d, OS version %s\n", VERSION, wxGetOsDescription().mb_str());
\r
3409 if (mapArgs.count("-dropmessages"))
\r
3411 nDropMessagesTest = atoi(mapArgs["-dropmessages"]);
\r
3412 if (nDropMessagesTest == 0)
\r
3413 nDropMessagesTest = 20;
\r
3416 if (mapArgs.count("-loadblockindextest"))
\r
3419 txdb.LoadBlockIndex();
\r
3425 // Load data files
\r
3431 printf("Loading addresses...\n");
\r
3432 nStart = GetTimeMillis();
\r
3433 if (!LoadAddresses())
\r
3434 strErrors += "Error loading addr.dat \n";
\r
3435 printf(" addresses %15"PRI64d"ms\n", GetTimeMillis() - nStart);
\r
3437 printf("Loading block index...\n");
\r
3438 nStart = GetTimeMillis();
\r
3439 if (!LoadBlockIndex())
\r
3440 strErrors += "Error loading blkindex.dat \n";
\r
3441 printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);
\r
3443 printf("Loading wallet...\n");
\r
3444 nStart = GetTimeMillis();
\r
3445 if (!LoadWallet(fFirstRun))
\r
3446 strErrors += "Error loading wallet.dat \n";
\r
3447 printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart);
\r
3449 printf("Done loading\n");
\r
3452 printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size());
\r
3453 printf("nBestHeight = %d\n", nBestHeight);
\r
3454 printf("mapKeys.size() = %d\n", mapKeys.size());
\r
3455 printf("mapPubKeys.size() = %d\n", mapPubKeys.size());
\r
3456 printf("mapWallet.size() = %d\n", mapWallet.size());
\r
3457 printf("mapAddressBook.size() = %d\n", mapAddressBook.size());
\r
3459 if (!strErrors.empty())
\r
3461 wxMessageBox(strErrors, "Bitcoin");
\r
3466 // Add wallet transactions that aren't already in a block to mapTransactions
\r
3467 ReacceptWalletTransactions();
\r
3472 if (mapArgs.count("-printblockindex") || mapArgs.count("-printblocktree"))
\r
3479 if (mapArgs.count("-printblock"))
\r
3481 string strMatch = mapArgs["-printblock"];
\r
3483 for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)
\r
3485 uint256 hash = (*mi).first;
\r
3486 if (strncmp(hash.ToString().c_str(), strMatch.c_str(), strMatch.size()) == 0)
\r
3488 CBlockIndex* pindex = (*mi).second;
\r
3490 block.ReadFromDisk(pindex, true);
\r
3491 block.BuildMerkleTree();
\r
3498 printf("No blocks matching %s were found\n", strMatch.c_str());
\r
3503 if (mapArgs.count("-gen"))
\r
3505 if (mapArgs["-gen"].empty())
\r
3506 fGenerateBitcoins = true;
\r
3508 fGenerateBitcoins = (atoi(mapArgs["-gen"].c_str()) != 0);
\r
3511 if (mapArgs.count("-proxy"))
\r
3514 addrProxy = CAddress(mapArgs["-proxy"]);
\r
3515 if (!addrProxy.IsValid())
\r
3517 wxMessageBox("Invalid -proxy address", "Bitcoin");
\r
3523 if (mapArgs.count("-addnode"))
\r
3526 foreach(string strAddr, mapMultiArgs["-addnode"])
\r
3528 CAddress addr(strAddr, NODE_NETWORK);
\r
3529 addr.nTime = 0; // so it won't relay unless successfully connected
\r
3530 if (addr.IsValid())
\r
3531 AddAddress(addrdb, addr);
\r
3536 // Create the main frame window
\r
3538 pframeMain = new CMainFrame(NULL);
\r
3539 if (mapArgs.count("-min"))
\r
3540 pframeMain->Iconize(true);
\r
3541 pframeMain->Show(true); // have to show first to get taskbar button to hide
\r
3542 pframeMain->Show(!fMinimizeToTray || !pframeMain->IsIconized());
\r
3543 ptaskbaricon->Show(fMinimizeToTray);
\r
3545 _beginthread(ThreadDelayedRepaint, 0, NULL);
\r
3547 if (!CheckDiskSpace())
\r
3553 RandAddSeedPerfmon();
\r
3555 if (!StartNode(strErrors))
\r
3556 wxMessageBox(strErrors, "Bitcoin");
\r
3558 GenerateBitcoins(fGenerateBitcoins);
\r
3561 SetStartOnSystemStartup(true);
\r
3568 if (argc >= 2 && stricmp(argv[1], "-send") == 0)
\r
3570 if (argc >= 2 && strcmp(argv[1], "-send") == 0)
\r
3575 ParseMoney(argv[2], nValue);
\r
3577 string strAddress;
\r
3579 strAddress = argv[3];
\r
3580 CAddress addr(strAddress);
\r
3583 wtx.mapValue["to"] = strAddress;
\r
3584 wtx.mapValue["from"] = addrLocalHost.ToString();
\r
3585 wtx.mapValue["message"] = "command line send";
\r
3587 // Send to IP address
\r
3588 CSendingDialog* pdialog = new CSendingDialog(pframeMain, addr, nValue, wtx);
\r
3589 if (!pdialog->ShowModal())
\r
3596 int CMyApp::OnExit()
\r
3599 return wxApp::OnExit();
\r
3602 bool CMyApp::OnExceptionInMainLoop()
\r
3608 catch (std::exception& e)
\r
3610 PrintException(&e, "CMyApp::OnExceptionInMainLoop()");
\r
3611 wxLogWarning("Exception %s %s", typeid(e).name(), e.what());
\r
3617 PrintException(NULL, "CMyApp::OnExceptionInMainLoop()");
\r
3618 wxLogWarning("Unknown exception");
\r
3626 void CMyApp::OnUnhandledException()
\r
3628 // this shows how we may let some exception propagate uncaught
\r
3633 catch (std::exception& e)
\r
3635 PrintException(&e, "CMyApp::OnUnhandledException()");
\r
3636 wxLogWarning("Exception %s %s", typeid(e).name(), e.what());
\r
3642 PrintException(NULL, "CMyApp::OnUnhandledException()");
\r
3643 wxLogWarning("Unknown exception");
\r
3649 void CMyApp::OnFatalException()
\r
3651 wxMessageBox("Program has crashed and will terminate. ", "Bitcoin", wxOK | wxICON_ERROR);
\r
3659 typedef WINSHELLAPI BOOL (WINAPI *PSHGETSPECIALFOLDERPATHA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);
\r
3661 string MyGetSpecialFolderPath(int nFolder, bool fCreate)
\r
3663 char pszPath[MAX_PATH+100] = "";
\r
3665 // SHGetSpecialFolderPath is not usually available on NT 4.0
\r
3666 HMODULE hShell32 = LoadLibrary("shell32.dll");
\r
3669 PSHGETSPECIALFOLDERPATHA pSHGetSpecialFolderPath =
\r
3670 (PSHGETSPECIALFOLDERPATHA)GetProcAddress(hShell32, "SHGetSpecialFolderPathA");
\r
3671 if (pSHGetSpecialFolderPath)
\r
3672 (*pSHGetSpecialFolderPath)(NULL, pszPath, nFolder, fCreate);
\r
3673 FreeModule(hShell32);
\r
3677 if (pszPath[0] == '\0')
\r
3679 if (nFolder == CSIDL_STARTUP)
\r
3681 strcpy(pszPath, getenv("USERPROFILE"));
\r
3682 strcat(pszPath, "\\Start Menu\\Programs\\Startup");
\r
3684 else if (nFolder == CSIDL_APPDATA)
\r
3686 strcpy(pszPath, getenv("APPDATA"));
\r
3693 string StartupShortcutPath()
\r
3695 return MyGetSpecialFolderPath(CSIDL_STARTUP, true) + "\\Bitcoin.lnk";
\r
3698 bool GetStartOnSystemStartup()
\r
3700 return wxFileExists(StartupShortcutPath());
\r
3703 void SetStartOnSystemStartup(bool fAutoStart)
\r
3705 // If the shortcut exists already, remove it for updating
\r
3706 remove(StartupShortcutPath().c_str());
\r
3710 CoInitialize(NULL);
\r
3712 // Get a pointer to the IShellLink interface.
\r
3713 HRESULT hres = NULL;
\r
3714 IShellLink* psl = NULL;
\r
3715 hres = CoCreateInstance(CLSID_ShellLink, NULL,
\r
3716 CLSCTX_INPROC_SERVER, IID_IShellLink,
\r
3717 reinterpret_cast<void**>(&psl));
\r
3719 if (SUCCEEDED(hres))
\r
3721 // Get the current executable path
\r
3722 char pszExePath[MAX_PATH];
\r
3723 GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));
\r
3725 // Set the path to the shortcut target
\r
3726 psl->SetPath(pszExePath);
\r
3727 PathRemoveFileSpec(pszExePath);
\r
3728 psl->SetWorkingDirectory(pszExePath);
\r
3729 psl->SetShowCmd(SW_SHOWMINNOACTIVE);
\r
3731 // Query IShellLink for the IPersistFile interface for
\r
3732 // saving the shortcut in persistent storage.
\r
3733 IPersistFile* ppf = NULL;
\r
3734 hres = psl->QueryInterface(IID_IPersistFile,
\r
3735 reinterpret_cast<void**>(&ppf));
\r
3736 if (SUCCEEDED(hres))
\r
3738 WCHAR pwsz[MAX_PATH];
\r
3739 // Ensure that the string is ANSI.
\r
3740 MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().c_str(), -1, pwsz, MAX_PATH);
\r
3741 // Save the link by calling IPersistFile::Save.
\r
3742 hres = ppf->Save(pwsz, TRUE);
\r
3751 bool GetStartOnSystemStartup() { return false; }
\r
3752 void SetStartOnSystemStartup(bool fAutoStart) { }
\r