1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2011 The PPCoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
10 #include <boost/filesystem/fstream.hpp>
11 #include <boost/filesystem/convenience.hpp>
17 using namespace boost;
20 DEFINE_EVENT_TYPE(wxEVT_UITHREADCALL)
22 CMainFrame* pframeMain = NULL;
23 CMyTaskBarIcon* ptaskbaricon = NULL;
24 bool fClosedToTray = false;
31 static const double nScaleX = 1.0;
32 static const double nScaleY = 1.0;
42 //////////////////////////////////////////////////////////////////////////////
47 void HandleCtrlA(wxKeyEvent& event)
51 wxTextCtrl* textCtrl = (wxTextCtrl*)event.GetEventObject();
52 if (event.GetModifiers() == wxMOD_CONTROL && event.GetKeyCode() == 'A')
53 textCtrl->SetSelection(-1, -1);
58 //char pszHourFormat[256];
59 //pszHourFormat[0] = '\0';
60 //GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ITIME, pszHourFormat, 256);
61 //return (pszHourFormat[0] != '0');
65 string DateStr(int64 nTime)
67 // Can only be used safely here in the UI
68 return (string)wxDateTime((time_t)nTime).FormatDate();
71 string DateTimeStr(int64 nTime)
73 // Can only be used safely here in the UI
74 wxDateTime datetime((time_t)nTime);
76 return (string)datetime.Format("%x %H:%M");
78 return (string)datetime.Format("%x ") + itostr((datetime.GetHour() + 11) % 12 + 1) + (string)datetime.Format(":%M %p");
81 wxString GetItemText(wxListCtrl* listCtrl, int nIndex, int nColumn)
83 // Helper to simplify access to listctrl
85 item.m_itemId = nIndex;
87 item.m_mask = wxLIST_MASK_TEXT;
88 if (!listCtrl->GetItem(item))
90 return item.GetText();
93 int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1)
95 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
96 listCtrl->SetItem(nIndex, 1, str1);
100 int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
102 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
103 listCtrl->SetItem(nIndex, 1, str1);
104 listCtrl->SetItem(nIndex, 2, str2);
105 listCtrl->SetItem(nIndex, 3, str3);
106 listCtrl->SetItem(nIndex, 4, str4);
110 int InsertLine(wxListCtrl* listCtrl, void* pdata, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
112 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
113 listCtrl->SetItemPtrData(nIndex, (wxUIntPtr)pdata);
114 listCtrl->SetItem(nIndex, 1, str1);
115 listCtrl->SetItem(nIndex, 2, str2);
116 listCtrl->SetItem(nIndex, 3, str3);
117 listCtrl->SetItem(nIndex, 4, str4);
121 void SetItemTextColour(wxListCtrl* listCtrl, int nIndex, const wxColour& colour)
123 // Repaint on Windows is more flickery if the colour has ever been set,
124 // so don't want to set it unless it's different. Default colour has
125 // alpha 0 transparent, so our colours don't match using operator==.
126 wxColour c1 = listCtrl->GetItemTextColour(nIndex);
128 c1 = wxColour(0,0,0);
129 if (colour.Red() != c1.Red() || colour.Green() != c1.Green() || colour.Blue() != c1.Blue())
130 listCtrl->SetItemTextColour(nIndex, colour);
133 void SetSelection(wxListCtrl* listCtrl, int nIndex)
135 int nSize = listCtrl->GetItemCount();
136 long nState = (wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
137 for (int i = 0; i < nSize; i++)
138 listCtrl->SetItemState(i, (i == nIndex ? nState : 0), nState);
141 int GetSelection(wxListCtrl* listCtrl)
143 int nSize = listCtrl->GetItemCount();
144 for (int i = 0; i < nSize; i++)
145 if (listCtrl->GetItemState(i, wxLIST_STATE_FOCUSED))
150 string HtmlEscape(const char* psz, bool fMultiLine=false)
153 for (const char* p = psz; *p; p++)
155 if (*p == '<') len += 4;
156 else if (*p == '>') len += 4;
157 else if (*p == '&') len += 5;
158 else if (*p == '"') len += 6;
159 else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') len += 6;
160 else if (*p == '\n' && fMultiLine) len += 5;
166 for (const char* p = psz; *p; p++)
168 if (*p == '<') str += "<";
169 else if (*p == '>') str += ">";
170 else if (*p == '&') str += "&";
171 else if (*p == '"') str += """;
172 else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') str += " ";
173 else if (*p == '\n' && fMultiLine) str += "<br>\n";
180 string HtmlEscape(const string& str, bool fMultiLine=false)
182 return HtmlEscape(str.c_str(), fMultiLine);
185 void CalledMessageBox(const string& message, const string& caption, int style, wxWindow* parent, int x, int y, int* pnRet, bool* pfDone)
187 *pnRet = wxMessageBox(message, caption, style, parent, x, y);
191 int ThreadSafeMessageBox(const string& message, const string& caption, int style, wxWindow* parent, int x, int y)
194 return wxMessageBox(message, caption, style, parent, x, y);
196 if (wxThread::IsMain() || fDaemon)
198 return wxMessageBox(message, caption, style, parent, x, y);
204 UIThreadCall(bind(CalledMessageBox, message, caption, style, parent, x, y, &nRet, &fDone));
212 bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* parent)
214 if (nFeeRequired < MIN_TX_FEE || nFeeRequired <= nTransactionFee || fDaemon)
216 string strMessage = strprintf(
217 _("This transaction is over the size limit. You can still send it for a fee of %s, "
218 "which goes to the nodes that process your transaction and helps to support the network. "
219 "Do you want to pay the fee?"),
220 FormatMoney(nFeeRequired).c_str());
221 return (ThreadSafeMessageBox(strMessage, strCaption, wxYES_NO, parent) == wxYES);
224 void CalledSetStatusBar(const string& strText, int nField)
226 if (nField == 0 && GetWarnings("statusbar") != "")
228 if (pframeMain && pframeMain->m_statusBar)
229 pframeMain->m_statusBar->SetStatusText(strText, nField);
232 void SetDefaultReceivingAddress(const string& strAddress)
234 // Update main window address and database
235 if (pframeMain == NULL)
237 if (strAddress != pframeMain->m_textCtrlAddress->GetValue())
240 if (!AddressToHash160(strAddress, hash160))
242 if (!mapPubKeys.count(hash160))
244 pwalletMain->SetDefaultKey(mapPubKeys[hash160]);
245 pframeMain->m_textCtrlAddress->SetValue(strAddress);
258 //////////////////////////////////////////////////////////////////////////////
263 CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent)
265 Connect(wxEVT_UITHREADCALL, wxCommandEventHandler(CMainFrame::OnUIThreadCall), NULL, this);
267 // Set initially selected page
268 wxNotebookEvent event;
269 event.SetSelection(0);
270 OnNotebookPageChanged(event);
271 m_notebook->ChangeSelection(0);
274 fRefreshListCtrl = false;
275 fRefreshListCtrlRunning = false;
276 fOnSetFocusAddress = false;
278 m_choiceFilter->SetSelection(0);
279 double dResize = nScaleX;
281 SetIcon(wxICON(bitcoin));
282 SetSize(dResize * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
284 SetIcon(bitcoin80_xpm);
285 SetBackgroundColour(m_toolBar->GetBackgroundColour());
286 wxFont fontTmp = m_staticText41->GetFont();
287 fontTmp.SetFamily(wxFONTFAMILY_TELETYPE);
288 m_staticTextBalance->SetFont(fontTmp);
289 m_staticTextBalance->SetSize(140, 17);
290 // resize to fit ubuntu's huge default font
292 SetSize(dResize * GetSize().GetWidth(), 1.15 * GetSize().GetHeight());
294 m_staticTextBalance->SetLabel(FormatMoney(pwalletMain->GetBalance()) + " ");
295 m_listCtrl->SetFocus();
296 ptaskbaricon = new CMyTaskBarIcon();
298 // Mac automatically moves wxID_EXIT, wxID_PREFERENCES and wxID_ABOUT
299 // to their standard places, leaving these menus empty.
300 GetMenuBar()->Remove(2); // remove Help menu
301 GetMenuBar()->Remove(0); // remove File menu
304 // Init column headers
305 int nDateWidth = DateTimeStr(1229413914).size() * 6 + 8;
306 if (!strstr(DateTimeStr(1229413914).c_str(), "2008"))
312 wxListCtrl* pplistCtrl[] = {m_listCtrlAll, m_listCtrlSentReceived, m_listCtrlSent, m_listCtrlReceived};
313 BOOST_FOREACH(wxListCtrl* p, pplistCtrl)
315 p->InsertColumn(0, "", wxLIST_FORMAT_LEFT, dResize * 0);
316 p->InsertColumn(1, "", wxLIST_FORMAT_LEFT, dResize * 0);
317 p->InsertColumn(2, _("Status"), wxLIST_FORMAT_LEFT, dResize * 112);
318 p->InsertColumn(3, _("Date"), wxLIST_FORMAT_LEFT, dResize * nDateWidth);
319 p->InsertColumn(4, _("Description"), wxLIST_FORMAT_LEFT, dResize * 409 - nDateWidth);
320 p->InsertColumn(5, _("Debit"), wxLIST_FORMAT_RIGHT, dResize * 79);
321 p->InsertColumn(6, _("Credit"), wxLIST_FORMAT_RIGHT, dResize * 79);
325 int pnWidths[3] = { -100, 88, 300 };
327 pnWidths[1] = pnWidths[1] * 1.1 * dResize;
328 pnWidths[2] = pnWidths[2] * 1.1 * dResize;
330 m_statusBar->SetFieldsCount(3, pnWidths);
332 // Fill your address text box
333 vector<unsigned char> vchPubKey;
334 if (CWalletDB(pwalletMain->strWalletFile,"r").ReadDefaultKey(vchPubKey))
335 m_textCtrlAddress->SetValue(PubKeyToAddress(vchPubKey));
337 // Fill listctrl with wallet transactions
341 CMainFrame::~CMainFrame()
348 void CMainFrame::OnNotebookPageChanged(wxNotebookEvent& event)
351 nPage = event.GetSelection();
354 m_listCtrl = m_listCtrlAll;
355 fShowGenerated = true;
357 fShowReceived = true;
359 else if (nPage == SENTRECEIVED)
361 m_listCtrl = m_listCtrlSentReceived;
362 fShowGenerated = false;
364 fShowReceived = true;
366 else if (nPage == SENT)
368 m_listCtrl = m_listCtrlSent;
369 fShowGenerated = false;
371 fShowReceived = false;
373 else if (nPage == RECEIVED)
375 m_listCtrl = m_listCtrlReceived;
376 fShowGenerated = false;
378 fShowReceived = true;
381 m_listCtrl->SetFocus();
384 void CMainFrame::OnClose(wxCloseEvent& event)
386 if (fMinimizeOnClose && event.CanVeto() && !IsIconized())
388 // Divert close to minimize
390 fClosedToTray = true;
396 CreateThread(Shutdown, NULL);
400 void CMainFrame::OnIconize(wxIconizeEvent& event)
403 // Hide the task bar button when minimized.
404 // Event is sent when the frame is minimized or restored.
405 // wxWidgets 2.8.9 doesn't have IsIconized() so there's no way
406 // to get rid of the deprecated warning. Just ignore it.
407 if (!event.Iconized())
408 fClosedToTray = false;
409 #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
410 if (GetBoolArg("-minimizetotray")) {
412 // The tray icon sometimes disappears on ubuntu karmic
413 // Hiding the taskbar button doesn't work cleanly on ubuntu lucid
414 // Reports of CPU peg on 64-bit linux
415 if (fMinimizeToTray && event.Iconized())
416 fClosedToTray = true;
417 Show(!fClosedToTray);
418 ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
419 #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
424 void CMainFrame::OnMouseEvents(wxMouseEvent& event)
428 RAND_add(&event.m_x, sizeof(event.m_x), 0.25);
429 RAND_add(&event.m_y, sizeof(event.m_y), 0.25);
432 void CMainFrame::OnListColBeginDrag(wxListEvent& event)
434 // Hidden columns not resizeable
435 if (event.GetColumn() <= 1 && !fDebug)
441 int CMainFrame::GetSortIndex(const string& strSort)
446 // The wx generic listctrl implementation used on GTK doesn't sort,
447 // so we have to do it ourselves. Remember, we sort in reverse order.
448 // In the wx generic implementation, they store the list of items
449 // in a vector, so indexed lookups are fast, but inserts are slower
450 // the closer they are to the top.
452 int high = m_listCtrl->GetItemCount();
455 int mid = low + ((high - low) / 2);
456 if (strSort.compare(m_listCtrl->GetItemText(mid).c_str()) >= 0)
465 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)
467 strSort = " " + strSort; // leading space to workaround wx2.9.0 ubuntu 9.10 bug
468 long nData = *(long*)&hashKey; // where first char of hidden column is displayed
471 if (!fNew && nIndex == -1)
473 string strHash = " " + hashKey.ToString();
474 while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)
475 if (GetItemText(m_listCtrl, nIndex, 1) == strHash)
479 // fNew is for blind insert, only use if you're sure it's new
480 if (fNew || nIndex == -1)
482 nIndex = m_listCtrl->InsertItem(GetSortIndex(strSort), strSort);
486 // If sort key changed, must delete and reinsert to make it relocate
487 if (GetItemText(m_listCtrl, nIndex, 0) != strSort)
489 m_listCtrl->DeleteItem(nIndex);
490 nIndex = m_listCtrl->InsertItem(GetSortIndex(strSort), strSort);
494 m_listCtrl->SetItem(nIndex, 1, " " + hashKey.ToString());
495 m_listCtrl->SetItem(nIndex, 2, str2);
496 m_listCtrl->SetItem(nIndex, 3, str3);
497 m_listCtrl->SetItem(nIndex, 4, str4);
498 m_listCtrl->SetItem(nIndex, 5, str5);
499 m_listCtrl->SetItem(nIndex, 6, str6);
500 m_listCtrl->SetItemData(nIndex, nData);
501 SetItemTextColour(m_listCtrl, nIndex, colour);
504 bool CMainFrame::DeleteLine(uint256 hashKey)
506 long nData = *(long*)&hashKey;
510 string strHash = " " + hashKey.ToString();
511 while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)
512 if (GetItemText(m_listCtrl, nIndex, 1) == strHash)
516 m_listCtrl->DeleteItem(nIndex);
521 string FormatTxStatus(const CWalletTx& wtx)
526 if (wtx.nLockTime < 500000000)
527 return strprintf(_("Open for %d blocks"), nBestHeight - wtx.nLockTime);
529 return strprintf(_("Open until %s"), DateTimeStr(wtx.nLockTime).c_str());
533 int nDepth = wtx.GetDepthInMainChain();
534 if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
535 return strprintf(_("%d/offline?"), nDepth);
537 return strprintf(_("%d/unconfirmed"), nDepth);
539 return strprintf(_("%d confirmations"), nDepth);
543 string SingleLine(const string& strIn)
546 bool fOneSpace = false;
547 BOOST_FOREACH(unsigned char c, strIn)
555 if (fOneSpace && !strOut.empty())
564 bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
566 int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime();
567 int64 nCredit = wtx.GetCredit(true);
568 int64 nDebit = wtx.GetDebit();
569 int64 nNet = nCredit - nDebit;
570 uint256 hash = wtx.GetHash();
571 string strStatus = FormatTxStatus(wtx);
572 bool fConfirmed = wtx.fConfirmedDisplayed = wtx.IsConfirmed();
573 wxColour colour = (fConfirmed ? wxColour(0,0,0) : wxColour(128,128,128));
574 map<string, string> mapValue = wtx.mapValue;
575 wtx.nLinesDisplayed = 1;
579 if (wtx.IsCoinBase())
581 // Don't show generated coin until confirmed by at least one block after it
582 // so we don't get the user's hopes up until it looks like it's probably accepted.
584 // It is not an error when generated blocks are not accepted. By design,
585 // some percentage of blocks, like 10% or more, will end up not accepted.
586 // This is the normal mechanism by which the network copes with latency.
588 // We display regular transactions right away before any confirmation
589 // because they can always get into some block eventually. Generated coins
590 // are special because if their block is not accepted, they are not valid.
592 if (wtx.GetDepthInMainChain() < 2)
594 wtx.nLinesDisplayed = 0;
602 // Find the block the tx is in
603 CBlockIndex* pindex = NULL;
604 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(wtx.hashBlock);
605 if (mi != mapBlockIndex.end())
606 pindex = (*mi).second;
608 // Sort order, unrecorded transactions sort to the top
609 string strSort = strprintf("%010d-%01d-%010u",
610 (pindex ? pindex->nHeight : INT_MAX),
611 (wtx.IsCoinBase() ? 1 : 0),
615 if (nNet > 0 || wtx.IsCoinBase())
620 string strDescription;
621 if (wtx.IsCoinBase())
624 strDescription = _("Generated");
627 int64 nUnmatured = 0;
628 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
629 nUnmatured += pwalletMain->GetCredit(txout);
630 if (wtx.IsInMainChain())
632 strDescription = strprintf(_("Generated (%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
634 // Check if the block was requested by anyone
635 if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
636 strDescription = _("Generated - Warning: This block was not received by any other nodes and will probably not be accepted!");
640 strDescription = _("Generated (not accepted)");
644 else if (!mapValue["from"].empty() || !mapValue["message"].empty())
646 // Received by IP connection
649 if (!mapValue["from"].empty())
650 strDescription += _("From: ") + mapValue["from"];
651 if (!mapValue["message"].empty())
653 if (!strDescription.empty())
654 strDescription += " - ";
655 strDescription += mapValue["message"];
660 // Received by Bitcoin Address
663 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
665 if (pwalletMain->IsMine(txout))
667 vector<unsigned char> vchPubKey;
668 if (ExtractPubKey(txout.scriptPubKey, pwalletMain, vchPubKey))
670 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
672 //strDescription += _("Received payment to ");
673 //strDescription += _("Received with address ");
674 strDescription += _("Received with: ");
675 string strAddress = PubKeyToAddress(vchPubKey);
676 map<string, string>::iterator mi = pwalletMain->mapAddressBook.find(strAddress);
677 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
679 string strLabel = (*mi).second;
680 strDescription += strAddress.substr(0,12) + "... ";
681 strDescription += "(" + strLabel + ")";
684 strDescription += strAddress;
692 string strCredit = FormatMoney(nNet, true);
694 strCredit = "[" + strCredit + "]";
696 InsertLine(fNew, nIndex, hash, strSort, colour,
698 nTime ? DateTimeStr(nTime) : "",
699 SingleLine(strDescription),
705 bool fAllFromMe = true;
706 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
707 fAllFromMe = fAllFromMe && pwalletMain->IsMine(txin);
709 bool fAllToMe = true;
710 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
711 fAllToMe = fAllToMe && pwalletMain->IsMine(txout);
713 if (fAllFromMe && fAllToMe)
716 int64 nChange = wtx.GetChange();
717 InsertLine(fNew, nIndex, hash, strSort, colour,
719 nTime ? DateTimeStr(nTime) : "",
720 _("Payment to yourself"),
721 FormatMoney(-(nDebit - nChange), true),
722 FormatMoney(nCredit - nChange, true));
732 int64 nTxFee = nDebit - wtx.GetValueOut();
733 wtx.nLinesDisplayed = 0;
734 for (int nOut = 0; nOut < wtx.vout.size(); nOut++)
736 const CTxOut& txout = wtx.vout[nOut];
737 if (pwalletMain->IsMine(txout))
741 if (!mapValue["to"].empty())
744 strAddress = mapValue["to"];
748 // Sent to Bitcoin Address
750 if (ExtractHash160(txout.scriptPubKey, hash160))
751 strAddress = Hash160ToAddress(hash160);
754 string strDescription = _("To: ");
755 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
756 if (pwalletMain->mapAddressBook.count(strAddress) && !pwalletMain->mapAddressBook[strAddress].empty())
757 strDescription += pwalletMain->mapAddressBook[strAddress] + " ";
758 strDescription += strAddress;
759 if (!mapValue["message"].empty())
761 if (!strDescription.empty())
762 strDescription += " - ";
763 strDescription += mapValue["message"];
765 else if (!mapValue["comment"].empty())
767 if (!strDescription.empty())
768 strDescription += " - ";
769 strDescription += mapValue["comment"];
772 int64 nValue = txout.nValue;
779 InsertLine(fNew, nIndex, hash, strprintf("%s-%d", strSort.c_str(), nOut), colour,
781 nTime ? DateTimeStr(nTime) : "",
782 SingleLine(strDescription),
783 FormatMoney(-nValue, true),
786 wtx.nLinesDisplayed++;
792 // Mixed debit transaction, can't break down payees
794 bool fAllMine = true;
795 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
796 fAllMine = fAllMine && pwalletMain->IsMine(txout);
797 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
798 fAllMine = fAllMine && pwalletMain->IsMine(txin);
800 InsertLine(fNew, nIndex, hash, strSort, colour,
802 nTime ? DateTimeStr(nTime) : "",
804 FormatMoney(nNet, true),
812 void CMainFrame::RefreshListCtrl()
814 fRefreshListCtrl = true;
818 void CMainFrame::OnIdle(wxIdleEvent& event)
820 if (fRefreshListCtrl)
822 // Collect list of wallet transactions and sort newest first
823 bool fEntered = false;
824 vector<pair<unsigned int, uint256> > vSorted;
825 TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
827 printf("RefreshListCtrl starting\n");
829 fRefreshListCtrl = false;
830 pwalletMain->vWalletUpdated.clear();
832 // Do the newest transactions first
833 vSorted.reserve(pwalletMain->mapWallet.size());
834 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
836 const CWalletTx& wtx = (*it).second;
837 unsigned int nTime = UINT_MAX - wtx.GetTxTime();
838 vSorted.push_back(make_pair(nTime, (*it).first));
840 m_listCtrl->DeleteAllItems();
845 sort(vSorted.begin(), vSorted.end());
848 for (int i = 0; i < vSorted.size();)
852 bool fEntered = false;
853 TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
856 uint256& hash = vSorted[i++].second;
857 map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash);
858 if (mi != pwalletMain->mapWallet.end())
859 InsertTransaction((*mi).second, true);
861 if (!fEntered || i == 100 || i % 500 == 0)
865 printf("RefreshListCtrl done\n");
867 // Update transaction total display
872 // Check for time updates
873 static int64 nLastTime;
874 if (GetTime() > nLastTime + 30)
876 TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
878 nLastTime = GetTime();
879 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
881 CWalletTx& wtx = (*it).second;
882 if (wtx.nTimeDisplayed && wtx.nTimeDisplayed != wtx.GetTxTime())
883 InsertTransaction(wtx, false);
890 void CMainFrame::RefreshStatusColumn()
893 static CBlockIndex* pindexLastBest;
894 static unsigned int nLastRefreshed;
896 int nTop = max((int)m_listCtrl->GetTopItem(), 0);
897 if (nTop == nLastTop && pindexLastBest == pindexBest)
900 TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
903 int nEnd = min(nStart + 100, m_listCtrl->GetItemCount());
905 if (pindexLastBest == pindexBest && nLastRefreshed == nListViewUpdated)
907 // If no updates, only need to do the part that moved onto the screen
908 if (nStart >= nLastTop && nStart < nLastTop + 100)
909 nStart = nLastTop + 100;
910 if (nEnd >= nLastTop && nEnd < nLastTop + 100)
914 pindexLastBest = pindexBest;
915 nLastRefreshed = nListViewUpdated;
917 for (int nIndex = nStart; nIndex < min(nEnd, m_listCtrl->GetItemCount()); nIndex++)
919 uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1));
920 map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash);
921 if (mi == pwalletMain->mapWallet.end())
923 printf("CMainFrame::RefreshStatusColumn() : tx not found in mapWallet\n");
926 CWalletTx& wtx = (*mi).second;
927 if (wtx.IsCoinBase() ||
928 wtx.GetTxTime() != wtx.nTimeDisplayed ||
929 wtx.IsConfirmed() != wtx.fConfirmedDisplayed)
931 if (!InsertTransaction(wtx, false, nIndex))
932 m_listCtrl->DeleteItem(nIndex--);
936 m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx));
942 void CMainFrame::OnPaint(wxPaintEvent& event)
953 unsigned int nNeedRepaint = 0;
954 unsigned int nLastRepaint = 0;
955 int64 nLastRepaintTime = 0;
956 int64 nRepaintInterval = 500;
958 void ThreadDelayedRepaint(void* parg)
962 if (nLastRepaint != nNeedRepaint && GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)
964 nLastRepaint = nNeedRepaint;
967 printf("DelayedRepaint\n");
969 pframeMain->fRefresh = true;
970 pframeMain->GetEventHandler()->AddPendingEvent(event);
973 Sleep(nRepaintInterval);
977 void MainFrameRepaint()
979 // This is called by network code that shouldn't access pframeMain
980 // directly because it could still be running after the UI is closed.
983 // Don't repaint too often
984 static int64 nLastRepaintRequest;
985 if (GetTimeMillis() - nLastRepaintRequest < 100)
990 nLastRepaintRequest = GetTimeMillis();
992 printf("MainFrameRepaint\n");
994 pframeMain->fRefresh = true;
995 pframeMain->GetEventHandler()->AddPendingEvent(event);
999 void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
1001 // Skip lets the listctrl do the paint, we're just hooking the message
1005 ptaskbaricon->UpdateTooltip();
1010 static int nTransactionCount;
1011 bool fPaintedBalance = false;
1012 if (GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)
1014 nLastRepaint = nNeedRepaint;
1015 nLastRepaintTime = GetTimeMillis();
1017 // Update listctrl contents
1018 if (!pwalletMain->vWalletUpdated.empty())
1020 TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
1023 if (m_listCtrl->GetItemCount())
1024 strTop = (string)m_listCtrl->GetItemText(0);
1025 BOOST_FOREACH(uint256 hash, pwalletMain->vWalletUpdated)
1027 map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash);
1028 if (mi != pwalletMain->mapWallet.end())
1029 InsertTransaction((*mi).second, false);
1031 pwalletMain->vWalletUpdated.clear();
1032 if (m_listCtrl->GetItemCount() && strTop != (string)m_listCtrl->GetItemText(0))
1033 m_listCtrl->ScrollList(0, INT_MIN/2);
1038 TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
1040 fPaintedBalance = true;
1041 m_staticTextBalance->SetLabel(FormatMoney(pwalletMain->GetBalance()) + " ");
1043 // Count hidden and multi-line transactions
1044 nTransactionCount = 0;
1045 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1047 CWalletTx& wtx = (*it).second;
1048 nTransactionCount += wtx.nLinesDisplayed;
1052 if (!pwalletMain->vWalletUpdated.empty() || !fPaintedBalance)
1055 // Update status column of visible items only
1056 RefreshStatusColumn();
1058 // Update status bar
1059 static string strPrevWarning;
1060 string strWarning = GetWarnings("statusbar");
1061 if (strWarning != "")
1062 m_statusBar->SetStatusText(string(" ") + _(strWarning), 0);
1063 else if (strPrevWarning != "")
1064 m_statusBar->SetStatusText("", 0);
1065 strPrevWarning = strWarning;
1068 if (fGenerateBitcoins)
1069 strGen = _(" Generating");
1070 if (fGenerateBitcoins && vNodes.empty())
1071 strGen = _("(not connected)");
1072 m_statusBar->SetStatusText(strGen, 1);
1074 string strStatus = strprintf(_(" %d connections %d blocks %d transactions"), vNodes.size(), nBestHeight, nTransactionCount);
1075 m_statusBar->SetStatusText(strStatus, 2);
1077 // Update receiving address
1078 string strDefaultAddress = PubKeyToAddress(pwalletMain->vchDefaultKey);
1079 if (m_textCtrlAddress->GetValue() != strDefaultAddress)
1080 m_textCtrlAddress->SetValue(strDefaultAddress);
1084 void UIThreadCall(boost::function0<void> fn)
1086 // Call this with a function object created with bind.
1087 // bind needs all parameters to match the function's expected types
1088 // and all default parameters specified. Some examples:
1089 // UIThreadCall(bind(wxBell));
1090 // UIThreadCall(bind(wxMessageBox, wxT("Message"), wxT("Title"), wxOK, (wxWindow*)NULL, -1, -1));
1091 // UIThreadCall(bind(&CMainFrame::OnMenuHelpAbout, pframeMain, event));
1094 wxCommandEvent event(wxEVT_UITHREADCALL);
1095 event.SetClientData((void*)new boost::function0<void>(fn));
1096 pframeMain->GetEventHandler()->AddPendingEvent(event);
1100 void CMainFrame::OnUIThreadCall(wxCommandEvent& event)
1102 boost::function0<void>* pfn = (boost::function0<void>*)event.GetClientData();
1107 void CMainFrame::OnMenuFileExit(wxCommandEvent& event)
1113 void CMainFrame::OnUpdateUIOptionsGenerate(wxUpdateUIEvent& event)
1115 event.Check(fGenerateBitcoins);
1118 void CMainFrame::OnMenuOptionsChangeYourAddress(wxCommandEvent& event)
1120 // Options->Your Receiving Addresses
1121 CAddressBookDialog dialog(this, "", CAddressBookDialog::RECEIVING, false);
1122 if (!dialog.ShowModal())
1126 void CMainFrame::OnMenuOptionsOptions(wxCommandEvent& event)
1129 COptionsDialog dialog(this);
1133 void CMainFrame::OnMenuHelpAbout(wxCommandEvent& event)
1136 CAboutDialog dialog(this);
1140 void CMainFrame::OnButtonSend(wxCommandEvent& event)
1143 CSendDialog dialog(this);
1147 void CMainFrame::OnButtonAddressBook(wxCommandEvent& event)
1149 // Toolbar: Address Book
1150 CAddressBookDialog dialogAddr(this, "", CAddressBookDialog::SENDING, false);
1151 if (dialogAddr.ShowModal() == 2)
1154 CSendDialog dialogSend(this, dialogAddr.GetSelectedAddress());
1155 dialogSend.ShowModal();
1159 void CMainFrame::OnSetFocusAddress(wxFocusEvent& event)
1161 // Automatically select-all when entering window
1163 m_textCtrlAddress->SetSelection(-1, -1);
1164 fOnSetFocusAddress = true;
1167 void CMainFrame::OnMouseEventsAddress(wxMouseEvent& event)
1170 if (fOnSetFocusAddress)
1171 m_textCtrlAddress->SetSelection(-1, -1);
1172 fOnSetFocusAddress = false;
1175 void CMainFrame::OnButtonNew(wxCommandEvent& event)
1178 CGetTextFromUserDialog dialog(this,
1179 _("New Receiving Address"),
1180 _("You should use a new address for each payment you receive.\n\nLabel"),
1182 if (!dialog.ShowModal())
1184 string strName = dialog.GetValue();
1187 string strAddress = PubKeyToAddress(pwalletMain->GetKeyFromKeyPool());
1190 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
1191 pwalletMain->SetAddressBookName(strAddress, strName);
1192 SetDefaultReceivingAddress(strAddress);
1195 void CMainFrame::OnButtonCopy(wxCommandEvent& event)
1197 // Copy address box to clipboard
1198 if (wxTheClipboard->Open())
1200 wxTheClipboard->SetData(new wxTextDataObject(m_textCtrlAddress->GetValue()));
1201 wxTheClipboard->Close();
1205 void CMainFrame::OnListItemActivated(wxListEvent& event)
1207 uint256 hash((string)GetItemText(m_listCtrl, event.GetIndex(), 1));
1209 CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
1211 map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash);
1212 if (mi == pwalletMain->mapWallet.end())
1214 printf("CMainFrame::OnListItemActivated() : tx not found in mapWallet\n");
1219 CTxDetailsDialog dialog(this, wtx);
1221 //CTxDetailsDialog* pdialog = new CTxDetailsDialog(this, wtx);
1230 //////////////////////////////////////////////////////////////////////////////
1235 CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetailsDialogBase(parent)
1238 SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
1240 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
1243 strHTML.reserve(4000);
1244 strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
1246 int64 nTime = wtx.GetTxTime();
1247 int64 nCredit = wtx.GetCredit();
1248 int64 nDebit = wtx.GetDebit();
1249 int64 nNet = nCredit - nDebit;
1253 strHTML += _("<b>Status:</b> ") + FormatTxStatus(wtx);
1254 int nRequests = wtx.GetRequestCount();
1255 if (nRequests != -1)
1258 strHTML += _(", has not been successfully broadcast yet");
1259 else if (nRequests == 1)
1260 strHTML += strprintf(_(", broadcast through %d node"), nRequests);
1262 strHTML += strprintf(_(", broadcast through %d nodes"), nRequests);
1266 strHTML += _("<b>Date:</b> ") + (nTime ? DateTimeStr(nTime) : "") + "<br>";
1272 if (wtx.IsCoinBase())
1274 strHTML += _("<b>Source:</b> Generated<br>");
1276 else if (!wtx.mapValue["from"].empty())
1278 // Online transaction
1279 if (!wtx.mapValue["from"].empty())
1280 strHTML += _("<b>From:</b> ") + HtmlEscape(wtx.mapValue["from"]) + "<br>";
1284 // Offline transaction
1288 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1290 if (pwalletMain->IsMine(txout))
1292 vector<unsigned char> vchPubKey;
1293 if (ExtractPubKey(txout.scriptPubKey, pwalletMain, vchPubKey))
1295 string strAddress = PubKeyToAddress(vchPubKey);
1296 if (pwalletMain->mapAddressBook.count(strAddress))
1298 strHTML += string() + _("<b>From:</b> ") + _("unknown") + "<br>";
1299 strHTML += _("<b>To:</b> ");
1300 strHTML += HtmlEscape(strAddress);
1301 if (!pwalletMain->mapAddressBook[strAddress].empty())
1302 strHTML += _(" (yours, label: ") + pwalletMain->mapAddressBook[strAddress] + ")";
1304 strHTML += _(" (yours)");
1319 if (!wtx.mapValue["to"].empty())
1321 // Online transaction
1322 strAddress = wtx.mapValue["to"];
1323 strHTML += _("<b>To:</b> ");
1324 if (pwalletMain->mapAddressBook.count(strAddress) && !pwalletMain->mapAddressBook[strAddress].empty())
1325 strHTML += pwalletMain->mapAddressBook[strAddress] + " ";
1326 strHTML += HtmlEscape(strAddress) + "<br>";
1333 if (wtx.IsCoinBase() && nCredit == 0)
1338 int64 nUnmatured = 0;
1339 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1340 nUnmatured += pwalletMain->GetCredit(txout);
1341 strHTML += _("<b>Credit:</b> ");
1342 if (wtx.IsInMainChain())
1343 strHTML += strprintf(_("(%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
1345 strHTML += _("(not accepted)");
1353 strHTML += _("<b>Credit:</b> ") + FormatMoney(nNet) + "<br>";
1357 bool fAllFromMe = true;
1358 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
1359 fAllFromMe = fAllFromMe && pwalletMain->IsMine(txin);
1361 bool fAllToMe = true;
1362 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1363 fAllToMe = fAllToMe && pwalletMain->IsMine(txout);
1370 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1372 if (pwalletMain->IsMine(txout))
1375 if (wtx.mapValue["to"].empty())
1377 // Offline transaction
1379 if (ExtractHash160(txout.scriptPubKey, hash160))
1381 string strAddress = Hash160ToAddress(hash160);
1382 strHTML += _("<b>To:</b> ");
1383 if (pwalletMain->mapAddressBook.count(strAddress) && !pwalletMain->mapAddressBook[strAddress].empty())
1384 strHTML += pwalletMain->mapAddressBook[strAddress] + " ";
1385 strHTML += strAddress;
1390 strHTML += _("<b>Debit:</b> ") + FormatMoney(-txout.nValue) + "<br>";
1396 int64 nChange = wtx.GetChange();
1397 int64 nValue = nCredit - nChange;
1398 strHTML += _("<b>Debit:</b> ") + FormatMoney(-nValue) + "<br>";
1399 strHTML += _("<b>Credit:</b> ") + FormatMoney(nValue) + "<br>";
1402 int64 nTxFee = nDebit - wtx.GetValueOut();
1404 strHTML += _("<b>Transaction fee:</b> ") + FormatMoney(-nTxFee) + "<br>";
1409 // Mixed debit transaction
1411 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
1412 if (pwalletMain->IsMine(txin))
1413 strHTML += _("<b>Debit:</b> ") + FormatMoney(-pwalletMain->GetDebit(txin)) + "<br>";
1414 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1415 if (pwalletMain->IsMine(txout))
1416 strHTML += _("<b>Credit:</b> ") + FormatMoney(pwalletMain->GetCredit(txout)) + "<br>";
1420 strHTML += _("<b>Net amount:</b> ") + FormatMoney(nNet, true) + "<br>";
1426 if (!wtx.mapValue["message"].empty())
1427 strHTML += string() + "<br><b>" + _("Message:") + "</b><br>" + HtmlEscape(wtx.mapValue["message"], true) + "<br>";
1428 if (!wtx.mapValue["comment"].empty())
1429 strHTML += string() + "<br><b>" + _("Comment:") + "</b><br>" + HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
1431 if (wtx.IsCoinBase())
1432 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>";
1440 strHTML += "<hr><br>debug print<br><br>";
1441 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
1442 if (pwalletMain->IsMine(txin))
1443 strHTML += "<b>Debit:</b> " + FormatMoney(-pwalletMain->GetDebit(txin)) + "<br>";
1444 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1445 if (pwalletMain->IsMine(txout))
1446 strHTML += "<b>Credit:</b> " + FormatMoney(pwalletMain->GetCredit(txout)) + "<br>";
1448 strHTML += "<br><b>Transaction:</b><br>";
1449 strHTML += HtmlEscape(wtx.ToString(), true);
1451 strHTML += "<br><b>Inputs:</b><br>";
1452 CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
1454 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
1456 COutPoint prevout = txin.prevout;
1457 map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(prevout.hash);
1458 if (mi != pwalletMain->mapWallet.end())
1460 const CWalletTx& prev = (*mi).second;
1461 if (prevout.n < prev.vout.size())
1463 strHTML += HtmlEscape(prev.ToString(), true);
1464 strHTML += " " + FormatTxStatus(prev) + ", ";
1465 strHTML = strHTML + "IsMine=" + (pwalletMain->IsMine(prev.vout[prevout.n]) ? "true" : "false") + "<br>";
1474 strHTML += "</font></html>";
1475 string(strHTML.begin(), strHTML.end()).swap(strHTML);
1476 m_htmlWin->SetPage(strHTML);
1477 m_buttonOK->SetFocus();
1481 void CTxDetailsDialog::OnButtonOK(wxCommandEvent& event)
1491 //////////////////////////////////////////////////////////////////////////////
1497 string StartupShortcutPath()
1499 return MyGetSpecialFolderPath(CSIDL_STARTUP, true) + "\\Bitcoin.lnk";
1502 bool GetStartOnSystemStartup()
1504 return filesystem::exists(StartupShortcutPath().c_str());
1507 void SetStartOnSystemStartup(bool fAutoStart)
1509 // If the shortcut exists already, remove it for updating
1510 remove(StartupShortcutPath().c_str());
1516 // Get a pointer to the IShellLink interface.
1517 IShellLink* psl = NULL;
1518 HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
1519 CLSCTX_INPROC_SERVER, IID_IShellLink,
1520 reinterpret_cast<void**>(&psl));
1522 if (SUCCEEDED(hres))
1524 // Get the current executable path
1525 TCHAR pszExePath[MAX_PATH];
1526 GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));
1528 // Set the path to the shortcut target
1529 psl->SetPath(pszExePath);
1530 PathRemoveFileSpec(pszExePath);
1531 psl->SetWorkingDirectory(pszExePath);
1532 psl->SetShowCmd(SW_SHOWMINNOACTIVE);
1534 // Query IShellLink for the IPersistFile interface for
1535 // saving the shortcut in persistent storage.
1536 IPersistFile* ppf = NULL;
1537 hres = psl->QueryInterface(IID_IPersistFile,
1538 reinterpret_cast<void**>(&ppf));
1539 if (SUCCEEDED(hres))
1541 WCHAR pwsz[MAX_PATH];
1542 // Ensure that the string is ANSI.
1543 MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().c_str(), -1, pwsz, MAX_PATH);
1544 // Save the link by calling IPersistFile::Save.
1545 hres = ppf->Save(pwsz, TRUE);
1554 #elif defined(__WXGTK__)
1556 // Follow the Desktop Application Autostart Spec:
1557 // http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
1559 boost::filesystem::path GetAutostartDir()
1561 namespace fs = boost::filesystem;
1563 char* pszConfigHome = getenv("XDG_CONFIG_HOME");
1564 if (pszConfigHome) return fs::path(pszConfigHome) / fs::path("autostart");
1565 char* pszHome = getenv("HOME");
1566 if (pszHome) return fs::path(pszHome) / fs::path(".config/autostart");
1570 boost::filesystem::path GetAutostartFilePath()
1572 return GetAutostartDir() / boost::filesystem::path("ppcoin.desktop");
1575 bool GetStartOnSystemStartup()
1577 boost::filesystem::ifstream optionFile(GetAutostartFilePath());
1578 if (!optionFile.good())
1580 // Scan through file for "Hidden=true":
1582 while (!optionFile.eof())
1584 getline(optionFile, line);
1585 if (line.find("Hidden") != string::npos &&
1586 line.find("true") != string::npos)
1594 void SetStartOnSystemStartup(bool fAutoStart)
1598 unlink(GetAutostartFilePath().native_file_string().c_str());
1602 char pszExePath[MAX_PATH+1];
1603 memset(pszExePath, 0, sizeof(pszExePath));
1604 if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1)
1607 boost::filesystem::create_directories(GetAutostartDir());
1609 boost::filesystem::ofstream optionFile(GetAutostartFilePath(), ios_base::out|ios_base::trunc);
1610 if (!optionFile.good())
1612 wxMessageBox(_("Cannot write autostart/ppcoin.desktop file"), "Bitcoin");
1615 // Write a ppcoin.desktop file to the autostart directory:
1616 optionFile << "[Desktop Entry]\n";
1617 optionFile << "Type=Application\n";
1618 optionFile << "Name=Bitcoin\n";
1619 optionFile << "Exec=" << pszExePath << "\n";
1620 optionFile << "Terminal=false\n";
1621 optionFile << "Hidden=false\n";
1627 // TODO: OSX startup stuff; see:
1628 // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html
1630 bool GetStartOnSystemStartup() { return false; }
1631 void SetStartOnSystemStartup(bool fAutoStart) { }
1640 //////////////////////////////////////////////////////////////////////////////
1645 COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent)
1647 // Set up list box of page choices
1648 m_listBox->Append(_("Main"));
1649 //m_listBox->Append(_("Test 2"));
1650 m_listBox->SetSelection(0);
1653 SetSize(1.0 * GetSize().GetWidth(), 1.2 * GetSize().GetHeight());
1655 SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
1657 #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
1658 m_checkBoxStartOnSystemStartup->SetLabel(_("&Start Bitcoin on window system startup"));
1659 if (!GetBoolArg("-minimizetotray"))
1661 // Minimize to tray is just too buggy on Linux
1662 fMinimizeToTray = false;
1663 m_checkBoxMinimizeToTray->SetValue(false);
1664 m_checkBoxMinimizeToTray->Enable(false);
1665 m_checkBoxMinimizeOnClose->SetLabel(_("&Minimize on close"));
1668 #ifdef __WXMAC_OSX__
1669 m_checkBoxStartOnSystemStartup->Enable(false); // not implemented yet
1673 m_textCtrlTransactionFee->SetValue(FormatMoney(nTransactionFee));
1674 m_checkBoxStartOnSystemStartup->SetValue(fTmpStartOnSystemStartup = GetStartOnSystemStartup());
1675 m_checkBoxMinimizeToTray->SetValue(fMinimizeToTray);
1676 m_checkBoxMinimizeOnClose->SetValue(fMinimizeOnClose);
1678 m_checkBoxUseUPnP->SetValue(fUseUPnP);
1680 m_checkBoxUseUPnP->Enable(false);
1681 m_checkBoxUseProxy->SetValue(fUseProxy);
1682 m_textCtrlProxyIP->Enable(fUseProxy);
1683 m_textCtrlProxyPort->Enable(fUseProxy);
1684 m_staticTextProxyIP->Enable(fUseProxy);
1685 m_staticTextProxyPort->Enable(fUseProxy);
1686 m_textCtrlProxyIP->SetValue(addrProxy.ToStringIP());
1687 m_textCtrlProxyPort->SetValue(addrProxy.ToStringPort());
1689 m_buttonOK->SetFocus();
1692 void COptionsDialog::SelectPage(int nPage)
1694 m_panelMain->Show(nPage == 0);
1695 m_panelTest2->Show(nPage == 1);
1697 m_scrolledWindow->Layout();
1698 m_scrolledWindow->SetScrollbars(0, 0, 0, 0, 0, 0);
1701 void COptionsDialog::OnListBox(wxCommandEvent& event)
1703 SelectPage(event.GetSelection());
1706 void COptionsDialog::OnKillFocusTransactionFee(wxFocusEvent& event)
1709 int64 nTmp = nTransactionFee;
1710 ParseMoney(m_textCtrlTransactionFee->GetValue(), nTmp);
1711 m_textCtrlTransactionFee->SetValue(FormatMoney(nTmp));
1714 void COptionsDialog::OnCheckBoxUseProxy(wxCommandEvent& event)
1716 m_textCtrlProxyIP->Enable(event.IsChecked());
1717 m_textCtrlProxyPort->Enable(event.IsChecked());
1718 m_staticTextProxyIP->Enable(event.IsChecked());
1719 m_staticTextProxyPort->Enable(event.IsChecked());
1722 CAddress COptionsDialog::GetProxyAddr()
1724 // Be careful about byte order, addr.ip and addr.port are big endian
1725 CAddress addr(m_textCtrlProxyIP->GetValue() + ":" + m_textCtrlProxyPort->GetValue());
1726 if (addr.ip == INADDR_NONE)
1727 addr.ip = addrProxy.ip;
1728 int nPort = atoi(m_textCtrlProxyPort->GetValue());
1729 addr.port = htons(nPort);
1730 if (nPort <= 0 || nPort > USHRT_MAX)
1731 addr.port = addrProxy.port;
1735 void COptionsDialog::OnKillFocusProxy(wxFocusEvent& event)
1738 m_textCtrlProxyIP->SetValue(GetProxyAddr().ToStringIP());
1739 m_textCtrlProxyPort->SetValue(GetProxyAddr().ToStringPort());
1743 void COptionsDialog::OnButtonOK(wxCommandEvent& event)
1745 OnButtonApply(event);
1749 void COptionsDialog::OnButtonCancel(wxCommandEvent& event)
1754 void COptionsDialog::OnButtonApply(wxCommandEvent& event)
1756 CWalletDB walletdb(pwalletMain->strWalletFile);
1758 int64 nPrevTransactionFee = nTransactionFee;
1759 if (ParseMoney(m_textCtrlTransactionFee->GetValue(), nTransactionFee) && nTransactionFee != nPrevTransactionFee)
1760 walletdb.WriteSetting("nTransactionFee", nTransactionFee);
1762 if (fTmpStartOnSystemStartup != m_checkBoxStartOnSystemStartup->GetValue())
1764 fTmpStartOnSystemStartup = m_checkBoxStartOnSystemStartup->GetValue();
1765 SetStartOnSystemStartup(fTmpStartOnSystemStartup);
1768 if (fMinimizeToTray != m_checkBoxMinimizeToTray->GetValue())
1770 fMinimizeToTray = m_checkBoxMinimizeToTray->GetValue();
1771 walletdb.WriteSetting("fMinimizeToTray", fMinimizeToTray);
1772 ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
1775 if (fMinimizeOnClose != m_checkBoxMinimizeOnClose->GetValue())
1777 fMinimizeOnClose = m_checkBoxMinimizeOnClose->GetValue();
1778 walletdb.WriteSetting("fMinimizeOnClose", fMinimizeOnClose);
1781 if (fHaveUPnP && fUseUPnP != m_checkBoxUseUPnP->GetValue())
1783 fUseUPnP = m_checkBoxUseUPnP->GetValue();
1784 walletdb.WriteSetting("fUseUPnP", fUseUPnP);
1788 fUseProxy = m_checkBoxUseProxy->GetValue();
1789 walletdb.WriteSetting("fUseProxy", fUseProxy);
1791 addrProxy = GetProxyAddr();
1792 walletdb.WriteSetting("addrProxy", addrProxy);
1800 //////////////////////////////////////////////////////////////////////////////
1805 CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent)
1807 m_staticTextVersion->SetLabel(strprintf(_("version %s"), FormatFullVersion().c_str()));
1809 // Change (c) into UTF-8 or ANSI copyright symbol
1810 wxString str = m_staticTextMain->GetLabel();
1812 str.Replace("(c)", wxString::FromUTF8("\xC2\xA9"));
1814 str.Replace("(c)", "\xA9");
1816 m_staticTextMain->SetLabel(str);
1818 // Resize on Linux to make the window fit the text.
1819 // The text was wrapped manually rather than using the Wrap setting because
1820 // the wrap would be too small on Linux and it can't be changed at this point.
1821 wxFont fontTmp = m_staticTextMain->GetFont();
1822 if (fontTmp.GetPointSize() > 8);
1823 fontTmp.SetPointSize(8);
1824 m_staticTextMain->SetFont(fontTmp);
1825 SetSize(GetSize().GetWidth() + 44, GetSize().GetHeight() + 10);
1827 SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
1831 void CAboutDialog::OnButtonOK(wxCommandEvent& event)
1841 //////////////////////////////////////////////////////////////////////////////
1846 CSendDialog::CSendDialog(wxWindow* parent, const wxString& strAddress) : CSendDialogBase(parent)
1849 m_textCtrlAddress->SetValue(strAddress);
1850 m_choiceTransferType->SetSelection(0);
1851 m_bitmapCheckMark->Show(false);
1852 fEnabledPrev = true;
1853 m_textCtrlAddress->SetFocus();
1855 //// todo: should add a display of your balance for convenience
1857 wxFont fontTmp = m_staticTextInstructions->GetFont();
1858 if (fontTmp.GetPointSize() > 9);
1859 fontTmp.SetPointSize(9);
1860 m_staticTextInstructions->SetFont(fontTmp);
1863 SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
1867 if (nScaleX == 1.0 && nScaleY == 1.0) // We don't have icons of the proper size otherwise
1870 iconSend.CopyFromBitmap(wxBitmap(send16noshadow_xpm));
1875 SetIcon(wxICON(bitcoin));
1878 // Fixup the tab order
1879 m_buttonPaste->MoveAfterInTabOrder(m_buttonCancel);
1880 m_buttonAddress->MoveAfterInTabOrder(m_buttonPaste);
1884 void CSendDialog::OnKillFocusAmount(wxFocusEvent& event)
1886 // Reformat the amount
1888 if (m_textCtrlAmount->GetValue().Trim().empty())
1891 if (ParseMoney(m_textCtrlAmount->GetValue(), nTmp))
1892 m_textCtrlAmount->SetValue(FormatMoney(nTmp));
1895 void CSendDialog::OnButtonAddressBook(wxCommandEvent& event)
1897 // Open address book
1898 CAddressBookDialog dialog(this, m_textCtrlAddress->GetValue(), CAddressBookDialog::SENDING, true);
1899 if (dialog.ShowModal())
1900 m_textCtrlAddress->SetValue(dialog.GetSelectedAddress());
1903 void CSendDialog::OnButtonPaste(wxCommandEvent& event)
1905 // Copy clipboard to address box
1906 if (wxTheClipboard->Open())
1908 if (wxTheClipboard->IsSupported(wxDF_TEXT))
1910 wxTextDataObject data;
1911 wxTheClipboard->GetData(data);
1912 m_textCtrlAddress->SetValue(data.GetText());
1914 wxTheClipboard->Close();
1918 void CSendDialog::OnButtonSend(wxCommandEvent& event)
1920 static CCriticalSection cs_sendlock;
1921 TRY_CRITICAL_BLOCK(cs_sendlock)
1924 string strAddress = (string)m_textCtrlAddress->GetValue();
1928 if (!ParseMoney(m_textCtrlAmount->GetValue(), nValue) || nValue <= 0)
1930 wxMessageBox(_("Error in amount "), _("Send Coins"));
1933 if (nValue > pwalletMain->GetBalance())
1935 wxMessageBox(_("Amount exceeds your balance "), _("Send Coins"));
1938 if (nValue + nTransactionFee > pwalletMain->GetBalance())
1940 wxMessageBox(string(_("Total exceeds your balance when the ")) + FormatMoney(nTransactionFee) + _(" transaction fee is included "), _("Send Coins"));
1944 // Parse bitcoin address
1946 bool fBitcoinAddress = AddressToHash160(strAddress, hash160);
1948 if (fBitcoinAddress)
1950 CRITICAL_BLOCK(cs_main)
1952 // Send to bitcoin address
1953 CScript scriptPubKey;
1954 scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
1956 string strError = pwalletMain->SendMoney(scriptPubKey, nValue, wtx, true);
1958 wxMessageBox(_("Payment sent "), _("Sending..."));
1959 else if (strError == "ABORTED")
1960 return; // leave send dialog open
1963 wxMessageBox(strError + " ", _("Sending..."));
1972 CAddress addr(strAddress);
1973 if (!addr.IsValid())
1975 wxMessageBox(_("Invalid address "), _("Send Coins"));
1980 wtx.mapValue["to"] = strAddress;
1982 // Send to IP address
1983 CSendingDialog* pdialog = new CSendingDialog(this, addr, nValue, wtx);
1984 if (!pdialog->ShowModal())
1988 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
1989 if (!pwalletMain->mapAddressBook.count(strAddress))
1990 pwalletMain->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());
2027 SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
2030 SetTitle(strprintf(_("Sending %s to %s"), FormatMoney(nPrice).c_str(), wtx.mapValue["to"].c_str()));
2031 m_textCtrlStatus->SetValue("");
2033 CreateThread(SendingDialogStartTransfer, this);
2036 CSendingDialog::~CSendingDialog()
2038 printf("~CSendingDialog()\n");
2041 void CSendingDialog::Close()
2043 // Last one out turn out the lights.
2044 // fWorkDone signals that work side is done and UI thread should call destroy.
2045 // fUIDone signals that UI window has closed and work thread should call destroy.
2046 // This allows the window to disappear and end modality when cancelled
2047 // without making the user wait for ConnectNode to return. The dialog object
2048 // hangs around in the background until the work thread exits.
2059 void CSendingDialog::OnClose(wxCloseEvent& event)
2061 if (!event.CanVeto() || fWorkDone || fAbort || !fCanCancel)
2068 wxCommandEvent cmdevent;
2069 OnButtonCancel(cmdevent);
2073 void CSendingDialog::OnButtonOK(wxCommandEvent& event)
2079 void CSendingDialog::OnButtonCancel(wxCommandEvent& event)
2085 void CSendingDialog::OnPaint(wxPaintEvent& event)
2088 if (strlen(pszStatus) > 130)
2089 m_textCtrlStatus->SetValue(string("\n") + pszStatus);
2091 m_textCtrlStatus->SetValue(string("\n\n") + pszStatus);
2092 m_staticTextSending->SetFocus();
2094 m_buttonCancel->Enable(false);
2097 m_buttonOK->Enable(true);
2098 m_buttonOK->SetFocus();
2099 m_buttonCancel->Enable(false);
2101 if (fAbort && fCanCancel && IsShown())
2103 strcpy(pszStatus, _("CANCELLED"));
2104 m_buttonOK->Enable(true);
2105 m_buttonOK->SetFocus();
2106 m_buttonCancel->Enable(false);
2107 m_buttonCancel->SetLabel(_("Cancelled"));
2109 wxMessageBox(_("Transfer cancelled "), _("Sending..."), wxOK, this);
2115 // Everything from here on is not in the UI thread and must only communicate
2116 // with the rest of the dialog through variables and calling repaint.
2119 void CSendingDialog::Repaint()
2123 GetEventHandler()->AddPendingEvent(event);
2126 bool CSendingDialog::Status()
2133 if (fAbort && fCanCancel)
2135 memset(pszStatus, 0, 10);
2136 strcpy(pszStatus, _("CANCELLED"));
2144 bool CSendingDialog::Status(const string& str)
2149 // This can be read by the UI thread at any time,
2150 // so copy in a way that can be read cleanly at all times.
2151 memset(pszStatus, 0, min(str.size()+1, sizeof(pszStatus)));
2152 strlcpy(pszStatus, str.c_str(), sizeof(pszStatus));
2158 bool CSendingDialog::Error(const string& str)
2162 Status(string(_("Error: ")) + str);
2166 void SendingDialogStartTransfer(void* parg)
2168 ((CSendingDialog*)parg)->StartTransfer();
2171 void CSendingDialog::StartTransfer()
2173 // Make sure we have enough money
2174 if (nPrice + nTransactionFee > pwalletMain->GetBalance())
2176 Error(_("Insufficient funds"));
2180 // We may have connected already for product details
2181 if (!Status(_("Connecting...")))
2183 CNode* pnode = ConnectNode(addr, 15 * 60);
2186 Error(_("Unable to connect"));
2190 // Send order to seller, with response going to OnReply2 via event handler
2191 if (!Status(_("Requesting public key...")))
2193 pnode->PushRequest("checkorder", wtx, SendingDialogOnReply2, this);
2196 void SendingDialogOnReply2(void* parg, CDataStream& vRecv)
2198 ((CSendingDialog*)parg)->OnReply2(vRecv);
2201 void CSendingDialog::OnReply2(CDataStream& vRecv)
2203 if (!Status(_("Received public key...")))
2206 CScript scriptPubKey;
2215 vRecv >> strMessage;
2217 Error(_("Recipient is not accepting transactions sent by IP address"));
2219 Error(_("Transfer was not accepted"));
2220 //// todo: enlarge the window and enable a hidden white box to put seller's message
2223 vRecv >> scriptPubKey;
2227 //// what do we want to do about this?
2228 Error(_("Invalid response received"));
2232 // Pause to give the user a chance to cancel
2233 while (wxDateTime::UNow() < start + wxTimeSpan(0, 0, 0, 2 * 1000))
2240 CRITICAL_BLOCK(cs_main)
2243 if (!Status(_("Creating transaction...")))
2245 if (nPrice + nTransactionFee > pwalletMain->GetBalance())
2247 Error(_("Insufficient funds"));
2250 CReserveKey reservekey(pwalletMain);
2252 if (!pwalletMain->CreateTransaction(scriptPubKey, nPrice, wtx, reservekey, nFeeRequired))
2254 if (nPrice + nFeeRequired > pwalletMain->GetBalance())
2255 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()));
2257 Error(_("Transaction creation failed"));
2262 if (!ThreadSafeAskFee(nFeeRequired, _("Sending..."), this))
2264 Error(_("Transaction aborted"));
2268 // Make sure we're still connected
2269 CNode* pnode = ConnectNode(addr, 2 * 60 * 60);
2272 Error(_("Lost connection, transaction cancelled"));
2276 // Last chance to cancel
2288 if (!Status(_("Sending payment...")))
2292 if (!pwalletMain->CommitTransaction(wtx, reservekey))
2294 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."));
2298 // Send payment tx to seller, with response going to OnReply3 via event handler
2299 CWalletTx wtxSend = wtx;
2300 wtxSend.fFromMe = false;
2301 pnode->PushRequest("submitorder", wtxSend, SendingDialogOnReply3, this);
2303 Status(_("Waiting for confirmation..."));
2308 void SendingDialogOnReply3(void* parg, CDataStream& vRecv)
2310 ((CSendingDialog*)parg)->OnReply3(vRecv);
2313 void CSendingDialog::OnReply3(CDataStream& vRecv)
2321 Error(_("The payment was sent, but the recipient was unable to verify it.\n"
2322 "The transaction is recorded and will credit to the recipient,\n"
2323 "but the comment information will be blank."));
2329 //// what do we want to do about this?
2330 Error(_("Payment was sent, but an invalid response was received"));
2336 Status(_("Payment completed"));
2344 //////////////////////////////////////////////////////////////////////////////
2346 // CAddressBookDialog
2349 CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInitSelected, int nPageIn, bool fDuringSendIn) : CAddressBookDialogBase(parent)
2352 SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
2355 // Set initially selected page
2356 wxNotebookEvent event;
2357 event.SetSelection(nPageIn);
2358 OnNotebookPageChanged(event);
2359 m_notebook->ChangeSelection(nPageIn);
2361 fDuringSend = fDuringSendIn;
2363 m_buttonCancel->Show(false);
2366 if (nScaleX == 1.0 && nScaleY == 1.0) // We don't have icons of the proper size otherwise
2368 wxIcon iconAddressBook;
2369 iconAddressBook.CopyFromBitmap(wxBitmap(addressbook16_xpm));
2370 SetIcon(iconAddressBook);
2374 SetIcon(wxICON(bitcoin));
2377 // Init column headers
2378 m_listCtrlSending->InsertColumn(0, _("Name"), wxLIST_FORMAT_LEFT, 200);
2379 m_listCtrlSending->InsertColumn(1, _("Address"), wxLIST_FORMAT_LEFT, 350);
2380 m_listCtrlSending->SetFocus();
2381 m_listCtrlReceiving->InsertColumn(0, _("Label"), wxLIST_FORMAT_LEFT, 200);
2382 m_listCtrlReceiving->InsertColumn(1, _("Bitcoin Address"), wxLIST_FORMAT_LEFT, 350);
2383 m_listCtrlReceiving->SetFocus();
2385 // Fill listctrl with address book data
2386 CRITICAL_BLOCK(pwalletMain->cs_mapKeys)
2387 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
2389 string strDefaultReceiving = (string)pframeMain->m_textCtrlAddress->GetValue();
2390 BOOST_FOREACH(const PAIRTYPE(string, string)& item, pwalletMain->mapAddressBook)
2392 string strAddress = item.first;
2393 string strName = item.second;
2395 bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
2396 wxListCtrl* plistCtrl = fMine ? m_listCtrlReceiving : m_listCtrlSending;
2397 int nIndex = InsertLine(plistCtrl, strName, strAddress);
2398 if (strAddress == (fMine ? strDefaultReceiving : string(strInitSelected)))
2399 plistCtrl->SetItemState(nIndex, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
2404 wxString CAddressBookDialog::GetSelectedAddress()
2406 int nIndex = GetSelection(m_listCtrl);
2409 return GetItemText(m_listCtrl, nIndex, 1);
2412 wxString CAddressBookDialog::GetSelectedSendingAddress()
2414 int nIndex = GetSelection(m_listCtrlSending);
2417 return GetItemText(m_listCtrlSending, nIndex, 1);
2420 wxString CAddressBookDialog::GetSelectedReceivingAddress()
2422 int nIndex = GetSelection(m_listCtrlReceiving);
2425 return GetItemText(m_listCtrlReceiving, nIndex, 1);
2428 void CAddressBookDialog::OnNotebookPageChanged(wxNotebookEvent& event)
2431 nPage = event.GetSelection();
2432 if (nPage == SENDING)
2433 m_listCtrl = m_listCtrlSending;
2434 else if (nPage == RECEIVING)
2435 m_listCtrl = m_listCtrlReceiving;
2436 m_buttonDelete->Show(nPage == SENDING);
2437 m_buttonCopy->Show(nPage == RECEIVING);
2439 m_listCtrl->SetFocus();
2442 void CAddressBookDialog::OnListEndLabelEdit(wxListEvent& event)
2444 // Update address book with edited name
2446 if (event.IsEditCancelled())
2448 string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1);
2449 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
2450 pwalletMain->SetAddressBookName(strAddress, string(event.GetText()));
2451 pframeMain->RefreshListCtrl();
2454 void CAddressBookDialog::OnListItemSelected(wxListEvent& event)
2457 if (nPage == RECEIVING)
2458 SetDefaultReceivingAddress((string)GetSelectedReceivingAddress());
2461 void CAddressBookDialog::OnListItemActivated(wxListEvent& event)
2466 // Doubleclick returns selection
2467 EndModal(GetSelectedAddress() != "" ? 2 : 0);
2471 // Doubleclick edits item
2472 wxCommandEvent event2;
2473 OnButtonEdit(event2);
2476 void CAddressBookDialog::OnButtonDelete(wxCommandEvent& event)
2478 if (nPage != SENDING)
2480 for (int nIndex = m_listCtrl->GetItemCount()-1; nIndex >= 0; nIndex--)
2482 if (m_listCtrl->GetItemState(nIndex, wxLIST_STATE_SELECTED))
2484 string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
2485 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
2486 pwalletMain->DelAddressBookName(strAddress);
2487 m_listCtrl->DeleteItem(nIndex);
2490 pframeMain->RefreshListCtrl();
2493 void CAddressBookDialog::OnButtonCopy(wxCommandEvent& event)
2495 // Copy address box to clipboard
2496 if (wxTheClipboard->Open())
2498 wxTheClipboard->SetData(new wxTextDataObject(GetSelectedAddress()));
2499 wxTheClipboard->Close();
2503 bool CAddressBookDialog::CheckIfMine(const string& strAddress, const string& strTitle)
2506 bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
2508 wxMessageBox(_("This is one of your own addresses for receiving payments and cannot be entered in the address book. "), strTitle);
2512 void CAddressBookDialog::OnButtonEdit(wxCommandEvent& event)
2514 int nIndex = GetSelection(m_listCtrl);
2517 string strName = (string)m_listCtrl->GetItemText(nIndex);
2518 string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
2519 string strAddressOrg = strAddress;
2521 if (nPage == SENDING)
2523 // Ask name and address
2526 CGetTextFromUserDialog dialog(this, _("Edit Address"), _("Name"), strName, _("Address"), strAddress);
2527 if (!dialog.ShowModal())
2529 strName = dialog.GetValue1();
2530 strAddress = dialog.GetValue2();
2532 while (CheckIfMine(strAddress, _("Edit Address")));
2535 else if (nPage == RECEIVING)
2538 CGetTextFromUserDialog dialog(this, _("Edit Address Label"), _("Label"), strName);
2539 if (!dialog.ShowModal())
2541 strName = dialog.GetValue();
2545 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
2547 if (strAddress != strAddressOrg)
2548 pwalletMain->DelAddressBookName(strAddressOrg);
2549 pwalletMain->SetAddressBookName(strAddress, strName);
2551 m_listCtrl->SetItem(nIndex, 1, strAddress);
2552 m_listCtrl->SetItemText(nIndex, strName);
2553 pframeMain->RefreshListCtrl();
2556 void CAddressBookDialog::OnButtonNew(wxCommandEvent& event)
2561 if (nPage == SENDING)
2563 // Ask name and address
2566 CGetTextFromUserDialog dialog(this, _("Add Address"), _("Name"), strName, _("Address"), strAddress);
2567 if (!dialog.ShowModal())
2569 strName = dialog.GetValue1();
2570 strAddress = dialog.GetValue2();
2572 while (CheckIfMine(strAddress, _("Add Address")));
2574 else if (nPage == RECEIVING)
2577 CGetTextFromUserDialog dialog(this,
2578 _("New Receiving Address"),
2579 _("You should use a new address for each payment you receive.\n\nLabel"),
2581 if (!dialog.ShowModal())
2583 strName = dialog.GetValue();
2586 strAddress = PubKeyToAddress(pwalletMain->GetKeyFromKeyPool());
2589 // Add to list and select it
2590 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
2591 pwalletMain->SetAddressBookName(strAddress, strName);
2592 int nIndex = InsertLine(m_listCtrl, strName, strAddress);
2593 SetSelection(m_listCtrl, nIndex);
2594 m_listCtrl->SetFocus();
2595 if (nPage == SENDING)
2596 pframeMain->RefreshListCtrl();
2599 void CAddressBookDialog::OnButtonOK(wxCommandEvent& event)
2602 EndModal(GetSelectedAddress() != "" ? 1 : 0);
2605 void CAddressBookDialog::OnButtonCancel(wxCommandEvent& event)
2611 void CAddressBookDialog::OnClose(wxCloseEvent& event)
2622 //////////////////////////////////////////////////////////////////////////////
2629 ID_TASKBAR_RESTORE = 10001,
2632 ID_TASKBAR_GENERATE,
2636 BEGIN_EVENT_TABLE(CMyTaskBarIcon, wxTaskBarIcon)
2637 EVT_TASKBAR_LEFT_DCLICK(CMyTaskBarIcon::OnLeftButtonDClick)
2638 EVT_MENU(ID_TASKBAR_RESTORE, CMyTaskBarIcon::OnMenuRestore)
2639 EVT_MENU(ID_TASKBAR_SEND, CMyTaskBarIcon::OnMenuSend)
2640 EVT_MENU(ID_TASKBAR_OPTIONS, CMyTaskBarIcon::OnMenuOptions)
2641 EVT_UPDATE_UI(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnUpdateUIGenerate)
2642 EVT_MENU(ID_TASKBAR_EXIT, CMyTaskBarIcon::OnMenuExit)
2645 void CMyTaskBarIcon::Show(bool fShow)
2647 static char pszPrevTip[200];
2650 string strTooltip = _("Bitcoin");
2651 if (fGenerateBitcoins)
2652 strTooltip = _("Bitcoin - Generating");
2653 if (fGenerateBitcoins && vNodes.empty())
2654 strTooltip = _("Bitcoin - (not connected)");
2656 // Optimization, only update when changed, using char array to be reentrant
2657 if (strncmp(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip)-1) != 0)
2659 strlcpy(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip));
2661 // somehow it'll choose the wrong size and scale it down if
2662 // we use the main icon, so we hand it one with only 16x16
2663 SetIcon(wxICON(favicon), strTooltip);
2665 SetIcon(bitcoin80_xpm, strTooltip);
2671 strlcpy(pszPrevTip, "", sizeof(pszPrevTip));
2676 void CMyTaskBarIcon::Hide()
2681 void CMyTaskBarIcon::OnLeftButtonDClick(wxTaskBarIconEvent& event)
2686 void CMyTaskBarIcon::OnMenuRestore(wxCommandEvent& event)
2691 void CMyTaskBarIcon::OnMenuSend(wxCommandEvent& event)
2694 CSendDialog dialog(pframeMain);
2698 void CMyTaskBarIcon::OnMenuOptions(wxCommandEvent& event)
2700 // Since it's modal, get the main window to do it
2701 wxCommandEvent event2(wxEVT_COMMAND_MENU_SELECTED, wxID_PREFERENCES);
2702 pframeMain->GetEventHandler()->AddPendingEvent(event2);
2705 void CMyTaskBarIcon::Restore()
2708 wxIconizeEvent event(0, false);
2709 pframeMain->GetEventHandler()->AddPendingEvent(event);
2710 pframeMain->Iconize(false);
2711 pframeMain->Raise();
2714 void CMyTaskBarIcon::OnUpdateUIGenerate(wxUpdateUIEvent& event)
2716 event.Check(fGenerateBitcoins);
2719 void CMyTaskBarIcon::OnMenuExit(wxCommandEvent& event)
2721 pframeMain->Close(true);
2724 void CMyTaskBarIcon::UpdateTooltip()
2726 if (IsIconInstalled())
2730 wxMenu* CMyTaskBarIcon::CreatePopupMenu()
2732 wxMenu* pmenu = new wxMenu;
2733 pmenu->Append(ID_TASKBAR_RESTORE, _("&Open Bitcoin"));
2734 pmenu->Append(ID_TASKBAR_SEND, _("&Send Bitcoins"));
2735 pmenu->Append(ID_TASKBAR_OPTIONS, _("O&ptions..."));
2736 #ifndef __WXMAC_OSX__ // Mac has built-in quit menu
2737 pmenu->AppendSeparator();
2738 pmenu->Append(ID_TASKBAR_EXIT, _("E&xit"));
2748 //////////////////////////////////////////////////////////////////////////////
2753 void CreateMainWindow()
2755 pframeMain = new CMainFrame(NULL);
2756 if (GetBoolArg("-min"))
2757 pframeMain->Iconize(true);
2758 #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
2759 if (!GetBoolArg("-minimizetotray"))
2760 fMinimizeToTray = false;
2762 pframeMain->Show(true); // have to show first to get taskbar button to hide
2763 if (fMinimizeToTray && pframeMain->IsIconized())
2764 fClosedToTray = true;
2765 pframeMain->Show(!fClosedToTray);
2766 ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
2767 CreateThread(ThreadDelayedRepaint, NULL);
2771 // Define a new application
2772 class CMyApp : public wxApp
2781 // Hook Initialize so we can start without GUI
2782 virtual bool Initialize(int& argc, wxChar** argv);
2784 // 2nd-level exception handling: we get all the exceptions occurring in any
2785 // event handler here
2786 virtual bool OnExceptionInMainLoop();
2788 // 3rd, and final, level exception handling: whenever an unhandled
2789 // exception is caught, this function is called
2790 virtual void OnUnhandledException();
2792 // and now for something different: this function is called in case of a
2793 // crash (e.g. dereferencing null pointer, division by 0, ...)
2794 virtual void OnFatalException();
2797 IMPLEMENT_APP(CMyApp)
2799 bool CMyApp::Initialize(int& argc, wxChar** argv)
2801 for (int i = 1; i < argc; i++)
2802 if (!IsSwitchChar(argv[i][0]))
2803 fCommandLine = true;
2807 // wxApp::Initialize will remove environment-specific parameters,
2808 // so it's too early to call ParseParameters yet
2809 for (int i = 1; i < argc; i++)
2811 wxString str = argv[i];
2813 if (str.size() >= 1 && str[0] == '/')
2815 char pszLower[MAX_PATH];
2816 strlcpy(pszLower, str.c_str(), sizeof(pszLower));
2820 if (str == "-daemon")
2826 if (fDaemon || fCommandLine)
2828 // Call the original Initialize while suppressing error messages
2829 // and ignoring failure. If unable to initialize GTK, it fails
2830 // near the end so hopefully the last few things don't matter.
2833 wxApp::Initialize(argc, argv);
2842 fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
2846 pthread_exit((void*)0);
2848 pid_t sid = setsid();
2850 fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno);
2857 return wxApp::Initialize(argc, argv);
2860 bool CMyApp::OnInit()
2862 #if defined(__WXMSW__) && defined(__WXDEBUG__) && defined(GUI)
2863 // Disable malfunctioning wxWidgets debug assertion
2864 extern int g_isPainting;
2865 g_isPainting = 10000;
2867 #if defined(__WXMSW__ ) || defined(__WXMAC_OSX__)
2868 SetAppName("PPCoin");
2870 SetAppName("ppcoin");
2874 // Hack to set wxConvLibc codepage to UTF-8 on Windows,
2875 // may break if wxMBConv_win32 implementation in strconv.cpp changes.
2876 class wxMBConv_win32 : public wxMBConv
2880 size_t m_minMBCharWidth;
2882 if (((wxMBConv_win32*)&wxConvLibc)->m_CodePage == CP_ACP)
2883 ((wxMBConv_win32*)&wxConvLibc)->m_CodePage = CP_UTF8;
2887 // Load locale/<lang>/LC_MESSAGES/bitcoin.mo language file
2888 g_locale.Init(wxLANGUAGE_DEFAULT, 0);
2889 g_locale.AddCatalogLookupPathPrefix("locale");
2891 g_locale.AddCatalogLookupPathPrefix("/usr/share/locale");
2892 g_locale.AddCatalogLookupPathPrefix("/usr/local/share/locale");
2894 g_locale.AddCatalog("wxstd"); // wxWidgets standard translations, if any
2895 g_locale.AddCatalog("bitcoin");
2898 HDC hdc = GetDC(NULL);
2901 nScaleX = GetDeviceCaps(hdc, LOGPIXELSX) / 96.0;
2902 nScaleY = GetDeviceCaps(hdc, LOGPIXELSY) / 96.0;
2903 ReleaseDC(NULL, hdc);
2907 return AppInit(argc, argv);
2910 int CMyApp::OnExit()
2913 return wxApp::OnExit();
2916 bool CMyApp::OnExceptionInMainLoop()
2922 catch (std::exception& e)
2924 PrintException(&e, "CMyApp::OnExceptionInMainLoop()");
2925 wxLogWarning("Exception %s %s", typeid(e).name(), e.what());
2931 PrintException(NULL, "CMyApp::OnExceptionInMainLoop()");
2932 wxLogWarning("Unknown exception");
2939 void CMyApp::OnUnhandledException()
2941 // this shows how we may let some exception propagate uncaught
2946 catch (std::exception& e)
2948 PrintException(&e, "CMyApp::OnUnhandledException()");
2949 wxLogWarning("Exception %s %s", typeid(e).name(), e.what());
2955 PrintException(NULL, "CMyApp::OnUnhandledException()");
2956 wxLogWarning("Unknown exception");
2962 void CMyApp::OnFatalException()
2964 wxMessageBox(_("Program has crashed and will terminate. "), "Bitcoin", wxOK | wxICON_ERROR);