1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
9 #include <boost/filesystem/fstream.hpp>
10 #include <boost/filesystem/convenience.hpp>
16 using namespace boost;
19 DEFINE_EVENT_TYPE(wxEVT_UITHREADCALL)
21 CMainFrame* pframeMain = NULL;
22 CMyTaskBarIcon* ptaskbaricon = NULL;
23 bool fClosedToTray = false;
30 static const double nScaleX = 1.0;
31 static const double nScaleY = 1.0;
41 //////////////////////////////////////////////////////////////////////////////
46 void HandleCtrlA(wxKeyEvent& event)
50 wxTextCtrl* textCtrl = (wxTextCtrl*)event.GetEventObject();
51 if (event.GetModifiers() == wxMOD_CONTROL && event.GetKeyCode() == 'A')
52 textCtrl->SetSelection(-1, -1);
57 //char pszHourFormat[256];
58 //pszHourFormat[0] = '\0';
59 //GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ITIME, pszHourFormat, 256);
60 //return (pszHourFormat[0] != '0');
64 string DateStr(int64 nTime)
66 // Can only be used safely here in the UI
67 return (string)wxDateTime((time_t)nTime).FormatDate();
70 string DateTimeStr(int64 nTime)
72 // Can only be used safely here in the UI
73 wxDateTime datetime((time_t)nTime);
75 return (string)datetime.Format("%x %H:%M");
77 return (string)datetime.Format("%x ") + itostr((datetime.GetHour() + 11) % 12 + 1) + (string)datetime.Format(":%M %p");
80 wxString GetItemText(wxListCtrl* listCtrl, int nIndex, int nColumn)
82 // Helper to simplify access to listctrl
84 item.m_itemId = nIndex;
86 item.m_mask = wxLIST_MASK_TEXT;
87 if (!listCtrl->GetItem(item))
89 return item.GetText();
92 int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1)
94 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
95 listCtrl->SetItem(nIndex, 1, str1);
99 int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
101 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
102 listCtrl->SetItem(nIndex, 1, str1);
103 listCtrl->SetItem(nIndex, 2, str2);
104 listCtrl->SetItem(nIndex, 3, str3);
105 listCtrl->SetItem(nIndex, 4, str4);
109 int InsertLine(wxListCtrl* listCtrl, void* pdata, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
111 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
112 listCtrl->SetItemPtrData(nIndex, (wxUIntPtr)pdata);
113 listCtrl->SetItem(nIndex, 1, str1);
114 listCtrl->SetItem(nIndex, 2, str2);
115 listCtrl->SetItem(nIndex, 3, str3);
116 listCtrl->SetItem(nIndex, 4, str4);
120 void SetItemTextColour(wxListCtrl* listCtrl, int nIndex, const wxColour& colour)
122 // Repaint on Windows is more flickery if the colour has ever been set,
123 // so don't want to set it unless it's different. Default colour has
124 // alpha 0 transparent, so our colours don't match using operator==.
125 wxColour c1 = listCtrl->GetItemTextColour(nIndex);
127 c1 = wxColour(0,0,0);
128 if (colour.Red() != c1.Red() || colour.Green() != c1.Green() || colour.Blue() != c1.Blue())
129 listCtrl->SetItemTextColour(nIndex, colour);
132 void SetSelection(wxListCtrl* listCtrl, int nIndex)
134 int nSize = listCtrl->GetItemCount();
135 long nState = (wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
136 for (int i = 0; i < nSize; i++)
137 listCtrl->SetItemState(i, (i == nIndex ? nState : 0), nState);
140 int GetSelection(wxListCtrl* listCtrl)
142 int nSize = listCtrl->GetItemCount();
143 for (int i = 0; i < nSize; i++)
144 if (listCtrl->GetItemState(i, wxLIST_STATE_FOCUSED))
149 string HtmlEscape(const char* psz, bool fMultiLine=false)
152 for (const char* p = psz; *p; p++)
154 if (*p == '<') len += 4;
155 else if (*p == '>') len += 4;
156 else if (*p == '&') len += 5;
157 else if (*p == '"') len += 6;
158 else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') len += 6;
159 else if (*p == '\n' && fMultiLine) len += 5;
165 for (const char* p = psz; *p; p++)
167 if (*p == '<') str += "<";
168 else if (*p == '>') str += ">";
169 else if (*p == '&') str += "&";
170 else if (*p == '"') str += """;
171 else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') str += " ";
172 else if (*p == '\n' && fMultiLine) str += "<br>\n";
179 string HtmlEscape(const string& str, bool fMultiLine=false)
181 return HtmlEscape(str.c_str(), fMultiLine);
184 void CalledMessageBox(const string& message, const string& caption, int style, wxWindow* parent, int x, int y, int* pnRet, bool* pfDone)
186 *pnRet = wxMessageBox(message, caption, style, parent, x, y);
190 int ThreadSafeMessageBox(const string& message, const string& caption, int style, wxWindow* parent, int x, int y)
193 return wxMessageBox(message, caption, style, parent, x, y);
195 if (wxThread::IsMain() || fDaemon)
197 return wxMessageBox(message, caption, style, parent, x, y);
203 UIThreadCall(bind(CalledMessageBox, message, caption, style, parent, x, y, &nRet, &fDone));
211 bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* parent)
213 if (nFeeRequired < MIN_TX_FEE || nFeeRequired <= nTransactionFee || fDaemon)
215 string strMessage = strprintf(
216 _("This transaction is over the size limit. You can still send it for a fee of %s, "
217 "which goes to the nodes that process your transaction and helps to support the network. "
218 "Do you want to pay the fee?"),
219 FormatMoney(nFeeRequired).c_str());
220 return (ThreadSafeMessageBox(strMessage, strCaption, wxYES_NO, parent) == wxYES);
223 void CalledSetStatusBar(const string& strText, int nField)
225 if (nField == 0 && GetWarnings("statusbar") != "")
227 if (pframeMain && pframeMain->m_statusBar)
228 pframeMain->m_statusBar->SetStatusText(strText, nField);
231 void SetDefaultReceivingAddress(const string& strAddress)
233 // Update main window address and database
234 if (pframeMain == NULL)
236 if (strAddress != pframeMain->m_textCtrlAddress->GetValue())
239 if (!AddressToHash160(strAddress, hash160))
241 if (!mapPubKeys.count(hash160))
243 CWalletDB(pwalletMain->strWalletFile).WriteDefaultKey(mapPubKeys[hash160]);
244 pframeMain->m_textCtrlAddress->SetValue(strAddress);
257 //////////////////////////////////////////////////////////////////////////////
262 CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent)
264 Connect(wxEVT_UITHREADCALL, wxCommandEventHandler(CMainFrame::OnUIThreadCall), NULL, this);
266 // Set initially selected page
267 wxNotebookEvent event;
268 event.SetSelection(0);
269 OnNotebookPageChanged(event);
270 m_notebook->ChangeSelection(0);
273 fRefreshListCtrl = false;
274 fRefreshListCtrlRunning = false;
275 fOnSetFocusAddress = false;
277 m_choiceFilter->SetSelection(0);
278 double dResize = nScaleX;
280 SetIcon(wxICON(bitcoin));
281 SetSize(dResize * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
283 SetIcon(bitcoin80_xpm);
284 SetBackgroundColour(m_toolBar->GetBackgroundColour());
285 wxFont fontTmp = m_staticText41->GetFont();
286 fontTmp.SetFamily(wxFONTFAMILY_TELETYPE);
287 m_staticTextBalance->SetFont(fontTmp);
288 m_staticTextBalance->SetSize(140, 17);
289 // resize to fit ubuntu's huge default font
291 SetSize(dResize * GetSize().GetWidth(), 1.15 * GetSize().GetHeight());
293 m_staticTextBalance->SetLabel(FormatMoney(pwalletMain->GetBalance()) + " ");
294 m_listCtrl->SetFocus();
295 ptaskbaricon = new CMyTaskBarIcon();
297 // Mac automatically moves wxID_EXIT, wxID_PREFERENCES and wxID_ABOUT
298 // to their standard places, leaving these menus empty.
299 GetMenuBar()->Remove(2); // remove Help menu
300 GetMenuBar()->Remove(0); // remove File menu
303 // Init column headers
304 int nDateWidth = DateTimeStr(1229413914).size() * 6 + 8;
305 if (!strstr(DateTimeStr(1229413914).c_str(), "2008"))
311 wxListCtrl* pplistCtrl[] = {m_listCtrlAll, m_listCtrlSentReceived, m_listCtrlSent, m_listCtrlReceived};
312 BOOST_FOREACH(wxListCtrl* p, pplistCtrl)
314 p->InsertColumn(0, "", wxLIST_FORMAT_LEFT, dResize * 0);
315 p->InsertColumn(1, "", wxLIST_FORMAT_LEFT, dResize * 0);
316 p->InsertColumn(2, _("Status"), wxLIST_FORMAT_LEFT, dResize * 112);
317 p->InsertColumn(3, _("Date"), wxLIST_FORMAT_LEFT, dResize * nDateWidth);
318 p->InsertColumn(4, _("Description"), wxLIST_FORMAT_LEFT, dResize * 409 - nDateWidth);
319 p->InsertColumn(5, _("Debit"), wxLIST_FORMAT_RIGHT, dResize * 79);
320 p->InsertColumn(6, _("Credit"), wxLIST_FORMAT_RIGHT, dResize * 79);
324 int pnWidths[3] = { -100, 88, 300 };
326 pnWidths[1] = pnWidths[1] * 1.1 * dResize;
327 pnWidths[2] = pnWidths[2] * 1.1 * dResize;
329 m_statusBar->SetFieldsCount(3, pnWidths);
331 // Fill your address text box
332 vector<unsigned char> vchPubKey;
333 if (CWalletDB(pwalletMain->strWalletFile,"r").ReadDefaultKey(vchPubKey))
334 m_textCtrlAddress->SetValue(PubKeyToAddress(vchPubKey));
336 // Fill listctrl with wallet transactions
340 CMainFrame::~CMainFrame()
347 void CMainFrame::OnNotebookPageChanged(wxNotebookEvent& event)
350 nPage = event.GetSelection();
353 m_listCtrl = m_listCtrlAll;
354 fShowGenerated = true;
356 fShowReceived = true;
358 else if (nPage == SENTRECEIVED)
360 m_listCtrl = m_listCtrlSentReceived;
361 fShowGenerated = false;
363 fShowReceived = true;
365 else if (nPage == SENT)
367 m_listCtrl = m_listCtrlSent;
368 fShowGenerated = false;
370 fShowReceived = false;
372 else if (nPage == RECEIVED)
374 m_listCtrl = m_listCtrlReceived;
375 fShowGenerated = false;
377 fShowReceived = true;
380 m_listCtrl->SetFocus();
383 void CMainFrame::OnClose(wxCloseEvent& event)
385 if (fMinimizeOnClose && event.CanVeto() && !IsIconized())
387 // Divert close to minimize
389 fClosedToTray = true;
395 CreateThread(Shutdown, NULL);
399 void CMainFrame::OnIconize(wxIconizeEvent& event)
402 // Hide the task bar button when minimized.
403 // Event is sent when the frame is minimized or restored.
404 // wxWidgets 2.8.9 doesn't have IsIconized() so there's no way
405 // to get rid of the deprecated warning. Just ignore it.
406 if (!event.Iconized())
407 fClosedToTray = false;
408 #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
409 if (GetBoolArg("-minimizetotray")) {
411 // The tray icon sometimes disappears on ubuntu karmic
412 // Hiding the taskbar button doesn't work cleanly on ubuntu lucid
413 // Reports of CPU peg on 64-bit linux
414 if (fMinimizeToTray && event.Iconized())
415 fClosedToTray = true;
416 Show(!fClosedToTray);
417 ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
418 #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
423 void CMainFrame::OnMouseEvents(wxMouseEvent& event)
427 RAND_add(&event.m_x, sizeof(event.m_x), 0.25);
428 RAND_add(&event.m_y, sizeof(event.m_y), 0.25);
431 void CMainFrame::OnListColBeginDrag(wxListEvent& event)
433 // Hidden columns not resizeable
434 if (event.GetColumn() <= 1 && !fDebug)
440 int CMainFrame::GetSortIndex(const string& strSort)
445 // The wx generic listctrl implementation used on GTK doesn't sort,
446 // so we have to do it ourselves. Remember, we sort in reverse order.
447 // In the wx generic implementation, they store the list of items
448 // in a vector, so indexed lookups are fast, but inserts are slower
449 // the closer they are to the top.
451 int high = m_listCtrl->GetItemCount();
454 int mid = low + ((high - low) / 2);
455 if (strSort.compare(m_listCtrl->GetItemText(mid).c_str()) >= 0)
464 void CMainFrame::InsertLine(bool fNew, int nIndex, uint256 hashKey, string strSort, const wxColour& colour, const wxString& str2, const wxString& str3, const wxString& str4, const wxString& str5, const wxString& str6)
466 strSort = " " + strSort; // leading space to workaround wx2.9.0 ubuntu 9.10 bug
467 long nData = *(long*)&hashKey; // where first char of hidden column is displayed
470 if (!fNew && nIndex == -1)
472 string strHash = " " + hashKey.ToString();
473 while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)
474 if (GetItemText(m_listCtrl, nIndex, 1) == strHash)
478 // fNew is for blind insert, only use if you're sure it's new
479 if (fNew || nIndex == -1)
481 nIndex = m_listCtrl->InsertItem(GetSortIndex(strSort), strSort);
485 // If sort key changed, must delete and reinsert to make it relocate
486 if (GetItemText(m_listCtrl, nIndex, 0) != strSort)
488 m_listCtrl->DeleteItem(nIndex);
489 nIndex = m_listCtrl->InsertItem(GetSortIndex(strSort), strSort);
493 m_listCtrl->SetItem(nIndex, 1, " " + hashKey.ToString());
494 m_listCtrl->SetItem(nIndex, 2, str2);
495 m_listCtrl->SetItem(nIndex, 3, str3);
496 m_listCtrl->SetItem(nIndex, 4, str4);
497 m_listCtrl->SetItem(nIndex, 5, str5);
498 m_listCtrl->SetItem(nIndex, 6, str6);
499 m_listCtrl->SetItemData(nIndex, nData);
500 SetItemTextColour(m_listCtrl, nIndex, colour);
503 bool CMainFrame::DeleteLine(uint256 hashKey)
505 long nData = *(long*)&hashKey;
509 string strHash = " " + hashKey.ToString();
510 while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)
511 if (GetItemText(m_listCtrl, nIndex, 1) == strHash)
515 m_listCtrl->DeleteItem(nIndex);
520 string FormatTxStatus(const CWalletTx& wtx)
525 if (wtx.nLockTime < 500000000)
526 return strprintf(_("Open for %d blocks"), nBestHeight - wtx.nLockTime);
528 return strprintf(_("Open until %s"), DateTimeStr(wtx.nLockTime).c_str());
532 int nDepth = wtx.GetDepthInMainChain();
533 if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
534 return strprintf(_("%d/offline?"), nDepth);
536 return strprintf(_("%d/unconfirmed"), nDepth);
538 return strprintf(_("%d confirmations"), nDepth);
542 string SingleLine(const string& strIn)
545 bool fOneSpace = false;
546 BOOST_FOREACH(unsigned char c, strIn)
554 if (fOneSpace && !strOut.empty())
563 bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
565 int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime();
566 int64 nCredit = wtx.GetCredit(true);
567 int64 nDebit = wtx.GetDebit();
568 int64 nNet = nCredit - nDebit;
569 uint256 hash = wtx.GetHash();
570 string strStatus = FormatTxStatus(wtx);
571 bool fConfirmed = wtx.fConfirmedDisplayed = wtx.IsConfirmed();
572 wxColour colour = (fConfirmed ? wxColour(0,0,0) : wxColour(128,128,128));
573 map<string, string> mapValue = wtx.mapValue;
574 wtx.nLinesDisplayed = 1;
578 if (wtx.IsCoinBase())
580 // Don't show generated coin until confirmed by at least one block after it
581 // so we don't get the user's hopes up until it looks like it's probably accepted.
583 // It is not an error when generated blocks are not accepted. By design,
584 // some percentage of blocks, like 10% or more, will end up not accepted.
585 // This is the normal mechanism by which the network copes with latency.
587 // We display regular transactions right away before any confirmation
588 // because they can always get into some block eventually. Generated coins
589 // are special because if their block is not accepted, they are not valid.
591 if (wtx.GetDepthInMainChain() < 2)
593 wtx.nLinesDisplayed = 0;
601 // Find the block the tx is in
602 CBlockIndex* pindex = NULL;
603 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(wtx.hashBlock);
604 if (mi != mapBlockIndex.end())
605 pindex = (*mi).second;
607 // Sort order, unrecorded transactions sort to the top
608 string strSort = strprintf("%010d-%01d-%010u",
609 (pindex ? pindex->nHeight : INT_MAX),
610 (wtx.IsCoinBase() ? 1 : 0),
614 if (nNet > 0 || wtx.IsCoinBase())
619 string strDescription;
620 if (wtx.IsCoinBase())
623 strDescription = _("Generated");
626 int64 nUnmatured = 0;
627 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
628 nUnmatured += pwalletMain->GetCredit(txout);
629 if (wtx.IsInMainChain())
631 strDescription = strprintf(_("Generated (%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
633 // Check if the block was requested by anyone
634 if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
635 strDescription = _("Generated - Warning: This block was not received by any other nodes and will probably not be accepted!");
639 strDescription = _("Generated (not accepted)");
643 else if (!mapValue["from"].empty() || !mapValue["message"].empty())
645 // Received by IP connection
648 if (!mapValue["from"].empty())
649 strDescription += _("From: ") + mapValue["from"];
650 if (!mapValue["message"].empty())
652 if (!strDescription.empty())
653 strDescription += " - ";
654 strDescription += mapValue["message"];
659 // Received by Bitcoin Address
662 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
664 if (pwalletMain->IsMine(txout))
666 vector<unsigned char> vchPubKey;
667 if (ExtractPubKey(txout.scriptPubKey, pwalletMain, vchPubKey))
669 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
671 //strDescription += _("Received payment to ");
672 //strDescription += _("Received with address ");
673 strDescription += _("Received with: ");
674 string strAddress = PubKeyToAddress(vchPubKey);
675 map<string, string>::iterator mi = pwalletMain->mapAddressBook.find(strAddress);
676 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
678 string strLabel = (*mi).second;
679 strDescription += strAddress.substr(0,12) + "... ";
680 strDescription += "(" + strLabel + ")";
683 strDescription += strAddress;
691 string strCredit = FormatMoney(nNet, true);
693 strCredit = "[" + strCredit + "]";
695 InsertLine(fNew, nIndex, hash, strSort, colour,
697 nTime ? DateTimeStr(nTime) : "",
698 SingleLine(strDescription),
704 bool fAllFromMe = true;
705 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
706 fAllFromMe = fAllFromMe && pwalletMain->IsMine(txin);
708 bool fAllToMe = true;
709 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
710 fAllToMe = fAllToMe && pwalletMain->IsMine(txout);
712 if (fAllFromMe && fAllToMe)
715 int64 nChange = wtx.GetChange();
716 InsertLine(fNew, nIndex, hash, strSort, colour,
718 nTime ? DateTimeStr(nTime) : "",
719 _("Payment to yourself"),
720 FormatMoney(-(nDebit - nChange), true),
721 FormatMoney(nCredit - nChange, true));
731 int64 nTxFee = nDebit - wtx.GetValueOut();
732 wtx.nLinesDisplayed = 0;
733 for (int nOut = 0; nOut < wtx.vout.size(); nOut++)
735 const CTxOut& txout = wtx.vout[nOut];
736 if (pwalletMain->IsMine(txout))
740 if (!mapValue["to"].empty())
743 strAddress = mapValue["to"];
747 // Sent to Bitcoin Address
749 if (ExtractHash160(txout.scriptPubKey, hash160))
750 strAddress = Hash160ToAddress(hash160);
753 string strDescription = _("To: ");
754 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
755 if (pwalletMain->mapAddressBook.count(strAddress) && !pwalletMain->mapAddressBook[strAddress].empty())
756 strDescription += pwalletMain->mapAddressBook[strAddress] + " ";
757 strDescription += strAddress;
758 if (!mapValue["message"].empty())
760 if (!strDescription.empty())
761 strDescription += " - ";
762 strDescription += mapValue["message"];
764 else if (!mapValue["comment"].empty())
766 if (!strDescription.empty())
767 strDescription += " - ";
768 strDescription += mapValue["comment"];
771 int64 nValue = txout.nValue;
778 InsertLine(fNew, nIndex, hash, strprintf("%s-%d", strSort.c_str(), nOut), colour,
780 nTime ? DateTimeStr(nTime) : "",
781 SingleLine(strDescription),
782 FormatMoney(-nValue, true),
785 wtx.nLinesDisplayed++;
791 // Mixed debit transaction, can't break down payees
793 bool fAllMine = true;
794 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
795 fAllMine = fAllMine && pwalletMain->IsMine(txout);
796 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
797 fAllMine = fAllMine && pwalletMain->IsMine(txin);
799 InsertLine(fNew, nIndex, hash, strSort, colour,
801 nTime ? DateTimeStr(nTime) : "",
803 FormatMoney(nNet, true),
811 void CMainFrame::RefreshListCtrl()
813 fRefreshListCtrl = true;
817 void CMainFrame::OnIdle(wxIdleEvent& event)
819 if (fRefreshListCtrl)
821 // Collect list of wallet transactions and sort newest first
822 bool fEntered = false;
823 vector<pair<unsigned int, uint256> > vSorted;
824 TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
826 printf("RefreshListCtrl starting\n");
828 fRefreshListCtrl = false;
829 pwalletMain->vWalletUpdated.clear();
831 // Do the newest transactions first
832 vSorted.reserve(pwalletMain->mapWallet.size());
833 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
835 const CWalletTx& wtx = (*it).second;
836 unsigned int nTime = UINT_MAX - wtx.GetTxTime();
837 vSorted.push_back(make_pair(nTime, (*it).first));
839 m_listCtrl->DeleteAllItems();
844 sort(vSorted.begin(), vSorted.end());
847 for (int i = 0; i < vSorted.size();)
851 bool fEntered = false;
852 TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
855 uint256& hash = vSorted[i++].second;
856 map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash);
857 if (mi != pwalletMain->mapWallet.end())
858 InsertTransaction((*mi).second, true);
860 if (!fEntered || i == 100 || i % 500 == 0)
864 printf("RefreshListCtrl done\n");
866 // Update transaction total display
871 // Check for time updates
872 static int64 nLastTime;
873 if (GetTime() > nLastTime + 30)
875 TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
877 nLastTime = GetTime();
878 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
880 CWalletTx& wtx = (*it).second;
881 if (wtx.nTimeDisplayed && wtx.nTimeDisplayed != wtx.GetTxTime())
882 InsertTransaction(wtx, false);
889 void CMainFrame::RefreshStatusColumn()
892 static CBlockIndex* pindexLastBest;
893 static unsigned int nLastRefreshed;
895 int nTop = max((int)m_listCtrl->GetTopItem(), 0);
896 if (nTop == nLastTop && pindexLastBest == pindexBest)
899 TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
902 int nEnd = min(nStart + 100, m_listCtrl->GetItemCount());
904 if (pindexLastBest == pindexBest && nLastRefreshed == nListViewUpdated)
906 // If no updates, only need to do the part that moved onto the screen
907 if (nStart >= nLastTop && nStart < nLastTop + 100)
908 nStart = nLastTop + 100;
909 if (nEnd >= nLastTop && nEnd < nLastTop + 100)
913 pindexLastBest = pindexBest;
914 nLastRefreshed = nListViewUpdated;
916 for (int nIndex = nStart; nIndex < min(nEnd, m_listCtrl->GetItemCount()); nIndex++)
918 uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1));
919 map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash);
920 if (mi == pwalletMain->mapWallet.end())
922 printf("CMainFrame::RefreshStatusColumn() : tx not found in mapWallet\n");
925 CWalletTx& wtx = (*mi).second;
926 if (wtx.IsCoinBase() ||
927 wtx.GetTxTime() != wtx.nTimeDisplayed ||
928 wtx.IsConfirmed() != wtx.fConfirmedDisplayed)
930 if (!InsertTransaction(wtx, false, nIndex))
931 m_listCtrl->DeleteItem(nIndex--);
935 m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx));
941 void CMainFrame::OnPaint(wxPaintEvent& event)
952 unsigned int nNeedRepaint = 0;
953 unsigned int nLastRepaint = 0;
954 int64 nLastRepaintTime = 0;
955 int64 nRepaintInterval = 500;
957 void ThreadDelayedRepaint(void* parg)
961 if (nLastRepaint != nNeedRepaint && GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)
963 nLastRepaint = nNeedRepaint;
966 printf("DelayedRepaint\n");
968 pframeMain->fRefresh = true;
969 pframeMain->GetEventHandler()->AddPendingEvent(event);
972 Sleep(nRepaintInterval);
976 void MainFrameRepaint()
978 // This is called by network code that shouldn't access pframeMain
979 // directly because it could still be running after the UI is closed.
982 // Don't repaint too often
983 static int64 nLastRepaintRequest;
984 if (GetTimeMillis() - nLastRepaintRequest < 100)
989 nLastRepaintRequest = GetTimeMillis();
991 printf("MainFrameRepaint\n");
993 pframeMain->fRefresh = true;
994 pframeMain->GetEventHandler()->AddPendingEvent(event);
998 void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
1000 // Skip lets the listctrl do the paint, we're just hooking the message
1004 ptaskbaricon->UpdateTooltip();
1009 static int nTransactionCount;
1010 bool fPaintedBalance = false;
1011 if (GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)
1013 nLastRepaint = nNeedRepaint;
1014 nLastRepaintTime = GetTimeMillis();
1016 // Update listctrl contents
1017 if (!pwalletMain->vWalletUpdated.empty())
1019 TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
1022 if (m_listCtrl->GetItemCount())
1023 strTop = (string)m_listCtrl->GetItemText(0);
1024 BOOST_FOREACH(uint256 hash, pwalletMain->vWalletUpdated)
1026 map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash);
1027 if (mi != pwalletMain->mapWallet.end())
1028 InsertTransaction((*mi).second, false);
1030 pwalletMain->vWalletUpdated.clear();
1031 if (m_listCtrl->GetItemCount() && strTop != (string)m_listCtrl->GetItemText(0))
1032 m_listCtrl->ScrollList(0, INT_MIN/2);
1037 TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
1039 fPaintedBalance = true;
1040 m_staticTextBalance->SetLabel(FormatMoney(pwalletMain->GetBalance()) + " ");
1042 // Count hidden and multi-line transactions
1043 nTransactionCount = 0;
1044 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1046 CWalletTx& wtx = (*it).second;
1047 nTransactionCount += wtx.nLinesDisplayed;
1051 if (!pwalletMain->vWalletUpdated.empty() || !fPaintedBalance)
1054 // Update status column of visible items only
1055 RefreshStatusColumn();
1057 // Update status bar
1058 static string strPrevWarning;
1059 string strWarning = GetWarnings("statusbar");
1060 if (strWarning != "")
1061 m_statusBar->SetStatusText(string(" ") + _(strWarning), 0);
1062 else if (strPrevWarning != "")
1063 m_statusBar->SetStatusText("", 0);
1064 strPrevWarning = strWarning;
1067 if (fGenerateBitcoins)
1068 strGen = _(" Generating");
1069 if (fGenerateBitcoins && vNodes.empty())
1070 strGen = _("(not connected)");
1071 m_statusBar->SetStatusText(strGen, 1);
1073 string strStatus = strprintf(_(" %d connections %d blocks %d transactions"), vNodes.size(), nBestHeight, nTransactionCount);
1074 m_statusBar->SetStatusText(strStatus, 2);
1076 // Update receiving address
1077 string strDefaultAddress = PubKeyToAddress(pwalletMain->vchDefaultKey);
1078 if (m_textCtrlAddress->GetValue() != strDefaultAddress)
1079 m_textCtrlAddress->SetValue(strDefaultAddress);
1083 void UIThreadCall(boost::function0<void> fn)
1085 // Call this with a function object created with bind.
1086 // bind needs all parameters to match the function's expected types
1087 // and all default parameters specified. Some examples:
1088 // UIThreadCall(bind(wxBell));
1089 // UIThreadCall(bind(wxMessageBox, wxT("Message"), wxT("Title"), wxOK, (wxWindow*)NULL, -1, -1));
1090 // UIThreadCall(bind(&CMainFrame::OnMenuHelpAbout, pframeMain, event));
1093 wxCommandEvent event(wxEVT_UITHREADCALL);
1094 event.SetClientData((void*)new boost::function0<void>(fn));
1095 pframeMain->GetEventHandler()->AddPendingEvent(event);
1099 void CMainFrame::OnUIThreadCall(wxCommandEvent& event)
1101 boost::function0<void>* pfn = (boost::function0<void>*)event.GetClientData();
1106 void CMainFrame::OnMenuFileExit(wxCommandEvent& event)
1112 void CMainFrame::OnUpdateUIOptionsGenerate(wxUpdateUIEvent& event)
1114 event.Check(fGenerateBitcoins);
1117 void CMainFrame::OnMenuOptionsChangeYourAddress(wxCommandEvent& event)
1119 // Options->Your Receiving Addresses
1120 CAddressBookDialog dialog(this, "", CAddressBookDialog::RECEIVING, false);
1121 if (!dialog.ShowModal())
1125 void CMainFrame::OnMenuOptionsOptions(wxCommandEvent& event)
1128 COptionsDialog dialog(this);
1132 void CMainFrame::OnMenuHelpAbout(wxCommandEvent& event)
1135 CAboutDialog dialog(this);
1139 void CMainFrame::OnButtonSend(wxCommandEvent& event)
1142 CSendDialog dialog(this);
1146 void CMainFrame::OnButtonAddressBook(wxCommandEvent& event)
1148 // Toolbar: Address Book
1149 CAddressBookDialog dialogAddr(this, "", CAddressBookDialog::SENDING, false);
1150 if (dialogAddr.ShowModal() == 2)
1153 CSendDialog dialogSend(this, dialogAddr.GetSelectedAddress());
1154 dialogSend.ShowModal();
1158 void CMainFrame::OnSetFocusAddress(wxFocusEvent& event)
1160 // Automatically select-all when entering window
1162 m_textCtrlAddress->SetSelection(-1, -1);
1163 fOnSetFocusAddress = true;
1166 void CMainFrame::OnMouseEventsAddress(wxMouseEvent& event)
1169 if (fOnSetFocusAddress)
1170 m_textCtrlAddress->SetSelection(-1, -1);
1171 fOnSetFocusAddress = false;
1174 void CMainFrame::OnButtonNew(wxCommandEvent& event)
1177 CGetTextFromUserDialog dialog(this,
1178 _("New Receiving Address"),
1179 _("You should use a new address for each payment you receive.\n\nLabel"),
1181 if (!dialog.ShowModal())
1183 string strName = dialog.GetValue();
1186 string strAddress = PubKeyToAddress(pwalletMain->GetKeyFromKeyPool());
1189 pwalletMain->SetAddressBookName(strAddress, strName);
1190 SetDefaultReceivingAddress(strAddress);
1193 void CMainFrame::OnButtonCopy(wxCommandEvent& event)
1195 // Copy address box to clipboard
1196 if (wxTheClipboard->Open())
1198 wxTheClipboard->SetData(new wxTextDataObject(m_textCtrlAddress->GetValue()));
1199 wxTheClipboard->Close();
1203 void CMainFrame::OnListItemActivated(wxListEvent& event)
1205 uint256 hash((string)GetItemText(m_listCtrl, event.GetIndex(), 1));
1207 CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
1209 map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash);
1210 if (mi == pwalletMain->mapWallet.end())
1212 printf("CMainFrame::OnListItemActivated() : tx not found in mapWallet\n");
1217 CTxDetailsDialog dialog(this, wtx);
1219 //CTxDetailsDialog* pdialog = new CTxDetailsDialog(this, wtx);
1228 //////////////////////////////////////////////////////////////////////////////
1233 CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetailsDialogBase(parent)
1236 SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
1238 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
1241 strHTML.reserve(4000);
1242 strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
1244 int64 nTime = wtx.GetTxTime();
1245 int64 nCredit = wtx.GetCredit();
1246 int64 nDebit = wtx.GetDebit();
1247 int64 nNet = nCredit - nDebit;
1251 strHTML += _("<b>Status:</b> ") + FormatTxStatus(wtx);
1252 int nRequests = wtx.GetRequestCount();
1253 if (nRequests != -1)
1256 strHTML += _(", has not been successfully broadcast yet");
1257 else if (nRequests == 1)
1258 strHTML += strprintf(_(", broadcast through %d node"), nRequests);
1260 strHTML += strprintf(_(", broadcast through %d nodes"), nRequests);
1264 strHTML += _("<b>Date:</b> ") + (nTime ? DateTimeStr(nTime) : "") + "<br>";
1270 if (wtx.IsCoinBase())
1272 strHTML += _("<b>Source:</b> Generated<br>");
1274 else if (!wtx.mapValue["from"].empty())
1276 // Online transaction
1277 if (!wtx.mapValue["from"].empty())
1278 strHTML += _("<b>From:</b> ") + HtmlEscape(wtx.mapValue["from"]) + "<br>";
1282 // Offline transaction
1286 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1288 if (pwalletMain->IsMine(txout))
1290 vector<unsigned char> vchPubKey;
1291 if (ExtractPubKey(txout.scriptPubKey, pwalletMain, vchPubKey))
1293 string strAddress = PubKeyToAddress(vchPubKey);
1294 if (pwalletMain->mapAddressBook.count(strAddress))
1296 strHTML += string() + _("<b>From:</b> ") + _("unknown") + "<br>";
1297 strHTML += _("<b>To:</b> ");
1298 strHTML += HtmlEscape(strAddress);
1299 if (!pwalletMain->mapAddressBook[strAddress].empty())
1300 strHTML += _(" (yours, label: ") + pwalletMain->mapAddressBook[strAddress] + ")";
1302 strHTML += _(" (yours)");
1317 if (!wtx.mapValue["to"].empty())
1319 // Online transaction
1320 strAddress = wtx.mapValue["to"];
1321 strHTML += _("<b>To:</b> ");
1322 if (pwalletMain->mapAddressBook.count(strAddress) && !pwalletMain->mapAddressBook[strAddress].empty())
1323 strHTML += pwalletMain->mapAddressBook[strAddress] + " ";
1324 strHTML += HtmlEscape(strAddress) + "<br>";
1331 if (wtx.IsCoinBase() && nCredit == 0)
1336 int64 nUnmatured = 0;
1337 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1338 nUnmatured += pwalletMain->GetCredit(txout);
1339 strHTML += _("<b>Credit:</b> ");
1340 if (wtx.IsInMainChain())
1341 strHTML += strprintf(_("(%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
1343 strHTML += _("(not accepted)");
1351 strHTML += _("<b>Credit:</b> ") + FormatMoney(nNet) + "<br>";
1355 bool fAllFromMe = true;
1356 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
1357 fAllFromMe = fAllFromMe && pwalletMain->IsMine(txin);
1359 bool fAllToMe = true;
1360 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1361 fAllToMe = fAllToMe && pwalletMain->IsMine(txout);
1368 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1370 if (pwalletMain->IsMine(txout))
1373 if (wtx.mapValue["to"].empty())
1375 // Offline transaction
1377 if (ExtractHash160(txout.scriptPubKey, hash160))
1379 string strAddress = Hash160ToAddress(hash160);
1380 strHTML += _("<b>To:</b> ");
1381 if (pwalletMain->mapAddressBook.count(strAddress) && !pwalletMain->mapAddressBook[strAddress].empty())
1382 strHTML += pwalletMain->mapAddressBook[strAddress] + " ";
1383 strHTML += strAddress;
1388 strHTML += _("<b>Debit:</b> ") + FormatMoney(-txout.nValue) + "<br>";
1394 int64 nChange = wtx.GetChange();
1395 int64 nValue = nCredit - nChange;
1396 strHTML += _("<b>Debit:</b> ") + FormatMoney(-nValue) + "<br>";
1397 strHTML += _("<b>Credit:</b> ") + FormatMoney(nValue) + "<br>";
1400 int64 nTxFee = nDebit - wtx.GetValueOut();
1402 strHTML += _("<b>Transaction fee:</b> ") + FormatMoney(-nTxFee) + "<br>";
1407 // Mixed debit transaction
1409 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
1410 if (pwalletMain->IsMine(txin))
1411 strHTML += _("<b>Debit:</b> ") + FormatMoney(-pwalletMain->GetDebit(txin)) + "<br>";
1412 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1413 if (pwalletMain->IsMine(txout))
1414 strHTML += _("<b>Credit:</b> ") + FormatMoney(pwalletMain->GetCredit(txout)) + "<br>";
1418 strHTML += _("<b>Net amount:</b> ") + FormatMoney(nNet, true) + "<br>";
1424 if (!wtx.mapValue["message"].empty())
1425 strHTML += string() + "<br><b>" + _("Message:") + "</b><br>" + HtmlEscape(wtx.mapValue["message"], true) + "<br>";
1426 if (!wtx.mapValue["comment"].empty())
1427 strHTML += string() + "<br><b>" + _("Comment:") + "</b><br>" + HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
1429 if (wtx.IsCoinBase())
1430 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>";
1438 strHTML += "<hr><br>debug print<br><br>";
1439 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
1440 if (pwalletMain->IsMine(txin))
1441 strHTML += "<b>Debit:</b> " + FormatMoney(-pwalletMain->GetDebit(txin)) + "<br>";
1442 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1443 if (pwalletMain->IsMine(txout))
1444 strHTML += "<b>Credit:</b> " + FormatMoney(pwalletMain->GetCredit(txout)) + "<br>";
1446 strHTML += "<br><b>Transaction:</b><br>";
1447 strHTML += HtmlEscape(wtx.ToString(), true);
1449 strHTML += "<br><b>Inputs:</b><br>";
1450 CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
1452 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
1454 COutPoint prevout = txin.prevout;
1455 map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(prevout.hash);
1456 if (mi != pwalletMain->mapWallet.end())
1458 const CWalletTx& prev = (*mi).second;
1459 if (prevout.n < prev.vout.size())
1461 strHTML += HtmlEscape(prev.ToString(), true);
1462 strHTML += " " + FormatTxStatus(prev) + ", ";
1463 strHTML = strHTML + "IsMine=" + (pwalletMain->IsMine(prev.vout[prevout.n]) ? "true" : "false") + "<br>";
1472 strHTML += "</font></html>";
1473 string(strHTML.begin(), strHTML.end()).swap(strHTML);
1474 m_htmlWin->SetPage(strHTML);
1475 m_buttonOK->SetFocus();
1479 void CTxDetailsDialog::OnButtonOK(wxCommandEvent& event)
1489 //////////////////////////////////////////////////////////////////////////////
1495 string StartupShortcutPath()
1497 return MyGetSpecialFolderPath(CSIDL_STARTUP, true) + "\\Bitcoin.lnk";
1500 bool GetStartOnSystemStartup()
1502 return filesystem::exists(StartupShortcutPath().c_str());
1505 void SetStartOnSystemStartup(bool fAutoStart)
1507 // If the shortcut exists already, remove it for updating
1508 remove(StartupShortcutPath().c_str());
1514 // Get a pointer to the IShellLink interface.
1515 IShellLink* psl = NULL;
1516 HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
1517 CLSCTX_INPROC_SERVER, IID_IShellLink,
1518 reinterpret_cast<void**>(&psl));
1520 if (SUCCEEDED(hres))
1522 // Get the current executable path
1523 TCHAR pszExePath[MAX_PATH];
1524 GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));
1526 // Set the path to the shortcut target
1527 psl->SetPath(pszExePath);
1528 PathRemoveFileSpec(pszExePath);
1529 psl->SetWorkingDirectory(pszExePath);
1530 psl->SetShowCmd(SW_SHOWMINNOACTIVE);
1532 // Query IShellLink for the IPersistFile interface for
1533 // saving the shortcut in persistent storage.
1534 IPersistFile* ppf = NULL;
1535 hres = psl->QueryInterface(IID_IPersistFile,
1536 reinterpret_cast<void**>(&ppf));
1537 if (SUCCEEDED(hres))
1539 WCHAR pwsz[MAX_PATH];
1540 // Ensure that the string is ANSI.
1541 MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().c_str(), -1, pwsz, MAX_PATH);
1542 // Save the link by calling IPersistFile::Save.
1543 hres = ppf->Save(pwsz, TRUE);
1552 #elif defined(__WXGTK__)
1554 // Follow the Desktop Application Autostart Spec:
1555 // http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
1557 boost::filesystem::path GetAutostartDir()
1559 namespace fs = boost::filesystem;
1561 char* pszConfigHome = getenv("XDG_CONFIG_HOME");
1562 if (pszConfigHome) return fs::path(pszConfigHome) / fs::path("autostart");
1563 char* pszHome = getenv("HOME");
1564 if (pszHome) return fs::path(pszHome) / fs::path(".config/autostart");
1568 boost::filesystem::path GetAutostartFilePath()
1570 return GetAutostartDir() / boost::filesystem::path("bitcoin.desktop");
1573 bool GetStartOnSystemStartup()
1575 boost::filesystem::ifstream optionFile(GetAutostartFilePath());
1576 if (!optionFile.good())
1578 // Scan through file for "Hidden=true":
1580 while (!optionFile.eof())
1582 getline(optionFile, line);
1583 if (line.find("Hidden") != string::npos &&
1584 line.find("true") != string::npos)
1592 void SetStartOnSystemStartup(bool fAutoStart)
1596 unlink(GetAutostartFilePath().native_file_string().c_str());
1600 char pszExePath[MAX_PATH+1];
1601 memset(pszExePath, 0, sizeof(pszExePath));
1602 if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1)
1605 boost::filesystem::create_directories(GetAutostartDir());
1607 boost::filesystem::ofstream optionFile(GetAutostartFilePath(), ios_base::out|ios_base::trunc);
1608 if (!optionFile.good())
1610 wxMessageBox(_("Cannot write autostart/bitcoin.desktop file"), "Bitcoin");
1613 // Write a bitcoin.desktop file to the autostart directory:
1614 optionFile << "[Desktop Entry]\n";
1615 optionFile << "Type=Application\n";
1616 optionFile << "Name=Bitcoin\n";
1617 optionFile << "Exec=" << pszExePath << "\n";
1618 optionFile << "Terminal=false\n";
1619 optionFile << "Hidden=false\n";
1625 // TODO: OSX startup stuff; see:
1626 // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html
1628 bool GetStartOnSystemStartup() { return false; }
1629 void SetStartOnSystemStartup(bool fAutoStart) { }
1638 //////////////////////////////////////////////////////////////////////////////
1643 COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent)
1645 // Set up list box of page choices
1646 m_listBox->Append(_("Main"));
1647 //m_listBox->Append(_("Test 2"));
1648 m_listBox->SetSelection(0);
1651 SetSize(1.0 * GetSize().GetWidth(), 1.2 * GetSize().GetHeight());
1653 SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
1655 #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
1656 m_checkBoxStartOnSystemStartup->SetLabel(_("&Start Bitcoin on window system startup"));
1657 if (!GetBoolArg("-minimizetotray"))
1659 // Minimize to tray is just too buggy on Linux
1660 fMinimizeToTray = false;
1661 m_checkBoxMinimizeToTray->SetValue(false);
1662 m_checkBoxMinimizeToTray->Enable(false);
1663 m_checkBoxMinimizeOnClose->SetLabel(_("&Minimize on close"));
1666 #ifdef __WXMAC_OSX__
1667 m_checkBoxStartOnSystemStartup->Enable(false); // not implemented yet
1671 m_textCtrlTransactionFee->SetValue(FormatMoney(nTransactionFee));
1672 m_checkBoxStartOnSystemStartup->SetValue(fTmpStartOnSystemStartup = GetStartOnSystemStartup());
1673 m_checkBoxMinimizeToTray->SetValue(fMinimizeToTray);
1674 m_checkBoxMinimizeOnClose->SetValue(fMinimizeOnClose);
1676 m_checkBoxUseUPnP->SetValue(fUseUPnP);
1678 m_checkBoxUseUPnP->Enable(false);
1679 m_checkBoxUseProxy->SetValue(fUseProxy);
1680 m_textCtrlProxyIP->Enable(fUseProxy);
1681 m_textCtrlProxyPort->Enable(fUseProxy);
1682 m_staticTextProxyIP->Enable(fUseProxy);
1683 m_staticTextProxyPort->Enable(fUseProxy);
1684 m_textCtrlProxyIP->SetValue(addrProxy.ToStringIP());
1685 m_textCtrlProxyPort->SetValue(addrProxy.ToStringPort());
1687 m_buttonOK->SetFocus();
1690 void COptionsDialog::SelectPage(int nPage)
1692 m_panelMain->Show(nPage == 0);
1693 m_panelTest2->Show(nPage == 1);
1695 m_scrolledWindow->Layout();
1696 m_scrolledWindow->SetScrollbars(0, 0, 0, 0, 0, 0);
1699 void COptionsDialog::OnListBox(wxCommandEvent& event)
1701 SelectPage(event.GetSelection());
1704 void COptionsDialog::OnKillFocusTransactionFee(wxFocusEvent& event)
1707 int64 nTmp = nTransactionFee;
1708 ParseMoney(m_textCtrlTransactionFee->GetValue(), nTmp);
1709 m_textCtrlTransactionFee->SetValue(FormatMoney(nTmp));
1712 void COptionsDialog::OnCheckBoxUseProxy(wxCommandEvent& event)
1714 m_textCtrlProxyIP->Enable(event.IsChecked());
1715 m_textCtrlProxyPort->Enable(event.IsChecked());
1716 m_staticTextProxyIP->Enable(event.IsChecked());
1717 m_staticTextProxyPort->Enable(event.IsChecked());
1720 CAddress COptionsDialog::GetProxyAddr()
1722 // Be careful about byte order, addr.ip and addr.port are big endian
1723 CAddress addr(m_textCtrlProxyIP->GetValue() + ":" + m_textCtrlProxyPort->GetValue());
1724 if (addr.ip == INADDR_NONE)
1725 addr.ip = addrProxy.ip;
1726 int nPort = atoi(m_textCtrlProxyPort->GetValue());
1727 addr.port = htons(nPort);
1728 if (nPort <= 0 || nPort > USHRT_MAX)
1729 addr.port = addrProxy.port;
1733 void COptionsDialog::OnKillFocusProxy(wxFocusEvent& event)
1736 m_textCtrlProxyIP->SetValue(GetProxyAddr().ToStringIP());
1737 m_textCtrlProxyPort->SetValue(GetProxyAddr().ToStringPort());
1741 void COptionsDialog::OnButtonOK(wxCommandEvent& event)
1743 OnButtonApply(event);
1747 void COptionsDialog::OnButtonCancel(wxCommandEvent& event)
1752 void COptionsDialog::OnButtonApply(wxCommandEvent& event)
1754 CWalletDB walletdb(pwalletMain->strWalletFile);
1756 int64 nPrevTransactionFee = nTransactionFee;
1757 if (ParseMoney(m_textCtrlTransactionFee->GetValue(), nTransactionFee) && nTransactionFee != nPrevTransactionFee)
1758 walletdb.WriteSetting("nTransactionFee", nTransactionFee);
1760 if (fTmpStartOnSystemStartup != m_checkBoxStartOnSystemStartup->GetValue())
1762 fTmpStartOnSystemStartup = m_checkBoxStartOnSystemStartup->GetValue();
1763 SetStartOnSystemStartup(fTmpStartOnSystemStartup);
1766 if (fMinimizeToTray != m_checkBoxMinimizeToTray->GetValue())
1768 fMinimizeToTray = m_checkBoxMinimizeToTray->GetValue();
1769 walletdb.WriteSetting("fMinimizeToTray", fMinimizeToTray);
1770 ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
1773 if (fMinimizeOnClose != m_checkBoxMinimizeOnClose->GetValue())
1775 fMinimizeOnClose = m_checkBoxMinimizeOnClose->GetValue();
1776 walletdb.WriteSetting("fMinimizeOnClose", fMinimizeOnClose);
1779 if (fHaveUPnP && fUseUPnP != m_checkBoxUseUPnP->GetValue())
1781 fUseUPnP = m_checkBoxUseUPnP->GetValue();
1782 walletdb.WriteSetting("fUseUPnP", fUseUPnP);
1786 fUseProxy = m_checkBoxUseProxy->GetValue();
1787 walletdb.WriteSetting("fUseProxy", fUseProxy);
1789 addrProxy = GetProxyAddr();
1790 walletdb.WriteSetting("addrProxy", addrProxy);
1798 //////////////////////////////////////////////////////////////////////////////
1803 CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent)
1805 m_staticTextVersion->SetLabel(strprintf(_("version %s"), FormatFullVersion().c_str()));
1807 // Change (c) into UTF-8 or ANSI copyright symbol
1808 wxString str = m_staticTextMain->GetLabel();
1810 str.Replace("(c)", wxString::FromUTF8("\xC2\xA9"));
1812 str.Replace("(c)", "\xA9");
1814 m_staticTextMain->SetLabel(str);
1816 // Resize on Linux to make the window fit the text.
1817 // The text was wrapped manually rather than using the Wrap setting because
1818 // the wrap would be too small on Linux and it can't be changed at this point.
1819 wxFont fontTmp = m_staticTextMain->GetFont();
1820 if (fontTmp.GetPointSize() > 8);
1821 fontTmp.SetPointSize(8);
1822 m_staticTextMain->SetFont(fontTmp);
1823 SetSize(GetSize().GetWidth() + 44, GetSize().GetHeight() + 10);
1825 SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
1829 void CAboutDialog::OnButtonOK(wxCommandEvent& event)
1839 //////////////////////////////////////////////////////////////////////////////
1844 CSendDialog::CSendDialog(wxWindow* parent, const wxString& strAddress) : CSendDialogBase(parent)
1847 m_textCtrlAddress->SetValue(strAddress);
1848 m_choiceTransferType->SetSelection(0);
1849 m_bitmapCheckMark->Show(false);
1850 fEnabledPrev = true;
1851 m_textCtrlAddress->SetFocus();
1853 //// todo: should add a display of your balance for convenience
1855 wxFont fontTmp = m_staticTextInstructions->GetFont();
1856 if (fontTmp.GetPointSize() > 9);
1857 fontTmp.SetPointSize(9);
1858 m_staticTextInstructions->SetFont(fontTmp);
1861 SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
1865 if (nScaleX == 1.0 && nScaleY == 1.0) // We don't have icons of the proper size otherwise
1868 iconSend.CopyFromBitmap(wxBitmap(send16noshadow_xpm));
1873 SetIcon(wxICON(bitcoin));
1876 // Fixup the tab order
1877 m_buttonPaste->MoveAfterInTabOrder(m_buttonCancel);
1878 m_buttonAddress->MoveAfterInTabOrder(m_buttonPaste);
1882 void CSendDialog::OnKillFocusAmount(wxFocusEvent& event)
1884 // Reformat the amount
1886 if (m_textCtrlAmount->GetValue().Trim().empty())
1889 if (ParseMoney(m_textCtrlAmount->GetValue(), nTmp))
1890 m_textCtrlAmount->SetValue(FormatMoney(nTmp));
1893 void CSendDialog::OnButtonAddressBook(wxCommandEvent& event)
1895 // Open address book
1896 CAddressBookDialog dialog(this, m_textCtrlAddress->GetValue(), CAddressBookDialog::SENDING, true);
1897 if (dialog.ShowModal())
1898 m_textCtrlAddress->SetValue(dialog.GetSelectedAddress());
1901 void CSendDialog::OnButtonPaste(wxCommandEvent& event)
1903 // Copy clipboard to address box
1904 if (wxTheClipboard->Open())
1906 if (wxTheClipboard->IsSupported(wxDF_TEXT))
1908 wxTextDataObject data;
1909 wxTheClipboard->GetData(data);
1910 m_textCtrlAddress->SetValue(data.GetText());
1912 wxTheClipboard->Close();
1916 void CSendDialog::OnButtonSend(wxCommandEvent& event)
1918 static CCriticalSection cs_sendlock;
1919 TRY_CRITICAL_BLOCK(cs_sendlock)
1922 string strAddress = (string)m_textCtrlAddress->GetValue();
1926 if (!ParseMoney(m_textCtrlAmount->GetValue(), nValue) || nValue <= 0)
1928 wxMessageBox(_("Error in amount "), _("Send Coins"));
1931 if (nValue > pwalletMain->GetBalance())
1933 wxMessageBox(_("Amount exceeds your balance "), _("Send Coins"));
1936 if (nValue + nTransactionFee > pwalletMain->GetBalance())
1938 wxMessageBox(string(_("Total exceeds your balance when the ")) + FormatMoney(nTransactionFee) + _(" transaction fee is included "), _("Send Coins"));
1942 // Parse bitcoin address
1944 bool fBitcoinAddress = AddressToHash160(strAddress, hash160);
1946 if (fBitcoinAddress)
1948 CRITICAL_BLOCK(cs_main)
1950 // Send to bitcoin address
1951 CScript scriptPubKey;
1952 scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
1954 string strError = pwalletMain->SendMoney(scriptPubKey, nValue, wtx, true);
1956 wxMessageBox(_("Payment sent "), _("Sending..."));
1957 else if (strError == "ABORTED")
1958 return; // leave send dialog open
1961 wxMessageBox(strError + " ", _("Sending..."));
1970 CAddress addr(strAddress);
1971 if (!addr.IsValid())
1973 wxMessageBox(_("Invalid address "), _("Send Coins"));
1978 wtx.mapValue["to"] = strAddress;
1980 // Send to IP address
1981 CSendingDialog* pdialog = new CSendingDialog(this, addr, nValue, wtx);
1982 if (!pdialog->ShowModal())
1986 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
1987 if (!pwalletMain->mapAddressBook.count(strAddress))
1988 pwalletMain->SetAddressBookName(strAddress, "");
1994 void CSendDialog::OnButtonCancel(wxCommandEvent& event)
2005 //////////////////////////////////////////////////////////////////////////////
2010 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
2015 start = wxDateTime::UNow();
2016 memset(pszStatus, 0, sizeof(pszStatus));
2023 SetSize(1.2 * GetSize().GetWidth(), 1.08 * GetSize().GetHeight());
2025 SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
2028 SetTitle(strprintf(_("Sending %s to %s"), FormatMoney(nPrice).c_str(), wtx.mapValue["to"].c_str()));
2029 m_textCtrlStatus->SetValue("");
2031 CreateThread(SendingDialogStartTransfer, this);
2034 CSendingDialog::~CSendingDialog()
2036 printf("~CSendingDialog()\n");
2039 void CSendingDialog::Close()
2041 // Last one out turn out the lights.
2042 // fWorkDone signals that work side is done and UI thread should call destroy.
2043 // fUIDone signals that UI window has closed and work thread should call destroy.
2044 // This allows the window to disappear and end modality when cancelled
2045 // without making the user wait for ConnectNode to return. The dialog object
2046 // hangs around in the background until the work thread exits.
2057 void CSendingDialog::OnClose(wxCloseEvent& event)
2059 if (!event.CanVeto() || fWorkDone || fAbort || !fCanCancel)
2066 wxCommandEvent cmdevent;
2067 OnButtonCancel(cmdevent);
2071 void CSendingDialog::OnButtonOK(wxCommandEvent& event)
2077 void CSendingDialog::OnButtonCancel(wxCommandEvent& event)
2083 void CSendingDialog::OnPaint(wxPaintEvent& event)
2086 if (strlen(pszStatus) > 130)
2087 m_textCtrlStatus->SetValue(string("\n") + pszStatus);
2089 m_textCtrlStatus->SetValue(string("\n\n") + pszStatus);
2090 m_staticTextSending->SetFocus();
2092 m_buttonCancel->Enable(false);
2095 m_buttonOK->Enable(true);
2096 m_buttonOK->SetFocus();
2097 m_buttonCancel->Enable(false);
2099 if (fAbort && fCanCancel && IsShown())
2101 strcpy(pszStatus, _("CANCELLED"));
2102 m_buttonOK->Enable(true);
2103 m_buttonOK->SetFocus();
2104 m_buttonCancel->Enable(false);
2105 m_buttonCancel->SetLabel(_("Cancelled"));
2107 wxMessageBox(_("Transfer cancelled "), _("Sending..."), wxOK, this);
2113 // Everything from here on is not in the UI thread and must only communicate
2114 // with the rest of the dialog through variables and calling repaint.
2117 void CSendingDialog::Repaint()
2121 GetEventHandler()->AddPendingEvent(event);
2124 bool CSendingDialog::Status()
2131 if (fAbort && fCanCancel)
2133 memset(pszStatus, 0, 10);
2134 strcpy(pszStatus, _("CANCELLED"));
2142 bool CSendingDialog::Status(const string& str)
2147 // This can be read by the UI thread at any time,
2148 // so copy in a way that can be read cleanly at all times.
2149 memset(pszStatus, 0, min(str.size()+1, sizeof(pszStatus)));
2150 strlcpy(pszStatus, str.c_str(), sizeof(pszStatus));
2156 bool CSendingDialog::Error(const string& str)
2160 Status(string(_("Error: ")) + str);
2164 void SendingDialogStartTransfer(void* parg)
2166 ((CSendingDialog*)parg)->StartTransfer();
2169 void CSendingDialog::StartTransfer()
2171 // Make sure we have enough money
2172 if (nPrice + nTransactionFee > pwalletMain->GetBalance())
2174 Error(_("Insufficient funds"));
2178 // We may have connected already for product details
2179 if (!Status(_("Connecting...")))
2181 CNode* pnode = ConnectNode(addr, 15 * 60);
2184 Error(_("Unable to connect"));
2188 // Send order to seller, with response going to OnReply2 via event handler
2189 if (!Status(_("Requesting public key...")))
2191 pnode->PushRequest("checkorder", wtx, SendingDialogOnReply2, this);
2194 void SendingDialogOnReply2(void* parg, CDataStream& vRecv)
2196 ((CSendingDialog*)parg)->OnReply2(vRecv);
2199 void CSendingDialog::OnReply2(CDataStream& vRecv)
2201 if (!Status(_("Received public key...")))
2204 CScript scriptPubKey;
2213 vRecv >> strMessage;
2215 Error(_("Recipient is not accepting transactions sent by IP address"));
2217 Error(_("Transfer was not accepted"));
2218 //// todo: enlarge the window and enable a hidden white box to put seller's message
2221 vRecv >> scriptPubKey;
2225 //// what do we want to do about this?
2226 Error(_("Invalid response received"));
2230 // Pause to give the user a chance to cancel
2231 while (wxDateTime::UNow() < start + wxTimeSpan(0, 0, 0, 2 * 1000))
2238 CRITICAL_BLOCK(cs_main)
2241 if (!Status(_("Creating transaction...")))
2243 if (nPrice + nTransactionFee > pwalletMain->GetBalance())
2245 Error(_("Insufficient funds"));
2248 CReserveKey reservekey(pwalletMain);
2250 if (!pwalletMain->CreateTransaction(scriptPubKey, nPrice, wtx, reservekey, nFeeRequired))
2252 if (nPrice + nFeeRequired > pwalletMain->GetBalance())
2253 Error(strprintf(_("This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds"), FormatMoney(nFeeRequired).c_str()));
2255 Error(_("Transaction creation failed"));
2260 if (!ThreadSafeAskFee(nFeeRequired, _("Sending..."), this))
2262 Error(_("Transaction aborted"));
2266 // Make sure we're still connected
2267 CNode* pnode = ConnectNode(addr, 2 * 60 * 60);
2270 Error(_("Lost connection, transaction cancelled"));
2274 // Last chance to cancel
2286 if (!Status(_("Sending payment...")))
2290 if (!pwalletMain->CommitTransaction(wtx, reservekey))
2292 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."));
2296 // Send payment tx to seller, with response going to OnReply3 via event handler
2297 CWalletTx wtxSend = wtx;
2298 wtxSend.fFromMe = false;
2299 pnode->PushRequest("submitorder", wtxSend, SendingDialogOnReply3, this);
2301 Status(_("Waiting for confirmation..."));
2306 void SendingDialogOnReply3(void* parg, CDataStream& vRecv)
2308 ((CSendingDialog*)parg)->OnReply3(vRecv);
2311 void CSendingDialog::OnReply3(CDataStream& vRecv)
2319 Error(_("The payment was sent, but the recipient was unable to verify it.\n"
2320 "The transaction is recorded and will credit to the recipient,\n"
2321 "but the comment information will be blank."));
2327 //// what do we want to do about this?
2328 Error(_("Payment was sent, but an invalid response was received"));
2334 Status(_("Payment completed"));
2342 //////////////////////////////////////////////////////////////////////////////
2344 // CAddressBookDialog
2347 CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInitSelected, int nPageIn, bool fDuringSendIn) : CAddressBookDialogBase(parent)
2350 SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
2353 // Set initially selected page
2354 wxNotebookEvent event;
2355 event.SetSelection(nPageIn);
2356 OnNotebookPageChanged(event);
2357 m_notebook->ChangeSelection(nPageIn);
2359 fDuringSend = fDuringSendIn;
2361 m_buttonCancel->Show(false);
2364 if (nScaleX == 1.0 && nScaleY == 1.0) // We don't have icons of the proper size otherwise
2366 wxIcon iconAddressBook;
2367 iconAddressBook.CopyFromBitmap(wxBitmap(addressbook16_xpm));
2368 SetIcon(iconAddressBook);
2372 SetIcon(wxICON(bitcoin));
2375 // Init column headers
2376 m_listCtrlSending->InsertColumn(0, _("Name"), wxLIST_FORMAT_LEFT, 200);
2377 m_listCtrlSending->InsertColumn(1, _("Address"), wxLIST_FORMAT_LEFT, 350);
2378 m_listCtrlSending->SetFocus();
2379 m_listCtrlReceiving->InsertColumn(0, _("Label"), wxLIST_FORMAT_LEFT, 200);
2380 m_listCtrlReceiving->InsertColumn(1, _("Bitcoin Address"), wxLIST_FORMAT_LEFT, 350);
2381 m_listCtrlReceiving->SetFocus();
2383 // Fill listctrl with address book data
2384 CRITICAL_BLOCK(pwalletMain->cs_mapKeys)
2385 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
2387 string strDefaultReceiving = (string)pframeMain->m_textCtrlAddress->GetValue();
2388 BOOST_FOREACH(const PAIRTYPE(string, string)& item, pwalletMain->mapAddressBook)
2390 string strAddress = item.first;
2391 string strName = item.second;
2393 bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
2394 wxListCtrl* plistCtrl = fMine ? m_listCtrlReceiving : m_listCtrlSending;
2395 int nIndex = InsertLine(plistCtrl, strName, strAddress);
2396 if (strAddress == (fMine ? strDefaultReceiving : string(strInitSelected)))
2397 plistCtrl->SetItemState(nIndex, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
2402 wxString CAddressBookDialog::GetSelectedAddress()
2404 int nIndex = GetSelection(m_listCtrl);
2407 return GetItemText(m_listCtrl, nIndex, 1);
2410 wxString CAddressBookDialog::GetSelectedSendingAddress()
2412 int nIndex = GetSelection(m_listCtrlSending);
2415 return GetItemText(m_listCtrlSending, nIndex, 1);
2418 wxString CAddressBookDialog::GetSelectedReceivingAddress()
2420 int nIndex = GetSelection(m_listCtrlReceiving);
2423 return GetItemText(m_listCtrlReceiving, nIndex, 1);
2426 void CAddressBookDialog::OnNotebookPageChanged(wxNotebookEvent& event)
2429 nPage = event.GetSelection();
2430 if (nPage == SENDING)
2431 m_listCtrl = m_listCtrlSending;
2432 else if (nPage == RECEIVING)
2433 m_listCtrl = m_listCtrlReceiving;
2434 m_buttonDelete->Show(nPage == SENDING);
2435 m_buttonCopy->Show(nPage == RECEIVING);
2437 m_listCtrl->SetFocus();
2440 void CAddressBookDialog::OnListEndLabelEdit(wxListEvent& event)
2442 // Update address book with edited name
2444 if (event.IsEditCancelled())
2446 string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1);
2447 pwalletMain->SetAddressBookName(strAddress, string(event.GetText()));
2448 pframeMain->RefreshListCtrl();
2451 void CAddressBookDialog::OnListItemSelected(wxListEvent& event)
2454 if (nPage == RECEIVING)
2455 SetDefaultReceivingAddress((string)GetSelectedReceivingAddress());
2458 void CAddressBookDialog::OnListItemActivated(wxListEvent& event)
2463 // Doubleclick returns selection
2464 EndModal(GetSelectedAddress() != "" ? 2 : 0);
2468 // Doubleclick edits item
2469 wxCommandEvent event2;
2470 OnButtonEdit(event2);
2473 void CAddressBookDialog::OnButtonDelete(wxCommandEvent& event)
2475 if (nPage != SENDING)
2477 for (int nIndex = m_listCtrl->GetItemCount()-1; nIndex >= 0; nIndex--)
2479 if (m_listCtrl->GetItemState(nIndex, wxLIST_STATE_SELECTED))
2481 string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
2482 CWalletDB(pwalletMain->strWalletFile).EraseName(strAddress);
2483 m_listCtrl->DeleteItem(nIndex);
2486 pframeMain->RefreshListCtrl();
2489 void CAddressBookDialog::OnButtonCopy(wxCommandEvent& event)
2491 // Copy address box to clipboard
2492 if (wxTheClipboard->Open())
2494 wxTheClipboard->SetData(new wxTextDataObject(GetSelectedAddress()));
2495 wxTheClipboard->Close();
2499 bool CAddressBookDialog::CheckIfMine(const string& strAddress, const string& strTitle)
2502 bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
2504 wxMessageBox(_("This is one of your own addresses for receiving payments and cannot be entered in the address book. "), strTitle);
2508 void CAddressBookDialog::OnButtonEdit(wxCommandEvent& event)
2510 int nIndex = GetSelection(m_listCtrl);
2513 string strName = (string)m_listCtrl->GetItemText(nIndex);
2514 string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
2515 string strAddressOrg = strAddress;
2517 if (nPage == SENDING)
2519 // Ask name and address
2522 CGetTextFromUserDialog dialog(this, _("Edit Address"), _("Name"), strName, _("Address"), strAddress);
2523 if (!dialog.ShowModal())
2525 strName = dialog.GetValue1();
2526 strAddress = dialog.GetValue2();
2528 while (CheckIfMine(strAddress, _("Edit Address")));
2531 else if (nPage == RECEIVING)
2534 CGetTextFromUserDialog dialog(this, _("Edit Address Label"), _("Label"), strName);
2535 if (!dialog.ShowModal())
2537 strName = dialog.GetValue();
2541 if (strAddress != strAddressOrg)
2542 CWalletDB(pwalletMain->strWalletFile).EraseName(strAddressOrg);
2543 pwalletMain->SetAddressBookName(strAddress, strName);
2544 m_listCtrl->SetItem(nIndex, 1, strAddress);
2545 m_listCtrl->SetItemText(nIndex, strName);
2546 pframeMain->RefreshListCtrl();
2549 void CAddressBookDialog::OnButtonNew(wxCommandEvent& event)
2554 if (nPage == SENDING)
2556 // Ask name and address
2559 CGetTextFromUserDialog dialog(this, _("Add Address"), _("Name"), strName, _("Address"), strAddress);
2560 if (!dialog.ShowModal())
2562 strName = dialog.GetValue1();
2563 strAddress = dialog.GetValue2();
2565 while (CheckIfMine(strAddress, _("Add Address")));
2567 else if (nPage == RECEIVING)
2570 CGetTextFromUserDialog dialog(this,
2571 _("New Receiving Address"),
2572 _("You should use a new address for each payment you receive.\n\nLabel"),
2574 if (!dialog.ShowModal())
2576 strName = dialog.GetValue();
2579 strAddress = PubKeyToAddress(pwalletMain->GetKeyFromKeyPool());
2582 // Add to list and select it
2583 pwalletMain->SetAddressBookName(strAddress, strName);
2584 int nIndex = InsertLine(m_listCtrl, strName, strAddress);
2585 SetSelection(m_listCtrl, nIndex);
2586 m_listCtrl->SetFocus();
2587 if (nPage == SENDING)
2588 pframeMain->RefreshListCtrl();
2591 void CAddressBookDialog::OnButtonOK(wxCommandEvent& event)
2594 EndModal(GetSelectedAddress() != "" ? 1 : 0);
2597 void CAddressBookDialog::OnButtonCancel(wxCommandEvent& event)
2603 void CAddressBookDialog::OnClose(wxCloseEvent& event)
2614 //////////////////////////////////////////////////////////////////////////////
2621 ID_TASKBAR_RESTORE = 10001,
2624 ID_TASKBAR_GENERATE,
2628 BEGIN_EVENT_TABLE(CMyTaskBarIcon, wxTaskBarIcon)
2629 EVT_TASKBAR_LEFT_DCLICK(CMyTaskBarIcon::OnLeftButtonDClick)
2630 EVT_MENU(ID_TASKBAR_RESTORE, CMyTaskBarIcon::OnMenuRestore)
2631 EVT_MENU(ID_TASKBAR_SEND, CMyTaskBarIcon::OnMenuSend)
2632 EVT_MENU(ID_TASKBAR_OPTIONS, CMyTaskBarIcon::OnMenuOptions)
2633 EVT_UPDATE_UI(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnUpdateUIGenerate)
2634 EVT_MENU(ID_TASKBAR_EXIT, CMyTaskBarIcon::OnMenuExit)
2637 void CMyTaskBarIcon::Show(bool fShow)
2639 static char pszPrevTip[200];
2642 string strTooltip = _("Bitcoin");
2643 if (fGenerateBitcoins)
2644 strTooltip = _("Bitcoin - Generating");
2645 if (fGenerateBitcoins && vNodes.empty())
2646 strTooltip = _("Bitcoin - (not connected)");
2648 // Optimization, only update when changed, using char array to be reentrant
2649 if (strncmp(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip)-1) != 0)
2651 strlcpy(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip));
2653 // somehow it'll choose the wrong size and scale it down if
2654 // we use the main icon, so we hand it one with only 16x16
2655 SetIcon(wxICON(favicon), strTooltip);
2657 SetIcon(bitcoin80_xpm, strTooltip);
2663 strlcpy(pszPrevTip, "", sizeof(pszPrevTip));
2668 void CMyTaskBarIcon::Hide()
2673 void CMyTaskBarIcon::OnLeftButtonDClick(wxTaskBarIconEvent& event)
2678 void CMyTaskBarIcon::OnMenuRestore(wxCommandEvent& event)
2683 void CMyTaskBarIcon::OnMenuSend(wxCommandEvent& event)
2686 CSendDialog dialog(pframeMain);
2690 void CMyTaskBarIcon::OnMenuOptions(wxCommandEvent& event)
2692 // Since it's modal, get the main window to do it
2693 wxCommandEvent event2(wxEVT_COMMAND_MENU_SELECTED, wxID_PREFERENCES);
2694 pframeMain->GetEventHandler()->AddPendingEvent(event2);
2697 void CMyTaskBarIcon::Restore()
2700 wxIconizeEvent event(0, false);
2701 pframeMain->GetEventHandler()->AddPendingEvent(event);
2702 pframeMain->Iconize(false);
2703 pframeMain->Raise();
2706 void CMyTaskBarIcon::OnUpdateUIGenerate(wxUpdateUIEvent& event)
2708 event.Check(fGenerateBitcoins);
2711 void CMyTaskBarIcon::OnMenuExit(wxCommandEvent& event)
2713 pframeMain->Close(true);
2716 void CMyTaskBarIcon::UpdateTooltip()
2718 if (IsIconInstalled())
2722 wxMenu* CMyTaskBarIcon::CreatePopupMenu()
2724 wxMenu* pmenu = new wxMenu;
2725 pmenu->Append(ID_TASKBAR_RESTORE, _("&Open Bitcoin"));
2726 pmenu->Append(ID_TASKBAR_SEND, _("&Send Bitcoins"));
2727 pmenu->Append(ID_TASKBAR_OPTIONS, _("O&ptions..."));
2728 #ifndef __WXMAC_OSX__ // Mac has built-in quit menu
2729 pmenu->AppendSeparator();
2730 pmenu->Append(ID_TASKBAR_EXIT, _("E&xit"));
2740 //////////////////////////////////////////////////////////////////////////////
2745 void CreateMainWindow()
2747 pframeMain = new CMainFrame(NULL);
2748 if (GetBoolArg("-min"))
2749 pframeMain->Iconize(true);
2750 #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
2751 if (!GetBoolArg("-minimizetotray"))
2752 fMinimizeToTray = false;
2754 pframeMain->Show(true); // have to show first to get taskbar button to hide
2755 if (fMinimizeToTray && pframeMain->IsIconized())
2756 fClosedToTray = true;
2757 pframeMain->Show(!fClosedToTray);
2758 ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
2759 CreateThread(ThreadDelayedRepaint, NULL);
2763 // Define a new application
2764 class CMyApp : public wxApp
2773 // Hook Initialize so we can start without GUI
2774 virtual bool Initialize(int& argc, wxChar** argv);
2776 // 2nd-level exception handling: we get all the exceptions occurring in any
2777 // event handler here
2778 virtual bool OnExceptionInMainLoop();
2780 // 3rd, and final, level exception handling: whenever an unhandled
2781 // exception is caught, this function is called
2782 virtual void OnUnhandledException();
2784 // and now for something different: this function is called in case of a
2785 // crash (e.g. dereferencing null pointer, division by 0, ...)
2786 virtual void OnFatalException();
2789 IMPLEMENT_APP(CMyApp)
2791 bool CMyApp::Initialize(int& argc, wxChar** argv)
2793 for (int i = 1; i < argc; i++)
2794 if (!IsSwitchChar(argv[i][0]))
2795 fCommandLine = true;
2799 // wxApp::Initialize will remove environment-specific parameters,
2800 // so it's too early to call ParseParameters yet
2801 for (int i = 1; i < argc; i++)
2803 wxString str = argv[i];
2805 if (str.size() >= 1 && str[0] == '/')
2807 char pszLower[MAX_PATH];
2808 strlcpy(pszLower, str.c_str(), sizeof(pszLower));
2812 if (str == "-daemon")
2818 if (fDaemon || fCommandLine)
2820 // Call the original Initialize while suppressing error messages
2821 // and ignoring failure. If unable to initialize GTK, it fails
2822 // near the end so hopefully the last few things don't matter.
2825 wxApp::Initialize(argc, argv);
2834 fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
2838 pthread_exit((void*)0);
2840 pid_t sid = setsid();
2842 fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno);
2849 return wxApp::Initialize(argc, argv);
2852 bool CMyApp::OnInit()
2854 #if defined(__WXMSW__) && defined(__WXDEBUG__) && defined(GUI)
2855 // Disable malfunctioning wxWidgets debug assertion
2856 extern int g_isPainting;
2857 g_isPainting = 10000;
2859 #if defined(__WXMSW__ ) || defined(__WXMAC_OSX__)
2860 SetAppName("Bitcoin");
2862 SetAppName("bitcoin");
2866 // Hack to set wxConvLibc codepage to UTF-8 on Windows,
2867 // may break if wxMBConv_win32 implementation in strconv.cpp changes.
2868 class wxMBConv_win32 : public wxMBConv
2872 size_t m_minMBCharWidth;
2874 if (((wxMBConv_win32*)&wxConvLibc)->m_CodePage == CP_ACP)
2875 ((wxMBConv_win32*)&wxConvLibc)->m_CodePage = CP_UTF8;
2879 // Load locale/<lang>/LC_MESSAGES/bitcoin.mo language file
2880 g_locale.Init(wxLANGUAGE_DEFAULT, 0);
2881 g_locale.AddCatalogLookupPathPrefix("locale");
2883 g_locale.AddCatalogLookupPathPrefix("/usr/share/locale");
2884 g_locale.AddCatalogLookupPathPrefix("/usr/local/share/locale");
2886 g_locale.AddCatalog("wxstd"); // wxWidgets standard translations, if any
2887 g_locale.AddCatalog("bitcoin");
2890 HDC hdc = GetDC(NULL);
2893 nScaleX = GetDeviceCaps(hdc, LOGPIXELSX) / 96.0;
2894 nScaleY = GetDeviceCaps(hdc, LOGPIXELSY) / 96.0;
2895 ReleaseDC(NULL, hdc);
2899 return AppInit(argc, argv);
2902 int CMyApp::OnExit()
2905 return wxApp::OnExit();
2908 bool CMyApp::OnExceptionInMainLoop()
2914 catch (std::exception& e)
2916 PrintException(&e, "CMyApp::OnExceptionInMainLoop()");
2917 wxLogWarning("Exception %s %s", typeid(e).name(), e.what());
2923 PrintException(NULL, "CMyApp::OnExceptionInMainLoop()");
2924 wxLogWarning("Unknown exception");
2931 void CMyApp::OnUnhandledException()
2933 // this shows how we may let some exception propagate uncaught
2938 catch (std::exception& e)
2940 PrintException(&e, "CMyApp::OnUnhandledException()");
2941 wxLogWarning("Exception %s %s", typeid(e).name(), e.what());
2947 PrintException(NULL, "CMyApp::OnUnhandledException()");
2948 wxLogWarning("Unknown exception");
2954 void CMyApp::OnFatalException()
2956 wxMessageBox(_("Program has crashed and will terminate. "), "Bitcoin", wxOK | wxICON_ERROR);