1 // Copyright (c) 2009-2010 Satoshi Nakamoto
\r
2 // Distributed under the MIT/X11 software license, see the accompanying
\r
3 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
\r
12 DEFINE_EVENT_TYPE(wxEVT_UITHREADCALL)
\r
14 CMainFrame* pframeMain = NULL;
\r
15 CMyTaskBarIcon* ptaskbaricon = NULL;
\r
16 bool fClosedToTray = false;
\r
26 //////////////////////////////////////////////////////////////////////////////
\r
31 void HandleCtrlA(wxKeyEvent& event)
\r
33 // Ctrl-a select all
\r
35 wxTextCtrl* textCtrl = (wxTextCtrl*)event.GetEventObject();
\r
36 if (event.GetModifiers() == wxMOD_CONTROL && event.GetKeyCode() == 'A')
\r
37 textCtrl->SetSelection(-1, -1);
\r
42 //char pszHourFormat[256];
\r
43 //pszHourFormat[0] = '\0';
\r
44 //GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ITIME, pszHourFormat, 256);
\r
45 //return (pszHourFormat[0] != '0');
\r
49 string DateStr(int64 nTime)
\r
51 // Can only be used safely here in the UI
\r
52 return (string)wxDateTime((time_t)nTime).FormatDate();
\r
55 string DateTimeStr(int64 nTime)
\r
57 // Can only be used safely here in the UI
\r
58 wxDateTime datetime((time_t)nTime);
\r
60 return (string)datetime.Format("%x %H:%M");
\r
62 return (string)datetime.Format("%x ") + itostr((datetime.GetHour() + 11) % 12 + 1) + (string)datetime.Format(":%M %p");
\r
65 wxString GetItemText(wxListCtrl* listCtrl, int nIndex, int nColumn)
\r
67 // Helper to simplify access to listctrl
\r
69 item.m_itemId = nIndex;
\r
70 item.m_col = nColumn;
\r
71 item.m_mask = wxLIST_MASK_TEXT;
\r
72 if (!listCtrl->GetItem(item))
\r
74 return item.GetText();
\r
77 int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1)
\r
79 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
\r
80 listCtrl->SetItem(nIndex, 1, str1);
\r
84 int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
\r
86 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
\r
87 listCtrl->SetItem(nIndex, 1, str1);
\r
88 listCtrl->SetItem(nIndex, 2, str2);
\r
89 listCtrl->SetItem(nIndex, 3, str3);
\r
90 listCtrl->SetItem(nIndex, 4, str4);
\r
94 int InsertLine(wxListCtrl* listCtrl, void* pdata, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
\r
96 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
\r
97 listCtrl->SetItemPtrData(nIndex, (wxUIntPtr)pdata);
\r
98 listCtrl->SetItem(nIndex, 1, str1);
\r
99 listCtrl->SetItem(nIndex, 2, str2);
\r
100 listCtrl->SetItem(nIndex, 3, str3);
\r
101 listCtrl->SetItem(nIndex, 4, str4);
\r
105 void SetSelection(wxListCtrl* listCtrl, int nIndex)
\r
107 int nSize = listCtrl->GetItemCount();
\r
108 long nState = (wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
\r
109 for (int i = 0; i < nSize; i++)
\r
110 listCtrl->SetItemState(i, (i == nIndex ? nState : 0), nState);
\r
113 int GetSelection(wxListCtrl* listCtrl)
\r
115 int nSize = listCtrl->GetItemCount();
\r
116 for (int i = 0; i < nSize; i++)
\r
117 if (listCtrl->GetItemState(i, wxLIST_STATE_FOCUSED))
\r
122 string HtmlEscape(const char* psz, bool fMultiLine=false)
\r
125 for (const char* p = psz; *p; p++)
\r
127 if (*p == '<') len += 4;
\r
128 else if (*p == '>') len += 4;
\r
129 else if (*p == '&') len += 5;
\r
130 else if (*p == '"') len += 6;
\r
131 else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') len += 6;
\r
132 else if (*p == '\n' && fMultiLine) len += 5;
\r
138 for (const char* p = psz; *p; p++)
\r
140 if (*p == '<') str += "<";
\r
141 else if (*p == '>') str += ">";
\r
142 else if (*p == '&') str += "&";
\r
143 else if (*p == '"') str += """;
\r
144 else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') str += " ";
\r
145 else if (*p == '\n' && fMultiLine) str += "<br>\n";
\r
152 string HtmlEscape(const string& str, bool fMultiLine=false)
\r
154 return HtmlEscape(str.c_str(), fMultiLine);
\r
157 void CalledMessageBox(const string& message, const string& caption, int style, wxWindow* parent, int x, int y, int* pnRet, bool* pfDone)
\r
159 *pnRet = wxMessageBox(message, caption, style, parent, x, y);
\r
163 int ThreadSafeMessageBox(const string& message, const string& caption, int style, wxWindow* parent, int x, int y)
\r
166 return wxMessageBox(message, caption, style, parent, x, y);
\r
168 if (wxThread::IsMain() || fDaemon)
\r
170 return wxMessageBox(message, caption, style, parent, x, y);
\r
175 bool fDone = false;
\r
176 UIThreadCall(bind(CalledMessageBox, message, caption, style, parent, x, y, &nRet, &fDone));
\r
184 bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* parent)
\r
186 if (nFeeRequired == 0 || fDaemon)
\r
188 string strMessage = strprintf(
\r
189 _("This transaction is over the size limit. You can still send it for a fee of %s, "
\r
190 "which goes to the nodes that process your transaction and helps to support the network. "
\r
191 "Do you want to pay the fee?"),
\r
192 FormatMoney(nFeeRequired).c_str());
\r
193 return (ThreadSafeMessageBox(strMessage, strCaption, wxYES_NO, parent) == wxYES);
\r
196 void SetDefaultReceivingAddress(const string& strAddress)
\r
198 // Update main window address and database
\r
199 if (pframeMain == NULL)
\r
201 if (strAddress != pframeMain->m_textCtrlAddress->GetValue())
\r
204 if (!AddressToHash160(strAddress, hash160))
\r
206 if (!mapPubKeys.count(hash160))
\r
208 CWalletDB().WriteDefaultKey(mapPubKeys[hash160]);
\r
209 pframeMain->m_textCtrlAddress->SetValue(strAddress);
\r
222 //////////////////////////////////////////////////////////////////////////////
\r
227 CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent)
\r
229 Connect(wxEVT_UITHREADCALL, wxCommandEventHandler(CMainFrame::OnUIThreadCall), NULL, this);
\r
231 // Set initially selected page
\r
232 wxNotebookEvent event;
\r
233 event.SetSelection(0);
\r
234 OnNotebookPageChanged(event);
\r
235 m_notebook->ChangeSelection(0);
\r
238 fRefreshListCtrl = false;
\r
239 fRefreshListCtrlRunning = false;
\r
240 fOnSetFocusAddress = false;
\r
242 m_choiceFilter->SetSelection(0);
\r
243 double dResize = 1.0;
\r
245 SetIcon(wxICON(bitcoin));
\r
247 SetIcon(bitcoin16_xpm);
\r
248 wxFont fontTmp = m_staticText41->GetFont();
\r
249 fontTmp.SetFamily(wxFONTFAMILY_TELETYPE);
\r
250 m_staticTextBalance->SetFont(fontTmp);
\r
251 m_staticTextBalance->SetSize(140, 17);
\r
252 // resize to fit ubuntu's huge default font
\r
254 SetSize(dResize * GetSize().GetWidth(), 1.15 * GetSize().GetHeight());
\r
256 m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " ");
\r
257 m_listCtrl->SetFocus();
\r
258 ptaskbaricon = new CMyTaskBarIcon();
\r
260 // Mac automatically moves wxID_EXIT, wxID_PREFERENCES and wxID_ABOUT
\r
261 // to their standard places, leaving these menus empty.
\r
262 GetMenuBar()->Remove(2); // remove Help menu
\r
263 GetMenuBar()->Remove(0); // remove File menu
\r
266 // Init column headers
\r
267 int nDateWidth = DateTimeStr(1229413914).size() * 6 + 8;
\r
268 if (!strstr(DateTimeStr(1229413914).c_str(), "2008"))
\r
273 wxListCtrl* pplistCtrl[] = {m_listCtrlAll, m_listCtrlSentReceived, m_listCtrlSent, m_listCtrlReceived};
\r
274 foreach(wxListCtrl* p, pplistCtrl)
\r
276 p->InsertColumn(0, "", wxLIST_FORMAT_LEFT, dResize * 0);
\r
277 p->InsertColumn(1, "", wxLIST_FORMAT_LEFT, dResize * 0);
\r
278 p->InsertColumn(2, _("Status"), wxLIST_FORMAT_LEFT, dResize * 112);
\r
279 p->InsertColumn(3, _("Date"), wxLIST_FORMAT_LEFT, dResize * nDateWidth);
\r
280 p->InsertColumn(4, _("Description"), wxLIST_FORMAT_LEFT, dResize * 409 - nDateWidth);
\r
281 p->InsertColumn(5, _("Debit"), wxLIST_FORMAT_RIGHT, dResize * 79);
\r
282 p->InsertColumn(6, _("Credit"), wxLIST_FORMAT_RIGHT, dResize * 79);
\r
286 int pnWidths[3] = { -100, 88, 300 };
\r
288 pnWidths[1] = pnWidths[1] * 1.1 * dResize;
\r
289 pnWidths[2] = pnWidths[2] * 1.1 * dResize;
\r
291 m_statusBar->SetFieldsCount(3, pnWidths);
\r
293 // Fill your address text box
\r
294 vector<unsigned char> vchPubKey;
\r
295 if (CWalletDB("r").ReadDefaultKey(vchPubKey))
\r
296 m_textCtrlAddress->SetValue(PubKeyToAddress(vchPubKey));
\r
298 // Fill listctrl with wallet transactions
\r
302 CMainFrame::~CMainFrame()
\r
305 delete ptaskbaricon;
\r
306 ptaskbaricon = NULL;
\r
309 void CMainFrame::OnNotebookPageChanged(wxNotebookEvent& event)
\r
312 nPage = event.GetSelection();
\r
315 m_listCtrl = m_listCtrlAll;
\r
316 fShowGenerated = true;
\r
318 fShowReceived = true;
\r
320 else if (nPage == SENTRECEIVED)
\r
322 m_listCtrl = m_listCtrlSentReceived;
\r
323 fShowGenerated = false;
\r
325 fShowReceived = true;
\r
327 else if (nPage == SENT)
\r
329 m_listCtrl = m_listCtrlSent;
\r
330 fShowGenerated = false;
\r
332 fShowReceived = false;
\r
334 else if (nPage == RECEIVED)
\r
336 m_listCtrl = m_listCtrlReceived;
\r
337 fShowGenerated = false;
\r
339 fShowReceived = true;
\r
342 m_listCtrl->SetFocus();
\r
345 void CMainFrame::OnClose(wxCloseEvent& event)
\r
347 if (fMinimizeOnClose && event.CanVeto() && !IsIconized())
\r
349 // Divert close to minimize
\r
351 fClosedToTray = true;
\r
357 CreateThread(Shutdown, NULL);
\r
361 void CMainFrame::OnIconize(wxIconizeEvent& event)
\r
364 // Hide the task bar button when minimized.
\r
365 // Event is sent when the frame is minimized or restored.
\r
366 // wxWidgets 2.8.9 doesn't have IsIconized() so there's no way
\r
367 // to get rid of the deprecated warning. Just ignore it.
\r
368 if (!event.Iconized())
\r
369 fClosedToTray = false;
\r
371 // Tray is not reliable on ubuntu 9.10 gnome
\r
372 fClosedToTray = false;
\r
374 if (fMinimizeToTray && event.Iconized())
\r
375 fClosedToTray = true;
\r
376 Show(!fClosedToTray);
\r
377 ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
\r
380 void CMainFrame::OnMouseEvents(wxMouseEvent& event)
\r
384 RAND_add(&event.m_x, sizeof(event.m_x), 0.25);
\r
385 RAND_add(&event.m_y, sizeof(event.m_y), 0.25);
\r
388 void CMainFrame::OnListColBeginDrag(wxListEvent& event)
\r
390 // Hidden columns not resizeable
\r
391 if (event.GetColumn() <= 1 && !fDebug)
\r
397 int CMainFrame::GetSortIndex(const string& strSort)
\r
402 // The wx generic listctrl implementation used on GTK doesn't sort,
\r
403 // so we have to do it ourselves. Remember, we sort in reverse order.
\r
404 // In the wx generic implementation, they store the list of items
\r
405 // in a vector, so indexed lookups are fast, but inserts are slower
\r
406 // the closer they are to the top.
\r
408 int high = m_listCtrl->GetItemCount();
\r
411 int mid = low + ((high - low) / 2);
\r
412 if (strSort.compare(m_listCtrl->GetItemText(mid).c_str()) >= 0)
\r
421 void CMainFrame::InsertLine(bool fNew, int nIndex, uint256 hashKey, string strSort, const wxString& str2, const wxString& str3, const wxString& str4, const wxString& str5, const wxString& str6)
\r
423 strSort = " " + strSort; // leading space to workaround wx2.9.0 ubuntu 9.10 bug
\r
424 long nData = *(long*)&hashKey; // where first char of hidden column is displayed
\r
427 if (!fNew && nIndex == -1)
\r
429 string strHash = " " + hashKey.ToString();
\r
430 while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)
\r
431 if (GetItemText(m_listCtrl, nIndex, 1) == strHash)
\r
435 // fNew is for blind insert, only use if you're sure it's new
\r
436 if (fNew || nIndex == -1)
\r
438 nIndex = m_listCtrl->InsertItem(GetSortIndex(strSort), strSort);
\r
442 // If sort key changed, must delete and reinsert to make it relocate
\r
443 if (GetItemText(m_listCtrl, nIndex, 0) != strSort)
\r
445 m_listCtrl->DeleteItem(nIndex);
\r
446 nIndex = m_listCtrl->InsertItem(GetSortIndex(strSort), strSort);
\r
450 m_listCtrl->SetItem(nIndex, 1, " " + hashKey.ToString());
\r
451 m_listCtrl->SetItem(nIndex, 2, str2);
\r
452 m_listCtrl->SetItem(nIndex, 3, str3);
\r
453 m_listCtrl->SetItem(nIndex, 4, str4);
\r
454 m_listCtrl->SetItem(nIndex, 5, str5);
\r
455 m_listCtrl->SetItem(nIndex, 6, str6);
\r
456 m_listCtrl->SetItemData(nIndex, nData);
\r
459 bool CMainFrame::DeleteLine(uint256 hashKey)
\r
461 long nData = *(long*)&hashKey;
\r
465 string strHash = " " + hashKey.ToString();
\r
466 while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)
\r
467 if (GetItemText(m_listCtrl, nIndex, 1) == strHash)
\r
471 m_listCtrl->DeleteItem(nIndex);
\r
473 return nIndex != -1;
\r
476 string FormatTxStatus(const CWalletTx& wtx)
\r
479 if (!wtx.IsFinal())
\r
481 if (wtx.nLockTime < 500000000)
\r
482 return strprintf(_("Open for %d blocks"), nBestHeight - wtx.nLockTime);
\r
484 return strprintf(_("Open until %s"), DateTimeStr(wtx.nLockTime).c_str());
\r
488 int nDepth = wtx.GetDepthInMainChain();
\r
489 if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
\r
490 return strprintf(_("%d/offline?"), nDepth);
\r
491 else if (nDepth < 6)
\r
492 return strprintf(_("%d/unconfirmed"), nDepth);
\r
494 return strprintf(_("%d confirmations"), nDepth);
\r
498 string SingleLine(const string& strIn)
\r
501 bool fOneSpace = false;
\r
502 foreach(int c, strIn)
\r
510 if (fOneSpace && !strOut.empty())
\r
519 bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
\r
521 int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime();
\r
522 int64 nCredit = wtx.GetCredit(true);
\r
523 int64 nDebit = wtx.GetDebit();
\r
524 int64 nNet = nCredit - nDebit;
\r
525 uint256 hash = wtx.GetHash();
\r
526 string strStatus = FormatTxStatus(wtx);
\r
527 map<string, string> mapValue = wtx.mapValue;
\r
528 wtx.nLinesDisplayed = 1;
\r
529 nListViewUpdated++;
\r
532 if (wtx.IsCoinBase())
\r
534 // Don't show generated coin until confirmed by at least one block after it
\r
535 // so we don't get the user's hopes up until it looks like it's probably accepted.
\r
537 // It is not an error when generated blocks are not accepted. By design,
\r
538 // some percentage of blocks, like 10% or more, will end up not accepted.
\r
539 // This is the normal mechanism by which the network copes with latency.
\r
541 // We display regular transactions right away before any confirmation
\r
542 // because they can always get into some block eventually. Generated coins
\r
543 // are special because if their block is not accepted, they are not valid.
\r
545 if (wtx.GetDepthInMainChain() < 2)
\r
547 wtx.nLinesDisplayed = 0;
\r
551 if (!fShowGenerated)
\r
555 // Find the block the tx is in
\r
556 CBlockIndex* pindex = NULL;
\r
557 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(wtx.hashBlock);
\r
558 if (mi != mapBlockIndex.end())
\r
559 pindex = (*mi).second;
\r
561 // Sort order, unrecorded transactions sort to the top
\r
562 string strSort = strprintf("%010d-%01d-%010u",
\r
563 (pindex ? pindex->nHeight : INT_MAX),
\r
564 (wtx.IsCoinBase() ? 1 : 0),
\r
565 wtx.nTimeReceived);
\r
568 if (nNet > 0 || wtx.IsCoinBase())
\r
573 string strDescription;
\r
574 if (wtx.IsCoinBase())
\r
577 strDescription = _("Generated");
\r
580 int64 nUnmatured = 0;
\r
581 foreach(const CTxOut& txout, wtx.vout)
\r
582 nUnmatured += txout.GetCredit();
\r
583 if (wtx.IsInMainChain())
\r
585 strDescription = strprintf(_("Generated (%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
\r
587 // Check if the block was requested by anyone
\r
588 if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
\r
589 strDescription = _("Generated - Warning: This block was not received by any other nodes and will probably not be accepted!");
\r
593 strDescription = _("Generated (not accepted)");
\r
597 else if (!mapValue["from"].empty() || !mapValue["message"].empty())
\r
599 // Received by IP connection
\r
600 if (!fShowReceived)
\r
602 if (!mapValue["from"].empty())
\r
603 strDescription += _("From: ") + mapValue["from"];
\r
604 if (!mapValue["message"].empty())
\r
606 if (!strDescription.empty())
\r
607 strDescription += " - ";
\r
608 strDescription += mapValue["message"];
\r
613 // Received by Bitcoin Address
\r
614 if (!fShowReceived)
\r
616 foreach(const CTxOut& txout, wtx.vout)
\r
618 if (txout.IsMine())
\r
620 vector<unsigned char> vchPubKey;
\r
621 if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
\r
623 CRITICAL_BLOCK(cs_mapAddressBook)
\r
625 //strDescription += _("Received payment to ");
\r
626 //strDescription += _("Received with address ");
\r
627 strDescription += _("From: unknown, Received with: ");
\r
628 string strAddress = PubKeyToAddress(vchPubKey);
\r
629 map<string, string>::iterator mi = mapAddressBook.find(strAddress);
\r
630 if (mi != mapAddressBook.end() && !(*mi).second.empty())
\r
632 string strLabel = (*mi).second;
\r
633 strDescription += strAddress.substr(0,12) + "... ";
\r
634 strDescription += "(" + strLabel + ")";
\r
637 strDescription += strAddress;
\r
645 InsertLine(fNew, nIndex, hash, strSort,
\r
647 nTime ? DateTimeStr(nTime) : "",
\r
648 SingleLine(strDescription),
\r
650 FormatMoney(nNet, true));
\r
654 bool fAllFromMe = true;
\r
655 foreach(const CTxIn& txin, wtx.vin)
\r
656 fAllFromMe = fAllFromMe && txin.IsMine();
\r
658 bool fAllToMe = true;
\r
659 foreach(const CTxOut& txout, wtx.vout)
\r
660 fAllToMe = fAllToMe && txout.IsMine();
\r
662 if (fAllFromMe && fAllToMe)
\r
665 int64 nValue = wtx.vout[0].nValue;
\r
666 InsertLine(fNew, nIndex, hash, strSort,
\r
668 nTime ? DateTimeStr(nTime) : "",
\r
669 _("Payment to yourself"),
\r
672 /// issue: can't tell which is the payment and which is the change anymore
\r
673 // FormatMoney(nNet - nValue, true),
\r
674 // FormatMoney(nValue, true));
\r
676 else if (fAllFromMe)
\r
684 int64 nTxFee = nDebit - wtx.GetValueOut();
\r
685 wtx.nLinesDisplayed = 0;
\r
686 for (int nOut = 0; nOut < wtx.vout.size(); nOut++)
\r
688 const CTxOut& txout = wtx.vout[nOut];
\r
689 if (txout.IsMine())
\r
693 if (!mapValue["to"].empty())
\r
696 strAddress = mapValue["to"];
\r
700 // Sent to Bitcoin Address
\r
702 if (ExtractHash160(txout.scriptPubKey, hash160))
\r
703 strAddress = Hash160ToAddress(hash160);
\r
706 string strDescription = _("To: ");
\r
707 CRITICAL_BLOCK(cs_mapAddressBook)
\r
708 if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
\r
709 strDescription += mapAddressBook[strAddress] + " ";
\r
710 strDescription += strAddress;
\r
711 if (!mapValue["message"].empty())
\r
713 if (!strDescription.empty())
\r
714 strDescription += " - ";
\r
715 strDescription += mapValue["message"];
\r
718 int64 nValue = txout.nValue;
\r
725 InsertLine(fNew, nIndex, hash, strprintf("%s-%d", strSort.c_str(), nOut),
\r
727 nTime ? DateTimeStr(nTime) : "",
\r
728 SingleLine(strDescription),
\r
729 FormatMoney(-nValue, true),
\r
731 wtx.nLinesDisplayed++;
\r
737 // Mixed debit transaction, can't break down payees
\r
739 bool fAllMine = true;
\r
740 foreach(const CTxOut& txout, wtx.vout)
\r
741 fAllMine = fAllMine && txout.IsMine();
\r
742 foreach(const CTxIn& txin, wtx.vin)
\r
743 fAllMine = fAllMine && txin.IsMine();
\r
745 InsertLine(fNew, nIndex, hash, strSort,
\r
747 nTime ? DateTimeStr(nTime) : "",
\r
749 FormatMoney(nNet, true),
\r
757 void CMainFrame::RefreshListCtrl()
\r
759 fRefreshListCtrl = true;
\r
763 void CMainFrame::OnIdle(wxIdleEvent& event)
\r
765 if (fRefreshListCtrl)
\r
767 // Collect list of wallet transactions and sort newest first
\r
768 bool fEntered = false;
\r
769 vector<pair<unsigned int, uint256> > vSorted;
\r
770 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
772 printf("RefreshListCtrl starting\n");
\r
774 fRefreshListCtrl = false;
\r
775 vWalletUpdated.clear();
\r
777 // Do the newest transactions first
\r
778 vSorted.reserve(mapWallet.size());
\r
779 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
\r
781 const CWalletTx& wtx = (*it).second;
\r
782 unsigned int nTime = UINT_MAX - wtx.GetTxTime();
\r
783 vSorted.push_back(make_pair(nTime, (*it).first));
\r
785 m_listCtrl->DeleteAllItems();
\r
790 sort(vSorted.begin(), vSorted.end());
\r
792 // Fill list control
\r
793 for (int i = 0; i < vSorted.size();)
\r
797 bool fEntered = false;
\r
798 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
801 uint256& hash = vSorted[i++].second;
\r
802 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
\r
803 if (mi != mapWallet.end())
\r
804 InsertTransaction((*mi).second, true);
\r
806 if (!fEntered || i == 100 || i % 500 == 0)
\r
810 printf("RefreshListCtrl done\n");
\r
812 // Update transaction total display
\r
813 MainFrameRepaint();
\r
817 // Check for time updates
\r
818 static int64 nLastTime;
\r
819 if (GetTime() > nLastTime + 30)
\r
821 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
823 nLastTime = GetTime();
\r
824 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
\r
826 CWalletTx& wtx = (*it).second;
\r
827 if (wtx.nTimeDisplayed && wtx.nTimeDisplayed != wtx.GetTxTime())
\r
828 InsertTransaction(wtx, false);
\r
835 void CMainFrame::RefreshStatusColumn()
\r
837 static int nLastTop;
\r
838 static CBlockIndex* pindexLastBest;
\r
839 static unsigned int nLastRefreshed;
\r
841 int nTop = max((int)m_listCtrl->GetTopItem(), 0);
\r
842 if (nTop == nLastTop && pindexLastBest == pindexBest)
\r
845 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
848 int nEnd = min(nStart + 100, m_listCtrl->GetItemCount());
\r
850 if (pindexLastBest == pindexBest && nLastRefreshed == nListViewUpdated)
\r
852 // If no updates, only need to do the part that moved onto the screen
\r
853 if (nStart >= nLastTop && nStart < nLastTop + 100)
\r
854 nStart = nLastTop + 100;
\r
855 if (nEnd >= nLastTop && nEnd < nLastTop + 100)
\r
859 pindexLastBest = pindexBest;
\r
860 nLastRefreshed = nListViewUpdated;
\r
862 for (int nIndex = nStart; nIndex < min(nEnd, m_listCtrl->GetItemCount()); nIndex++)
\r
864 uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1));
\r
865 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
\r
866 if (mi == mapWallet.end())
\r
868 printf("CMainFrame::RefreshStatusColumn() : tx not found in mapWallet\n");
\r
871 CWalletTx& wtx = (*mi).second;
\r
872 if (wtx.IsCoinBase() || wtx.GetTxTime() != wtx.nTimeDisplayed)
\r
874 if (!InsertTransaction(wtx, false, nIndex))
\r
875 m_listCtrl->DeleteItem(nIndex--);
\r
878 m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx));
\r
883 void CMainFrame::OnPaint(wxPaintEvent& event)
\r
894 unsigned int nNeedRepaint = 0;
\r
895 unsigned int nLastRepaint = 0;
\r
896 int64 nLastRepaintTime = 0;
\r
897 int64 nRepaintInterval = 500;
\r
899 void ThreadDelayedRepaint(void* parg)
\r
903 if (nLastRepaint != nNeedRepaint && GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)
\r
905 nLastRepaint = nNeedRepaint;
\r
908 printf("DelayedRepaint\n");
\r
909 wxPaintEvent event;
\r
910 pframeMain->fRefresh = true;
\r
911 pframeMain->GetEventHandler()->AddPendingEvent(event);
\r
914 Sleep(nRepaintInterval);
\r
918 void MainFrameRepaint()
\r
920 // This is called by network code that shouldn't access pframeMain
\r
921 // directly because it could still be running after the UI is closed.
\r
924 // Don't repaint too often
\r
925 static int64 nLastRepaintRequest;
\r
926 if (GetTimeMillis() - nLastRepaintRequest < 100)
\r
931 nLastRepaintRequest = GetTimeMillis();
\r
933 printf("MainFrameRepaint\n");
\r
934 wxPaintEvent event;
\r
935 pframeMain->fRefresh = true;
\r
936 pframeMain->GetEventHandler()->AddPendingEvent(event);
\r
940 void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
\r
942 // Skip lets the listctrl do the paint, we're just hooking the message
\r
946 ptaskbaricon->UpdateTooltip();
\r
951 static int nTransactionCount;
\r
952 bool fPaintedBalance = false;
\r
953 if (GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)
\r
955 nLastRepaint = nNeedRepaint;
\r
956 nLastRepaintTime = GetTimeMillis();
\r
958 // Update listctrl contents
\r
959 if (!vWalletUpdated.empty())
\r
961 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
964 if (m_listCtrl->GetItemCount())
\r
965 strTop = (string)m_listCtrl->GetItemText(0);
\r
966 foreach(uint256 hash, vWalletUpdated)
\r
968 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
\r
969 if (mi != mapWallet.end())
\r
970 InsertTransaction((*mi).second, false);
\r
972 vWalletUpdated.clear();
\r
973 if (m_listCtrl->GetItemCount() && strTop != (string)m_listCtrl->GetItemText(0))
\r
974 m_listCtrl->ScrollList(0, INT_MIN/2);
\r
979 TRY_CRITICAL_BLOCK(cs_mapWallet)
\r
981 fPaintedBalance = true;
\r
982 m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " ");
\r
984 // Count hidden and multi-line transactions
\r
985 nTransactionCount = 0;
\r
986 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
\r
988 CWalletTx& wtx = (*it).second;
\r
989 nTransactionCount += wtx.nLinesDisplayed;
\r
993 if (!vWalletUpdated.empty() || !fPaintedBalance)
\r
996 // Update status column of visible items only
\r
997 RefreshStatusColumn();
\r
999 // Update status bar
\r
1000 string strGen = "";
\r
1001 if (fGenerateBitcoins)
\r
1002 strGen = _(" Generating");
\r
1003 if (fGenerateBitcoins && vNodes.empty())
\r
1004 strGen = _("(not connected)");
\r
1005 m_statusBar->SetStatusText(strGen, 1);
\r
1007 string strStatus = strprintf(_(" %d connections %d blocks %d transactions"), vNodes.size(), nBestHeight + 1, nTransactionCount);
\r
1008 m_statusBar->SetStatusText(strStatus, 2);
\r
1010 if (fDebug && GetTime() - nThreadSocketHandlerHeartbeat > 60)
\r
1011 m_statusBar->SetStatusText(" ERROR: ThreadSocketHandler has stopped", 0);
\r
1015 void UIThreadCall(boost::function0<void> fn)
\r
1017 // Call this with a function object created with bind.
\r
1018 // bind needs all parameters to match the function's expected types
\r
1019 // and all default parameters specified. Some examples:
\r
1020 // UIThreadCall(bind(wxBell));
\r
1021 // UIThreadCall(bind(wxMessageBox, wxT("Message"), wxT("Title"), wxOK, (wxWindow*)NULL, -1, -1));
\r
1022 // UIThreadCall(bind(&CMainFrame::OnMenuHelpAbout, pframeMain, event));
\r
1025 wxCommandEvent event(wxEVT_UITHREADCALL);
\r
1026 event.SetClientData((void*)new boost::function0<void>(fn));
\r
1027 pframeMain->GetEventHandler()->AddPendingEvent(event);
\r
1031 void CMainFrame::OnUIThreadCall(wxCommandEvent& event)
\r
1033 boost::function0<void>* pfn = (boost::function0<void>*)event.GetClientData();
\r
1038 void CMainFrame::OnMenuFileExit(wxCommandEvent& event)
\r
1044 void CMainFrame::OnMenuOptionsGenerate(wxCommandEvent& event)
\r
1046 // Options->Generate Coins
\r
1047 GenerateBitcoins(event.IsChecked());
\r
1050 void CMainFrame::OnUpdateUIOptionsGenerate(wxUpdateUIEvent& event)
\r
1052 event.Check(fGenerateBitcoins);
\r
1055 void CMainFrame::OnMenuOptionsChangeYourAddress(wxCommandEvent& event)
\r
1057 // Options->Your Receiving Addresses
\r
1058 CAddressBookDialog dialog(this, "", CAddressBookDialog::RECEIVING, false);
\r
1059 if (!dialog.ShowModal())
\r
1063 void CMainFrame::OnMenuOptionsOptions(wxCommandEvent& event)
\r
1065 // Options->Options
\r
1066 COptionsDialog dialog(this);
\r
1067 dialog.ShowModal();
\r
1070 void CMainFrame::OnMenuHelpAbout(wxCommandEvent& event)
\r
1073 CAboutDialog dialog(this);
\r
1074 dialog.ShowModal();
\r
1077 void CMainFrame::OnButtonSend(wxCommandEvent& event)
\r
1080 CSendDialog dialog(this);
\r
1081 dialog.ShowModal();
\r
1084 void CMainFrame::OnButtonAddressBook(wxCommandEvent& event)
\r
1086 // Toolbar: Address Book
\r
1087 CAddressBookDialog dialogAddr(this, "", CAddressBookDialog::SENDING, false);
\r
1088 if (dialogAddr.ShowModal() == 2)
\r
1091 CSendDialog dialogSend(this, dialogAddr.GetSelectedAddress());
\r
1092 dialogSend.ShowModal();
\r
1096 void CMainFrame::OnSetFocusAddress(wxFocusEvent& event)
\r
1098 // Automatically select-all when entering window
\r
1100 m_textCtrlAddress->SetSelection(-1, -1);
\r
1101 fOnSetFocusAddress = true;
\r
1104 void CMainFrame::OnMouseEventsAddress(wxMouseEvent& event)
\r
1107 if (fOnSetFocusAddress)
\r
1108 m_textCtrlAddress->SetSelection(-1, -1);
\r
1109 fOnSetFocusAddress = false;
\r
1112 void CMainFrame::OnButtonNew(wxCommandEvent& event)
\r
1115 CGetTextFromUserDialog dialog(this,
\r
1116 _("New Receiving Address"),
\r
1117 _("It's good policy to use a new address for each payment you receive.\n\nLabel"),
\r
1119 if (!dialog.ShowModal())
\r
1121 string strName = dialog.GetValue();
\r
1123 // Generate new key
\r
1124 string strAddress = PubKeyToAddress(GenerateNewKey());
\r
1127 SetAddressBookName(strAddress, strName);
\r
1128 SetDefaultReceivingAddress(strAddress);
\r
1131 void CMainFrame::OnButtonCopy(wxCommandEvent& event)
\r
1133 // Copy address box to clipboard
\r
1134 if (wxTheClipboard->Open())
\r
1136 wxTheClipboard->SetData(new wxTextDataObject(m_textCtrlAddress->GetValue()));
\r
1137 wxTheClipboard->Close();
\r
1141 void CMainFrame::OnListItemActivated(wxListEvent& event)
\r
1143 uint256 hash((string)GetItemText(m_listCtrl, event.GetIndex(), 1));
\r
1145 CRITICAL_BLOCK(cs_mapWallet)
\r
1147 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
\r
1148 if (mi == mapWallet.end())
\r
1150 printf("CMainFrame::OnListItemActivated() : tx not found in mapWallet\n");
\r
1153 wtx = (*mi).second;
\r
1155 CTxDetailsDialog dialog(this, wtx);
\r
1156 dialog.ShowModal();
\r
1157 //CTxDetailsDialog* pdialog = new CTxDetailsDialog(this, wtx);
\r
1158 //pdialog->Show();
\r
1166 //////////////////////////////////////////////////////////////////////////////
\r
1168 // CTxDetailsDialog
\r
1171 CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetailsDialogBase(parent)
\r
1173 CRITICAL_BLOCK(cs_mapAddressBook)
\r
1176 strHTML.reserve(4000);
\r
1177 strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
\r
1179 int64 nTime = wtx.GetTxTime();
\r
1180 int64 nCredit = wtx.GetCredit();
\r
1181 int64 nDebit = wtx.GetDebit();
\r
1182 int64 nNet = nCredit - nDebit;
\r
1186 strHTML += _("<b>Status:</b> ") + FormatTxStatus(wtx);
\r
1187 int nRequests = wtx.GetRequestCount();
\r
1188 if (nRequests != -1)
\r
1190 if (nRequests == 0)
\r
1191 strHTML += _(", has not been successfully broadcast yet");
\r
1192 else if (nRequests == 1)
\r
1193 strHTML += strprintf(_(", broadcast through %d node"), nRequests);
\r
1195 strHTML += strprintf(_(", broadcast through %d nodes"), nRequests);
\r
1197 strHTML += "<br>";
\r
1199 strHTML += _("<b>Date:</b> ") + (nTime ? DateTimeStr(nTime) : "") + "<br>";
\r
1205 if (wtx.IsCoinBase())
\r
1207 strHTML += _("<b>Source:</b> Generated<br>");
\r
1209 else if (!wtx.mapValue["from"].empty())
\r
1211 // Online transaction
\r
1212 if (!wtx.mapValue["from"].empty())
\r
1213 strHTML += _("<b>From:</b> ") + HtmlEscape(wtx.mapValue["from"]) + "<br>";
\r
1217 // Offline transaction
\r
1221 foreach(const CTxOut& txout, wtx.vout)
\r
1223 if (txout.IsMine())
\r
1225 vector<unsigned char> vchPubKey;
\r
1226 if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
\r
1228 string strAddress = PubKeyToAddress(vchPubKey);
\r
1229 if (mapAddressBook.count(strAddress))
\r
1231 strHTML += string() + _("<b>From:</b> ") + _("unknown") + "<br>";
\r
1232 strHTML += _("<b>To:</b> ");
\r
1233 strHTML += HtmlEscape(strAddress);
\r
1234 if (!mapAddressBook[strAddress].empty())
\r
1235 strHTML += _(" (yours, label: ") + mapAddressBook[strAddress] + ")";
\r
1237 strHTML += _(" (yours)");
\r
1238 strHTML += "<br>";
\r
1251 string strAddress;
\r
1252 if (!wtx.mapValue["to"].empty())
\r
1254 // Online transaction
\r
1255 strAddress = wtx.mapValue["to"];
\r
1256 strHTML += _("<b>To:</b> ");
\r
1257 if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
\r
1258 strHTML += mapAddressBook[strAddress] + " ";
\r
1259 strHTML += HtmlEscape(strAddress) + "<br>";
\r
1266 if (wtx.IsCoinBase() && nCredit == 0)
\r
1271 int64 nUnmatured = 0;
\r
1272 foreach(const CTxOut& txout, wtx.vout)
\r
1273 nUnmatured += txout.GetCredit();
\r
1274 strHTML += _("<b>Credit:</b> ");
\r
1275 if (wtx.IsInMainChain())
\r
1276 strHTML += strprintf(_("(%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
\r
1278 strHTML += _("(not accepted)");
\r
1279 strHTML += "<br>";
\r
1281 else if (nNet > 0)
\r
1286 strHTML += _("<b>Credit:</b> ") + FormatMoney(nNet) + "<br>";
\r
1290 bool fAllFromMe = true;
\r
1291 foreach(const CTxIn& txin, wtx.vin)
\r
1292 fAllFromMe = fAllFromMe && txin.IsMine();
\r
1294 bool fAllToMe = true;
\r
1295 foreach(const CTxOut& txout, wtx.vout)
\r
1296 fAllToMe = fAllToMe && txout.IsMine();
\r
1303 foreach(const CTxOut& txout, wtx.vout)
\r
1305 if (txout.IsMine())
\r
1308 if (wtx.mapValue["to"].empty())
\r
1310 // Offline transaction
\r
1312 if (ExtractHash160(txout.scriptPubKey, hash160))
\r
1314 string strAddress = Hash160ToAddress(hash160);
\r
1315 strHTML += _("<b>To:</b> ");
\r
1316 if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
\r
1317 strHTML += mapAddressBook[strAddress] + " ";
\r
1318 strHTML += strAddress;
\r
1319 strHTML += "<br>";
\r
1323 strHTML += _("<b>Debit:</b> ") + FormatMoney(-txout.nValue) + "<br>";
\r
1328 // Payment to self
\r
1329 /// issue: can't tell which is the payment and which is the change anymore
\r
1330 //int64 nValue = wtx.vout[0].nValue;
\r
1331 //strHTML += _("<b>Debit:</b> ") + FormatMoney(-nValue) + "<br>";
\r
1332 //strHTML += _("<b>Credit:</b> ") + FormatMoney(nValue) + "<br>";
\r
1335 int64 nTxFee = nDebit - wtx.GetValueOut();
\r
1337 strHTML += _("<b>Transaction fee:</b> ") + FormatMoney(-nTxFee) + "<br>";
\r
1342 // Mixed debit transaction
\r
1344 foreach(const CTxIn& txin, wtx.vin)
\r
1345 if (txin.IsMine())
\r
1346 strHTML += _("<b>Debit:</b> ") + FormatMoney(-txin.GetDebit()) + "<br>";
\r
1347 foreach(const CTxOut& txout, wtx.vout)
\r
1348 if (txout.IsMine())
\r
1349 strHTML += _("<b>Credit:</b> ") + FormatMoney(txout.GetCredit()) + "<br>";
\r
1353 strHTML += _("<b>Net amount:</b> ") + FormatMoney(nNet, true) + "<br>";
\r
1359 if (!wtx.mapValue["message"].empty())
\r
1360 strHTML += string() + "<br><b>" + _("Message:") + "</b><br>" + HtmlEscape(wtx.mapValue["message"], true) + "<br>";
\r
1362 if (wtx.IsCoinBase())
\r
1363 strHTML += string() + "<br>" + _("Generated coins must wait 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, it will change to \"not accepted\" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.") + "<br>";
\r
1371 strHTML += "<hr><br>debug print<br><br>";
\r
1372 foreach(const CTxIn& txin, wtx.vin)
\r
1373 if (txin.IsMine())
\r
1374 strHTML += "<b>Debit:</b> " + FormatMoney(-txin.GetDebit()) + "<br>";
\r
1375 foreach(const CTxOut& txout, wtx.vout)
\r
1376 if (txout.IsMine())
\r
1377 strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";
\r
1379 strHTML += "<b>Inputs:</b><br>";
\r
1380 CRITICAL_BLOCK(cs_mapWallet)
\r
1382 foreach(const CTxIn& txin, wtx.vin)
\r
1384 COutPoint prevout = txin.prevout;
\r
1385 map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
\r
1386 if (mi != mapWallet.end())
\r
1388 const CWalletTx& prev = (*mi).second;
\r
1389 if (prevout.n < prev.vout.size())
\r
1391 strHTML += HtmlEscape(prev.ToString(), true);
\r
1392 strHTML += " " + FormatTxStatus(prev) + ", ";
\r
1393 strHTML = strHTML + "IsMine=" + (prev.vout[prevout.n].IsMine() ? "true" : "false") + "<br>";
\r
1399 strHTML += "<br><hr><br><b>Transaction:</b><br>";
\r
1400 strHTML += HtmlEscape(wtx.ToString(), true);
\r
1405 strHTML += "</font></html>";
\r
1406 string(strHTML.begin(), strHTML.end()).swap(strHTML);
\r
1407 m_htmlWin->SetPage(strHTML);
\r
1408 m_buttonOK->SetFocus();
\r
1412 void CTxDetailsDialog::OnButtonOK(wxCommandEvent& event)
\r
1422 //////////////////////////////////////////////////////////////////////////////
\r
1427 COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent)
\r
1429 // Set up list box of page choices
\r
1430 m_listBox->Append(_("Main"));
\r
1431 //m_listBox->Append(_("Test 2"));
\r
1432 m_listBox->SetSelection(0);
\r
1435 m_checkBoxMinimizeOnClose->SetLabel(_("&Minimize on close"));
\r
1436 m_checkBoxStartOnSystemStartup->Enable(false); // not implemented yet
\r
1440 m_textCtrlTransactionFee->SetValue(FormatMoney(nTransactionFee));
\r
1441 m_checkBoxLimitProcessors->SetValue(fLimitProcessors);
\r
1442 m_spinCtrlLimitProcessors->Enable(fLimitProcessors);
\r
1443 m_spinCtrlLimitProcessors->SetValue(nLimitProcessors);
\r
1444 int nProcessors = wxThread::GetCPUCount();
\r
1445 if (nProcessors < 1)
\r
1446 nProcessors = 999;
\r
1447 m_spinCtrlLimitProcessors->SetRange(1, nProcessors);
\r
1448 m_checkBoxStartOnSystemStartup->SetValue(fTmpStartOnSystemStartup = GetStartOnSystemStartup());
\r
1449 m_checkBoxMinimizeToTray->SetValue(fMinimizeToTray);
\r
1450 m_checkBoxMinimizeOnClose->SetValue(fMinimizeOnClose);
\r
1451 m_checkBoxUseProxy->SetValue(fUseProxy);
\r
1452 m_textCtrlProxyIP->Enable(fUseProxy);
\r
1453 m_textCtrlProxyPort->Enable(fUseProxy);
\r
1454 m_staticTextProxyIP->Enable(fUseProxy);
\r
1455 m_staticTextProxyPort->Enable(fUseProxy);
\r
1456 m_textCtrlProxyIP->SetValue(addrProxy.ToStringIP());
\r
1457 m_textCtrlProxyPort->SetValue(addrProxy.ToStringPort());
\r
1459 m_buttonOK->SetFocus();
\r
1462 void COptionsDialog::SelectPage(int nPage)
\r
1464 m_panelMain->Show(nPage == 0);
\r
1465 m_panelTest2->Show(nPage == 1);
\r
1467 m_scrolledWindow->Layout();
\r
1468 m_scrolledWindow->SetScrollbars(0, 0, 0, 0, 0, 0);
\r
1471 void COptionsDialog::OnListBox(wxCommandEvent& event)
\r
1473 SelectPage(event.GetSelection());
\r
1476 void COptionsDialog::OnKillFocusTransactionFee(wxFocusEvent& event)
\r
1479 int64 nTmp = nTransactionFee;
\r
1480 ParseMoney(m_textCtrlTransactionFee->GetValue(), nTmp);
\r
1481 m_textCtrlTransactionFee->SetValue(FormatMoney(nTmp));
\r
1484 void COptionsDialog::OnCheckBoxLimitProcessors(wxCommandEvent& event)
\r
1486 m_spinCtrlLimitProcessors->Enable(event.IsChecked());
\r
1489 void COptionsDialog::OnCheckBoxUseProxy(wxCommandEvent& event)
\r
1491 m_textCtrlProxyIP->Enable(event.IsChecked());
\r
1492 m_textCtrlProxyPort->Enable(event.IsChecked());
\r
1493 m_staticTextProxyIP->Enable(event.IsChecked());
\r
1494 m_staticTextProxyPort->Enable(event.IsChecked());
\r
1497 CAddress COptionsDialog::GetProxyAddr()
\r
1499 // Be careful about byte order, addr.ip and addr.port are big endian
\r
1500 CAddress addr(m_textCtrlProxyIP->GetValue() + ":" + m_textCtrlProxyPort->GetValue());
\r
1501 if (addr.ip == INADDR_NONE)
\r
1502 addr.ip = addrProxy.ip;
\r
1503 int nPort = atoi(m_textCtrlProxyPort->GetValue());
\r
1504 addr.port = htons(nPort);
\r
1505 if (nPort <= 0 || nPort > USHRT_MAX)
\r
1506 addr.port = addrProxy.port;
\r
1510 void COptionsDialog::OnKillFocusProxy(wxFocusEvent& event)
\r
1513 m_textCtrlProxyIP->SetValue(GetProxyAddr().ToStringIP());
\r
1514 m_textCtrlProxyPort->SetValue(GetProxyAddr().ToStringPort());
\r
1518 void COptionsDialog::OnButtonOK(wxCommandEvent& event)
\r
1520 OnButtonApply(event);
\r
1524 void COptionsDialog::OnButtonCancel(wxCommandEvent& event)
\r
1529 void COptionsDialog::OnButtonApply(wxCommandEvent& event)
\r
1531 CWalletDB walletdb;
\r
1533 int64 nPrevTransactionFee = nTransactionFee;
\r
1534 if (ParseMoney(m_textCtrlTransactionFee->GetValue(), nTransactionFee) && nTransactionFee != nPrevTransactionFee)
\r
1535 walletdb.WriteSetting("nTransactionFee", nTransactionFee);
\r
1537 int nPrevMaxProc = (fLimitProcessors ? nLimitProcessors : INT_MAX);
\r
1538 if (fLimitProcessors != m_checkBoxLimitProcessors->GetValue())
\r
1540 fLimitProcessors = m_checkBoxLimitProcessors->GetValue();
\r
1541 walletdb.WriteSetting("fLimitProcessors", fLimitProcessors);
\r
1543 if (nLimitProcessors != m_spinCtrlLimitProcessors->GetValue())
\r
1545 nLimitProcessors = m_spinCtrlLimitProcessors->GetValue();
\r
1546 walletdb.WriteSetting("nLimitProcessors", nLimitProcessors);
\r
1548 if (fGenerateBitcoins && (fLimitProcessors ? nLimitProcessors : INT_MAX) > nPrevMaxProc)
\r
1549 GenerateBitcoins(fGenerateBitcoins);
\r
1551 if (fTmpStartOnSystemStartup != m_checkBoxStartOnSystemStartup->GetValue())
\r
1553 fTmpStartOnSystemStartup = m_checkBoxStartOnSystemStartup->GetValue();
\r
1554 SetStartOnSystemStartup(fTmpStartOnSystemStartup);
\r
1557 if (fMinimizeToTray != m_checkBoxMinimizeToTray->GetValue())
\r
1559 fMinimizeToTray = m_checkBoxMinimizeToTray->GetValue();
\r
1560 walletdb.WriteSetting("fMinimizeToTray", fMinimizeToTray);
\r
1561 ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
\r
1564 if (fMinimizeOnClose != m_checkBoxMinimizeOnClose->GetValue())
\r
1566 fMinimizeOnClose = m_checkBoxMinimizeOnClose->GetValue();
\r
1567 walletdb.WriteSetting("fMinimizeOnClose", fMinimizeOnClose);
\r
1570 fUseProxy = m_checkBoxUseProxy->GetValue();
\r
1571 walletdb.WriteSetting("fUseProxy", fUseProxy);
\r
1573 addrProxy = GetProxyAddr();
\r
1574 walletdb.WriteSetting("addrProxy", addrProxy);
\r
1581 //////////////////////////////////////////////////////////////////////////////
\r
1586 CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent)
\r
1588 m_staticTextVersion->SetLabel(strprintf(_("version 0.%d.%d beta"), VERSION/100, VERSION%100));
\r
1590 // Change (c) into UTF-8 or ANSI copyright symbol
\r
1591 wxString str = m_staticTextMain->GetLabel();
\r
1593 str.Replace("(c)", wxString::FromUTF8("\xC2\xA9"));
\r
1595 str.Replace("(c)", "\xA9");
\r
1597 m_staticTextMain->SetLabel(str);
\r
1599 // Resize on Linux to make the window fit the text.
\r
1600 // The text was wrapped manually rather than using the Wrap setting because
\r
1601 // the wrap would be too small on Linux and it can't be changed at this point.
\r
1602 wxFont fontTmp = m_staticTextMain->GetFont();
\r
1603 if (fontTmp.GetPointSize() > 8);
\r
1604 fontTmp.SetPointSize(8);
\r
1605 m_staticTextMain->SetFont(fontTmp);
\r
1606 SetSize(GetSize().GetWidth() + 44, GetSize().GetHeight() + 10);
\r
1610 void CAboutDialog::OnButtonOK(wxCommandEvent& event)
\r
1620 //////////////////////////////////////////////////////////////////////////////
\r
1625 CSendDialog::CSendDialog(wxWindow* parent, const wxString& strAddress) : CSendDialogBase(parent)
\r
1628 m_textCtrlAddress->SetValue(strAddress);
\r
1629 m_choiceTransferType->SetSelection(0);
\r
1630 m_bitmapCheckMark->Show(false);
\r
1631 fEnabledPrev = true;
\r
1632 m_textCtrlAddress->SetFocus();
\r
1633 //// todo: should add a display of your balance for convenience
\r
1635 wxFont fontTmp = m_staticTextInstructions->GetFont();
\r
1636 if (fontTmp.GetPointSize() > 9);
\r
1637 fontTmp.SetPointSize(9);
\r
1638 m_staticTextInstructions->SetFont(fontTmp);
\r
1639 SetSize(725, 380);
\r
1644 iconSend.CopyFromBitmap(wxBitmap(send16noshadow_xpm));
\r
1645 SetIcon(iconSend);
\r
1647 wxCommandEvent event;
\r
1648 OnTextAddress(event);
\r
1650 // Fixup the tab order
\r
1651 m_buttonPaste->MoveAfterInTabOrder(m_buttonCancel);
\r
1652 m_buttonAddress->MoveAfterInTabOrder(m_buttonPaste);
\r
1656 void CSendDialog::OnTextAddress(wxCommandEvent& event)
\r
1660 bool fBitcoinAddress = IsValidBitcoinAddress(m_textCtrlAddress->GetValue());
\r
1661 m_bitmapCheckMark->Show(fBitcoinAddress);
\r
1663 // Grey out message if bitcoin address
\r
1664 bool fEnable = !fBitcoinAddress;
\r
1665 m_staticTextFrom->Enable(fEnable);
\r
1666 m_textCtrlFrom->Enable(fEnable);
\r
1667 m_staticTextMessage->Enable(fEnable);
\r
1668 m_textCtrlMessage->Enable(fEnable);
\r
1669 m_textCtrlMessage->SetBackgroundColour(wxSystemSettings::GetColour(fEnable ? wxSYS_COLOUR_WINDOW : wxSYS_COLOUR_BTNFACE));
\r
1670 if (!fEnable && fEnabledPrev)
\r
1672 strFromSave = m_textCtrlFrom->GetValue();
\r
1673 strMessageSave = m_textCtrlMessage->GetValue();
\r
1674 m_textCtrlFrom->SetValue(_("Will appear as \"From: Unknown\""));
\r
1675 m_textCtrlMessage->SetValue(_("Can't include a message when sending to a Bitcoin address"));
\r
1677 else if (fEnable && !fEnabledPrev)
\r
1679 m_textCtrlFrom->SetValue(strFromSave);
\r
1680 m_textCtrlMessage->SetValue(strMessageSave);
\r
1682 fEnabledPrev = fEnable;
\r
1685 void CSendDialog::OnKillFocusAmount(wxFocusEvent& event)
\r
1687 // Reformat the amount
\r
1689 if (m_textCtrlAmount->GetValue().Trim().empty())
\r
1692 if (ParseMoney(m_textCtrlAmount->GetValue(), nTmp))
\r
1693 m_textCtrlAmount->SetValue(FormatMoney(nTmp));
\r
1696 void CSendDialog::OnButtonAddressBook(wxCommandEvent& event)
\r
1698 // Open address book
\r
1699 CAddressBookDialog dialog(this, m_textCtrlAddress->GetValue(), CAddressBookDialog::SENDING, true);
\r
1700 if (dialog.ShowModal())
\r
1701 m_textCtrlAddress->SetValue(dialog.GetSelectedAddress());
\r
1704 void CSendDialog::OnButtonPaste(wxCommandEvent& event)
\r
1706 // Copy clipboard to address box
\r
1707 if (wxTheClipboard->Open())
\r
1709 if (wxTheClipboard->IsSupported(wxDF_TEXT))
\r
1711 wxTextDataObject data;
\r
1712 wxTheClipboard->GetData(data);
\r
1713 m_textCtrlAddress->SetValue(data.GetText());
\r
1715 wxTheClipboard->Close();
\r
1719 void CSendDialog::OnButtonSend(wxCommandEvent& event)
\r
1722 string strAddress = (string)m_textCtrlAddress->GetValue();
\r
1726 if (!ParseMoney(m_textCtrlAmount->GetValue(), nValue) || nValue <= 0)
\r
1728 wxMessageBox(_("Error in amount "), _("Send Coins"));
\r
1731 if (nValue > GetBalance())
\r
1733 wxMessageBox(_("Amount exceeds your balance "), _("Send Coins"));
\r
1736 if (nValue + nTransactionFee > GetBalance())
\r
1738 wxMessageBox(string(_("Total exceeds your balance when the ")) + FormatMoney(nTransactionFee) + _(" transaction fee is included "), _("Send Coins"));
\r
1742 // Parse bitcoin address
\r
1744 bool fBitcoinAddress = AddressToHash160(strAddress, hash160);
\r
1746 if (fBitcoinAddress)
\r
1748 // Send to bitcoin address
\r
1749 CScript scriptPubKey;
\r
1750 scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
\r
1752 string strError = SendMoney(scriptPubKey, nValue, wtx, true);
\r
1753 if (strError == "")
\r
1754 wxMessageBox(_("Payment sent "), _("Sending..."));
\r
1755 else if (strError != "ABORTED")
\r
1756 wxMessageBox(strError + " ", _("Sending..."));
\r
1760 // Parse IP address
\r
1761 CAddress addr(strAddress);
\r
1762 if (!addr.IsValid())
\r
1764 wxMessageBox(_("Invalid address "), _("Send Coins"));
\r
1769 wtx.mapValue["to"] = strAddress;
\r
1770 wtx.mapValue["from"] = m_textCtrlFrom->GetValue();
\r
1771 wtx.mapValue["message"] = m_textCtrlMessage->GetValue();
\r
1773 // Send to IP address
\r
1774 CSendingDialog* pdialog = new CSendingDialog(this, addr, nValue, wtx);
\r
1775 if (!pdialog->ShowModal())
\r
1779 CRITICAL_BLOCK(cs_mapAddressBook)
\r
1780 if (!mapAddressBook.count(strAddress))
\r
1781 SetAddressBookName(strAddress, "");
\r
1786 void CSendDialog::OnButtonCancel(wxCommandEvent& event)
\r
1797 //////////////////////////////////////////////////////////////////////////////
\r
1802 CSendingDialog::CSendingDialog(wxWindow* parent, const CAddress& addrIn, int64 nPriceIn, const CWalletTx& wtxIn) : CSendingDialogBase(NULL) // we have to give null so parent can't destroy us
\r
1805 nPrice = nPriceIn;
\r
1807 start = wxDateTime::UNow();
\r
1808 memset(pszStatus, 0, sizeof(pszStatus));
\r
1809 fCanCancel = true;
\r
1813 fWorkDone = false;
\r
1815 SetSize(1.2 * GetSize().GetWidth(), 1.08 * GetSize().GetHeight());
\r
1818 SetTitle(strprintf(_("Sending %s to %s"), FormatMoney(nPrice).c_str(), wtx.mapValue["to"].c_str()));
\r
1819 m_textCtrlStatus->SetValue("");
\r
1821 CreateThread(SendingDialogStartTransfer, this);
\r
1824 CSendingDialog::~CSendingDialog()
\r
1826 printf("~CSendingDialog()\n");
\r
1829 void CSendingDialog::Close()
\r
1831 // Last one out turn out the lights.
\r
1832 // fWorkDone signals that work side is done and UI thread should call destroy.
\r
1833 // fUIDone signals that UI window has closed and work thread should call destroy.
\r
1834 // This allows the window to disappear and end modality when cancelled
\r
1835 // without making the user wait for ConnectNode to return. The dialog object
\r
1836 // hangs around in the background until the work thread exits.
\r
1838 EndModal(fSuccess);
\r
1847 void CSendingDialog::OnClose(wxCloseEvent& event)
\r
1849 if (!event.CanVeto() || fWorkDone || fAbort || !fCanCancel)
\r
1856 wxCommandEvent cmdevent;
\r
1857 OnButtonCancel(cmdevent);
\r
1861 void CSendingDialog::OnButtonOK(wxCommandEvent& event)
\r
1867 void CSendingDialog::OnButtonCancel(wxCommandEvent& event)
\r
1873 void CSendingDialog::OnPaint(wxPaintEvent& event)
\r
1876 if (strlen(pszStatus) > 130)
\r
1877 m_textCtrlStatus->SetValue(string("\n") + pszStatus);
\r
1879 m_textCtrlStatus->SetValue(string("\n\n") + pszStatus);
\r
1880 m_staticTextSending->SetFocus();
\r
1882 m_buttonCancel->Enable(false);
\r
1885 m_buttonOK->Enable(true);
\r
1886 m_buttonOK->SetFocus();
\r
1887 m_buttonCancel->Enable(false);
\r
1889 if (fAbort && fCanCancel && IsShown())
\r
1891 strcpy(pszStatus, _("CANCELLED"));
\r
1892 m_buttonOK->Enable(true);
\r
1893 m_buttonOK->SetFocus();
\r
1894 m_buttonCancel->Enable(false);
\r
1895 m_buttonCancel->SetLabel(_("Cancelled"));
\r
1897 wxMessageBox(_("Transfer cancelled "), _("Sending..."), wxOK, this);
\r
1903 // Everything from here on is not in the UI thread and must only communicate
\r
1904 // with the rest of the dialog through variables and calling repaint.
\r
1907 void CSendingDialog::Repaint()
\r
1910 wxPaintEvent event;
\r
1911 GetEventHandler()->AddPendingEvent(event);
\r
1914 bool CSendingDialog::Status()
\r
1921 if (fAbort && fCanCancel)
\r
1923 memset(pszStatus, 0, 10);
\r
1924 strcpy(pszStatus, _("CANCELLED"));
\r
1932 bool CSendingDialog::Status(const string& str)
\r
1937 // This can be read by the UI thread at any time,
\r
1938 // so copy in a way that can be read cleanly at all times.
\r
1939 memset(pszStatus, 0, min(str.size()+1, sizeof(pszStatus)));
\r
1940 strlcpy(pszStatus, str.c_str(), sizeof(pszStatus));
\r
1946 bool CSendingDialog::Error(const string& str)
\r
1948 fCanCancel = false;
\r
1950 Status(string(_("Error: ")) + str);
\r
1954 void SendingDialogStartTransfer(void* parg)
\r
1956 ((CSendingDialog*)parg)->StartTransfer();
\r
1959 void CSendingDialog::StartTransfer()
\r
1961 // Make sure we have enough money
\r
1962 if (nPrice + nTransactionFee > GetBalance())
\r
1964 Error(_("Insufficient funds"));
\r
1968 // We may have connected already for product details
\r
1969 if (!Status(_("Connecting...")))
\r
1971 CNode* pnode = ConnectNode(addr, 15 * 60);
\r
1974 Error(_("Unable to connect"));
\r
1978 // Send order to seller, with response going to OnReply2 via event handler
\r
1979 if (!Status(_("Requesting public key...")))
\r
1981 pnode->PushRequest("checkorder", wtx, SendingDialogOnReply2, this);
\r
1984 void SendingDialogOnReply2(void* parg, CDataStream& vRecv)
\r
1986 ((CSendingDialog*)parg)->OnReply2(vRecv);
\r
1989 void CSendingDialog::OnReply2(CDataStream& vRecv)
\r
1991 if (!Status(_("Received public key...")))
\r
1994 CScript scriptPubKey;
\r
2001 string strMessage;
\r
2002 vRecv >> strMessage;
\r
2003 Error(_("Transfer was not accepted"));
\r
2004 //// todo: enlarge the window and enable a hidden white box to put seller's message
\r
2007 vRecv >> scriptPubKey;
\r
2011 //// what do we want to do about this?
\r
2012 Error(_("Invalid response received"));
\r
2016 // Pause to give the user a chance to cancel
\r
2017 while (wxDateTime::UNow() < start + wxTimeSpan(0, 0, 0, 2 * 1000))
\r
2024 CRITICAL_BLOCK(cs_main)
\r
2027 if (!Status(_("Creating transaction...")))
\r
2029 if (nPrice + nTransactionFee > GetBalance())
\r
2031 Error(_("Insufficient funds"));
\r
2035 int64 nFeeRequired;
\r
2036 if (!CreateTransaction(scriptPubKey, nPrice, wtx, key, nFeeRequired))
\r
2038 if (nPrice + nFeeRequired > GetBalance())
\r
2039 Error(strprintf(_("This is an oversized transaction that requires a transaction fee of %s"), FormatMoney(nFeeRequired).c_str()));
\r
2041 Error(_("Transaction creation failed"));
\r
2045 // Transaction fee
\r
2046 if (!ThreadSafeAskFee(nFeeRequired, _("Sending..."), this))
\r
2048 Error(_("Transaction aborted"));
\r
2052 // Make sure we're still connected
\r
2053 CNode* pnode = ConnectNode(addr, 2 * 60 * 60);
\r
2056 Error(_("Lost connection, transaction cancelled"));
\r
2060 // Last chance to cancel
\r
2064 fCanCancel = false;
\r
2067 fCanCancel = true;
\r
2070 fCanCancel = false;
\r
2072 if (!Status(_("Sending payment...")))
\r
2076 if (!CommitTransaction(wtx, key))
\r
2078 Error(_("The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."));
\r
2082 // Send payment tx to seller, with response going to OnReply3 via event handler
\r
2083 pnode->PushRequest("submitorder", wtx, SendingDialogOnReply3, this);
\r
2085 Status(_("Waiting for confirmation..."));
\r
2086 MainFrameRepaint();
\r
2090 void SendingDialogOnReply3(void* parg, CDataStream& vRecv)
\r
2092 ((CSendingDialog*)parg)->OnReply3(vRecv);
\r
2095 void CSendingDialog::OnReply3(CDataStream& vRecv)
\r
2103 Error(_("The payment was sent, but the recipient was unable to verify it.\n"
\r
2104 "The transaction is recorded and will credit to the recipient,\n"
\r
2105 "but the comment information will be blank."));
\r
2111 //// what do we want to do about this?
\r
2112 Error(_("Payment was sent, but an invalid response was received"));
\r
2118 Status(_("Payment completed"));
\r
2126 //////////////////////////////////////////////////////////////////////////////
\r
2128 // CAddressBookDialog
\r
2131 CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInitSelected, int nPageIn, bool fDuringSendIn) : CAddressBookDialogBase(parent)
\r
2133 // Set initially selected page
\r
2134 wxNotebookEvent event;
\r
2135 event.SetSelection(nPageIn);
\r
2136 OnNotebookPageChanged(event);
\r
2137 m_notebook->ChangeSelection(nPageIn);
\r
2139 fDuringSend = fDuringSendIn;
\r
2141 m_buttonCancel->Show(false);
\r
2144 wxIcon iconAddressBook;
\r
2145 iconAddressBook.CopyFromBitmap(wxBitmap(addressbook16_xpm));
\r
2146 SetIcon(iconAddressBook);
\r
2148 // Init column headers
\r
2149 m_listCtrlSending->InsertColumn(0, _("Name"), wxLIST_FORMAT_LEFT, 200);
\r
2150 m_listCtrlSending->InsertColumn(1, _("Address"), wxLIST_FORMAT_LEFT, 350);
\r
2151 m_listCtrlSending->SetFocus();
\r
2152 m_listCtrlReceiving->InsertColumn(0, _("Label"), wxLIST_FORMAT_LEFT, 200);
\r
2153 m_listCtrlReceiving->InsertColumn(1, _("Bitcoin Address"), wxLIST_FORMAT_LEFT, 350);
\r
2154 m_listCtrlReceiving->SetFocus();
\r
2156 // Fill listctrl with address book data
\r
2157 CRITICAL_BLOCK(cs_mapKeys)
\r
2158 CRITICAL_BLOCK(cs_mapAddressBook)
\r
2160 string strDefaultReceiving = (string)pframeMain->m_textCtrlAddress->GetValue();
\r
2161 foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
\r
2163 string strAddress = item.first;
\r
2164 string strName = item.second;
\r
2166 bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
\r
2167 wxListCtrl* plistCtrl = fMine ? m_listCtrlReceiving : m_listCtrlSending;
\r
2168 int nIndex = InsertLine(plistCtrl, strName, strAddress);
\r
2169 if (strAddress == (fMine ? strDefaultReceiving : string(strInitSelected)))
\r
2170 plistCtrl->SetItemState(nIndex, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
\r
2175 wxString CAddressBookDialog::GetSelectedAddress()
\r
2177 int nIndex = GetSelection(m_listCtrl);
\r
2180 return GetItemText(m_listCtrl, nIndex, 1);
\r
2183 wxString CAddressBookDialog::GetSelectedSendingAddress()
\r
2185 int nIndex = GetSelection(m_listCtrlSending);
\r
2188 return GetItemText(m_listCtrlSending, nIndex, 1);
\r
2191 wxString CAddressBookDialog::GetSelectedReceivingAddress()
\r
2193 int nIndex = GetSelection(m_listCtrlReceiving);
\r
2196 return GetItemText(m_listCtrlReceiving, nIndex, 1);
\r
2199 void CAddressBookDialog::OnNotebookPageChanged(wxNotebookEvent& event)
\r
2202 nPage = event.GetSelection();
\r
2203 if (nPage == SENDING)
\r
2204 m_listCtrl = m_listCtrlSending;
\r
2205 else if (nPage == RECEIVING)
\r
2206 m_listCtrl = m_listCtrlReceiving;
\r
2207 m_buttonDelete->Show(nPage == SENDING);
\r
2208 m_buttonCopy->Show(nPage == RECEIVING);
\r
2210 m_listCtrl->SetFocus();
\r
2213 void CAddressBookDialog::OnListEndLabelEdit(wxListEvent& event)
\r
2215 // Update address book with edited name
\r
2217 if (event.IsEditCancelled())
\r
2219 string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1);
\r
2220 SetAddressBookName(strAddress, string(event.GetText()));
\r
2221 pframeMain->RefreshListCtrl();
\r
2224 void CAddressBookDialog::OnListItemSelected(wxListEvent& event)
\r
2227 if (nPage == RECEIVING)
\r
2228 SetDefaultReceivingAddress((string)GetSelectedReceivingAddress());
\r
2231 void CAddressBookDialog::OnListItemActivated(wxListEvent& event)
\r
2236 // Doubleclick returns selection
\r
2237 EndModal(GetSelectedAddress() != "" ? 2 : 0);
\r
2241 // Doubleclick edits item
\r
2242 wxCommandEvent event2;
\r
2243 OnButtonEdit(event2);
\r
2246 void CAddressBookDialog::OnButtonDelete(wxCommandEvent& event)
\r
2248 if (nPage != SENDING)
\r
2250 for (int nIndex = m_listCtrl->GetItemCount()-1; nIndex >= 0; nIndex--)
\r
2252 if (m_listCtrl->GetItemState(nIndex, wxLIST_STATE_SELECTED))
\r
2254 string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
\r
2255 CWalletDB().EraseName(strAddress);
\r
2256 m_listCtrl->DeleteItem(nIndex);
\r
2259 pframeMain->RefreshListCtrl();
\r
2262 void CAddressBookDialog::OnButtonCopy(wxCommandEvent& event)
\r
2264 // Copy address box to clipboard
\r
2265 if (wxTheClipboard->Open())
\r
2267 wxTheClipboard->SetData(new wxTextDataObject(GetSelectedAddress()));
\r
2268 wxTheClipboard->Close();
\r
2272 bool CAddressBookDialog::CheckIfMine(const string& strAddress, const string& strTitle)
\r
2275 bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
\r
2277 wxMessageBox(_("This is one of your own addresses for receiving payments and cannot be entered in the address book. "), strTitle);
\r
2281 void CAddressBookDialog::OnButtonEdit(wxCommandEvent& event)
\r
2283 int nIndex = GetSelection(m_listCtrl);
\r
2286 string strName = (string)m_listCtrl->GetItemText(nIndex);
\r
2287 string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
\r
2288 string strAddressOrg = strAddress;
\r
2290 if (nPage == SENDING)
\r
2292 // Ask name and address
\r
2295 CGetTextFromUserDialog dialog(this, _("Edit Address"), _("Name"), strName, _("Address"), strAddress);
\r
2296 if (!dialog.ShowModal())
\r
2298 strName = dialog.GetValue1();
\r
2299 strAddress = dialog.GetValue2();
\r
2301 while (CheckIfMine(strAddress, _("Edit Address")));
\r
2304 else if (nPage == RECEIVING)
\r
2307 CGetTextFromUserDialog dialog(this, _("Edit Address Label"), _("Label"), strName);
\r
2308 if (!dialog.ShowModal())
\r
2310 strName = dialog.GetValue();
\r
2314 if (strAddress != strAddressOrg)
\r
2315 CWalletDB().EraseName(strAddressOrg);
\r
2316 SetAddressBookName(strAddress, strName);
\r
2317 m_listCtrl->SetItem(nIndex, 1, strAddress);
\r
2318 m_listCtrl->SetItemText(nIndex, strName);
\r
2319 pframeMain->RefreshListCtrl();
\r
2322 void CAddressBookDialog::OnButtonNew(wxCommandEvent& event)
\r
2325 string strAddress;
\r
2327 if (nPage == SENDING)
\r
2329 // Ask name and address
\r
2332 CGetTextFromUserDialog dialog(this, _("Add Address"), _("Name"), strName, _("Address"), strAddress);
\r
2333 if (!dialog.ShowModal())
\r
2335 strName = dialog.GetValue1();
\r
2336 strAddress = dialog.GetValue2();
\r
2338 while (CheckIfMine(strAddress, _("Add Address")));
\r
2340 else if (nPage == RECEIVING)
\r
2343 CGetTextFromUserDialog dialog(this,
\r
2344 _("New Receiving Address"),
\r
2345 _("It's good policy to use a new address for each payment you receive.\n\nLabel"),
\r
2347 if (!dialog.ShowModal())
\r
2349 strName = dialog.GetValue();
\r
2351 // Generate new key
\r
2352 strAddress = PubKeyToAddress(GenerateNewKey());
\r
2355 // Add to list and select it
\r
2356 SetAddressBookName(strAddress, strName);
\r
2357 int nIndex = InsertLine(m_listCtrl, strName, strAddress);
\r
2358 SetSelection(m_listCtrl, nIndex);
\r
2359 m_listCtrl->SetFocus();
\r
2360 if (nPage == SENDING)
\r
2361 pframeMain->RefreshListCtrl();
\r
2364 void CAddressBookDialog::OnButtonOK(wxCommandEvent& event)
\r
2367 EndModal(GetSelectedAddress() != "" ? 1 : 0);
\r
2370 void CAddressBookDialog::OnButtonCancel(wxCommandEvent& event)
\r
2376 void CAddressBookDialog::OnClose(wxCloseEvent& event)
\r
2387 //////////////////////////////////////////////////////////////////////////////
\r
2394 ID_TASKBAR_RESTORE = 10001,
\r
2395 ID_TASKBAR_OPTIONS,
\r
2396 ID_TASKBAR_GENERATE,
\r
2400 BEGIN_EVENT_TABLE(CMyTaskBarIcon, wxTaskBarIcon)
\r
2401 EVT_TASKBAR_LEFT_DCLICK(CMyTaskBarIcon::OnLeftButtonDClick)
\r
2402 EVT_MENU(ID_TASKBAR_RESTORE, CMyTaskBarIcon::OnMenuRestore)
\r
2403 EVT_MENU(ID_TASKBAR_OPTIONS, CMyTaskBarIcon::OnMenuOptions)
\r
2404 EVT_MENU(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnMenuGenerate)
\r
2405 EVT_UPDATE_UI(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnUpdateUIGenerate)
\r
2406 EVT_MENU(ID_TASKBAR_EXIT, CMyTaskBarIcon::OnMenuExit)
\r
2409 void CMyTaskBarIcon::Show(bool fShow)
\r
2411 static char pszPrevTip[200];
\r
2414 string strTooltip = _("Bitcoin");
\r
2415 if (fGenerateBitcoins)
\r
2416 strTooltip = _("Bitcoin - Generating");
\r
2417 if (fGenerateBitcoins && vNodes.empty())
\r
2418 strTooltip = _("Bitcoin - (not connected)");
\r
2420 // Optimization, only update when changed, using char array to be reentrant
\r
2421 if (strncmp(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip)-1) != 0)
\r
2423 strlcpy(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip));
\r
2425 SetIcon(wxICON(bitcoin), strTooltip);
\r
2427 SetIcon(bitcoin20_xpm, strTooltip);
\r
2433 strlcpy(pszPrevTip, "", sizeof(pszPrevTip));
\r
2438 void CMyTaskBarIcon::Hide()
\r
2443 void CMyTaskBarIcon::OnLeftButtonDClick(wxTaskBarIconEvent& event)
\r
2448 void CMyTaskBarIcon::OnMenuRestore(wxCommandEvent& event)
\r
2453 void CMyTaskBarIcon::OnMenuOptions(wxCommandEvent& event)
\r
2455 // Since it's modal, get the main window to do it
\r
2456 wxCommandEvent event2(wxEVT_COMMAND_MENU_SELECTED, wxID_PREFERENCES);
\r
2457 pframeMain->GetEventHandler()->AddPendingEvent(event2);
\r
2460 void CMyTaskBarIcon::Restore()
\r
2462 pframeMain->Show();
\r
2463 wxIconizeEvent event(0, false);
\r
2464 pframeMain->GetEventHandler()->AddPendingEvent(event);
\r
2465 pframeMain->Iconize(false);
\r
2466 pframeMain->Raise();
\r
2469 void CMyTaskBarIcon::OnMenuGenerate(wxCommandEvent& event)
\r
2471 GenerateBitcoins(event.IsChecked());
\r
2474 void CMyTaskBarIcon::OnUpdateUIGenerate(wxUpdateUIEvent& event)
\r
2476 event.Check(fGenerateBitcoins);
\r
2479 void CMyTaskBarIcon::OnMenuExit(wxCommandEvent& event)
\r
2481 pframeMain->Close(true);
\r
2484 void CMyTaskBarIcon::UpdateTooltip()
\r
2486 if (IsIconInstalled())
\r
2490 wxMenu* CMyTaskBarIcon::CreatePopupMenu()
\r
2492 wxMenu* pmenu = new wxMenu;
\r
2493 pmenu->Append(ID_TASKBAR_RESTORE, _("&Open Bitcoin"));
\r
2494 pmenu->Append(ID_TASKBAR_OPTIONS, _("O&ptions..."));
\r
2495 pmenu->AppendCheckItem(ID_TASKBAR_GENERATE, _("&Generate Coins"))->Check(fGenerateBitcoins);
\r
2496 #ifndef __WXMAC_OSX__ // Mac has built-in quit menu
\r
2497 pmenu->AppendSeparator();
\r
2498 pmenu->Append(ID_TASKBAR_EXIT, _("E&xit"));
\r
2515 void CreateMainWindow()
\r
2517 pframeMain = new CMainFrame(NULL);
\r
2518 if (mapArgs.count("-min"))
\r
2519 pframeMain->Iconize(true);
\r
2520 pframeMain->Show(true); // have to show first to get taskbar button to hide
\r
2521 if (fMinimizeToTray && pframeMain->IsIconized())
\r
2522 fClosedToTray = true;
\r
2523 pframeMain->Show(!fClosedToTray);
\r
2524 ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
\r
2525 CreateThread(ThreadDelayedRepaint, NULL);
\r