1 // Copyright (c) 2009-2010 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
12 DEFINE_EVENT_TYPE(wxEVT_UITHREADCALL)
\r
14 CMainFrame* pframeMain = NULL;
\r
15 CMyTaskBarIcon* ptaskbaricon = NULL;
\r
16 bool fClosedToTray = false;
\r
26 //////////////////////////////////////////////////////////////////////////////
\r
31 void HandleCtrlA(wxKeyEvent& event)
\r
33 // Ctrl-a select all
\r
35 wxTextCtrl* textCtrl = (wxTextCtrl*)event.GetEventObject();
\r
36 if (event.GetModifiers() == wxMOD_CONTROL && event.GetKeyCode() == 'A')
\r
37 textCtrl->SetSelection(-1, -1);
\r
42 //char pszHourFormat[256];
\r
43 //pszHourFormat[0] = '\0';
\r
44 //GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ITIME, pszHourFormat, 256);
\r
45 //return (pszHourFormat[0] != '0');
\r
49 string DateStr(int64 nTime)
\r
51 // Can only be used safely here in the UI
\r
52 return (string)wxDateTime((time_t)nTime).FormatDate();
\r
55 string DateTimeStr(int64 nTime)
\r
57 // Can only be used safely here in the UI
\r
58 wxDateTime datetime((time_t)nTime);
\r
60 return (string)datetime.Format("%x %H:%M");
\r
62 return (string)datetime.Format("%x ") + itostr((datetime.GetHour() + 11) % 12 + 1) + (string)datetime.Format(":%M %p");
\r
65 wxString GetItemText(wxListCtrl* listCtrl, int nIndex, int nColumn)
\r
67 // Helper to simplify access to listctrl
\r
69 item.m_itemId = nIndex;
\r
70 item.m_col = nColumn;
\r
71 item.m_mask = wxLIST_MASK_TEXT;
\r
72 if (!listCtrl->GetItem(item))
\r
74 return item.GetText();
\r
77 int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1)
\r
79 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
\r
80 listCtrl->SetItem(nIndex, 1, str1);
\r
84 int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
\r
86 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
\r
87 listCtrl->SetItem(nIndex, 1, str1);
\r
88 listCtrl->SetItem(nIndex, 2, str2);
\r
89 listCtrl->SetItem(nIndex, 3, str3);
\r
90 listCtrl->SetItem(nIndex, 4, str4);
\r
94 int InsertLine(wxListCtrl* listCtrl, void* pdata, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
\r
96 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
\r
97 listCtrl->SetItemPtrData(nIndex, (wxUIntPtr)pdata);
\r
98 listCtrl->SetItem(nIndex, 1, str1);
\r
99 listCtrl->SetItem(nIndex, 2, str2);
\r
100 listCtrl->SetItem(nIndex, 3, str3);
\r
101 listCtrl->SetItem(nIndex, 4, str4);
\r
105 void SetSelection(wxListCtrl* listCtrl, int nIndex)
\r
107 int nSize = listCtrl->GetItemCount();
\r
108 long nState = (wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
\r
109 for (int i = 0; i < nSize; i++)
\r
110 listCtrl->SetItemState(i, (i == nIndex ? nState : 0), nState);
\r
113 int GetSelection(wxListCtrl* listCtrl)
\r
115 int nSize = listCtrl->GetItemCount();
\r
116 for (int i = 0; i < nSize; i++)
\r
117 if (listCtrl->GetItemState(i, wxLIST_STATE_FOCUSED))
\r
122 string HtmlEscape(const char* psz, bool fMultiLine=false)
\r
125 for (const char* p = psz; *p; p++)
\r
127 if (*p == '<') len += 4;
\r
128 else if (*p == '>') len += 4;
\r
129 else if (*p == '&') len += 5;
\r
130 else if (*p == '"') len += 6;
\r
131 else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') len += 6;
\r
132 else if (*p == '\n' && fMultiLine) len += 5;
\r
138 for (const char* p = psz; *p; p++)
\r
140 if (*p == '<') str += "<";
\r
141 else if (*p == '>') str += ">";
\r
142 else if (*p == '&') str += "&";
\r
143 else if (*p == '"') str += """;
\r
144 else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') str += " ";
\r
145 else if (*p == '\n' && fMultiLine) str += "<br>\n";
\r
152 string HtmlEscape(const string& str, bool fMultiLine=false)
\r
154 return HtmlEscape(str.c_str(), fMultiLine);
\r
157 void CalledMessageBox(const string& message, const string& caption, int style, wxWindow* parent, int x, int y, int* pnRet, bool* pfDone)
\r
159 *pnRet = wxMessageBox(message, caption, style, parent, x, y);
\r
163 int ThreadSafeMessageBox(const string& message, const string& caption, int style, wxWindow* parent, int x, int y)
\r
166 return wxMessageBox(message, caption, style, parent, x, y);
\r
168 if (wxThread::IsMain() || fDaemon)
\r
170 return wxMessageBox(message, caption, style, parent, x, y);
\r
175 bool fDone = false;
\r
176 UIThreadCall(bind(CalledMessageBox, message, caption, style, parent, x, y, &nRet, &fDone));
\r
184 bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* parent)
\r
186 if (nFeeRequired == 0 || fDaemon)
\r
188 string strMessage = strprintf(
\r
189 _("This transaction is over the size limit. You can still send it for a fee of %s, "
\r
190 "which goes to the nodes that process your transaction and helps to support the network. "
\r
191 "Do you want to pay the fee?"),
\r
192 FormatMoney(nFeeRequired).c_str());
\r
193 return (ThreadSafeMessageBox(strMessage, strCaption, wxYES_NO, parent) == wxYES);
\r
196 void CalledSetStatusBar(const string& strText, int nField)
\r
198 if (pframeMain && pframeMain->m_statusBar)
\r
199 pframeMain->m_statusBar->SetStatusText(strText, nField);
\r
202 void SetDefaultReceivingAddress(const string& strAddress)
\r
204 // Update main window address and database
\r
205 if (pframeMain == NULL)
\r
207 if (strAddress != pframeMain->m_textCtrlAddress->GetValue())
\r
210 if (!AddressToHash160(strAddress, hash160))
\r
212 if (!mapPubKeys.count(hash160))
\r
214 CWalletDB().WriteDefaultKey(mapPubKeys[hash160]);
\r
215 pframeMain->m_textCtrlAddress->SetValue(strAddress);
\r
228 //////////////////////////////////////////////////////////////////////////////
\r
233 CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent)
\r
235 Connect(wxEVT_UITHREADCALL, wxCommandEventHandler(CMainFrame::OnUIThreadCall), NULL, this);
\r
237 // Set initially selected page
\r
238 wxNotebookEvent event;
\r
239 event.SetSelection(0);
\r
240 OnNotebookPageChanged(event);
\r
241 m_notebook->ChangeSelection(0);
\r
244 fRefreshListCtrl = false;
\r
245 fRefreshListCtrlRunning = false;
\r
246 fOnSetFocusAddress = false;
\r
248 m_choiceFilter->SetSelection(0);
\r
249 double dResize = 1.0;
\r
251 SetIcon(wxICON(bitcoin));
\r
253 SetIcon(bitcoin16_xpm);
\r
254 wxFont fontTmp = m_staticText41->GetFont();
\r
255 fontTmp.SetFamily(wxFONTFAMILY_TELETYPE);
\r
256 m_staticTextBalance->SetFont(fontTmp);
\r
257 m_staticTextBalance->SetSize(140, 17);
\r
258 // resize to fit ubuntu's huge default font
\r
260 SetSize(dResize * GetSize().GetWidth(), 1.15 * GetSize().GetHeight());
\r
262 m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " ");
\r
263 m_listCtrl->SetFocus();
\r
264 ptaskbaricon = new CMyTaskBarIcon();
\r
266 // Mac automatically moves wxID_EXIT, wxID_PREFERENCES and wxID_ABOUT
\r
267 // to their standard places, leaving these menus empty.
\r
268 GetMenuBar()->Remove(2); // remove Help menu
\r
269 GetMenuBar()->Remove(0); // remove File menu
\r
272 // Init column headers
\r
273 int nDateWidth = DateTimeStr(1229413914).size() * 6 + 8;
\r
274 if (!strstr(DateTimeStr(1229413914).c_str(), "2008"))
\r
280 wxListCtrl* pplistCtrl[] = {m_listCtrlAll, m_listCtrlSentReceived, m_listCtrlSent, m_listCtrlReceived};
\r
281 foreach(wxListCtrl* p, pplistCtrl)
\r
283 p->InsertColumn(0, "", wxLIST_FORMAT_LEFT, dResize * 0);
\r
284 p->InsertColumn(1, "", wxLIST_FORMAT_LEFT, dResize * 0);
\r
285 p->InsertColumn(2, _("Status"), wxLIST_FORMAT_LEFT, dResize * 112);
\r
286 p->InsertColumn(3, _("Date"), wxLIST_FORMAT_LEFT, dResize * nDateWidth);
\r
287 p->InsertColumn(4, _("Description"), wxLIST_FORMAT_LEFT, dResize * 409 - nDateWidth);
\r
288 p->InsertColumn(5, _("Debit"), wxLIST_FORMAT_RIGHT, dResize * 79);
\r
289 p->InsertColumn(6, _("Credit"), wxLIST_FORMAT_RIGHT, dResize * 79);
\r
293 int pnWidths[3] = { -100, 88, 300 };
\r
295 pnWidths[1] = pnWidths[1] * 1.1 * dResize;
\r
296 pnWidths[2] = pnWidths[2] * 1.1 * dResize;
\r
298 m_statusBar->SetFieldsCount(3, pnWidths);
\r
300 // Fill your address text box
\r
301 vector<unsigned char> vchPubKey;
\r
302 if (CWalletDB("r").ReadDefaultKey(vchPubKey))
\r
303 m_textCtrlAddress->SetValue(PubKeyToAddress(vchPubKey));
\r
305 // Fill listctrl with wallet transactions
\r
309 CMainFrame::~CMainFrame()
\r
312 delete ptaskbaricon;
\r
313 ptaskbaricon = NULL;
\r
316 void CMainFrame::OnNotebookPageChanged(wxNotebookEvent& event)
\r
319 nPage = event.GetSelection();
\r
322 m_listCtrl = m_listCtrlAll;
\r
323 fShowGenerated = true;
\r
325 fShowReceived = true;
\r
327 else if (nPage == SENTRECEIVED)
\r
329 m_listCtrl = m_listCtrlSentReceived;
\r
330 fShowGenerated = false;
\r
332 fShowReceived = true;
\r
334 else if (nPage == SENT)
\r
336 m_listCtrl = m_listCtrlSent;
\r
337 fShowGenerated = false;
\r
339 fShowReceived = false;
\r
341 else if (nPage == RECEIVED)
\r
343 m_listCtrl = m_listCtrlReceived;
\r
344 fShowGenerated = false;
\r
346 fShowReceived = true;
\r
349 m_listCtrl->SetFocus();
\r
352 void CMainFrame::OnClose(wxCloseEvent& event)
\r
354 if (fMinimizeOnClose && event.CanVeto() && !IsIconized())
\r
356 // Divert close to minimize
\r
358 fClosedToTray = true;
\r
364 CreateThread(Shutdown, NULL);
\r
368 void CMainFrame::OnIconize(wxIconizeEvent& event)
\r
371 // Hide the task bar button when minimized.
\r
372 // Event is sent when the frame is minimized or restored.
\r
373 // wxWidgets 2.8.9 doesn't have IsIconized() so there's no way
\r
374 // to get rid of the deprecated warning. Just ignore it.
\r
375 if (!event.Iconized())
\r
376 fClosedToTray = false;
\r
378 // Tray is not reliable on ubuntu 9.10 gnome
\r
379 fClosedToTray = false;
\r
381 if (fMinimizeToTray && event.Iconized())
\r
382 fClosedToTray = true;
\r
383 Show(!fClosedToTray);
\r
384 ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
\r
387 void CMainFrame::OnMouseEvents(wxMouseEvent& event)
\r
391 RAND_add(&event.m_x, sizeof(event.m_x), 0.25);
\r
392 RAND_add(&event.m_y, sizeof(event.m_y), 0.25);
\r
395 void CMainFrame::OnListColBeginDrag(wxListEvent& event)
\r
397 // Hidden columns not resizeable
\r
398 if (event.GetColumn() <= 1 && !fDebug)
\r
404 int CMainFrame::GetSortIndex(const string& strSort)
\r
409 // The wx generic listctrl implementation used on GTK doesn't sort,
\r
410 // so we have to do it ourselves. Remember, we sort in reverse order.
\r
411 // In the wx generic implementation, they store the list of items
\r
412 // in a vector, so indexed lookups are fast, but inserts are slower
\r
413 // the closer they are to the top.
\r
415 int high = m_listCtrl->GetItemCount();
\r
418 int mid = low + ((high - low) / 2);
\r
419 if (strSort.compare(m_listCtrl->GetItemText(mid).c_str()) >= 0)
\r
428 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
430 strSort = " " + strSort; // leading space to workaround wx2.9.0 ubuntu 9.10 bug
\r
431 long nData = *(long*)&hashKey; // where first char of hidden column is displayed
\r
434 if (!fNew && nIndex == -1)
\r
436 string strHash = " " + hashKey.ToString();
\r
437 while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)
\r
438 if (GetItemText(m_listCtrl, nIndex, 1) == strHash)
\r
442 // fNew is for blind insert, only use if you're sure it's new
\r
443 if (fNew || nIndex == -1)
\r
445 nIndex = m_listCtrl->InsertItem(GetSortIndex(strSort), strSort);
\r
449 // If sort key changed, must delete and reinsert to make it relocate
\r
450 if (GetItemText(m_listCtrl, nIndex, 0) != strSort)
\r
452 m_listCtrl->DeleteItem(nIndex);
\r
453 nIndex = m_listCtrl->InsertItem(GetSortIndex(strSort), strSort);
\r
457 m_listCtrl->SetItem(nIndex, 1, " " + hashKey.ToString());
\r
458 m_listCtrl->SetItem(nIndex, 2, str2);
\r
459 m_listCtrl->SetItem(nIndex, 3, str3);
\r
460 m_listCtrl->SetItem(nIndex, 4, str4);
\r
461 m_listCtrl->SetItem(nIndex, 5, str5);
\r
462 m_listCtrl->SetItem(nIndex, 6, str6);
\r
463 m_listCtrl->SetItemData(nIndex, nData);
\r
466 bool CMainFrame::DeleteLine(uint256 hashKey)
\r
468 long nData = *(long*)&hashKey;
\r
472 string strHash = " " + hashKey.ToString();
\r
473 while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)
\r
474 if (GetItemText(m_listCtrl, nIndex, 1) == strHash)
\r
478 m_listCtrl->DeleteItem(nIndex);
\r
480 return nIndex != -1;
\r
483 string FormatTxStatus(const CWalletTx& wtx)
\r
486 if (!wtx.IsFinal())
\r
488 if (wtx.nLockTime < 500000000)
\r
489 return strprintf(_("Open for %d blocks"), nBestHeight - wtx.nLockTime);
\r
491 return strprintf(_("Open until %s"), DateTimeStr(wtx.nLockTime).c_str());
\r
495 int nDepth = wtx.GetDepthInMainChain();
\r
496 if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
\r
497 return strprintf(_("%d/offline?"), nDepth);
\r
498 else if (nDepth < 6)
\r
499 return strprintf(_("%d/unconfirmed"), nDepth);
\r
501 return strprintf(_("%d confirmations"), nDepth);
\r
505 string SingleLine(const string& strIn)
\r
508 bool fOneSpace = false;
\r
509 foreach(int c, strIn)
\r
517 if (fOneSpace && !strOut.empty())
\r
526 bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
\r
528 int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime();
\r
529 int64 nCredit = wtx.GetCredit(true);
\r
530 int64 nDebit = wtx.GetDebit();
\r
531 int64 nNet = nCredit - nDebit;
\r
532 uint256 hash = wtx.GetHash();
\r
533 string strStatus = FormatTxStatus(wtx);
\r
534 map<string, string> mapValue = wtx.mapValue;
\r
535 wtx.nLinesDisplayed = 1;
\r
536 nListViewUpdated++;
\r
539 if (wtx.IsCoinBase())
\r
541 // Don't show generated coin until confirmed by at least one block after it
\r
542 // so we don't get the user's hopes up until it looks like it's probably accepted.
\r
544 // It is not an error when generated blocks are not accepted. By design,
\r
545 // some percentage of blocks, like 10% or more, will end up not accepted.
\r
546 // This is the normal mechanism by which the network copes with latency.
\r
548 // We display regular transactions right away before any confirmation
\r
549 // because they can always get into some block eventually. Generated coins
\r
550 // are special because if their block is not accepted, they are not valid.
\r
552 if (wtx.GetDepthInMainChain() < 2)
\r
554 wtx.nLinesDisplayed = 0;
\r
558 if (!fShowGenerated)
\r
562 // Find the block the tx is in
\r
563 CBlockIndex* pindex = NULL;
\r
564 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(wtx.hashBlock);
\r
565 if (mi != mapBlockIndex.end())
\r
566 pindex = (*mi).second;
\r
568 // Sort order, unrecorded transactions sort to the top
\r
569 string strSort = strprintf("%010d-%01d-%010u",
\r
570 (pindex ? pindex->nHeight : INT_MAX),
\r
571 (wtx.IsCoinBase() ? 1 : 0),
\r
572 wtx.nTimeReceived);
\r
575 if (nNet > 0 || wtx.IsCoinBase())
\r
580 string strDescription;
\r
581 if (wtx.IsCoinBase())
\r
584 strDescription = _("Generated");
\r
587 int64 nUnmatured = 0;
\r
588 foreach(const CTxOut& txout, wtx.vout)
\r
589 nUnmatured += txout.GetCredit();
\r
590 if (wtx.IsInMainChain())
\r
592 strDescription = strprintf(_("Generated (%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
\r
594 // Check if the block was requested by anyone
\r
595 if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
\r
596 strDescription = _("Generated - Warning: This block was not received by any other nodes and will probably not be accepted!");
\r
600 strDescription = _("Generated (not accepted)");
\r
604 else if (!mapValue["from"].empty() || !mapValue["message"].empty())
\r
606 // Received by IP connection
\r
607 if (!fShowReceived)
\r
609 if (!mapValue["from"].empty())
\r
610 strDescription += _("From: ") + mapValue["from"];
\r
611 if (!mapValue["message"].empty())
\r
613 if (!strDescription.empty())
\r
614 strDescription += " - ";
\r
615 strDescription += mapValue["message"];
\r
620 // Received by Bitcoin Address
\r
621 if (!fShowReceived)
\r
623 foreach(const CTxOut& txout, wtx.vout)
\r
625 if (txout.IsMine())
\r
627 vector<unsigned char> vchPubKey;
\r
628 if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
\r
630 CRITICAL_BLOCK(cs_mapAddressBook)
\r
632 //strDescription += _("Received payment to ");
\r
633 //strDescription += _("Received with address ");
\r
634 strDescription += _("From: unknown, Received with: ");
\r
635 string strAddress = PubKeyToAddress(vchPubKey);
\r
636 map<string, string>::iterator mi = mapAddressBook.find(strAddress);
\r
637 if (mi != mapAddressBook.end() && !(*mi).second.empty())
\r
639 string strLabel = (*mi).second;
\r
640 strDescription += strAddress.substr(0,12) + "... ";
\r
641 strDescription += "(" + strLabel + ")";
\r
644 strDescription += strAddress;
\r
652 InsertLine(fNew, nIndex, hash, strSort,
\r
654 nTime ? DateTimeStr(nTime) : "",
\r
655 SingleLine(strDescription),
\r
657 FormatMoney(nNet, true));
\r
661 bool fAllFromMe = true;
\r
662 foreach(const CTxIn& txin, wtx.vin)
\r
663 fAllFromMe = fAllFromMe && txin.IsMine();
\r
665 bool fAllToMe = true;
\r
666 foreach(const CTxOut& txout, wtx.vout)
\r
667 fAllToMe = fAllToMe && txout.IsMine();
\r
669 if (fAllFromMe && fAllToMe)
\r
672 int64 nValue = wtx.vout[0].nValue;
\r
673 InsertLine(fNew, nIndex, hash, strSort,
\r
675 nTime ? DateTimeStr(nTime) : "",
\r
676 _("Payment to yourself"),
\r
679 /// issue: can't tell which is the payment and which is the change anymore
\r
680 // FormatMoney(nNet - nValue, true),
\r
681 // FormatMoney(nValue, true));
\r
683 else if (fAllFromMe)
\r
691 int64 nTxFee = nDebit - wtx.GetValueOut();
\r
692 wtx.nLinesDisplayed = 0;
\r
693 for (int nOut = 0; nOut < wtx.vout.size(); nOut++)
\r
695 const CTxOut& txout = wtx.vout[nOut];
\r
696 if (txout.IsMine())
\r
700 if (!mapValue["to"].empty())
\r
703 strAddress = mapValue["to"];
\r
707 // Sent to Bitcoin Address
\r
709 if (ExtractHash160(txout.scriptPubKey, hash160))
\r
710 strAddress = Hash160ToAddress(hash160);
\r
713 string strDescription = _("To: ");
\r
714 CRITICAL_BLOCK(cs_mapAddressBook)
\r
715 if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
\r
716 strDescription += mapAddressBook[strAddress] + " ";
\r
717 strDescription += strAddress;
\r
718 if (!mapValue["message"].empty())
\r
720 if (!strDescription.empty())
\r
721 strDescription += " - ";
\r
722 strDescription += mapValue["message"];
\r
725 int64 nValue = txout.nValue;
\r
732 InsertLine(fNew, nIndex, hash, strprintf("%s-%d", strSort.c_str(), nOut),
\r
734 nTime ? DateTimeStr(nTime) : "",
\r
735 SingleLine(strDescription),
\r
736 FormatMoney(-nValue, true),
\r
738 wtx.nLinesDisplayed++;
\r
744 // Mixed debit transaction, can't break down payees
\r
746 bool fAllMine = true;
\r
747 foreach(const CTxOut& txout, wtx.vout)
\r
748 fAllMine = fAllMine && txout.IsMine();
\r
749 foreach(const CTxIn& txin, wtx.vin)
\r
750 fAllMine = fAllMine && txin.IsMine();
\r
752 InsertLine(fNew, nIndex, hash, strSort,
\r
754 nTime ? DateTimeStr(nTime) : "",
\r
756 FormatMoney(nNet, true),
\r
764 void CMainFrame::RefreshListCtrl()
\r
766 fRefreshListCtrl = true;
\r
770 void CMainFrame::OnIdle(wxIdleEvent& event)
\r
772 if (fRefreshListCtrl)
\r
774 // Collect list of wallet transactions and sort newest first
\r
775 bool fEntered = false;
\r
776 vector<pair<unsigned int, uint256> > vSorted;
\r
777 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
779 printf("RefreshListCtrl starting\n");
\r
781 fRefreshListCtrl = false;
\r
782 vWalletUpdated.clear();
\r
784 // Do the newest transactions first
\r
785 vSorted.reserve(mapWallet.size());
\r
786 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
\r
788 const CWalletTx& wtx = (*it).second;
\r
789 unsigned int nTime = UINT_MAX - wtx.GetTxTime();
\r
790 vSorted.push_back(make_pair(nTime, (*it).first));
\r
792 m_listCtrl->DeleteAllItems();
\r
797 sort(vSorted.begin(), vSorted.end());
\r
799 // Fill list control
\r
800 for (int i = 0; i < vSorted.size();)
\r
804 bool fEntered = false;
\r
805 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
808 uint256& hash = vSorted[i++].second;
\r
809 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
\r
810 if (mi != mapWallet.end())
\r
811 InsertTransaction((*mi).second, true);
\r
813 if (!fEntered || i == 100 || i % 500 == 0)
\r
817 printf("RefreshListCtrl done\n");
\r
819 // Update transaction total display
\r
820 MainFrameRepaint();
\r
824 // Check for time updates
\r
825 static int64 nLastTime;
\r
826 if (GetTime() > nLastTime + 30)
\r
828 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
830 nLastTime = GetTime();
\r
831 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
\r
833 CWalletTx& wtx = (*it).second;
\r
834 if (wtx.nTimeDisplayed && wtx.nTimeDisplayed != wtx.GetTxTime())
\r
835 InsertTransaction(wtx, false);
\r
842 void CMainFrame::RefreshStatusColumn()
\r
844 static int nLastTop;
\r
845 static CBlockIndex* pindexLastBest;
\r
846 static unsigned int nLastRefreshed;
\r
848 int nTop = max((int)m_listCtrl->GetTopItem(), 0);
\r
849 if (nTop == nLastTop && pindexLastBest == pindexBest)
\r
852 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
855 int nEnd = min(nStart + 100, m_listCtrl->GetItemCount());
\r
857 if (pindexLastBest == pindexBest && nLastRefreshed == nListViewUpdated)
\r
859 // If no updates, only need to do the part that moved onto the screen
\r
860 if (nStart >= nLastTop && nStart < nLastTop + 100)
\r
861 nStart = nLastTop + 100;
\r
862 if (nEnd >= nLastTop && nEnd < nLastTop + 100)
\r
866 pindexLastBest = pindexBest;
\r
867 nLastRefreshed = nListViewUpdated;
\r
869 for (int nIndex = nStart; nIndex < min(nEnd, m_listCtrl->GetItemCount()); nIndex++)
\r
871 uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1));
\r
872 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
\r
873 if (mi == mapWallet.end())
\r
875 printf("CMainFrame::RefreshStatusColumn() : tx not found in mapWallet\n");
\r
878 CWalletTx& wtx = (*mi).second;
\r
879 if (wtx.IsCoinBase() || wtx.GetTxTime() != wtx.nTimeDisplayed)
\r
881 if (!InsertTransaction(wtx, false, nIndex))
\r
882 m_listCtrl->DeleteItem(nIndex--);
\r
885 m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx));
\r
890 void CMainFrame::OnPaint(wxPaintEvent& event)
\r
901 unsigned int nNeedRepaint = 0;
\r
902 unsigned int nLastRepaint = 0;
\r
903 int64 nLastRepaintTime = 0;
\r
904 int64 nRepaintInterval = 500;
\r
906 void ThreadDelayedRepaint(void* parg)
\r
910 if (nLastRepaint != nNeedRepaint && GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)
\r
912 nLastRepaint = nNeedRepaint;
\r
915 printf("DelayedRepaint\n");
\r
916 wxPaintEvent event;
\r
917 pframeMain->fRefresh = true;
\r
918 pframeMain->GetEventHandler()->AddPendingEvent(event);
\r
921 Sleep(nRepaintInterval);
\r
925 void MainFrameRepaint()
\r
927 // This is called by network code that shouldn't access pframeMain
\r
928 // directly because it could still be running after the UI is closed.
\r
931 // Don't repaint too often
\r
932 static int64 nLastRepaintRequest;
\r
933 if (GetTimeMillis() - nLastRepaintRequest < 100)
\r
938 nLastRepaintRequest = GetTimeMillis();
\r
940 printf("MainFrameRepaint\n");
\r
941 wxPaintEvent event;
\r
942 pframeMain->fRefresh = true;
\r
943 pframeMain->GetEventHandler()->AddPendingEvent(event);
\r
947 void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
\r
949 // Skip lets the listctrl do the paint, we're just hooking the message
\r
953 ptaskbaricon->UpdateTooltip();
\r
958 static int nTransactionCount;
\r
959 bool fPaintedBalance = false;
\r
960 if (GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)
\r
962 nLastRepaint = nNeedRepaint;
\r
963 nLastRepaintTime = GetTimeMillis();
\r
965 // Update listctrl contents
\r
966 if (!vWalletUpdated.empty())
\r
968 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
971 if (m_listCtrl->GetItemCount())
\r
972 strTop = (string)m_listCtrl->GetItemText(0);
\r
973 foreach(uint256 hash, vWalletUpdated)
\r
975 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
\r
976 if (mi != mapWallet.end())
\r
977 InsertTransaction((*mi).second, false);
\r
979 vWalletUpdated.clear();
\r
980 if (m_listCtrl->GetItemCount() && strTop != (string)m_listCtrl->GetItemText(0))
\r
981 m_listCtrl->ScrollList(0, INT_MIN/2);
\r
986 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
988 fPaintedBalance = true;
\r
989 m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " ");
\r
991 // Count hidden and multi-line transactions
\r
992 nTransactionCount = 0;
\r
993 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
\r
995 CWalletTx& wtx = (*it).second;
\r
996 nTransactionCount += wtx.nLinesDisplayed;
\r
1000 if (!vWalletUpdated.empty() || !fPaintedBalance)
\r
1003 // Update status column of visible items only
\r
1004 RefreshStatusColumn();
\r
1006 // Update status bar
\r
1007 string strGen = "";
\r
1008 if (fGenerateBitcoins)
\r
1009 strGen = _(" Generating");
\r
1010 if (fGenerateBitcoins && vNodes.empty())
\r
1011 strGen = _("(not connected)");
\r
1012 m_statusBar->SetStatusText(strGen, 1);
\r
1014 string strStatus = strprintf(_(" %d connections %d blocks %d transactions"), vNodes.size(), nBestHeight + 1, nTransactionCount);
\r
1015 m_statusBar->SetStatusText(strStatus, 2);
\r
1017 if (fDebug && GetTime() - nThreadSocketHandlerHeartbeat > 60)
\r
1018 m_statusBar->SetStatusText(" ERROR: ThreadSocketHandler has stopped", 0);
\r
1020 // Update receiving address
\r
1021 string strDefaultAddress = PubKeyToAddress(vchDefaultKey);
\r
1022 if (m_textCtrlAddress->GetValue() != strDefaultAddress)
\r
1023 m_textCtrlAddress->SetValue(strDefaultAddress);
\r
1027 void UIThreadCall(boost::function0<void> fn)
\r
1029 // Call this with a function object created with bind.
\r
1030 // bind needs all parameters to match the function's expected types
\r
1031 // and all default parameters specified. Some examples:
\r
1032 // UIThreadCall(bind(wxBell));
\r
1033 // UIThreadCall(bind(wxMessageBox, wxT("Message"), wxT("Title"), wxOK, (wxWindow*)NULL, -1, -1));
\r
1034 // UIThreadCall(bind(&CMainFrame::OnMenuHelpAbout, pframeMain, event));
\r
1037 wxCommandEvent event(wxEVT_UITHREADCALL);
\r
1038 event.SetClientData((void*)new boost::function0<void>(fn));
\r
1039 pframeMain->GetEventHandler()->AddPendingEvent(event);
\r
1043 void CMainFrame::OnUIThreadCall(wxCommandEvent& event)
\r
1045 boost::function0<void>* pfn = (boost::function0<void>*)event.GetClientData();
\r
1050 void CMainFrame::OnMenuFileExit(wxCommandEvent& event)
\r
1056 void CMainFrame::OnMenuOptionsGenerate(wxCommandEvent& event)
\r
1058 // Options->Generate Coins
\r
1059 GenerateBitcoins(event.IsChecked());
\r
1062 void CMainFrame::OnUpdateUIOptionsGenerate(wxUpdateUIEvent& event)
\r
1064 event.Check(fGenerateBitcoins);
\r
1067 void CMainFrame::OnMenuOptionsChangeYourAddress(wxCommandEvent& event)
\r
1069 // Options->Your Receiving Addresses
\r
1070 CAddressBookDialog dialog(this, "", CAddressBookDialog::RECEIVING, false);
\r
1071 if (!dialog.ShowModal())
\r
1075 void CMainFrame::OnMenuOptionsOptions(wxCommandEvent& event)
\r
1077 // Options->Options
\r
1078 COptionsDialog dialog(this);
\r
1079 dialog.ShowModal();
\r
1082 void CMainFrame::OnMenuHelpAbout(wxCommandEvent& event)
\r
1085 CAboutDialog dialog(this);
\r
1086 dialog.ShowModal();
\r
1089 void CMainFrame::OnButtonSend(wxCommandEvent& event)
\r
1092 CSendDialog dialog(this);
\r
1093 dialog.ShowModal();
\r
1096 void CMainFrame::OnButtonAddressBook(wxCommandEvent& event)
\r
1098 // Toolbar: Address Book
\r
1099 CAddressBookDialog dialogAddr(this, "", CAddressBookDialog::SENDING, false);
\r
1100 if (dialogAddr.ShowModal() == 2)
\r
1103 CSendDialog dialogSend(this, dialogAddr.GetSelectedAddress());
\r
1104 dialogSend.ShowModal();
\r
1108 void CMainFrame::OnSetFocusAddress(wxFocusEvent& event)
\r
1110 // Automatically select-all when entering window
\r
1112 m_textCtrlAddress->SetSelection(-1, -1);
\r
1113 fOnSetFocusAddress = true;
\r
1116 void CMainFrame::OnMouseEventsAddress(wxMouseEvent& event)
\r
1119 if (fOnSetFocusAddress)
\r
1120 m_textCtrlAddress->SetSelection(-1, -1);
\r
1121 fOnSetFocusAddress = false;
\r
1124 void CMainFrame::OnButtonNew(wxCommandEvent& event)
\r
1127 CGetTextFromUserDialog dialog(this,
\r
1128 _("New Receiving Address"),
\r
1129 _("It's good policy to use a new address for each payment you receive.\n\nLabel"),
\r
1131 if (!dialog.ShowModal())
\r
1133 string strName = dialog.GetValue();
\r
1135 // Generate new key
\r
1136 string strAddress = PubKeyToAddress(GenerateNewKey());
\r
1139 SetAddressBookName(strAddress, strName);
\r
1140 SetDefaultReceivingAddress(strAddress);
\r
1143 void CMainFrame::OnButtonCopy(wxCommandEvent& event)
\r
1145 // Copy address box to clipboard
\r
1146 if (wxTheClipboard->Open())
\r
1148 wxTheClipboard->SetData(new wxTextDataObject(m_textCtrlAddress->GetValue()));
\r
1149 wxTheClipboard->Close();
\r
1153 void CMainFrame::OnListItemActivated(wxListEvent& event)
\r
1155 uint256 hash((string)GetItemText(m_listCtrl, event.GetIndex(), 1));
\r
1157 CRITICAL_BLOCK(cs_mapWallet)
\r
1159 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
\r
1160 if (mi == mapWallet.end())
\r
1162 printf("CMainFrame::OnListItemActivated() : tx not found in mapWallet\n");
\r
1165 wtx = (*mi).second;
\r
1167 CTxDetailsDialog dialog(this, wtx);
\r
1168 dialog.ShowModal();
\r
1169 //CTxDetailsDialog* pdialog = new CTxDetailsDialog(this, wtx);
\r
1170 //pdialog->Show();
\r
1178 //////////////////////////////////////////////////////////////////////////////
\r
1180 // CTxDetailsDialog
\r
1183 CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetailsDialogBase(parent)
\r
1185 CRITICAL_BLOCK(cs_mapAddressBook)
\r
1188 strHTML.reserve(4000);
\r
1189 strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
\r
1191 int64 nTime = wtx.GetTxTime();
\r
1192 int64 nCredit = wtx.GetCredit();
\r
1193 int64 nDebit = wtx.GetDebit();
\r
1194 int64 nNet = nCredit - nDebit;
\r
1198 strHTML += _("<b>Status:</b> ") + FormatTxStatus(wtx);
\r
1199 int nRequests = wtx.GetRequestCount();
\r
1200 if (nRequests != -1)
\r
1202 if (nRequests == 0)
\r
1203 strHTML += _(", has not been successfully broadcast yet");
\r
1204 else if (nRequests == 1)
\r
1205 strHTML += strprintf(_(", broadcast through %d node"), nRequests);
\r
1207 strHTML += strprintf(_(", broadcast through %d nodes"), nRequests);
\r
1209 strHTML += "<br>";
\r
1211 strHTML += _("<b>Date:</b> ") + (nTime ? DateTimeStr(nTime) : "") + "<br>";
\r
1217 if (wtx.IsCoinBase())
\r
1219 strHTML += _("<b>Source:</b> Generated<br>");
\r
1221 else if (!wtx.mapValue["from"].empty())
\r
1223 // Online transaction
\r
1224 if (!wtx.mapValue["from"].empty())
\r
1225 strHTML += _("<b>From:</b> ") + HtmlEscape(wtx.mapValue["from"]) + "<br>";
\r
1229 // Offline transaction
\r
1233 foreach(const CTxOut& txout, wtx.vout)
\r
1235 if (txout.IsMine())
\r
1237 vector<unsigned char> vchPubKey;
\r
1238 if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
\r
1240 string strAddress = PubKeyToAddress(vchPubKey);
\r
1241 if (mapAddressBook.count(strAddress))
\r
1243 strHTML += string() + _("<b>From:</b> ") + _("unknown") + "<br>";
\r
1244 strHTML += _("<b>To:</b> ");
\r
1245 strHTML += HtmlEscape(strAddress);
\r
1246 if (!mapAddressBook[strAddress].empty())
\r
1247 strHTML += _(" (yours, label: ") + mapAddressBook[strAddress] + ")";
\r
1249 strHTML += _(" (yours)");
\r
1250 strHTML += "<br>";
\r
1263 string strAddress;
\r
1264 if (!wtx.mapValue["to"].empty())
\r
1266 // Online transaction
\r
1267 strAddress = wtx.mapValue["to"];
\r
1268 strHTML += _("<b>To:</b> ");
\r
1269 if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
\r
1270 strHTML += mapAddressBook[strAddress] + " ";
\r
1271 strHTML += HtmlEscape(strAddress) + "<br>";
\r
1278 if (wtx.IsCoinBase() && nCredit == 0)
\r
1283 int64 nUnmatured = 0;
\r
1284 foreach(const CTxOut& txout, wtx.vout)
\r
1285 nUnmatured += txout.GetCredit();
\r
1286 strHTML += _("<b>Credit:</b> ");
\r
1287 if (wtx.IsInMainChain())
\r
1288 strHTML += strprintf(_("(%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
\r
1290 strHTML += _("(not accepted)");
\r
1291 strHTML += "<br>";
\r
1293 else if (nNet > 0)
\r
1298 strHTML += _("<b>Credit:</b> ") + FormatMoney(nNet) + "<br>";
\r
1302 bool fAllFromMe = true;
\r
1303 foreach(const CTxIn& txin, wtx.vin)
\r
1304 fAllFromMe = fAllFromMe && txin.IsMine();
\r
1306 bool fAllToMe = true;
\r
1307 foreach(const CTxOut& txout, wtx.vout)
\r
1308 fAllToMe = fAllToMe && txout.IsMine();
\r
1315 foreach(const CTxOut& txout, wtx.vout)
\r
1317 if (txout.IsMine())
\r
1320 if (wtx.mapValue["to"].empty())
\r
1322 // Offline transaction
\r
1324 if (ExtractHash160(txout.scriptPubKey, hash160))
\r
1326 string strAddress = Hash160ToAddress(hash160);
\r
1327 strHTML += _("<b>To:</b> ");
\r
1328 if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
\r
1329 strHTML += mapAddressBook[strAddress] + " ";
\r
1330 strHTML += strAddress;
\r
1331 strHTML += "<br>";
\r
1335 strHTML += _("<b>Debit:</b> ") + FormatMoney(-txout.nValue) + "<br>";
\r
1340 // Payment to self
\r
1341 /// issue: can't tell which is the payment and which is the change anymore
\r
1342 //int64 nValue = wtx.vout[0].nValue;
\r
1343 //strHTML += _("<b>Debit:</b> ") + FormatMoney(-nValue) + "<br>";
\r
1344 //strHTML += _("<b>Credit:</b> ") + FormatMoney(nValue) + "<br>";
\r
1347 int64 nTxFee = nDebit - wtx.GetValueOut();
\r
1349 strHTML += _("<b>Transaction fee:</b> ") + FormatMoney(-nTxFee) + "<br>";
\r
1354 // Mixed debit transaction
\r
1356 foreach(const CTxIn& txin, wtx.vin)
\r
1357 if (txin.IsMine())
\r
1358 strHTML += _("<b>Debit:</b> ") + FormatMoney(-txin.GetDebit()) + "<br>";
\r
1359 foreach(const CTxOut& txout, wtx.vout)
\r
1360 if (txout.IsMine())
\r
1361 strHTML += _("<b>Credit:</b> ") + FormatMoney(txout.GetCredit()) + "<br>";
\r
1365 strHTML += _("<b>Net amount:</b> ") + FormatMoney(nNet, true) + "<br>";
\r
1371 if (!wtx.mapValue["message"].empty())
\r
1372 strHTML += string() + "<br><b>" + _("Message:") + "</b><br>" + HtmlEscape(wtx.mapValue["message"], true) + "<br>";
\r
1374 if (wtx.IsCoinBase())
\r
1375 strHTML += string() + "<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
1383 strHTML += "<hr><br>debug print<br><br>";
\r
1384 foreach(const CTxIn& txin, wtx.vin)
\r
1385 if (txin.IsMine())
\r
1386 strHTML += "<b>Debit:</b> " + FormatMoney(-txin.GetDebit()) + "<br>";
\r
1387 foreach(const CTxOut& txout, wtx.vout)
\r
1388 if (txout.IsMine())
\r
1389 strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";
\r
1391 strHTML += "<b>Inputs:</b><br>";
\r
1392 CRITICAL_BLOCK(cs_mapWallet)
\r
1394 foreach(const CTxIn& txin, wtx.vin)
\r
1396 COutPoint prevout = txin.prevout;
\r
1397 map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
\r
1398 if (mi != mapWallet.end())
\r
1400 const CWalletTx& prev = (*mi).second;
\r
1401 if (prevout.n < prev.vout.size())
\r
1403 strHTML += HtmlEscape(prev.ToString(), true);
\r
1404 strHTML += " " + FormatTxStatus(prev) + ", ";
\r
1405 strHTML = strHTML + "IsMine=" + (prev.vout[prevout.n].IsMine() ? "true" : "false") + "<br>";
\r
1411 strHTML += "<br><hr><br><b>Transaction:</b><br>";
\r
1412 strHTML += HtmlEscape(wtx.ToString(), true);
\r
1417 strHTML += "</font></html>";
\r
1418 string(strHTML.begin(), strHTML.end()).swap(strHTML);
\r
1419 m_htmlWin->SetPage(strHTML);
\r
1420 m_buttonOK->SetFocus();
\r
1424 void CTxDetailsDialog::OnButtonOK(wxCommandEvent& event)
\r
1434 //////////////////////////////////////////////////////////////////////////////
\r
1439 COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent)
\r
1441 // Set up list box of page choices
\r
1442 m_listBox->Append(_("Main"));
\r
1443 //m_listBox->Append(_("Test 2"));
\r
1444 m_listBox->SetSelection(0);
\r
1447 m_checkBoxMinimizeOnClose->SetLabel(_("&Minimize on close"));
\r
1448 m_checkBoxStartOnSystemStartup->Enable(false); // not implemented yet
\r
1452 m_textCtrlTransactionFee->SetValue(FormatMoney(nTransactionFee));
\r
1453 m_checkBoxLimitProcessors->SetValue(fLimitProcessors);
\r
1454 m_spinCtrlLimitProcessors->Enable(fLimitProcessors);
\r
1455 m_spinCtrlLimitProcessors->SetValue(nLimitProcessors);
\r
1456 int nProcessors = wxThread::GetCPUCount();
\r
1457 if (nProcessors < 1)
\r
1458 nProcessors = 999;
\r
1459 m_spinCtrlLimitProcessors->SetRange(1, nProcessors);
\r
1460 m_checkBoxStartOnSystemStartup->SetValue(fTmpStartOnSystemStartup = GetStartOnSystemStartup());
\r
1461 m_checkBoxMinimizeToTray->SetValue(fMinimizeToTray);
\r
1462 m_checkBoxMinimizeOnClose->SetValue(fMinimizeOnClose);
\r
1463 m_checkBoxUseProxy->SetValue(fUseProxy);
\r
1464 m_textCtrlProxyIP->Enable(fUseProxy);
\r
1465 m_textCtrlProxyPort->Enable(fUseProxy);
\r
1466 m_staticTextProxyIP->Enable(fUseProxy);
\r
1467 m_staticTextProxyPort->Enable(fUseProxy);
\r
1468 m_textCtrlProxyIP->SetValue(addrProxy.ToStringIP());
\r
1469 m_textCtrlProxyPort->SetValue(addrProxy.ToStringPort());
\r
1471 m_buttonOK->SetFocus();
\r
1474 void COptionsDialog::SelectPage(int nPage)
\r
1476 m_panelMain->Show(nPage == 0);
\r
1477 m_panelTest2->Show(nPage == 1);
\r
1479 m_scrolledWindow->Layout();
\r
1480 m_scrolledWindow->SetScrollbars(0, 0, 0, 0, 0, 0);
\r
1483 void COptionsDialog::OnListBox(wxCommandEvent& event)
\r
1485 SelectPage(event.GetSelection());
\r
1488 void COptionsDialog::OnKillFocusTransactionFee(wxFocusEvent& event)
\r
1491 int64 nTmp = nTransactionFee;
\r
1492 ParseMoney(m_textCtrlTransactionFee->GetValue(), nTmp);
\r
1493 m_textCtrlTransactionFee->SetValue(FormatMoney(nTmp));
\r
1496 void COptionsDialog::OnCheckBoxLimitProcessors(wxCommandEvent& event)
\r
1498 m_spinCtrlLimitProcessors->Enable(event.IsChecked());
\r
1501 void COptionsDialog::OnCheckBoxUseProxy(wxCommandEvent& event)
\r
1503 m_textCtrlProxyIP->Enable(event.IsChecked());
\r
1504 m_textCtrlProxyPort->Enable(event.IsChecked());
\r
1505 m_staticTextProxyIP->Enable(event.IsChecked());
\r
1506 m_staticTextProxyPort->Enable(event.IsChecked());
\r
1509 CAddress COptionsDialog::GetProxyAddr()
\r
1511 // Be careful about byte order, addr.ip and addr.port are big endian
\r
1512 CAddress addr(m_textCtrlProxyIP->GetValue() + ":" + m_textCtrlProxyPort->GetValue());
\r
1513 if (addr.ip == INADDR_NONE)
\r
1514 addr.ip = addrProxy.ip;
\r
1515 int nPort = atoi(m_textCtrlProxyPort->GetValue());
\r
1516 addr.port = htons(nPort);
\r
1517 if (nPort <= 0 || nPort > USHRT_MAX)
\r
1518 addr.port = addrProxy.port;
\r
1522 void COptionsDialog::OnKillFocusProxy(wxFocusEvent& event)
\r
1525 m_textCtrlProxyIP->SetValue(GetProxyAddr().ToStringIP());
\r
1526 m_textCtrlProxyPort->SetValue(GetProxyAddr().ToStringPort());
\r
1530 void COptionsDialog::OnButtonOK(wxCommandEvent& event)
\r
1532 OnButtonApply(event);
\r
1536 void COptionsDialog::OnButtonCancel(wxCommandEvent& event)
\r
1541 void COptionsDialog::OnButtonApply(wxCommandEvent& event)
\r
1543 CWalletDB walletdb;
\r
1545 int64 nPrevTransactionFee = nTransactionFee;
\r
1546 if (ParseMoney(m_textCtrlTransactionFee->GetValue(), nTransactionFee) && nTransactionFee != nPrevTransactionFee)
\r
1547 walletdb.WriteSetting("nTransactionFee", nTransactionFee);
\r
1549 int nPrevMaxProc = (fLimitProcessors ? nLimitProcessors : INT_MAX);
\r
1550 if (fLimitProcessors != m_checkBoxLimitProcessors->GetValue())
\r
1552 fLimitProcessors = m_checkBoxLimitProcessors->GetValue();
\r
1553 walletdb.WriteSetting("fLimitProcessors", fLimitProcessors);
\r
1555 if (nLimitProcessors != m_spinCtrlLimitProcessors->GetValue())
\r
1557 nLimitProcessors = m_spinCtrlLimitProcessors->GetValue();
\r
1558 walletdb.WriteSetting("nLimitProcessors", nLimitProcessors);
\r
1560 if (fGenerateBitcoins && (fLimitProcessors ? nLimitProcessors : INT_MAX) > nPrevMaxProc)
\r
1561 GenerateBitcoins(fGenerateBitcoins);
\r
1563 if (fTmpStartOnSystemStartup != m_checkBoxStartOnSystemStartup->GetValue())
\r
1565 fTmpStartOnSystemStartup = m_checkBoxStartOnSystemStartup->GetValue();
\r
1566 SetStartOnSystemStartup(fTmpStartOnSystemStartup);
\r
1569 if (fMinimizeToTray != m_checkBoxMinimizeToTray->GetValue())
\r
1571 fMinimizeToTray = m_checkBoxMinimizeToTray->GetValue();
\r
1572 walletdb.WriteSetting("fMinimizeToTray", fMinimizeToTray);
\r
1573 ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
\r
1576 if (fMinimizeOnClose != m_checkBoxMinimizeOnClose->GetValue())
\r
1578 fMinimizeOnClose = m_checkBoxMinimizeOnClose->GetValue();
\r
1579 walletdb.WriteSetting("fMinimizeOnClose", fMinimizeOnClose);
\r
1582 fUseProxy = m_checkBoxUseProxy->GetValue();
\r
1583 walletdb.WriteSetting("fUseProxy", fUseProxy);
\r
1585 addrProxy = GetProxyAddr();
\r
1586 walletdb.WriteSetting("addrProxy", addrProxy);
\r
1593 //////////////////////////////////////////////////////////////////////////////
\r
1598 CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent)
\r
1600 m_staticTextVersion->SetLabel(strprintf(_("version 0.%d.%d beta"), VERSION/100, VERSION%100));
\r
1602 // Change (c) into UTF-8 or ANSI copyright symbol
\r
1603 wxString str = m_staticTextMain->GetLabel();
\r
1605 str.Replace("(c)", wxString::FromUTF8("\xC2\xA9"));
\r
1607 str.Replace("(c)", "\xA9");
\r
1609 m_staticTextMain->SetLabel(str);
\r
1611 // Resize on Linux to make the window fit the text.
\r
1612 // The text was wrapped manually rather than using the Wrap setting because
\r
1613 // the wrap would be too small on Linux and it can't be changed at this point.
\r
1614 wxFont fontTmp = m_staticTextMain->GetFont();
\r
1615 if (fontTmp.GetPointSize() > 8);
\r
1616 fontTmp.SetPointSize(8);
\r
1617 m_staticTextMain->SetFont(fontTmp);
\r
1618 SetSize(GetSize().GetWidth() + 44, GetSize().GetHeight() + 10);
\r
1622 void CAboutDialog::OnButtonOK(wxCommandEvent& event)
\r
1632 //////////////////////////////////////////////////////////////////////////////
\r
1637 CSendDialog::CSendDialog(wxWindow* parent, const wxString& strAddress) : CSendDialogBase(parent)
\r
1640 m_textCtrlAddress->SetValue(strAddress);
\r
1641 m_choiceTransferType->SetSelection(0);
\r
1642 m_bitmapCheckMark->Show(false);
\r
1643 fEnabledPrev = true;
\r
1644 m_textCtrlAddress->SetFocus();
\r
1645 //// todo: should add a display of your balance for convenience
\r
1647 wxFont fontTmp = m_staticTextInstructions->GetFont();
\r
1648 if (fontTmp.GetPointSize() > 9);
\r
1649 fontTmp.SetPointSize(9);
\r
1650 m_staticTextInstructions->SetFont(fontTmp);
\r
1651 SetSize(725, 380);
\r
1656 iconSend.CopyFromBitmap(wxBitmap(send16noshadow_xpm));
\r
1657 SetIcon(iconSend);
\r
1659 wxCommandEvent event;
\r
1660 OnTextAddress(event);
\r
1662 // Fixup the tab order
\r
1663 m_buttonPaste->MoveAfterInTabOrder(m_buttonCancel);
\r
1664 m_buttonAddress->MoveAfterInTabOrder(m_buttonPaste);
\r
1668 void CSendDialog::OnTextAddress(wxCommandEvent& event)
\r
1672 bool fBitcoinAddress = IsValidBitcoinAddress(m_textCtrlAddress->GetValue());
\r
1673 m_bitmapCheckMark->Show(fBitcoinAddress);
\r
1675 // Grey out message if bitcoin address
\r
1676 bool fEnable = !fBitcoinAddress;
\r
1677 m_staticTextFrom->Enable(fEnable);
\r
1678 m_textCtrlFrom->Enable(fEnable);
\r
1679 m_staticTextMessage->Enable(fEnable);
\r
1680 m_textCtrlMessage->Enable(fEnable);
\r
1681 m_textCtrlMessage->SetBackgroundColour(wxSystemSettings::GetColour(fEnable ? wxSYS_COLOUR_WINDOW : wxSYS_COLOUR_BTNFACE));
\r
1682 if (!fEnable && fEnabledPrev)
\r
1684 strFromSave = m_textCtrlFrom->GetValue();
\r
1685 strMessageSave = m_textCtrlMessage->GetValue();
\r
1686 m_textCtrlFrom->SetValue(_("Will appear as \"From: Unknown\""));
\r
1687 m_textCtrlMessage->SetValue(_("Can't include a message when sending to a Bitcoin address"));
\r
1689 else if (fEnable && !fEnabledPrev)
\r
1691 m_textCtrlFrom->SetValue(strFromSave);
\r
1692 m_textCtrlMessage->SetValue(strMessageSave);
\r
1694 fEnabledPrev = fEnable;
\r
1697 void CSendDialog::OnKillFocusAmount(wxFocusEvent& event)
\r
1699 // Reformat the amount
\r
1701 if (m_textCtrlAmount->GetValue().Trim().empty())
\r
1704 if (ParseMoney(m_textCtrlAmount->GetValue(), nTmp))
\r
1705 m_textCtrlAmount->SetValue(FormatMoney(nTmp));
\r
1708 void CSendDialog::OnButtonAddressBook(wxCommandEvent& event)
\r
1710 // Open address book
\r
1711 CAddressBookDialog dialog(this, m_textCtrlAddress->GetValue(), CAddressBookDialog::SENDING, true);
\r
1712 if (dialog.ShowModal())
\r
1713 m_textCtrlAddress->SetValue(dialog.GetSelectedAddress());
\r
1716 void CSendDialog::OnButtonPaste(wxCommandEvent& event)
\r
1718 // Copy clipboard to address box
\r
1719 if (wxTheClipboard->Open())
\r
1721 if (wxTheClipboard->IsSupported(wxDF_TEXT))
\r
1723 wxTextDataObject data;
\r
1724 wxTheClipboard->GetData(data);
\r
1725 m_textCtrlAddress->SetValue(data.GetText());
\r
1727 wxTheClipboard->Close();
\r
1731 void CSendDialog::OnButtonSend(wxCommandEvent& event)
\r
1734 string strAddress = (string)m_textCtrlAddress->GetValue();
\r
1738 if (!ParseMoney(m_textCtrlAmount->GetValue(), nValue) || nValue <= 0)
\r
1740 wxMessageBox(_("Error in amount "), _("Send Coins"));
\r
1743 if (nValue > GetBalance())
\r
1745 wxMessageBox(_("Amount exceeds your balance "), _("Send Coins"));
\r
1748 if (nValue + nTransactionFee > GetBalance())
\r
1750 wxMessageBox(string(_("Total exceeds your balance when the ")) + FormatMoney(nTransactionFee) + _(" transaction fee is included "), _("Send Coins"));
\r
1754 // Parse bitcoin address
\r
1756 bool fBitcoinAddress = AddressToHash160(strAddress, hash160);
\r
1758 if (fBitcoinAddress)
\r
1760 // Send to bitcoin address
\r
1761 CScript scriptPubKey;
\r
1762 scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
\r
1764 string strError = SendMoney(scriptPubKey, nValue, wtx, true);
\r
1765 if (strError == "")
\r
1766 wxMessageBox(_("Payment sent "), _("Sending..."));
\r
1767 else if (strError != "ABORTED")
\r
1768 wxMessageBox(strError + " ", _("Sending..."));
\r
1772 // Parse IP address
\r
1773 CAddress addr(strAddress);
\r
1774 if (!addr.IsValid())
\r
1776 wxMessageBox(_("Invalid address "), _("Send Coins"));
\r
1781 wtx.mapValue["to"] = strAddress;
\r
1782 wtx.mapValue["from"] = m_textCtrlFrom->GetValue();
\r
1783 wtx.mapValue["message"] = m_textCtrlMessage->GetValue();
\r
1785 // Send to IP address
\r
1786 CSendingDialog* pdialog = new CSendingDialog(this, addr, nValue, wtx);
\r
1787 if (!pdialog->ShowModal())
\r
1791 CRITICAL_BLOCK(cs_mapAddressBook)
\r
1792 if (!mapAddressBook.count(strAddress))
\r
1793 SetAddressBookName(strAddress, "");
\r
1798 void CSendDialog::OnButtonCancel(wxCommandEvent& event)
\r
1809 //////////////////////////////////////////////////////////////////////////////
\r
1814 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
1817 nPrice = nPriceIn;
\r
1819 start = wxDateTime::UNow();
\r
1820 memset(pszStatus, 0, sizeof(pszStatus));
\r
1821 fCanCancel = true;
\r
1825 fWorkDone = false;
\r
1827 SetSize(1.2 * GetSize().GetWidth(), 1.08 * GetSize().GetHeight());
\r
1830 SetTitle(strprintf(_("Sending %s to %s"), FormatMoney(nPrice).c_str(), wtx.mapValue["to"].c_str()));
\r
1831 m_textCtrlStatus->SetValue("");
\r
1833 CreateThread(SendingDialogStartTransfer, this);
\r
1836 CSendingDialog::~CSendingDialog()
\r
1838 printf("~CSendingDialog()\n");
\r
1841 void CSendingDialog::Close()
\r
1843 // Last one out turn out the lights.
\r
1844 // fWorkDone signals that work side is done and UI thread should call destroy.
\r
1845 // fUIDone signals that UI window has closed and work thread should call destroy.
\r
1846 // This allows the window to disappear and end modality when cancelled
\r
1847 // without making the user wait for ConnectNode to return. The dialog object
\r
1848 // hangs around in the background until the work thread exits.
\r
1850 EndModal(fSuccess);
\r
1859 void CSendingDialog::OnClose(wxCloseEvent& event)
\r
1861 if (!event.CanVeto() || fWorkDone || fAbort || !fCanCancel)
\r
1868 wxCommandEvent cmdevent;
\r
1869 OnButtonCancel(cmdevent);
\r
1873 void CSendingDialog::OnButtonOK(wxCommandEvent& event)
\r
1879 void CSendingDialog::OnButtonCancel(wxCommandEvent& event)
\r
1885 void CSendingDialog::OnPaint(wxPaintEvent& event)
\r
1888 if (strlen(pszStatus) > 130)
\r
1889 m_textCtrlStatus->SetValue(string("\n") + pszStatus);
\r
1891 m_textCtrlStatus->SetValue(string("\n\n") + pszStatus);
\r
1892 m_staticTextSending->SetFocus();
\r
1894 m_buttonCancel->Enable(false);
\r
1897 m_buttonOK->Enable(true);
\r
1898 m_buttonOK->SetFocus();
\r
1899 m_buttonCancel->Enable(false);
\r
1901 if (fAbort && fCanCancel && IsShown())
\r
1903 strcpy(pszStatus, _("CANCELLED"));
\r
1904 m_buttonOK->Enable(true);
\r
1905 m_buttonOK->SetFocus();
\r
1906 m_buttonCancel->Enable(false);
\r
1907 m_buttonCancel->SetLabel(_("Cancelled"));
\r
1909 wxMessageBox(_("Transfer cancelled "), _("Sending..."), wxOK, this);
\r
1915 // Everything from here on is not in the UI thread and must only communicate
\r
1916 // with the rest of the dialog through variables and calling repaint.
\r
1919 void CSendingDialog::Repaint()
\r
1922 wxPaintEvent event;
\r
1923 GetEventHandler()->AddPendingEvent(event);
\r
1926 bool CSendingDialog::Status()
\r
1933 if (fAbort && fCanCancel)
\r
1935 memset(pszStatus, 0, 10);
\r
1936 strcpy(pszStatus, _("CANCELLED"));
\r
1944 bool CSendingDialog::Status(const string& str)
\r
1949 // This can be read by the UI thread at any time,
\r
1950 // so copy in a way that can be read cleanly at all times.
\r
1951 memset(pszStatus, 0, min(str.size()+1, sizeof(pszStatus)));
\r
1952 strlcpy(pszStatus, str.c_str(), sizeof(pszStatus));
\r
1958 bool CSendingDialog::Error(const string& str)
\r
1960 fCanCancel = false;
\r
1962 Status(string(_("Error: ")) + str);
\r
1966 void SendingDialogStartTransfer(void* parg)
\r
1968 ((CSendingDialog*)parg)->StartTransfer();
\r
1971 void CSendingDialog::StartTransfer()
\r
1973 // Make sure we have enough money
\r
1974 if (nPrice + nTransactionFee > GetBalance())
\r
1976 Error(_("Insufficient funds"));
\r
1980 // We may have connected already for product details
\r
1981 if (!Status(_("Connecting...")))
\r
1983 CNode* pnode = ConnectNode(addr, 15 * 60);
\r
1986 Error(_("Unable to connect"));
\r
1990 // Send order to seller, with response going to OnReply2 via event handler
\r
1991 if (!Status(_("Requesting public key...")))
\r
1993 pnode->PushRequest("checkorder", wtx, SendingDialogOnReply2, this);
\r
1996 void SendingDialogOnReply2(void* parg, CDataStream& vRecv)
\r
1998 ((CSendingDialog*)parg)->OnReply2(vRecv);
\r
2001 void CSendingDialog::OnReply2(CDataStream& vRecv)
\r
2003 if (!Status(_("Received public key...")))
\r
2006 CScript scriptPubKey;
\r
2013 string strMessage;
\r
2014 vRecv >> strMessage;
\r
2015 Error(_("Transfer was not accepted"));
\r
2016 //// todo: enlarge the window and enable a hidden white box to put seller's message
\r
2019 vRecv >> scriptPubKey;
\r
2023 //// what do we want to do about this?
\r
2024 Error(_("Invalid response received"));
\r
2028 // Pause to give the user a chance to cancel
\r
2029 while (wxDateTime::UNow() < start + wxTimeSpan(0, 0, 0, 2 * 1000))
\r
2036 CRITICAL_BLOCK(cs_main)
\r
2039 if (!Status(_("Creating transaction...")))
\r
2041 if (nPrice + nTransactionFee > GetBalance())
\r
2043 Error(_("Insufficient funds"));
\r
2047 int64 nFeeRequired;
\r
2048 if (!CreateTransaction(scriptPubKey, nPrice, wtx, key, nFeeRequired))
\r
2050 if (nPrice + nFeeRequired > GetBalance())
\r
2051 Error(strprintf(_("This is an oversized transaction that requires a transaction fee of %s"), FormatMoney(nFeeRequired).c_str()));
\r
2053 Error(_("Transaction creation failed"));
\r
2057 // Transaction fee
\r
2058 if (!ThreadSafeAskFee(nFeeRequired, _("Sending..."), this))
\r
2060 Error(_("Transaction aborted"));
\r
2064 // Make sure we're still connected
\r
2065 CNode* pnode = ConnectNode(addr, 2 * 60 * 60);
\r
2068 Error(_("Lost connection, transaction cancelled"));
\r
2072 // Last chance to cancel
\r
2076 fCanCancel = false;
\r
2079 fCanCancel = true;
\r
2082 fCanCancel = false;
\r
2084 if (!Status(_("Sending payment...")))
\r
2088 if (!CommitTransaction(wtx, key))
\r
2090 Error(_("The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."));
\r
2094 // Send payment tx to seller, with response going to OnReply3 via event handler
\r
2095 CWalletTx wtxSend = wtx;
\r
2096 wtxSend.fFromMe = false;
\r
2097 pnode->PushRequest("submitorder", wtxSend, SendingDialogOnReply3, this);
\r
2099 Status(_("Waiting for confirmation..."));
\r
2100 MainFrameRepaint();
\r
2104 void SendingDialogOnReply3(void* parg, CDataStream& vRecv)
\r
2106 ((CSendingDialog*)parg)->OnReply3(vRecv);
\r
2109 void CSendingDialog::OnReply3(CDataStream& vRecv)
\r
2117 Error(_("The payment was sent, but the recipient was unable to verify it.\n"
\r
2118 "The transaction is recorded and will credit to the recipient,\n"
\r
2119 "but the comment information will be blank."));
\r
2125 //// what do we want to do about this?
\r
2126 Error(_("Payment was sent, but an invalid response was received"));
\r
2132 Status(_("Payment completed"));
\r
2140 //////////////////////////////////////////////////////////////////////////////
\r
2142 // CAddressBookDialog
\r
2145 CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInitSelected, int nPageIn, bool fDuringSendIn) : CAddressBookDialogBase(parent)
\r
2147 // Set initially selected page
\r
2148 wxNotebookEvent event;
\r
2149 event.SetSelection(nPageIn);
\r
2150 OnNotebookPageChanged(event);
\r
2151 m_notebook->ChangeSelection(nPageIn);
\r
2153 fDuringSend = fDuringSendIn;
\r
2155 m_buttonCancel->Show(false);
\r
2158 wxIcon iconAddressBook;
\r
2159 iconAddressBook.CopyFromBitmap(wxBitmap(addressbook16_xpm));
\r
2160 SetIcon(iconAddressBook);
\r
2162 // Init column headers
\r
2163 m_listCtrlSending->InsertColumn(0, _("Name"), wxLIST_FORMAT_LEFT, 200);
\r
2164 m_listCtrlSending->InsertColumn(1, _("Address"), wxLIST_FORMAT_LEFT, 350);
\r
2165 m_listCtrlSending->SetFocus();
\r
2166 m_listCtrlReceiving->InsertColumn(0, _("Label"), wxLIST_FORMAT_LEFT, 200);
\r
2167 m_listCtrlReceiving->InsertColumn(1, _("Bitcoin Address"), wxLIST_FORMAT_LEFT, 350);
\r
2168 m_listCtrlReceiving->SetFocus();
\r
2170 // Fill listctrl with address book data
\r
2171 CRITICAL_BLOCK(cs_mapKeys)
\r
2172 CRITICAL_BLOCK(cs_mapAddressBook)
\r
2174 string strDefaultReceiving = (string)pframeMain->m_textCtrlAddress->GetValue();
\r
2175 foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
\r
2177 string strAddress = item.first;
\r
2178 string strName = item.second;
\r
2180 bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
\r
2181 wxListCtrl* plistCtrl = fMine ? m_listCtrlReceiving : m_listCtrlSending;
\r
2182 int nIndex = InsertLine(plistCtrl, strName, strAddress);
\r
2183 if (strAddress == (fMine ? strDefaultReceiving : string(strInitSelected)))
\r
2184 plistCtrl->SetItemState(nIndex, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
\r
2189 wxString CAddressBookDialog::GetSelectedAddress()
\r
2191 int nIndex = GetSelection(m_listCtrl);
\r
2194 return GetItemText(m_listCtrl, nIndex, 1);
\r
2197 wxString CAddressBookDialog::GetSelectedSendingAddress()
\r
2199 int nIndex = GetSelection(m_listCtrlSending);
\r
2202 return GetItemText(m_listCtrlSending, nIndex, 1);
\r
2205 wxString CAddressBookDialog::GetSelectedReceivingAddress()
\r
2207 int nIndex = GetSelection(m_listCtrlReceiving);
\r
2210 return GetItemText(m_listCtrlReceiving, nIndex, 1);
\r
2213 void CAddressBookDialog::OnNotebookPageChanged(wxNotebookEvent& event)
\r
2216 nPage = event.GetSelection();
\r
2217 if (nPage == SENDING)
\r
2218 m_listCtrl = m_listCtrlSending;
\r
2219 else if (nPage == RECEIVING)
\r
2220 m_listCtrl = m_listCtrlReceiving;
\r
2221 m_buttonDelete->Show(nPage == SENDING);
\r
2222 m_buttonCopy->Show(nPage == RECEIVING);
\r
2224 m_listCtrl->SetFocus();
\r
2227 void CAddressBookDialog::OnListEndLabelEdit(wxListEvent& event)
\r
2229 // Update address book with edited name
\r
2231 if (event.IsEditCancelled())
\r
2233 string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1);
\r
2234 SetAddressBookName(strAddress, string(event.GetText()));
\r
2235 pframeMain->RefreshListCtrl();
\r
2238 void CAddressBookDialog::OnListItemSelected(wxListEvent& event)
\r
2241 if (nPage == RECEIVING)
\r
2242 SetDefaultReceivingAddress((string)GetSelectedReceivingAddress());
\r
2245 void CAddressBookDialog::OnListItemActivated(wxListEvent& event)
\r
2250 // Doubleclick returns selection
\r
2251 EndModal(GetSelectedAddress() != "" ? 2 : 0);
\r
2255 // Doubleclick edits item
\r
2256 wxCommandEvent event2;
\r
2257 OnButtonEdit(event2);
\r
2260 void CAddressBookDialog::OnButtonDelete(wxCommandEvent& event)
\r
2262 if (nPage != SENDING)
\r
2264 for (int nIndex = m_listCtrl->GetItemCount()-1; nIndex >= 0; nIndex--)
\r
2266 if (m_listCtrl->GetItemState(nIndex, wxLIST_STATE_SELECTED))
\r
2268 string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
\r
2269 CWalletDB().EraseName(strAddress);
\r
2270 m_listCtrl->DeleteItem(nIndex);
\r
2273 pframeMain->RefreshListCtrl();
\r
2276 void CAddressBookDialog::OnButtonCopy(wxCommandEvent& event)
\r
2278 // Copy address box to clipboard
\r
2279 if (wxTheClipboard->Open())
\r
2281 wxTheClipboard->SetData(new wxTextDataObject(GetSelectedAddress()));
\r
2282 wxTheClipboard->Close();
\r
2286 bool CAddressBookDialog::CheckIfMine(const string& strAddress, const string& strTitle)
\r
2289 bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
\r
2291 wxMessageBox(_("This is one of your own addresses for receiving payments and cannot be entered in the address book. "), strTitle);
\r
2295 void CAddressBookDialog::OnButtonEdit(wxCommandEvent& event)
\r
2297 int nIndex = GetSelection(m_listCtrl);
\r
2300 string strName = (string)m_listCtrl->GetItemText(nIndex);
\r
2301 string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
\r
2302 string strAddressOrg = strAddress;
\r
2304 if (nPage == SENDING)
\r
2306 // Ask name and address
\r
2309 CGetTextFromUserDialog dialog(this, _("Edit Address"), _("Name"), strName, _("Address"), strAddress);
\r
2310 if (!dialog.ShowModal())
\r
2312 strName = dialog.GetValue1();
\r
2313 strAddress = dialog.GetValue2();
\r
2315 while (CheckIfMine(strAddress, _("Edit Address")));
\r
2318 else if (nPage == RECEIVING)
\r
2321 CGetTextFromUserDialog dialog(this, _("Edit Address Label"), _("Label"), strName);
\r
2322 if (!dialog.ShowModal())
\r
2324 strName = dialog.GetValue();
\r
2328 if (strAddress != strAddressOrg)
\r
2329 CWalletDB().EraseName(strAddressOrg);
\r
2330 SetAddressBookName(strAddress, strName);
\r
2331 m_listCtrl->SetItem(nIndex, 1, strAddress);
\r
2332 m_listCtrl->SetItemText(nIndex, strName);
\r
2333 pframeMain->RefreshListCtrl();
\r
2336 void CAddressBookDialog::OnButtonNew(wxCommandEvent& event)
\r
2339 string strAddress;
\r
2341 if (nPage == SENDING)
\r
2343 // Ask name and address
\r
2346 CGetTextFromUserDialog dialog(this, _("Add Address"), _("Name"), strName, _("Address"), strAddress);
\r
2347 if (!dialog.ShowModal())
\r
2349 strName = dialog.GetValue1();
\r
2350 strAddress = dialog.GetValue2();
\r
2352 while (CheckIfMine(strAddress, _("Add Address")));
\r
2354 else if (nPage == RECEIVING)
\r
2357 CGetTextFromUserDialog dialog(this,
\r
2358 _("New Receiving Address"),
\r
2359 _("It's good policy to use a new address for each payment you receive.\n\nLabel"),
\r
2361 if (!dialog.ShowModal())
\r
2363 strName = dialog.GetValue();
\r
2365 // Generate new key
\r
2366 strAddress = PubKeyToAddress(GenerateNewKey());
\r
2369 // Add to list and select it
\r
2370 SetAddressBookName(strAddress, strName);
\r
2371 int nIndex = InsertLine(m_listCtrl, strName, strAddress);
\r
2372 SetSelection(m_listCtrl, nIndex);
\r
2373 m_listCtrl->SetFocus();
\r
2374 if (nPage == SENDING)
\r
2375 pframeMain->RefreshListCtrl();
\r
2378 void CAddressBookDialog::OnButtonOK(wxCommandEvent& event)
\r
2381 EndModal(GetSelectedAddress() != "" ? 1 : 0);
\r
2384 void CAddressBookDialog::OnButtonCancel(wxCommandEvent& event)
\r
2390 void CAddressBookDialog::OnClose(wxCloseEvent& event)
\r
2401 //////////////////////////////////////////////////////////////////////////////
\r
2408 ID_TASKBAR_RESTORE = 10001,
\r
2409 ID_TASKBAR_OPTIONS,
\r
2410 ID_TASKBAR_GENERATE,
\r
2414 BEGIN_EVENT_TABLE(CMyTaskBarIcon, wxTaskBarIcon)
\r
2415 EVT_TASKBAR_LEFT_DCLICK(CMyTaskBarIcon::OnLeftButtonDClick)
\r
2416 EVT_MENU(ID_TASKBAR_RESTORE, CMyTaskBarIcon::OnMenuRestore)
\r
2417 EVT_MENU(ID_TASKBAR_OPTIONS, CMyTaskBarIcon::OnMenuOptions)
\r
2418 EVT_MENU(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnMenuGenerate)
\r
2419 EVT_UPDATE_UI(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnUpdateUIGenerate)
\r
2420 EVT_MENU(ID_TASKBAR_EXIT, CMyTaskBarIcon::OnMenuExit)
\r
2423 void CMyTaskBarIcon::Show(bool fShow)
\r
2425 static char pszPrevTip[200];
\r
2428 string strTooltip = _("Bitcoin");
\r
2429 if (fGenerateBitcoins)
\r
2430 strTooltip = _("Bitcoin - Generating");
\r
2431 if (fGenerateBitcoins && vNodes.empty())
\r
2432 strTooltip = _("Bitcoin - (not connected)");
\r
2434 // Optimization, only update when changed, using char array to be reentrant
\r
2435 if (strncmp(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip)-1) != 0)
\r
2437 strlcpy(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip));
\r
2439 SetIcon(wxICON(bitcoin), strTooltip);
\r
2441 SetIcon(bitcoin20_xpm, strTooltip);
\r
2447 strlcpy(pszPrevTip, "", sizeof(pszPrevTip));
\r
2452 void CMyTaskBarIcon::Hide()
\r
2457 void CMyTaskBarIcon::OnLeftButtonDClick(wxTaskBarIconEvent& event)
\r
2462 void CMyTaskBarIcon::OnMenuRestore(wxCommandEvent& event)
\r
2467 void CMyTaskBarIcon::OnMenuOptions(wxCommandEvent& event)
\r
2469 // Since it's modal, get the main window to do it
\r
2470 wxCommandEvent event2(wxEVT_COMMAND_MENU_SELECTED, wxID_PREFERENCES);
\r
2471 pframeMain->GetEventHandler()->AddPendingEvent(event2);
\r
2474 void CMyTaskBarIcon::Restore()
\r
2476 pframeMain->Show();
\r
2477 wxIconizeEvent event(0, false);
\r
2478 pframeMain->GetEventHandler()->AddPendingEvent(event);
\r
2479 pframeMain->Iconize(false);
\r
2480 pframeMain->Raise();
\r
2483 void CMyTaskBarIcon::OnMenuGenerate(wxCommandEvent& event)
\r
2485 GenerateBitcoins(event.IsChecked());
\r
2488 void CMyTaskBarIcon::OnUpdateUIGenerate(wxUpdateUIEvent& event)
\r
2490 event.Check(fGenerateBitcoins);
\r
2493 void CMyTaskBarIcon::OnMenuExit(wxCommandEvent& event)
\r
2495 pframeMain->Close(true);
\r
2498 void CMyTaskBarIcon::UpdateTooltip()
\r
2500 if (IsIconInstalled())
\r
2504 wxMenu* CMyTaskBarIcon::CreatePopupMenu()
\r
2506 wxMenu* pmenu = new wxMenu;
\r
2507 pmenu->Append(ID_TASKBAR_RESTORE, _("&Open Bitcoin"));
\r
2508 pmenu->Append(ID_TASKBAR_OPTIONS, _("O&ptions..."));
\r
2509 pmenu->AppendCheckItem(ID_TASKBAR_GENERATE, _("&Generate Coins"))->Check(fGenerateBitcoins);
\r
2510 #ifndef __WXMAC_OSX__ // Mac has built-in quit menu
\r
2511 pmenu->AppendSeparator();
\r
2512 pmenu->Append(ID_TASKBAR_EXIT, _("E&xit"));
\r
2529 void CreateMainWindow()
\r
2531 pframeMain = new CMainFrame(NULL);
\r
2532 if (mapArgs.count("-min"))
\r
2533 pframeMain->Iconize(true);
\r
2534 pframeMain->Show(true); // have to show first to get taskbar button to hide
\r
2535 if (fMinimizeToTray && pframeMain->IsIconized())
\r
2536 fClosedToTray = true;
\r
2537 pframeMain->Show(!fClosedToTray);
\r
2538 ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
\r
2539 CreateThread(ThreadDelayedRepaint, NULL);
\r