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.
12 DEFINE_EVENT_TYPE(wxEVT_UITHREADCALL)
14 CMainFrame* pframeMain = NULL;
15 CMyTaskBarIcon* ptaskbaricon = NULL;
16 bool fClosedToTray = false;
27 //////////////////////////////////////////////////////////////////////////////
32 void HandleCtrlA(wxKeyEvent& event)
36 wxTextCtrl* textCtrl = (wxTextCtrl*)event.GetEventObject();
37 if (event.GetModifiers() == wxMOD_CONTROL && event.GetKeyCode() == 'A')
38 textCtrl->SetSelection(-1, -1);
43 //char pszHourFormat[256];
44 //pszHourFormat[0] = '\0';
45 //GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ITIME, pszHourFormat, 256);
46 //return (pszHourFormat[0] != '0');
50 string DateStr(int64 nTime)
52 // Can only be used safely here in the UI
53 return (string)wxDateTime((time_t)nTime).FormatDate();
56 string DateTimeStr(int64 nTime)
58 // Can only be used safely here in the UI
59 wxDateTime datetime((time_t)nTime);
61 return (string)datetime.Format("%x %H:%M");
63 return (string)datetime.Format("%x ") + itostr((datetime.GetHour() + 11) % 12 + 1) + (string)datetime.Format(":%M %p");
66 wxString GetItemText(wxListCtrl* listCtrl, int nIndex, int nColumn)
68 // Helper to simplify access to listctrl
70 item.m_itemId = nIndex;
72 item.m_mask = wxLIST_MASK_TEXT;
73 if (!listCtrl->GetItem(item))
75 return item.GetText();
78 int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1)
80 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
81 listCtrl->SetItem(nIndex, 1, str1);
85 int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
87 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
88 listCtrl->SetItem(nIndex, 1, str1);
89 listCtrl->SetItem(nIndex, 2, str2);
90 listCtrl->SetItem(nIndex, 3, str3);
91 listCtrl->SetItem(nIndex, 4, str4);
95 int InsertLine(wxListCtrl* listCtrl, void* pdata, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
97 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
98 listCtrl->SetItemPtrData(nIndex, (wxUIntPtr)pdata);
99 listCtrl->SetItem(nIndex, 1, str1);
100 listCtrl->SetItem(nIndex, 2, str2);
101 listCtrl->SetItem(nIndex, 3, str3);
102 listCtrl->SetItem(nIndex, 4, str4);
106 void SetItemTextColour(wxListCtrl* listCtrl, int nIndex, const wxColour& colour)
108 // Repaint on Windows is more flickery if the colour has ever been set,
109 // so don't want to set it unless it's different. Default colour has
110 // alpha 0 transparent, so our colours don't match using operator==.
111 wxColour c1 = listCtrl->GetItemTextColour(nIndex);
113 c1 = wxColour(0,0,0);
114 if (colour.Red() != c1.Red() || colour.Green() != c1.Green() || colour.Blue() != c1.Blue())
115 listCtrl->SetItemTextColour(nIndex, colour);
118 void SetSelection(wxListCtrl* listCtrl, int nIndex)
120 int nSize = listCtrl->GetItemCount();
121 long nState = (wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
122 for (int i = 0; i < nSize; i++)
123 listCtrl->SetItemState(i, (i == nIndex ? nState : 0), nState);
126 int GetSelection(wxListCtrl* listCtrl)
128 int nSize = listCtrl->GetItemCount();
129 for (int i = 0; i < nSize; i++)
130 if (listCtrl->GetItemState(i, wxLIST_STATE_FOCUSED))
135 string HtmlEscape(const char* psz, bool fMultiLine=false)
138 for (const char* p = psz; *p; p++)
140 if (*p == '<') len += 4;
141 else if (*p == '>') len += 4;
142 else if (*p == '&') len += 5;
143 else if (*p == '"') len += 6;
144 else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') len += 6;
145 else if (*p == '\n' && fMultiLine) len += 5;
151 for (const char* p = psz; *p; p++)
153 if (*p == '<') str += "<";
154 else if (*p == '>') str += ">";
155 else if (*p == '&') str += "&";
156 else if (*p == '"') str += """;
157 else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') str += " ";
158 else if (*p == '\n' && fMultiLine) str += "<br>\n";
165 string HtmlEscape(const string& str, bool fMultiLine=false)
167 return HtmlEscape(str.c_str(), fMultiLine);
170 void CalledMessageBox(const string& message, const string& caption, int style, wxWindow* parent, int x, int y, int* pnRet, bool* pfDone)
172 *pnRet = wxMessageBox(message, caption, style, parent, x, y);
176 int ThreadSafeMessageBox(const string& message, const string& caption, int style, wxWindow* parent, int x, int y)
179 return wxMessageBox(message, caption, style, parent, x, y);
181 if (wxThread::IsMain() || fDaemon)
183 return wxMessageBox(message, caption, style, parent, x, y);
189 UIThreadCall(bind(CalledMessageBox, message, caption, style, parent, x, y, &nRet, &fDone));
197 bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* parent)
199 if (nFeeRequired < CENT || fDaemon)
201 string strMessage = strprintf(
202 _("This transaction is over the size limit. You can still send it for a fee of %s, "
203 "which goes to the nodes that process your transaction and helps to support the network. "
204 "Do you want to pay the fee?"),
205 FormatMoney(nFeeRequired).c_str());
206 return (ThreadSafeMessageBox(strMessage, strCaption, wxYES_NO, parent) == wxYES);
209 void CalledSetStatusBar(const string& strText, int nField)
211 if (nField == 0 && GetWarnings("statusbar") != "")
213 if (pframeMain && pframeMain->m_statusBar)
214 pframeMain->m_statusBar->SetStatusText(strText, nField);
217 void SetDefaultReceivingAddress(const string& strAddress)
219 // Update main window address and database
220 if (pframeMain == NULL)
222 if (strAddress != pframeMain->m_textCtrlAddress->GetValue())
225 if (!AddressToHash160(strAddress, hash160))
227 if (!mapPubKeys.count(hash160))
229 CWalletDB().WriteDefaultKey(mapPubKeys[hash160]);
230 pframeMain->m_textCtrlAddress->SetValue(strAddress);
243 //////////////////////////////////////////////////////////////////////////////
248 CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent)
250 Connect(wxEVT_UITHREADCALL, wxCommandEventHandler(CMainFrame::OnUIThreadCall), NULL, this);
252 // Set initially selected page
253 wxNotebookEvent event;
254 event.SetSelection(0);
255 OnNotebookPageChanged(event);
256 m_notebook->ChangeSelection(0);
259 fRefreshListCtrl = false;
260 fRefreshListCtrlRunning = false;
261 fOnSetFocusAddress = false;
263 m_choiceFilter->SetSelection(0);
264 double dResize = 1.0;
266 SetIcon(wxICON(bitcoin));
268 SetIcon(bitcoin80_xpm);
269 SetBackgroundColour(m_toolBar->GetBackgroundColour());
270 wxFont fontTmp = m_staticText41->GetFont();
271 fontTmp.SetFamily(wxFONTFAMILY_TELETYPE);
272 m_staticTextBalance->SetFont(fontTmp);
273 m_staticTextBalance->SetSize(140, 17);
274 // resize to fit ubuntu's huge default font
276 SetSize(dResize * GetSize().GetWidth(), 1.15 * GetSize().GetHeight());
278 m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " ");
279 m_listCtrl->SetFocus();
280 ptaskbaricon = new CMyTaskBarIcon();
282 // Mac automatically moves wxID_EXIT, wxID_PREFERENCES and wxID_ABOUT
283 // to their standard places, leaving these menus empty.
284 GetMenuBar()->Remove(2); // remove Help menu
285 GetMenuBar()->Remove(0); // remove File menu
288 // Init column headers
289 int nDateWidth = DateTimeStr(1229413914).size() * 6 + 8;
290 if (!strstr(DateTimeStr(1229413914).c_str(), "2008"))
296 wxListCtrl* pplistCtrl[] = {m_listCtrlAll, m_listCtrlSentReceived, m_listCtrlSent, m_listCtrlReceived};
297 foreach(wxListCtrl* p, pplistCtrl)
299 p->InsertColumn(0, "", wxLIST_FORMAT_LEFT, dResize * 0);
300 p->InsertColumn(1, "", wxLIST_FORMAT_LEFT, dResize * 0);
301 p->InsertColumn(2, _("Status"), wxLIST_FORMAT_LEFT, dResize * 112);
302 p->InsertColumn(3, _("Date"), wxLIST_FORMAT_LEFT, dResize * nDateWidth);
303 p->InsertColumn(4, _("Description"), wxLIST_FORMAT_LEFT, dResize * 409 - nDateWidth);
304 p->InsertColumn(5, _("Debit"), wxLIST_FORMAT_RIGHT, dResize * 79);
305 p->InsertColumn(6, _("Credit"), wxLIST_FORMAT_RIGHT, dResize * 79);
309 int pnWidths[3] = { -100, 88, 300 };
311 pnWidths[1] = pnWidths[1] * 1.1 * dResize;
312 pnWidths[2] = pnWidths[2] * 1.1 * dResize;
314 m_statusBar->SetFieldsCount(3, pnWidths);
316 // Fill your address text box
317 vector<unsigned char> vchPubKey;
318 if (CWalletDB("r").ReadDefaultKey(vchPubKey))
319 m_textCtrlAddress->SetValue(PubKeyToAddress(vchPubKey));
321 // Fill listctrl with wallet transactions
325 CMainFrame::~CMainFrame()
332 void CMainFrame::OnNotebookPageChanged(wxNotebookEvent& event)
335 nPage = event.GetSelection();
338 m_listCtrl = m_listCtrlAll;
339 fShowGenerated = true;
341 fShowReceived = true;
343 else if (nPage == SENTRECEIVED)
345 m_listCtrl = m_listCtrlSentReceived;
346 fShowGenerated = false;
348 fShowReceived = true;
350 else if (nPage == SENT)
352 m_listCtrl = m_listCtrlSent;
353 fShowGenerated = false;
355 fShowReceived = false;
357 else if (nPage == RECEIVED)
359 m_listCtrl = m_listCtrlReceived;
360 fShowGenerated = false;
362 fShowReceived = true;
365 m_listCtrl->SetFocus();
368 void CMainFrame::OnClose(wxCloseEvent& event)
370 if (fMinimizeOnClose && event.CanVeto() && !IsIconized())
372 // Divert close to minimize
374 fClosedToTray = true;
380 CreateThread(Shutdown, NULL);
384 void CMainFrame::OnIconize(wxIconizeEvent& event)
387 // Hide the task bar button when minimized.
388 // Event is sent when the frame is minimized or restored.
389 // wxWidgets 2.8.9 doesn't have IsIconized() so there's no way
390 // to get rid of the deprecated warning. Just ignore it.
391 if (!event.Iconized())
392 fClosedToTray = false;
393 #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
394 if (mapArgs.count("-minimizetotray")) {
396 // The tray icon sometimes disappears on ubuntu karmic
397 // Hiding the taskbar button doesn't work cleanly on ubuntu lucid
398 // Reports of CPU peg on 64-bit linux
399 if (fMinimizeToTray && event.Iconized())
400 fClosedToTray = true;
401 Show(!fClosedToTray);
402 ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
403 #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
408 void CMainFrame::OnMouseEvents(wxMouseEvent& event)
412 RAND_add(&event.m_x, sizeof(event.m_x), 0.25);
413 RAND_add(&event.m_y, sizeof(event.m_y), 0.25);
416 void CMainFrame::OnListColBeginDrag(wxListEvent& event)
418 // Hidden columns not resizeable
419 if (event.GetColumn() <= 1 && !fDebug)
425 int CMainFrame::GetSortIndex(const string& strSort)
430 // The wx generic listctrl implementation used on GTK doesn't sort,
431 // so we have to do it ourselves. Remember, we sort in reverse order.
432 // In the wx generic implementation, they store the list of items
433 // in a vector, so indexed lookups are fast, but inserts are slower
434 // the closer they are to the top.
436 int high = m_listCtrl->GetItemCount();
439 int mid = low + ((high - low) / 2);
440 if (strSort.compare(m_listCtrl->GetItemText(mid).c_str()) >= 0)
449 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)
451 strSort = " " + strSort; // leading space to workaround wx2.9.0 ubuntu 9.10 bug
452 long nData = *(long*)&hashKey; // where first char of hidden column is displayed
455 if (!fNew && nIndex == -1)
457 string strHash = " " + hashKey.ToString();
458 while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)
459 if (GetItemText(m_listCtrl, nIndex, 1) == strHash)
463 // fNew is for blind insert, only use if you're sure it's new
464 if (fNew || nIndex == -1)
466 nIndex = m_listCtrl->InsertItem(GetSortIndex(strSort), strSort);
470 // If sort key changed, must delete and reinsert to make it relocate
471 if (GetItemText(m_listCtrl, nIndex, 0) != strSort)
473 m_listCtrl->DeleteItem(nIndex);
474 nIndex = m_listCtrl->InsertItem(GetSortIndex(strSort), strSort);
478 m_listCtrl->SetItem(nIndex, 1, " " + hashKey.ToString());
479 m_listCtrl->SetItem(nIndex, 2, str2);
480 m_listCtrl->SetItem(nIndex, 3, str3);
481 m_listCtrl->SetItem(nIndex, 4, str4);
482 m_listCtrl->SetItem(nIndex, 5, str5);
483 m_listCtrl->SetItem(nIndex, 6, str6);
484 m_listCtrl->SetItemData(nIndex, nData);
485 SetItemTextColour(m_listCtrl, nIndex, colour);
488 bool CMainFrame::DeleteLine(uint256 hashKey)
490 long nData = *(long*)&hashKey;
494 string strHash = " " + hashKey.ToString();
495 while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)
496 if (GetItemText(m_listCtrl, nIndex, 1) == strHash)
500 m_listCtrl->DeleteItem(nIndex);
505 string FormatTxStatus(const CWalletTx& wtx)
510 if (wtx.nLockTime < 500000000)
511 return strprintf(_("Open for %d blocks"), nBestHeight - wtx.nLockTime);
513 return strprintf(_("Open until %s"), DateTimeStr(wtx.nLockTime).c_str());
517 int nDepth = wtx.GetDepthInMainChain();
518 if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
519 return strprintf(_("%d/offline?"), nDepth);
521 return strprintf(_("%d/unconfirmed"), nDepth);
523 return strprintf(_("%d confirmations"), nDepth);
527 string SingleLine(const string& strIn)
530 bool fOneSpace = false;
531 foreach(unsigned char c, strIn)
539 if (fOneSpace && !strOut.empty())
548 bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
550 int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime();
551 int64 nCredit = wtx.GetCredit(true);
552 int64 nDebit = wtx.GetDebit();
553 int64 nNet = nCredit - nDebit;
554 uint256 hash = wtx.GetHash();
555 string strStatus = FormatTxStatus(wtx);
556 bool fConfirmed = wtx.fConfirmedDisplayed = wtx.IsConfirmed();
557 wxColour colour = (fConfirmed ? wxColour(0,0,0) : wxColour(128,128,128));
558 map<string, string> mapValue = wtx.mapValue;
559 wtx.nLinesDisplayed = 1;
563 if (wtx.IsCoinBase())
565 // Don't show generated coin until confirmed by at least one block after it
566 // so we don't get the user's hopes up until it looks like it's probably accepted.
568 // It is not an error when generated blocks are not accepted. By design,
569 // some percentage of blocks, like 10% or more, will end up not accepted.
570 // This is the normal mechanism by which the network copes with latency.
572 // We display regular transactions right away before any confirmation
573 // because they can always get into some block eventually. Generated coins
574 // are special because if their block is not accepted, they are not valid.
576 if (wtx.GetDepthInMainChain() < 2)
578 wtx.nLinesDisplayed = 0;
586 // Find the block the tx is in
587 CBlockIndex* pindex = NULL;
588 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(wtx.hashBlock);
589 if (mi != mapBlockIndex.end())
590 pindex = (*mi).second;
592 // Sort order, unrecorded transactions sort to the top
593 string strSort = strprintf("%010d-%01d-%010u",
594 (pindex ? pindex->nHeight : INT_MAX),
595 (wtx.IsCoinBase() ? 1 : 0),
599 if (nNet > 0 || wtx.IsCoinBase())
604 string strDescription;
605 if (wtx.IsCoinBase())
608 strDescription = _("Generated");
611 int64 nUnmatured = 0;
612 foreach(const CTxOut& txout, wtx.vout)
613 nUnmatured += txout.GetCredit();
614 if (wtx.IsInMainChain())
616 strDescription = strprintf(_("Generated (%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
618 // Check if the block was requested by anyone
619 if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
620 strDescription = _("Generated - Warning: This block was not received by any other nodes and will probably not be accepted!");
624 strDescription = _("Generated (not accepted)");
628 else if (!mapValue["from"].empty() || !mapValue["message"].empty())
630 // Received by IP connection
633 if (!mapValue["from"].empty())
634 strDescription += _("From: ") + mapValue["from"];
635 if (!mapValue["message"].empty())
637 if (!strDescription.empty())
638 strDescription += " - ";
639 strDescription += mapValue["message"];
644 // Received by Bitcoin Address
647 foreach(const CTxOut& txout, wtx.vout)
651 vector<unsigned char> vchPubKey;
652 if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
654 CRITICAL_BLOCK(cs_mapAddressBook)
656 //strDescription += _("Received payment to ");
657 //strDescription += _("Received with address ");
658 strDescription += _("Received with: ");
659 string strAddress = PubKeyToAddress(vchPubKey);
660 map<string, string>::iterator mi = mapAddressBook.find(strAddress);
661 if (mi != mapAddressBook.end() && !(*mi).second.empty())
663 string strLabel = (*mi).second;
664 strDescription += strAddress.substr(0,12) + "... ";
665 strDescription += "(" + strLabel + ")";
668 strDescription += strAddress;
676 string strCredit = FormatMoney(nNet, true);
678 strCredit = "[" + strCredit + "]";
680 InsertLine(fNew, nIndex, hash, strSort, colour,
682 nTime ? DateTimeStr(nTime) : "",
683 SingleLine(strDescription),
689 bool fAllFromMe = true;
690 foreach(const CTxIn& txin, wtx.vin)
691 fAllFromMe = fAllFromMe && txin.IsMine();
693 bool fAllToMe = true;
694 foreach(const CTxOut& txout, wtx.vout)
695 fAllToMe = fAllToMe && txout.IsMine();
697 if (fAllFromMe && fAllToMe)
700 int64 nValue = wtx.vout[0].nValue;
701 InsertLine(fNew, nIndex, hash, strSort, colour,
703 nTime ? DateTimeStr(nTime) : "",
704 _("Payment to yourself"),
707 /// issue: can't tell which is the payment and which is the change anymore
708 // FormatMoney(nNet - nValue, true),
709 // FormatMoney(nValue, true));
719 int64 nTxFee = nDebit - wtx.GetValueOut();
720 wtx.nLinesDisplayed = 0;
721 for (int nOut = 0; nOut < wtx.vout.size(); nOut++)
723 const CTxOut& txout = wtx.vout[nOut];
728 if (!mapValue["to"].empty())
731 strAddress = mapValue["to"];
735 // Sent to Bitcoin Address
737 if (ExtractHash160(txout.scriptPubKey, hash160))
738 strAddress = Hash160ToAddress(hash160);
741 string strDescription = _("To: ");
742 CRITICAL_BLOCK(cs_mapAddressBook)
743 if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
744 strDescription += mapAddressBook[strAddress] + " ";
745 strDescription += strAddress;
746 if (!mapValue["message"].empty())
748 if (!strDescription.empty())
749 strDescription += " - ";
750 strDescription += mapValue["message"];
753 int64 nValue = txout.nValue;
760 InsertLine(fNew, nIndex, hash, strprintf("%s-%d", strSort.c_str(), nOut), colour,
762 nTime ? DateTimeStr(nTime) : "",
763 SingleLine(strDescription),
764 FormatMoney(-nValue, true),
766 wtx.nLinesDisplayed++;
772 // Mixed debit transaction, can't break down payees
774 bool fAllMine = true;
775 foreach(const CTxOut& txout, wtx.vout)
776 fAllMine = fAllMine && txout.IsMine();
777 foreach(const CTxIn& txin, wtx.vin)
778 fAllMine = fAllMine && txin.IsMine();
780 InsertLine(fNew, nIndex, hash, strSort, colour,
782 nTime ? DateTimeStr(nTime) : "",
784 FormatMoney(nNet, true),
792 void CMainFrame::RefreshListCtrl()
794 fRefreshListCtrl = true;
798 void CMainFrame::OnIdle(wxIdleEvent& event)
800 if (fRefreshListCtrl)
802 // Collect list of wallet transactions and sort newest first
803 bool fEntered = false;
804 vector<pair<unsigned int, uint256> > vSorted;
805 TRY_CRITICAL_BLOCK(cs_mapWallet)
807 printf("RefreshListCtrl starting\n");
809 fRefreshListCtrl = false;
810 vWalletUpdated.clear();
812 // Do the newest transactions first
813 vSorted.reserve(mapWallet.size());
814 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
816 const CWalletTx& wtx = (*it).second;
817 unsigned int nTime = UINT_MAX - wtx.GetTxTime();
818 vSorted.push_back(make_pair(nTime, (*it).first));
820 m_listCtrl->DeleteAllItems();
825 sort(vSorted.begin(), vSorted.end());
828 for (int i = 0; i < vSorted.size();)
832 bool fEntered = false;
833 TRY_CRITICAL_BLOCK(cs_mapWallet)
836 uint256& hash = vSorted[i++].second;
837 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
838 if (mi != mapWallet.end())
839 InsertTransaction((*mi).second, true);
841 if (!fEntered || i == 100 || i % 500 == 0)
845 printf("RefreshListCtrl done\n");
847 // Update transaction total display
852 // Check for time updates
853 static int64 nLastTime;
854 if (GetTime() > nLastTime + 30)
856 TRY_CRITICAL_BLOCK(cs_mapWallet)
858 nLastTime = GetTime();
859 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
861 CWalletTx& wtx = (*it).second;
862 if (wtx.nTimeDisplayed && wtx.nTimeDisplayed != wtx.GetTxTime())
863 InsertTransaction(wtx, false);
870 void CMainFrame::RefreshStatusColumn()
873 static CBlockIndex* pindexLastBest;
874 static unsigned int nLastRefreshed;
876 int nTop = max((int)m_listCtrl->GetTopItem(), 0);
877 if (nTop == nLastTop && pindexLastBest == pindexBest)
880 TRY_CRITICAL_BLOCK(cs_mapWallet)
883 int nEnd = min(nStart + 100, m_listCtrl->GetItemCount());
885 if (pindexLastBest == pindexBest && nLastRefreshed == nListViewUpdated)
887 // If no updates, only need to do the part that moved onto the screen
888 if (nStart >= nLastTop && nStart < nLastTop + 100)
889 nStart = nLastTop + 100;
890 if (nEnd >= nLastTop && nEnd < nLastTop + 100)
894 pindexLastBest = pindexBest;
895 nLastRefreshed = nListViewUpdated;
897 for (int nIndex = nStart; nIndex < min(nEnd, m_listCtrl->GetItemCount()); nIndex++)
899 uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1));
900 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
901 if (mi == mapWallet.end())
903 printf("CMainFrame::RefreshStatusColumn() : tx not found in mapWallet\n");
906 CWalletTx& wtx = (*mi).second;
907 if (wtx.IsCoinBase() ||
908 wtx.GetTxTime() != wtx.nTimeDisplayed ||
909 wtx.IsConfirmed() != wtx.fConfirmedDisplayed)
911 if (!InsertTransaction(wtx, false, nIndex))
912 m_listCtrl->DeleteItem(nIndex--);
916 m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx));
922 void CMainFrame::OnPaint(wxPaintEvent& event)
933 unsigned int nNeedRepaint = 0;
934 unsigned int nLastRepaint = 0;
935 int64 nLastRepaintTime = 0;
936 int64 nRepaintInterval = 500;
938 void ThreadDelayedRepaint(void* parg)
942 if (nLastRepaint != nNeedRepaint && GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)
944 nLastRepaint = nNeedRepaint;
947 printf("DelayedRepaint\n");
949 pframeMain->fRefresh = true;
950 pframeMain->GetEventHandler()->AddPendingEvent(event);
953 Sleep(nRepaintInterval);
957 void MainFrameRepaint()
959 // This is called by network code that shouldn't access pframeMain
960 // directly because it could still be running after the UI is closed.
963 // Don't repaint too often
964 static int64 nLastRepaintRequest;
965 if (GetTimeMillis() - nLastRepaintRequest < 100)
970 nLastRepaintRequest = GetTimeMillis();
972 printf("MainFrameRepaint\n");
974 pframeMain->fRefresh = true;
975 pframeMain->GetEventHandler()->AddPendingEvent(event);
979 void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
981 // Skip lets the listctrl do the paint, we're just hooking the message
985 ptaskbaricon->UpdateTooltip();
990 static int nTransactionCount;
991 bool fPaintedBalance = false;
992 if (GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)
994 nLastRepaint = nNeedRepaint;
995 nLastRepaintTime = GetTimeMillis();
997 // Update listctrl contents
998 if (!vWalletUpdated.empty())
1000 TRY_CRITICAL_BLOCK(cs_mapWallet)
1003 if (m_listCtrl->GetItemCount())
1004 strTop = (string)m_listCtrl->GetItemText(0);
1005 foreach(uint256 hash, vWalletUpdated)
1007 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
1008 if (mi != mapWallet.end())
1009 InsertTransaction((*mi).second, false);
1011 vWalletUpdated.clear();
1012 if (m_listCtrl->GetItemCount() && strTop != (string)m_listCtrl->GetItemText(0))
1013 m_listCtrl->ScrollList(0, INT_MIN/2);
1018 TRY_CRITICAL_BLOCK(cs_mapWallet)
1020 fPaintedBalance = true;
1021 m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " ");
1023 // Count hidden and multi-line transactions
1024 nTransactionCount = 0;
1025 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
1027 CWalletTx& wtx = (*it).second;
1028 nTransactionCount += wtx.nLinesDisplayed;
1032 if (!vWalletUpdated.empty() || !fPaintedBalance)
1035 // Update status column of visible items only
1036 RefreshStatusColumn();
1038 // Update status bar
1039 static string strPrevWarning;
1040 string strWarning = GetWarnings("statusbar");
1041 if (strWarning != "")
1042 m_statusBar->SetStatusText(string(" ") + _(strWarning), 0);
1043 else if (strPrevWarning != "")
1044 m_statusBar->SetStatusText("", 0);
1045 strPrevWarning = strWarning;
1048 if (fGenerateBitcoins)
1049 strGen = _(" Generating");
1050 if (fGenerateBitcoins && vNodes.empty())
1051 strGen = _("(not connected)");
1052 m_statusBar->SetStatusText(strGen, 1);
1054 string strStatus = strprintf(_(" %d connections %d blocks %d transactions"), vNodes.size(), nBestHeight, nTransactionCount);
1055 m_statusBar->SetStatusText(strStatus, 2);
1057 // Update receiving address
1058 string strDefaultAddress = PubKeyToAddress(vchDefaultKey);
1059 if (m_textCtrlAddress->GetValue() != strDefaultAddress)
1060 m_textCtrlAddress->SetValue(strDefaultAddress);
1064 void UIThreadCall(boost::function0<void> fn)
1066 // Call this with a function object created with bind.
1067 // bind needs all parameters to match the function's expected types
1068 // and all default parameters specified. Some examples:
1069 // UIThreadCall(bind(wxBell));
1070 // UIThreadCall(bind(wxMessageBox, wxT("Message"), wxT("Title"), wxOK, (wxWindow*)NULL, -1, -1));
1071 // UIThreadCall(bind(&CMainFrame::OnMenuHelpAbout, pframeMain, event));
1074 wxCommandEvent event(wxEVT_UITHREADCALL);
1075 event.SetClientData((void*)new boost::function0<void>(fn));
1076 pframeMain->GetEventHandler()->AddPendingEvent(event);
1080 void CMainFrame::OnUIThreadCall(wxCommandEvent& event)
1082 boost::function0<void>* pfn = (boost::function0<void>*)event.GetClientData();
1087 void CMainFrame::OnMenuFileExit(wxCommandEvent& event)
1093 void CMainFrame::OnMenuOptionsGenerate(wxCommandEvent& event)
1095 // Options->Generate Coins
1096 GenerateBitcoins(event.IsChecked());
1099 void CMainFrame::OnUpdateUIOptionsGenerate(wxUpdateUIEvent& event)
1101 event.Check(fGenerateBitcoins);
1104 void CMainFrame::OnMenuOptionsChangeYourAddress(wxCommandEvent& event)
1106 // Options->Your Receiving Addresses
1107 CAddressBookDialog dialog(this, "", CAddressBookDialog::RECEIVING, false);
1108 if (!dialog.ShowModal())
1112 void CMainFrame::OnMenuOptionsOptions(wxCommandEvent& event)
1115 COptionsDialog dialog(this);
1119 void CMainFrame::OnMenuHelpAbout(wxCommandEvent& event)
1122 CAboutDialog dialog(this);
1126 void CMainFrame::OnButtonSend(wxCommandEvent& event)
1129 CSendDialog dialog(this);
1133 void CMainFrame::OnButtonAddressBook(wxCommandEvent& event)
1135 // Toolbar: Address Book
1136 CAddressBookDialog dialogAddr(this, "", CAddressBookDialog::SENDING, false);
1137 if (dialogAddr.ShowModal() == 2)
1140 CSendDialog dialogSend(this, dialogAddr.GetSelectedAddress());
1141 dialogSend.ShowModal();
1145 void CMainFrame::OnSetFocusAddress(wxFocusEvent& event)
1147 // Automatically select-all when entering window
1149 m_textCtrlAddress->SetSelection(-1, -1);
1150 fOnSetFocusAddress = true;
1153 void CMainFrame::OnMouseEventsAddress(wxMouseEvent& event)
1156 if (fOnSetFocusAddress)
1157 m_textCtrlAddress->SetSelection(-1, -1);
1158 fOnSetFocusAddress = false;
1161 void CMainFrame::OnButtonNew(wxCommandEvent& event)
1164 CGetTextFromUserDialog dialog(this,
1165 _("New Receiving Address"),
1166 _("You should use a new address for each payment you receive.\n\nLabel"),
1168 if (!dialog.ShowModal())
1170 string strName = dialog.GetValue();
1173 string strAddress = PubKeyToAddress(CWalletDB().GetKeyFromKeyPool());
1176 SetAddressBookName(strAddress, strName);
1177 SetDefaultReceivingAddress(strAddress);
1180 void CMainFrame::OnButtonCopy(wxCommandEvent& event)
1182 // Copy address box to clipboard
1183 if (wxTheClipboard->Open())
1185 wxTheClipboard->SetData(new wxTextDataObject(m_textCtrlAddress->GetValue()));
1186 wxTheClipboard->Close();
1190 void CMainFrame::OnListItemActivated(wxListEvent& event)
1192 uint256 hash((string)GetItemText(m_listCtrl, event.GetIndex(), 1));
1194 CRITICAL_BLOCK(cs_mapWallet)
1196 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
1197 if (mi == mapWallet.end())
1199 printf("CMainFrame::OnListItemActivated() : tx not found in mapWallet\n");
1204 CTxDetailsDialog dialog(this, wtx);
1206 //CTxDetailsDialog* pdialog = new CTxDetailsDialog(this, wtx);
1215 //////////////////////////////////////////////////////////////////////////////
1220 CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetailsDialogBase(parent)
1222 CRITICAL_BLOCK(cs_mapAddressBook)
1225 strHTML.reserve(4000);
1226 strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
1228 int64 nTime = wtx.GetTxTime();
1229 int64 nCredit = wtx.GetCredit();
1230 int64 nDebit = wtx.GetDebit();
1231 int64 nNet = nCredit - nDebit;
1235 strHTML += _("<b>Status:</b> ") + FormatTxStatus(wtx);
1236 int nRequests = wtx.GetRequestCount();
1237 if (nRequests != -1)
1240 strHTML += _(", has not been successfully broadcast yet");
1241 else if (nRequests == 1)
1242 strHTML += strprintf(_(", broadcast through %d node"), nRequests);
1244 strHTML += strprintf(_(", broadcast through %d nodes"), nRequests);
1248 strHTML += _("<b>Date:</b> ") + (nTime ? DateTimeStr(nTime) : "") + "<br>";
1254 if (wtx.IsCoinBase())
1256 strHTML += _("<b>Source:</b> Generated<br>");
1258 else if (!wtx.mapValue["from"].empty())
1260 // Online transaction
1261 if (!wtx.mapValue["from"].empty())
1262 strHTML += _("<b>From:</b> ") + HtmlEscape(wtx.mapValue["from"]) + "<br>";
1266 // Offline transaction
1270 foreach(const CTxOut& txout, wtx.vout)
1274 vector<unsigned char> vchPubKey;
1275 if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
1277 string strAddress = PubKeyToAddress(vchPubKey);
1278 if (mapAddressBook.count(strAddress))
1280 strHTML += string() + _("<b>From:</b> ") + _("unknown") + "<br>";
1281 strHTML += _("<b>To:</b> ");
1282 strHTML += HtmlEscape(strAddress);
1283 if (!mapAddressBook[strAddress].empty())
1284 strHTML += _(" (yours, label: ") + mapAddressBook[strAddress] + ")";
1286 strHTML += _(" (yours)");
1301 if (!wtx.mapValue["to"].empty())
1303 // Online transaction
1304 strAddress = wtx.mapValue["to"];
1305 strHTML += _("<b>To:</b> ");
1306 if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
1307 strHTML += mapAddressBook[strAddress] + " ";
1308 strHTML += HtmlEscape(strAddress) + "<br>";
1315 if (wtx.IsCoinBase() && nCredit == 0)
1320 int64 nUnmatured = 0;
1321 foreach(const CTxOut& txout, wtx.vout)
1322 nUnmatured += txout.GetCredit();
1323 strHTML += _("<b>Credit:</b> ");
1324 if (wtx.IsInMainChain())
1325 strHTML += strprintf(_("(%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
1327 strHTML += _("(not accepted)");
1335 strHTML += _("<b>Credit:</b> ") + FormatMoney(nNet) + "<br>";
1339 bool fAllFromMe = true;
1340 foreach(const CTxIn& txin, wtx.vin)
1341 fAllFromMe = fAllFromMe && txin.IsMine();
1343 bool fAllToMe = true;
1344 foreach(const CTxOut& txout, wtx.vout)
1345 fAllToMe = fAllToMe && txout.IsMine();
1352 foreach(const CTxOut& txout, wtx.vout)
1357 if (wtx.mapValue["to"].empty())
1359 // Offline transaction
1361 if (ExtractHash160(txout.scriptPubKey, hash160))
1363 string strAddress = Hash160ToAddress(hash160);
1364 strHTML += _("<b>To:</b> ");
1365 if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
1366 strHTML += mapAddressBook[strAddress] + " ";
1367 strHTML += strAddress;
1372 strHTML += _("<b>Debit:</b> ") + FormatMoney(-txout.nValue) + "<br>";
1378 /// issue: can't tell which is the payment and which is the change anymore
1379 //int64 nValue = wtx.vout[0].nValue;
1380 //strHTML += _("<b>Debit:</b> ") + FormatMoney(-nValue) + "<br>";
1381 //strHTML += _("<b>Credit:</b> ") + FormatMoney(nValue) + "<br>";
1384 int64 nTxFee = nDebit - wtx.GetValueOut();
1386 strHTML += _("<b>Transaction fee:</b> ") + FormatMoney(-nTxFee) + "<br>";
1391 // Mixed debit transaction
1393 foreach(const CTxIn& txin, wtx.vin)
1395 strHTML += _("<b>Debit:</b> ") + FormatMoney(-txin.GetDebit()) + "<br>";
1396 foreach(const CTxOut& txout, wtx.vout)
1398 strHTML += _("<b>Credit:</b> ") + FormatMoney(txout.GetCredit()) + "<br>";
1402 strHTML += _("<b>Net amount:</b> ") + FormatMoney(nNet, true) + "<br>";
1408 if (!wtx.mapValue["message"].empty())
1409 strHTML += string() + "<br><b>" + _("Message:") + "</b><br>" + HtmlEscape(wtx.mapValue["message"], true) + "<br>";
1411 if (wtx.IsCoinBase())
1412 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>";
1420 strHTML += "<hr><br>debug print<br><br>";
1421 foreach(const CTxIn& txin, wtx.vin)
1423 strHTML += "<b>Debit:</b> " + FormatMoney(-txin.GetDebit()) + "<br>";
1424 foreach(const CTxOut& txout, wtx.vout)
1426 strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";
1428 strHTML += "<br><b>Transaction:</b><br>";
1429 strHTML += HtmlEscape(wtx.ToString(), true);
1431 strHTML += "<br><b>Inputs:</b><br>";
1432 CRITICAL_BLOCK(cs_mapWallet)
1434 foreach(const CTxIn& txin, wtx.vin)
1436 COutPoint prevout = txin.prevout;
1437 map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
1438 if (mi != mapWallet.end())
1440 const CWalletTx& prev = (*mi).second;
1441 if (prevout.n < prev.vout.size())
1443 strHTML += HtmlEscape(prev.ToString(), true);
1444 strHTML += " " + FormatTxStatus(prev) + ", ";
1445 strHTML = strHTML + "IsMine=" + (prev.vout[prevout.n].IsMine() ? "true" : "false") + "<br>";
1454 strHTML += "</font></html>";
1455 string(strHTML.begin(), strHTML.end()).swap(strHTML);
1456 m_htmlWin->SetPage(strHTML);
1457 m_buttonOK->SetFocus();
1461 void CTxDetailsDialog::OnButtonOK(wxCommandEvent& event)
1472 //////////////////////////////////////////////////////////////////////////////
1478 string StartupShortcutPath()
1480 return MyGetSpecialFolderPath(CSIDL_STARTUP, true) + "\\Bitcoin.lnk";
1483 bool GetStartOnSystemStartup()
1485 return filesystem::exists(StartupShortcutPath().c_str());
1488 void SetStartOnSystemStartup(bool fAutoStart)
1490 // If the shortcut exists already, remove it for updating
1491 remove(StartupShortcutPath().c_str());
1497 // Get a pointer to the IShellLink interface.
1498 IShellLink* psl = NULL;
1499 HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
1500 CLSCTX_INPROC_SERVER, IID_IShellLink,
1501 reinterpret_cast<void**>(&psl));
1503 if (SUCCEEDED(hres))
1505 // Get the current executable path
1506 TCHAR pszExePath[MAX_PATH];
1507 GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));
1509 // Set the path to the shortcut target
1510 psl->SetPath(pszExePath);
1511 PathRemoveFileSpec(pszExePath);
1512 psl->SetWorkingDirectory(pszExePath);
1513 psl->SetShowCmd(SW_SHOWMINNOACTIVE);
1515 // Query IShellLink for the IPersistFile interface for
1516 // saving the shortcut in persistent storage.
1517 IPersistFile* ppf = NULL;
1518 hres = psl->QueryInterface(IID_IPersistFile,
1519 reinterpret_cast<void**>(&ppf));
1520 if (SUCCEEDED(hres))
1522 WCHAR pwsz[MAX_PATH];
1523 // Ensure that the string is ANSI.
1524 MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().c_str(), -1, pwsz, MAX_PATH);
1525 // Save the link by calling IPersistFile::Save.
1526 hres = ppf->Save(pwsz, TRUE);
1535 #elif defined(__WXGTK__)
1537 // Follow the Desktop Application Autostart Spec:
1538 // http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
1540 boost::filesystem::path GetAutostartDir()
1542 namespace fs = boost::filesystem;
1544 char* pszConfigHome = getenv("XDG_CONFIG_HOME");
1545 if (pszConfigHome) return fs::path(pszConfigHome) / fs::path("autostart");
1546 char* pszHome = getenv("HOME");
1547 if (pszHome) return fs::path(pszHome) / fs::path(".config/autostart");
1551 boost::filesystem::path GetAutostartFilePath()
1553 return GetAutostartDir() / boost::filesystem::path("bitcoin.desktop");
1556 bool GetStartOnSystemStartup()
1558 boost::filesystem::ifstream optionFile(GetAutostartFilePath());
1559 if (!optionFile.good())
1561 // Scan through file for "Hidden=true":
1563 while (!optionFile.eof())
1565 getline(optionFile, line);
1566 if (line.find("Hidden") != string::npos &&
1567 line.find("true") != string::npos)
1575 void SetStartOnSystemStartup(bool fAutoStart)
1579 unlink(GetAutostartFilePath().native_file_string().c_str());
1583 char pszExePath[MAX_PATH+1];
1584 memset(pszExePath, 0, sizeof(pszExePath));
1585 if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1)
1588 boost::filesystem::create_directories(GetAutostartDir());
1590 boost::filesystem::ofstream optionFile(GetAutostartFilePath(), ios_base::out|ios_base::trunc);
1591 if (!optionFile.good())
1593 wxMessageBox(_("Cannot write autostart/bitcoin.desktop file"), "Bitcoin");
1596 // Write a bitcoin.desktop file to the autostart directory:
1597 optionFile << "[Desktop Entry]\n";
1598 optionFile << "Type=Application\n";
1599 optionFile << "Name=Bitcoin\n";
1600 optionFile << "Exec=" << pszExePath << "\n";
1601 optionFile << "Terminal=false\n";
1602 optionFile << "Hidden=false\n";
1608 // TODO: OSX startup stuff; see:
1609 // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html
1611 bool GetStartOnSystemStartup() { return false; }
1612 void SetStartOnSystemStartup(bool fAutoStart) { }
1621 //////////////////////////////////////////////////////////////////////////////
1626 COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent)
1628 // Set up list box of page choices
1629 m_listBox->Append(_("Main"));
1630 //m_listBox->Append(_("Test 2"));
1631 m_listBox->SetSelection(0);
1633 #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
1634 m_checkBoxStartOnSystemStartup->SetLabel(_("&Start Bitcoin on window system startup"));
1635 if (!mapArgs.count("-minimizetotray"))
1637 // Minimize to tray is just too buggy on Linux
1638 fMinimizeToTray = false;
1639 m_checkBoxMinimizeToTray->SetValue(false);
1640 m_checkBoxMinimizeToTray->Enable(false);
1641 m_checkBoxMinimizeOnClose->SetLabel(_("&Minimize on close"));
1644 #ifdef __WXMAC_OSX__
1645 m_checkBoxStartOnSystemStartup->Enable(false); // not implemented yet
1649 m_textCtrlTransactionFee->SetValue(FormatMoney(nTransactionFee));
1650 m_checkBoxLimitProcessors->SetValue(fLimitProcessors);
1651 m_spinCtrlLimitProcessors->Enable(fLimitProcessors);
1652 m_spinCtrlLimitProcessors->SetValue(nLimitProcessors);
1653 int nProcessors = wxThread::GetCPUCount();
1654 if (nProcessors < 1)
1656 m_spinCtrlLimitProcessors->SetRange(1, nProcessors);
1657 m_checkBoxStartOnSystemStartup->SetValue(fTmpStartOnSystemStartup = GetStartOnSystemStartup());
1658 m_checkBoxMinimizeToTray->SetValue(fMinimizeToTray);
1659 m_checkBoxMinimizeOnClose->SetValue(fMinimizeOnClose);
1660 m_checkBoxUseProxy->SetValue(fUseProxy);
1661 m_textCtrlProxyIP->Enable(fUseProxy);
1662 m_textCtrlProxyPort->Enable(fUseProxy);
1663 m_staticTextProxyIP->Enable(fUseProxy);
1664 m_staticTextProxyPort->Enable(fUseProxy);
1665 m_textCtrlProxyIP->SetValue(addrProxy.ToStringIP());
1666 m_textCtrlProxyPort->SetValue(addrProxy.ToStringPort());
1668 m_buttonOK->SetFocus();
1671 void COptionsDialog::SelectPage(int nPage)
1673 m_panelMain->Show(nPage == 0);
1674 m_panelTest2->Show(nPage == 1);
1676 m_scrolledWindow->Layout();
1677 m_scrolledWindow->SetScrollbars(0, 0, 0, 0, 0, 0);
1680 void COptionsDialog::OnListBox(wxCommandEvent& event)
1682 SelectPage(event.GetSelection());
1685 void COptionsDialog::OnKillFocusTransactionFee(wxFocusEvent& event)
1688 int64 nTmp = nTransactionFee;
1689 ParseMoney(m_textCtrlTransactionFee->GetValue(), nTmp);
1690 m_textCtrlTransactionFee->SetValue(FormatMoney(nTmp));
1693 void COptionsDialog::OnCheckBoxLimitProcessors(wxCommandEvent& event)
1695 m_spinCtrlLimitProcessors->Enable(event.IsChecked());
1698 void COptionsDialog::OnCheckBoxUseProxy(wxCommandEvent& event)
1700 m_textCtrlProxyIP->Enable(event.IsChecked());
1701 m_textCtrlProxyPort->Enable(event.IsChecked());
1702 m_staticTextProxyIP->Enable(event.IsChecked());
1703 m_staticTextProxyPort->Enable(event.IsChecked());
1706 CAddress COptionsDialog::GetProxyAddr()
1708 // Be careful about byte order, addr.ip and addr.port are big endian
1709 CAddress addr(m_textCtrlProxyIP->GetValue() + ":" + m_textCtrlProxyPort->GetValue());
1710 if (addr.ip == INADDR_NONE)
1711 addr.ip = addrProxy.ip;
1712 int nPort = atoi(m_textCtrlProxyPort->GetValue());
1713 addr.port = htons(nPort);
1714 if (nPort <= 0 || nPort > USHRT_MAX)
1715 addr.port = addrProxy.port;
1719 void COptionsDialog::OnKillFocusProxy(wxFocusEvent& event)
1722 m_textCtrlProxyIP->SetValue(GetProxyAddr().ToStringIP());
1723 m_textCtrlProxyPort->SetValue(GetProxyAddr().ToStringPort());
1727 void COptionsDialog::OnButtonOK(wxCommandEvent& event)
1729 OnButtonApply(event);
1733 void COptionsDialog::OnButtonCancel(wxCommandEvent& event)
1738 void COptionsDialog::OnButtonApply(wxCommandEvent& event)
1742 int64 nPrevTransactionFee = nTransactionFee;
1743 if (ParseMoney(m_textCtrlTransactionFee->GetValue(), nTransactionFee) && nTransactionFee != nPrevTransactionFee)
1744 walletdb.WriteSetting("nTransactionFee", nTransactionFee);
1746 int nPrevMaxProc = (fLimitProcessors ? nLimitProcessors : INT_MAX);
1747 if (fLimitProcessors != m_checkBoxLimitProcessors->GetValue())
1749 fLimitProcessors = m_checkBoxLimitProcessors->GetValue();
1750 walletdb.WriteSetting("fLimitProcessors", fLimitProcessors);
1752 if (nLimitProcessors != m_spinCtrlLimitProcessors->GetValue())
1754 nLimitProcessors = m_spinCtrlLimitProcessors->GetValue();
1755 walletdb.WriteSetting("nLimitProcessors", nLimitProcessors);
1757 if (fGenerateBitcoins && (fLimitProcessors ? nLimitProcessors : INT_MAX) > nPrevMaxProc)
1758 GenerateBitcoins(fGenerateBitcoins);
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 fUseProxy = m_checkBoxUseProxy->GetValue();
1780 walletdb.WriteSetting("fUseProxy", fUseProxy);
1782 addrProxy = GetProxyAddr();
1783 walletdb.WriteSetting("addrProxy", addrProxy);
1791 //////////////////////////////////////////////////////////////////////////////
1796 CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent)
1798 m_staticTextVersion->SetLabel(strprintf(_("version %s%s beta"), FormatVersion(VERSION).c_str(), pszSubVer));
1800 // Change (c) into UTF-8 or ANSI copyright symbol
1801 wxString str = m_staticTextMain->GetLabel();
1803 str.Replace("(c)", wxString::FromUTF8("\xC2\xA9"));
1805 str.Replace("(c)", "\xA9");
1807 m_staticTextMain->SetLabel(str);
1809 // Resize on Linux to make the window fit the text.
1810 // The text was wrapped manually rather than using the Wrap setting because
1811 // the wrap would be too small on Linux and it can't be changed at this point.
1812 wxFont fontTmp = m_staticTextMain->GetFont();
1813 if (fontTmp.GetPointSize() > 8);
1814 fontTmp.SetPointSize(8);
1815 m_staticTextMain->SetFont(fontTmp);
1816 SetSize(GetSize().GetWidth() + 44, GetSize().GetHeight() + 10);
1820 void CAboutDialog::OnButtonOK(wxCommandEvent& event)
1830 //////////////////////////////////////////////////////////////////////////////
1835 CSendDialog::CSendDialog(wxWindow* parent, const wxString& strAddress) : CSendDialogBase(parent)
1838 m_textCtrlAddress->SetValue(strAddress);
1839 m_choiceTransferType->SetSelection(0);
1840 m_bitmapCheckMark->Show(false);
1841 fEnabledPrev = true;
1842 m_textCtrlAddress->SetFocus();
1843 //// todo: should add a display of your balance for convenience
1845 wxFont fontTmp = m_staticTextInstructions->GetFont();
1846 if (fontTmp.GetPointSize() > 9);
1847 fontTmp.SetPointSize(9);
1848 m_staticTextInstructions->SetFont(fontTmp);
1854 iconSend.CopyFromBitmap(wxBitmap(send16noshadow_xpm));
1857 wxCommandEvent event;
1858 OnTextAddress(event);
1860 // Fixup the tab order
1861 m_buttonPaste->MoveAfterInTabOrder(m_buttonCancel);
1862 m_buttonAddress->MoveAfterInTabOrder(m_buttonPaste);
1866 void CSendDialog::OnTextAddress(wxCommandEvent& event)
1870 bool fBitcoinAddress = IsValidBitcoinAddress(m_textCtrlAddress->GetValue());
1871 m_bitmapCheckMark->Show(fBitcoinAddress);
1873 // Grey out message if bitcoin address
1874 bool fEnable = !fBitcoinAddress;
1875 m_staticTextFrom->Enable(fEnable);
1876 m_textCtrlFrom->Enable(fEnable);
1877 m_staticTextMessage->Enable(fEnable);
1878 m_textCtrlMessage->Enable(fEnable);
1879 m_textCtrlMessage->SetBackgroundColour(wxSystemSettings::GetColour(fEnable ? wxSYS_COLOUR_WINDOW : wxSYS_COLOUR_BTNFACE));
1880 if (!fEnable && fEnabledPrev)
1882 strFromSave = m_textCtrlFrom->GetValue();
1883 strMessageSave = m_textCtrlMessage->GetValue();
1884 m_textCtrlFrom->SetValue(_("n/a"));
1885 m_textCtrlMessage->SetValue(_("Can't include a message when sending to a Bitcoin address"));
1887 else if (fEnable && !fEnabledPrev)
1889 m_textCtrlFrom->SetValue(strFromSave);
1890 m_textCtrlMessage->SetValue(strMessageSave);
1892 fEnabledPrev = fEnable;
1895 void CSendDialog::OnKillFocusAmount(wxFocusEvent& event)
1897 // Reformat the amount
1899 if (m_textCtrlAmount->GetValue().Trim().empty())
1902 if (ParseMoney(m_textCtrlAmount->GetValue(), nTmp))
1903 m_textCtrlAmount->SetValue(FormatMoney(nTmp));
1906 void CSendDialog::OnButtonAddressBook(wxCommandEvent& event)
1908 // Open address book
1909 CAddressBookDialog dialog(this, m_textCtrlAddress->GetValue(), CAddressBookDialog::SENDING, true);
1910 if (dialog.ShowModal())
1911 m_textCtrlAddress->SetValue(dialog.GetSelectedAddress());
1914 void CSendDialog::OnButtonPaste(wxCommandEvent& event)
1916 // Copy clipboard to address box
1917 if (wxTheClipboard->Open())
1919 if (wxTheClipboard->IsSupported(wxDF_TEXT))
1921 wxTextDataObject data;
1922 wxTheClipboard->GetData(data);
1923 m_textCtrlAddress->SetValue(data.GetText());
1925 wxTheClipboard->Close();
1929 void CSendDialog::OnButtonSend(wxCommandEvent& event)
1932 string strAddress = (string)m_textCtrlAddress->GetValue();
1936 if (!ParseMoney(m_textCtrlAmount->GetValue(), nValue) || nValue <= 0)
1938 wxMessageBox(_("Error in amount "), _("Send Coins"));
1941 if (nValue > GetBalance())
1943 wxMessageBox(_("Amount exceeds your balance "), _("Send Coins"));
1946 if (nValue + nTransactionFee > GetBalance())
1948 wxMessageBox(string(_("Total exceeds your balance when the ")) + FormatMoney(nTransactionFee) + _(" transaction fee is included "), _("Send Coins"));
1952 // Parse bitcoin address
1954 bool fBitcoinAddress = AddressToHash160(strAddress, hash160);
1956 if (fBitcoinAddress)
1958 // Send to bitcoin address
1959 CScript scriptPubKey;
1960 scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
1962 string strError = SendMoney(scriptPubKey, nValue, wtx, true);
1964 wxMessageBox(_("Payment sent "), _("Sending..."));
1965 else if (strError != "ABORTED")
1966 wxMessageBox(strError + " ", _("Sending..."));
1971 CAddress addr(strAddress);
1972 if (!addr.IsValid())
1974 wxMessageBox(_("Invalid address "), _("Send Coins"));
1979 wtx.mapValue["to"] = strAddress;
1980 wtx.mapValue["from"] = m_textCtrlFrom->GetValue();
1981 wtx.mapValue["message"] = m_textCtrlMessage->GetValue();
1983 // Send to IP address
1984 CSendingDialog* pdialog = new CSendingDialog(this, addr, nValue, wtx);
1985 if (!pdialog->ShowModal())
1989 CRITICAL_BLOCK(cs_mapAddressBook)
1990 if (!mapAddressBook.count(strAddress))
1991 SetAddressBookName(strAddress, "");
1996 void CSendDialog::OnButtonCancel(wxCommandEvent& event)
2007 //////////////////////////////////////////////////////////////////////////////
2012 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
2017 start = wxDateTime::UNow();
2018 memset(pszStatus, 0, sizeof(pszStatus));
2025 SetSize(1.2 * GetSize().GetWidth(), 1.08 * 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 > 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 > GetBalance())
2245 Error(_("Insufficient funds"));
2248 CReserveKey reservekey;
2250 if (!CreateTransaction(scriptPubKey, nPrice, wtx, reservekey, nFeeRequired))
2252 if (nPrice + nFeeRequired > GetBalance())
2253 Error(strprintf(_("This is an oversized transaction that requires a transaction fee of %s"), 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 (!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)
2349 // Set initially selected page
2350 wxNotebookEvent event;
2351 event.SetSelection(nPageIn);
2352 OnNotebookPageChanged(event);
2353 m_notebook->ChangeSelection(nPageIn);
2355 fDuringSend = fDuringSendIn;
2357 m_buttonCancel->Show(false);
2360 wxIcon iconAddressBook;
2361 iconAddressBook.CopyFromBitmap(wxBitmap(addressbook16_xpm));
2362 SetIcon(iconAddressBook);
2364 // Init column headers
2365 m_listCtrlSending->InsertColumn(0, _("Name"), wxLIST_FORMAT_LEFT, 200);
2366 m_listCtrlSending->InsertColumn(1, _("Address"), wxLIST_FORMAT_LEFT, 350);
2367 m_listCtrlSending->SetFocus();
2368 m_listCtrlReceiving->InsertColumn(0, _("Label"), wxLIST_FORMAT_LEFT, 200);
2369 m_listCtrlReceiving->InsertColumn(1, _("Bitcoin Address"), wxLIST_FORMAT_LEFT, 350);
2370 m_listCtrlReceiving->SetFocus();
2372 // Fill listctrl with address book data
2373 CRITICAL_BLOCK(cs_mapKeys)
2374 CRITICAL_BLOCK(cs_mapAddressBook)
2376 string strDefaultReceiving = (string)pframeMain->m_textCtrlAddress->GetValue();
2377 foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
2379 string strAddress = item.first;
2380 string strName = item.second;
2382 bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
2383 wxListCtrl* plistCtrl = fMine ? m_listCtrlReceiving : m_listCtrlSending;
2384 int nIndex = InsertLine(plistCtrl, strName, strAddress);
2385 if (strAddress == (fMine ? strDefaultReceiving : string(strInitSelected)))
2386 plistCtrl->SetItemState(nIndex, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
2391 wxString CAddressBookDialog::GetSelectedAddress()
2393 int nIndex = GetSelection(m_listCtrl);
2396 return GetItemText(m_listCtrl, nIndex, 1);
2399 wxString CAddressBookDialog::GetSelectedSendingAddress()
2401 int nIndex = GetSelection(m_listCtrlSending);
2404 return GetItemText(m_listCtrlSending, nIndex, 1);
2407 wxString CAddressBookDialog::GetSelectedReceivingAddress()
2409 int nIndex = GetSelection(m_listCtrlReceiving);
2412 return GetItemText(m_listCtrlReceiving, nIndex, 1);
2415 void CAddressBookDialog::OnNotebookPageChanged(wxNotebookEvent& event)
2418 nPage = event.GetSelection();
2419 if (nPage == SENDING)
2420 m_listCtrl = m_listCtrlSending;
2421 else if (nPage == RECEIVING)
2422 m_listCtrl = m_listCtrlReceiving;
2423 m_buttonDelete->Show(nPage == SENDING);
2424 m_buttonCopy->Show(nPage == RECEIVING);
2426 m_listCtrl->SetFocus();
2429 void CAddressBookDialog::OnListEndLabelEdit(wxListEvent& event)
2431 // Update address book with edited name
2433 if (event.IsEditCancelled())
2435 string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1);
2436 SetAddressBookName(strAddress, string(event.GetText()));
2437 pframeMain->RefreshListCtrl();
2440 void CAddressBookDialog::OnListItemSelected(wxListEvent& event)
2443 if (nPage == RECEIVING)
2444 SetDefaultReceivingAddress((string)GetSelectedReceivingAddress());
2447 void CAddressBookDialog::OnListItemActivated(wxListEvent& event)
2452 // Doubleclick returns selection
2453 EndModal(GetSelectedAddress() != "" ? 2 : 0);
2457 // Doubleclick edits item
2458 wxCommandEvent event2;
2459 OnButtonEdit(event2);
2462 void CAddressBookDialog::OnButtonDelete(wxCommandEvent& event)
2464 if (nPage != SENDING)
2466 for (int nIndex = m_listCtrl->GetItemCount()-1; nIndex >= 0; nIndex--)
2468 if (m_listCtrl->GetItemState(nIndex, wxLIST_STATE_SELECTED))
2470 string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
2471 CWalletDB().EraseName(strAddress);
2472 m_listCtrl->DeleteItem(nIndex);
2475 pframeMain->RefreshListCtrl();
2478 void CAddressBookDialog::OnButtonCopy(wxCommandEvent& event)
2480 // Copy address box to clipboard
2481 if (wxTheClipboard->Open())
2483 wxTheClipboard->SetData(new wxTextDataObject(GetSelectedAddress()));
2484 wxTheClipboard->Close();
2488 bool CAddressBookDialog::CheckIfMine(const string& strAddress, const string& strTitle)
2491 bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
2493 wxMessageBox(_("This is one of your own addresses for receiving payments and cannot be entered in the address book. "), strTitle);
2497 void CAddressBookDialog::OnButtonEdit(wxCommandEvent& event)
2499 int nIndex = GetSelection(m_listCtrl);
2502 string strName = (string)m_listCtrl->GetItemText(nIndex);
2503 string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
2504 string strAddressOrg = strAddress;
2506 if (nPage == SENDING)
2508 // Ask name and address
2511 CGetTextFromUserDialog dialog(this, _("Edit Address"), _("Name"), strName, _("Address"), strAddress);
2512 if (!dialog.ShowModal())
2514 strName = dialog.GetValue1();
2515 strAddress = dialog.GetValue2();
2517 while (CheckIfMine(strAddress, _("Edit Address")));
2520 else if (nPage == RECEIVING)
2523 CGetTextFromUserDialog dialog(this, _("Edit Address Label"), _("Label"), strName);
2524 if (!dialog.ShowModal())
2526 strName = dialog.GetValue();
2530 if (strAddress != strAddressOrg)
2531 CWalletDB().EraseName(strAddressOrg);
2532 SetAddressBookName(strAddress, strName);
2533 m_listCtrl->SetItem(nIndex, 1, strAddress);
2534 m_listCtrl->SetItemText(nIndex, strName);
2535 pframeMain->RefreshListCtrl();
2538 void CAddressBookDialog::OnButtonNew(wxCommandEvent& event)
2543 if (nPage == SENDING)
2545 // Ask name and address
2548 CGetTextFromUserDialog dialog(this, _("Add Address"), _("Name"), strName, _("Address"), strAddress);
2549 if (!dialog.ShowModal())
2551 strName = dialog.GetValue1();
2552 strAddress = dialog.GetValue2();
2554 while (CheckIfMine(strAddress, _("Add Address")));
2556 else if (nPage == RECEIVING)
2559 CGetTextFromUserDialog dialog(this,
2560 _("New Receiving Address"),
2561 _("You should use a new address for each payment you receive.\n\nLabel"),
2563 if (!dialog.ShowModal())
2565 strName = dialog.GetValue();
2568 strAddress = PubKeyToAddress(CWalletDB().GetKeyFromKeyPool());
2571 // Add to list and select it
2572 SetAddressBookName(strAddress, strName);
2573 int nIndex = InsertLine(m_listCtrl, strName, strAddress);
2574 SetSelection(m_listCtrl, nIndex);
2575 m_listCtrl->SetFocus();
2576 if (nPage == SENDING)
2577 pframeMain->RefreshListCtrl();
2580 void CAddressBookDialog::OnButtonOK(wxCommandEvent& event)
2583 EndModal(GetSelectedAddress() != "" ? 1 : 0);
2586 void CAddressBookDialog::OnButtonCancel(wxCommandEvent& event)
2592 void CAddressBookDialog::OnClose(wxCloseEvent& event)
2603 //////////////////////////////////////////////////////////////////////////////
2610 ID_TASKBAR_RESTORE = 10001,
2612 ID_TASKBAR_GENERATE,
2616 BEGIN_EVENT_TABLE(CMyTaskBarIcon, wxTaskBarIcon)
2617 EVT_TASKBAR_LEFT_DCLICK(CMyTaskBarIcon::OnLeftButtonDClick)
2618 EVT_MENU(ID_TASKBAR_RESTORE, CMyTaskBarIcon::OnMenuRestore)
2619 EVT_MENU(ID_TASKBAR_OPTIONS, CMyTaskBarIcon::OnMenuOptions)
2620 EVT_MENU(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnMenuGenerate)
2621 EVT_UPDATE_UI(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnUpdateUIGenerate)
2622 EVT_MENU(ID_TASKBAR_EXIT, CMyTaskBarIcon::OnMenuExit)
2625 void CMyTaskBarIcon::Show(bool fShow)
2627 static char pszPrevTip[200];
2630 string strTooltip = _("Bitcoin");
2631 if (fGenerateBitcoins)
2632 strTooltip = _("Bitcoin - Generating");
2633 if (fGenerateBitcoins && vNodes.empty())
2634 strTooltip = _("Bitcoin - (not connected)");
2636 // Optimization, only update when changed, using char array to be reentrant
2637 if (strncmp(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip)-1) != 0)
2639 strlcpy(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip));
2641 // somehow it'll choose the wrong size and scale it down if
2642 // we use the main icon, so we hand it one with only 16x16
2643 SetIcon(wxICON(favicon), strTooltip);
2645 SetIcon(bitcoin80_xpm, strTooltip);
2651 strlcpy(pszPrevTip, "", sizeof(pszPrevTip));
2656 void CMyTaskBarIcon::Hide()
2661 void CMyTaskBarIcon::OnLeftButtonDClick(wxTaskBarIconEvent& event)
2666 void CMyTaskBarIcon::OnMenuRestore(wxCommandEvent& event)
2671 void CMyTaskBarIcon::OnMenuOptions(wxCommandEvent& event)
2673 // Since it's modal, get the main window to do it
2674 wxCommandEvent event2(wxEVT_COMMAND_MENU_SELECTED, wxID_PREFERENCES);
2675 pframeMain->GetEventHandler()->AddPendingEvent(event2);
2678 void CMyTaskBarIcon::Restore()
2681 wxIconizeEvent event(0, false);
2682 pframeMain->GetEventHandler()->AddPendingEvent(event);
2683 pframeMain->Iconize(false);
2684 pframeMain->Raise();
2687 void CMyTaskBarIcon::OnMenuGenerate(wxCommandEvent& event)
2689 GenerateBitcoins(event.IsChecked());
2692 void CMyTaskBarIcon::OnUpdateUIGenerate(wxUpdateUIEvent& event)
2694 event.Check(fGenerateBitcoins);
2697 void CMyTaskBarIcon::OnMenuExit(wxCommandEvent& event)
2699 pframeMain->Close(true);
2702 void CMyTaskBarIcon::UpdateTooltip()
2704 if (IsIconInstalled())
2708 wxMenu* CMyTaskBarIcon::CreatePopupMenu()
2710 wxMenu* pmenu = new wxMenu;
2711 pmenu->Append(ID_TASKBAR_RESTORE, _("&Open Bitcoin"));
2712 pmenu->Append(ID_TASKBAR_OPTIONS, _("O&ptions..."));
2713 pmenu->AppendCheckItem(ID_TASKBAR_GENERATE, _("&Generate Coins"))->Check(fGenerateBitcoins);
2714 #ifndef __WXMAC_OSX__ // Mac has built-in quit menu
2715 pmenu->AppendSeparator();
2716 pmenu->Append(ID_TASKBAR_EXIT, _("E&xit"));
2726 //////////////////////////////////////////////////////////////////////////////
2731 void CreateMainWindow()
2733 pframeMain = new CMainFrame(NULL);
2734 if (mapArgs.count("-min"))
2735 pframeMain->Iconize(true);
2736 #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
2737 if (!mapArgs.count("-minimizetotray"))
2738 fMinimizeToTray = false;
2740 pframeMain->Show(true); // have to show first to get taskbar button to hide
2741 if (fMinimizeToTray && pframeMain->IsIconized())
2742 fClosedToTray = true;
2743 pframeMain->Show(!fClosedToTray);
2744 ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
2745 CreateThread(ThreadDelayedRepaint, NULL);
2749 // Define a new application
2750 class CMyApp : public wxApp
2759 // Hook Initialize so we can start without GUI
2760 virtual bool Initialize(int& argc, wxChar** argv);
2762 // 2nd-level exception handling: we get all the exceptions occurring in any
2763 // event handler here
2764 virtual bool OnExceptionInMainLoop();
2766 // 3rd, and final, level exception handling: whenever an unhandled
2767 // exception is caught, this function is called
2768 virtual void OnUnhandledException();
2770 // and now for something different: this function is called in case of a
2771 // crash (e.g. dereferencing null pointer, division by 0, ...)
2772 virtual void OnFatalException();
2775 IMPLEMENT_APP(CMyApp)
2777 bool CMyApp::Initialize(int& argc, wxChar** argv)
2779 for (int i = 1; i < argc; i++)
2780 if (!IsSwitchChar(argv[i][0]))
2781 fCommandLine = true;
2785 // wxApp::Initialize will remove environment-specific parameters,
2786 // so it's too early to call ParseParameters yet
2787 for (int i = 1; i < argc; i++)
2789 wxString str = argv[i];
2791 if (str.size() >= 1 && str[0] == '/')
2793 char pszLower[MAX_PATH];
2794 strlcpy(pszLower, str.c_str(), sizeof(pszLower));
2798 if (str == "-daemon")
2804 if (fDaemon || fCommandLine)
2806 // Call the original Initialize while suppressing error messages
2807 // and ignoring failure. If unable to initialize GTK, it fails
2808 // near the end so hopefully the last few things don't matter.
2811 wxApp::Initialize(argc, argv);
2820 fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
2824 pthread_exit((void*)0);
2831 return wxApp::Initialize(argc, argv);
2834 bool CMyApp::OnInit()
2836 #if defined(__WXMSW__) && defined(__WXDEBUG__) && defined(GUI)
2837 // Disable malfunctioning wxWidgets debug assertion
2838 extern int g_isPainting;
2839 g_isPainting = 10000;
2842 wxImage::AddHandler(new wxPNGHandler);
2844 #if defined(__WXMSW__ ) || defined(__WXMAC_OSX__)
2845 SetAppName("Bitcoin");
2847 SetAppName("bitcoin");
2851 // Hack to set wxConvLibc codepage to UTF-8 on Windows,
2852 // may break if wxMBConv_win32 implementation in strconv.cpp changes.
2853 class wxMBConv_win32 : public wxMBConv
2857 size_t m_minMBCharWidth;
2859 if (((wxMBConv_win32*)&wxConvLibc)->m_CodePage == CP_ACP)
2860 ((wxMBConv_win32*)&wxConvLibc)->m_CodePage = CP_UTF8;
2864 // Load locale/<lang>/LC_MESSAGES/bitcoin.mo language file
2865 g_locale.Init(wxLANGUAGE_DEFAULT, 0);
2866 g_locale.AddCatalogLookupPathPrefix("locale");
2868 g_locale.AddCatalogLookupPathPrefix("/usr/share/locale");
2869 g_locale.AddCatalogLookupPathPrefix("/usr/local/share/locale");
2871 g_locale.AddCatalog("wxstd"); // wxWidgets standard translations, if any
2872 g_locale.AddCatalog("bitcoin");
2874 return AppInit(argc, argv);
2877 int CMyApp::OnExit()
2880 return wxApp::OnExit();
2883 bool CMyApp::OnExceptionInMainLoop()
2889 catch (std::exception& e)
2891 PrintException(&e, "CMyApp::OnExceptionInMainLoop()");
2892 wxLogWarning("Exception %s %s", typeid(e).name(), e.what());
2898 PrintException(NULL, "CMyApp::OnExceptionInMainLoop()");
2899 wxLogWarning("Unknown exception");
2906 void CMyApp::OnUnhandledException()
2908 // this shows how we may let some exception propagate uncaught
2913 catch (std::exception& e)
2915 PrintException(&e, "CMyApp::OnUnhandledException()");
2916 wxLogWarning("Exception %s %s", typeid(e).name(), e.what());
2922 PrintException(NULL, "CMyApp::OnUnhandledException()");
2923 wxLogWarning("Unknown exception");
2929 void CMyApp::OnFatalException()
2931 wxMessageBox(_("Program has crashed and will terminate. "), "Bitcoin", wxOK | wxICON_ERROR);