]> Git Repo - VerusCoin.git/blob - ui.cpp
Merge remote branch 'refs/remotes/svn/trunk' into svn
[VerusCoin.git] / ui.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
4
5 #include "headers.h"
6 #ifdef _MSC_VER
7 #include <crtdbg.h>
8 #endif
9
10
11
12 DEFINE_EVENT_TYPE(wxEVT_UITHREADCALL)
13
14 CMainFrame* pframeMain = NULL;
15 CMyTaskBarIcon* ptaskbaricon = NULL;
16 bool fClosedToTray = false;
17 wxLocale g_locale;
18
19
20
21
22
23
24
25
26
27 //////////////////////////////////////////////////////////////////////////////
28 //
29 // Util
30 //
31
32 void HandleCtrlA(wxKeyEvent& event)
33 {
34     // Ctrl-a select all
35     event.Skip();
36     wxTextCtrl* textCtrl = (wxTextCtrl*)event.GetEventObject();
37     if (event.GetModifiers() == wxMOD_CONTROL && event.GetKeyCode() == 'A')
38         textCtrl->SetSelection(-1, -1);
39 }
40
41 bool Is24HourTime()
42 {
43     //char pszHourFormat[256];
44     //pszHourFormat[0] = '\0';
45     //GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ITIME, pszHourFormat, 256);
46     //return (pszHourFormat[0] != '0');
47     return true;
48 }
49
50 string DateStr(int64 nTime)
51 {
52     // Can only be used safely here in the UI
53     return (string)wxDateTime((time_t)nTime).FormatDate();
54 }
55
56 string DateTimeStr(int64 nTime)
57 {
58     // Can only be used safely here in the UI
59     wxDateTime datetime((time_t)nTime);
60     if (Is24HourTime())
61         return (string)datetime.Format("%x %H:%M");
62     else
63         return (string)datetime.Format("%x ") + itostr((datetime.GetHour() + 11) % 12 + 1) + (string)datetime.Format(":%M %p");
64 }
65
66 wxString GetItemText(wxListCtrl* listCtrl, int nIndex, int nColumn)
67 {
68     // Helper to simplify access to listctrl
69     wxListItem item;
70     item.m_itemId = nIndex;
71     item.m_col = nColumn;
72     item.m_mask = wxLIST_MASK_TEXT;
73     if (!listCtrl->GetItem(item))
74         return "";
75     return item.GetText();
76 }
77
78 int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1)
79 {
80     int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
81     listCtrl->SetItem(nIndex, 1, str1);
82     return nIndex;
83 }
84
85 int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
86 {
87     int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
88     listCtrl->SetItem(nIndex, 1, str1);
89     listCtrl->SetItem(nIndex, 2, str2);
90     listCtrl->SetItem(nIndex, 3, str3);
91     listCtrl->SetItem(nIndex, 4, str4);
92     return nIndex;
93 }
94
95 int InsertLine(wxListCtrl* listCtrl, void* pdata, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
96 {
97     int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
98     listCtrl->SetItemPtrData(nIndex, (wxUIntPtr)pdata);
99     listCtrl->SetItem(nIndex, 1, str1);
100     listCtrl->SetItem(nIndex, 2, str2);
101     listCtrl->SetItem(nIndex, 3, str3);
102     listCtrl->SetItem(nIndex, 4, str4);
103     return nIndex;
104 }
105
106 void SetItemTextColour(wxListCtrl* listCtrl, int nIndex, const wxColour& colour)
107 {
108     // Repaint on Windows is more flickery if the colour has ever been set,
109     // so don't want to set it unless it's different.  Default colour has
110     // alpha 0 transparent, so our colours don't match using operator==.
111     wxColour c1 = listCtrl->GetItemTextColour(nIndex);
112     if (colour.Red() != c1.Red() || colour.Green() != c1.Green() || colour.Blue() != c1.Blue())
113         listCtrl->SetItemTextColour(nIndex, colour);
114 }
115
116 void SetSelection(wxListCtrl* listCtrl, int nIndex)
117 {
118     int nSize = listCtrl->GetItemCount();
119     long nState = (wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
120     for (int i = 0; i < nSize; i++)
121         listCtrl->SetItemState(i, (i == nIndex ? nState : 0), nState);
122 }
123
124 int GetSelection(wxListCtrl* listCtrl)
125 {
126     int nSize = listCtrl->GetItemCount();
127     for (int i = 0; i < nSize; i++)
128         if (listCtrl->GetItemState(i, wxLIST_STATE_FOCUSED))
129             return i;
130     return -1;
131 }
132
133 string HtmlEscape(const char* psz, bool fMultiLine=false)
134 {
135     int len = 0;
136     for (const char* p = psz; *p; p++)
137     {
138              if (*p == '<') len += 4;
139         else if (*p == '>') len += 4;
140         else if (*p == '&') len += 5;
141         else if (*p == '"') len += 6;
142         else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') len += 6;
143         else if (*p == '\n' && fMultiLine) len += 5;
144         else
145             len++;
146     }
147     string str;
148     str.reserve(len);
149     for (const char* p = psz; *p; p++)
150     {
151              if (*p == '<') str += "&lt;";
152         else if (*p == '>') str += "&gt;";
153         else if (*p == '&') str += "&amp;";
154         else if (*p == '"') str += "&quot;";
155         else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') str += "&nbsp;";
156         else if (*p == '\n' && fMultiLine) str += "<br>\n";
157         else
158             str += *p;
159     }
160     return str;
161 }
162
163 string HtmlEscape(const string& str, bool fMultiLine=false)
164 {
165     return HtmlEscape(str.c_str(), fMultiLine);
166 }
167
168 void CalledMessageBox(const string& message, const string& caption, int style, wxWindow* parent, int x, int y, int* pnRet, bool* pfDone)
169 {
170     *pnRet = wxMessageBox(message, caption, style, parent, x, y);
171     *pfDone = true;
172 }
173
174 int ThreadSafeMessageBox(const string& message, const string& caption, int style, wxWindow* parent, int x, int y)
175 {
176 #ifdef __WXMSW__
177     return wxMessageBox(message, caption, style, parent, x, y);
178 #else
179     if (wxThread::IsMain() || fDaemon)
180     {
181         return wxMessageBox(message, caption, style, parent, x, y);
182     }
183     else
184     {
185         int nRet = 0;
186         bool fDone = false;
187         UIThreadCall(bind(CalledMessageBox, message, caption, style, parent, x, y, &nRet, &fDone));
188         while (!fDone)
189             Sleep(100);
190         return nRet;
191     }
192 #endif
193 }
194
195 bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* parent)
196 {
197     if (nFeeRequired < CENT || fDaemon)
198         return true;
199     string strMessage = strprintf(
200         _("This transaction is over the size limit.  You can still send it for a fee of %s, "
201           "which goes to the nodes that process your transaction and helps to support the network.  "
202           "Do you want to pay the fee?"),
203         FormatMoney(nFeeRequired).c_str());
204     return (ThreadSafeMessageBox(strMessage, strCaption, wxYES_NO, parent) == wxYES);
205 }
206
207 void CalledSetStatusBar(const string& strText, int nField)
208 {
209     if (nField == 0 && GetWarnings("statusbar") != "")
210         return;
211     if (pframeMain && pframeMain->m_statusBar)
212         pframeMain->m_statusBar->SetStatusText(strText, nField);
213 }
214
215 void SetDefaultReceivingAddress(const string& strAddress)
216 {
217     // Update main window address and database
218     if (pframeMain == NULL)
219         return;
220     if (strAddress != pframeMain->m_textCtrlAddress->GetValue())
221     {
222         uint160 hash160;
223         if (!AddressToHash160(strAddress, hash160))
224             return;
225         if (!mapPubKeys.count(hash160))
226             return;
227         CWalletDB().WriteDefaultKey(mapPubKeys[hash160]);
228         pframeMain->m_textCtrlAddress->SetValue(strAddress);
229     }
230 }
231
232
233
234
235
236
237
238
239
240
241 //////////////////////////////////////////////////////////////////////////////
242 //
243 // CMainFrame
244 //
245
246 CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent)
247 {
248     Connect(wxEVT_UITHREADCALL, wxCommandEventHandler(CMainFrame::OnUIThreadCall), NULL, this);
249
250     // Set initially selected page
251     wxNotebookEvent event;
252     event.SetSelection(0);
253     OnNotebookPageChanged(event);
254     m_notebook->ChangeSelection(0);
255
256     // Init
257     fRefreshListCtrl = false;
258     fRefreshListCtrlRunning = false;
259     fOnSetFocusAddress = false;
260     fRefresh = false;
261     m_choiceFilter->SetSelection(0);
262     double dResize = 1.0;
263 #ifdef __WXMSW__
264     SetIcon(wxICON(bitcoin));
265 #else
266     SetIcon(bitcoin80_xpm);
267     SetBackgroundColour(m_toolBar->GetBackgroundColour());
268     wxFont fontTmp = m_staticText41->GetFont();
269     fontTmp.SetFamily(wxFONTFAMILY_TELETYPE);
270     m_staticTextBalance->SetFont(fontTmp);
271     m_staticTextBalance->SetSize(140, 17);
272     // resize to fit ubuntu's huge default font
273     dResize = 1.22;
274     SetSize(dResize * GetSize().GetWidth(), 1.15 * GetSize().GetHeight());
275 #endif
276     m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + "  ");
277     m_listCtrl->SetFocus();
278     ptaskbaricon = new CMyTaskBarIcon();
279 #ifdef __WXMAC_OSX__
280     // Mac automatically moves wxID_EXIT, wxID_PREFERENCES and wxID_ABOUT
281     // to their standard places, leaving these menus empty.
282     GetMenuBar()->Remove(2); // remove Help menu
283     GetMenuBar()->Remove(0); // remove File menu
284 #endif
285
286     // Init column headers
287     int nDateWidth = DateTimeStr(1229413914).size() * 6 + 8;
288     if (!strstr(DateTimeStr(1229413914).c_str(), "2008"))
289         nDateWidth += 12;
290 #ifdef __WXMAC_OSX__
291     nDateWidth += 5;
292     dResize -= 0.01;
293 #endif
294     wxListCtrl* pplistCtrl[] = {m_listCtrlAll, m_listCtrlSentReceived, m_listCtrlSent, m_listCtrlReceived};
295     foreach(wxListCtrl* p, pplistCtrl)
296     {
297         p->InsertColumn(0, "",               wxLIST_FORMAT_LEFT,  dResize * 0);
298         p->InsertColumn(1, "",               wxLIST_FORMAT_LEFT,  dResize * 0);
299         p->InsertColumn(2, _("Status"),      wxLIST_FORMAT_LEFT,  dResize * 112);
300         p->InsertColumn(3, _("Date"),        wxLIST_FORMAT_LEFT,  dResize * nDateWidth);
301         p->InsertColumn(4, _("Description"), wxLIST_FORMAT_LEFT,  dResize * 409 - nDateWidth);
302         p->InsertColumn(5, _("Debit"),       wxLIST_FORMAT_RIGHT, dResize * 79);
303         p->InsertColumn(6, _("Credit"),      wxLIST_FORMAT_RIGHT, dResize * 79);
304     }
305
306     // Init status bar
307     int pnWidths[3] = { -100, 88, 300 };
308 #ifndef __WXMSW__
309     pnWidths[1] = pnWidths[1] * 1.1 * dResize;
310     pnWidths[2] = pnWidths[2] * 1.1 * dResize;
311 #endif
312     m_statusBar->SetFieldsCount(3, pnWidths);
313
314     // Fill your address text box
315     vector<unsigned char> vchPubKey;
316     if (CWalletDB("r").ReadDefaultKey(vchPubKey))
317         m_textCtrlAddress->SetValue(PubKeyToAddress(vchPubKey));
318
319     // Fill listctrl with wallet transactions
320     RefreshListCtrl();
321 }
322
323 CMainFrame::~CMainFrame()
324 {
325     pframeMain = NULL;
326     delete ptaskbaricon;
327     ptaskbaricon = NULL;
328 }
329
330 void CMainFrame::OnNotebookPageChanged(wxNotebookEvent& event)
331 {
332     event.Skip();
333     nPage = event.GetSelection();
334     if (nPage == ALL)
335     {
336         m_listCtrl = m_listCtrlAll;
337         fShowGenerated = true;
338         fShowSent = true;
339         fShowReceived = true;
340     }
341     else if (nPage == SENTRECEIVED)
342     {
343         m_listCtrl = m_listCtrlSentReceived;
344         fShowGenerated = false;
345         fShowSent = true;
346         fShowReceived = true;
347     }
348     else if (nPage == SENT)
349     {
350         m_listCtrl = m_listCtrlSent;
351         fShowGenerated = false;
352         fShowSent = true;
353         fShowReceived = false;
354     }
355     else if (nPage == RECEIVED)
356     {
357         m_listCtrl = m_listCtrlReceived;
358         fShowGenerated = false;
359         fShowSent = false;
360         fShowReceived = true;
361     }
362     RefreshListCtrl();
363     m_listCtrl->SetFocus();
364 }
365
366 void CMainFrame::OnClose(wxCloseEvent& event)
367 {
368     if (fMinimizeOnClose && event.CanVeto() && !IsIconized())
369     {
370         // Divert close to minimize
371         event.Veto();
372         fClosedToTray = true;
373         Iconize(true);
374     }
375     else
376     {
377         Destroy();
378         CreateThread(Shutdown, NULL);
379     }
380 }
381
382 void CMainFrame::OnIconize(wxIconizeEvent& event)
383 {
384     event.Skip();
385     // Hide the task bar button when minimized.
386     // Event is sent when the frame is minimized or restored.
387     // wxWidgets 2.8.9 doesn't have IsIconized() so there's no way
388     // to get rid of the deprecated warning.  Just ignore it.
389     if (!event.Iconized())
390         fClosedToTray = false;
391 #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
392     if (mapArgs.count("-minimizetotray")) {
393 #endif
394     // The tray icon sometimes disappears on ubuntu karmic
395     // Hiding the taskbar button doesn't work cleanly on ubuntu lucid
396     // Reports of CPU peg on 64-bit linux
397     if (fMinimizeToTray && event.Iconized())
398         fClosedToTray = true;
399     Show(!fClosedToTray);
400     ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
401 #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
402     }
403 #endif
404 }
405
406 void CMainFrame::OnMouseEvents(wxMouseEvent& event)
407 {
408     event.Skip();
409     RandAddSeed();
410     RAND_add(&event.m_x, sizeof(event.m_x), 0.25);
411     RAND_add(&event.m_y, sizeof(event.m_y), 0.25);
412 }
413
414 void CMainFrame::OnListColBeginDrag(wxListEvent& event)
415 {
416     // Hidden columns not resizeable
417     if (event.GetColumn() <= 1 && !fDebug)
418         event.Veto();
419     else
420         event.Skip();
421 }
422
423 int CMainFrame::GetSortIndex(const string& strSort)
424 {
425 #ifdef __WXMSW__
426     return 0;
427 #else
428     // The wx generic listctrl implementation used on GTK doesn't sort,
429     // so we have to do it ourselves.  Remember, we sort in reverse order.
430     // In the wx generic implementation, they store the list of items
431     // in a vector, so indexed lookups are fast, but inserts are slower
432     // the closer they are to the top.
433     int low = 0;
434     int high = m_listCtrl->GetItemCount();
435     while (low < high)
436     {
437         int mid = low + ((high - low) / 2);
438         if (strSort.compare(m_listCtrl->GetItemText(mid).c_str()) >= 0)
439             high = mid;
440         else
441             low = mid + 1;
442     }
443     return low;
444 #endif
445 }
446
447 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)
448 {
449     strSort = " " + strSort;       // leading space to workaround wx2.9.0 ubuntu 9.10 bug
450     long nData = *(long*)&hashKey; //  where first char of hidden column is displayed
451
452     // Find item
453     if (!fNew && nIndex == -1)
454     {
455         string strHash = " " + hashKey.ToString();
456         while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)
457             if (GetItemText(m_listCtrl, nIndex, 1) == strHash)
458                 break;
459     }
460
461     // fNew is for blind insert, only use if you're sure it's new
462     if (fNew || nIndex == -1)
463     {
464         nIndex = m_listCtrl->InsertItem(GetSortIndex(strSort), strSort);
465     }
466     else
467     {
468         // If sort key changed, must delete and reinsert to make it relocate
469         if (GetItemText(m_listCtrl, nIndex, 0) != strSort)
470         {
471             m_listCtrl->DeleteItem(nIndex);
472             nIndex = m_listCtrl->InsertItem(GetSortIndex(strSort), strSort);
473         }
474     }
475
476     m_listCtrl->SetItem(nIndex, 1, " " + hashKey.ToString());
477     m_listCtrl->SetItem(nIndex, 2, str2);
478     m_listCtrl->SetItem(nIndex, 3, str3);
479     m_listCtrl->SetItem(nIndex, 4, str4);
480     m_listCtrl->SetItem(nIndex, 5, str5);
481     m_listCtrl->SetItem(nIndex, 6, str6);
482     m_listCtrl->SetItemData(nIndex, nData);
483     SetItemTextColour(m_listCtrl, nIndex, colour);
484 }
485
486 bool CMainFrame::DeleteLine(uint256 hashKey)
487 {
488     long nData = *(long*)&hashKey;
489
490     // Find item
491     int nIndex = -1;
492     string strHash = " " + hashKey.ToString();
493     while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)
494         if (GetItemText(m_listCtrl, nIndex, 1) == strHash)
495             break;
496
497     if (nIndex != -1)
498         m_listCtrl->DeleteItem(nIndex);
499
500     return nIndex != -1;
501 }
502
503 string FormatTxStatus(const CWalletTx& wtx, bool& fConfirmed)
504 {
505     // Status
506     fConfirmed = false;
507     if (!wtx.IsFinal())
508     {
509         if (wtx.nLockTime < 500000000)
510             return strprintf(_("Open for %d blocks"), nBestHeight - wtx.nLockTime);
511         else
512             return strprintf(_("Open until %s"), DateTimeStr(wtx.nLockTime).c_str());
513     }
514     else
515     {
516         int nDepth = wtx.GetDepthInMainChain();
517         if (nDepth >= 1 || wtx.GetDebit() > 0)
518             fConfirmed = true;
519         if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
520             return strprintf(_("%d/offline?"), nDepth);
521         else if (nDepth < 6)
522             return strprintf(_("%d/unconfirmed"), nDepth);
523         else
524             return strprintf(_("%d confirmations"), nDepth);
525     }
526 }
527
528 string FormatTxStatus(const CWalletTx& wtx)
529 {
530     bool fConfirmed;
531     return FormatTxStatus(wtx, fConfirmed);
532 }
533
534 string SingleLine(const string& strIn)
535 {
536     string strOut;
537     bool fOneSpace = false;
538     foreach(unsigned char c, strIn)
539     {
540         if (isspace(c))
541         {
542             fOneSpace = true;
543         }
544         else if (c > ' ')
545         {
546             if (fOneSpace && !strOut.empty())
547                 strOut += ' ';
548             strOut += c;
549             fOneSpace = false;
550         }
551     }
552     return strOut;
553 }
554
555 bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
556 {
557     int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime();
558     int64 nCredit = wtx.GetCredit(true);
559     int64 nDebit = wtx.GetDebit();
560     int64 nNet = nCredit - nDebit;
561     uint256 hash = wtx.GetHash();
562     bool fConfirmed;
563     string strStatus = FormatTxStatus(wtx, fConfirmed);
564     wtx.fConfirmedDisplayed = fConfirmed;
565     wxColour colour = (fConfirmed ? wxColour(0,0,0) : wxColour(128,128,128));
566     map<string, string> mapValue = wtx.mapValue;
567     wtx.nLinesDisplayed = 1;
568     nListViewUpdated++;
569
570     // Filter
571     if (wtx.IsCoinBase())
572     {
573         // Don't show generated coin until confirmed by at least one block after it
574         // so we don't get the user's hopes up until it looks like it's probably accepted.
575         //
576         // It is not an error when generated blocks are not accepted.  By design,
577         // some percentage of blocks, like 10% or more, will end up not accepted.
578         // This is the normal mechanism by which the network copes with latency.
579         //
580         // We display regular transactions right away before any confirmation
581         // because they can always get into some block eventually.  Generated coins
582         // are special because if their block is not accepted, they are not valid.
583         //
584         if (wtx.GetDepthInMainChain() < 2)
585         {
586             wtx.nLinesDisplayed = 0;
587             return false;
588         }
589
590         if (!fShowGenerated)
591             return false;
592     }
593
594     // Find the block the tx is in
595     CBlockIndex* pindex = NULL;
596     map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(wtx.hashBlock);
597     if (mi != mapBlockIndex.end())
598         pindex = (*mi).second;
599
600     // Sort order, unrecorded transactions sort to the top
601     string strSort = strprintf("%010d-%01d-%010u",
602         (pindex ? pindex->nHeight : INT_MAX),
603         (wtx.IsCoinBase() ? 1 : 0),
604         wtx.nTimeReceived);
605
606     // Insert line
607     if (nNet > 0 || wtx.IsCoinBase())
608     {
609         //
610         // Credit
611         //
612         string strDescription;
613         if (wtx.IsCoinBase())
614         {
615             // Generated
616             strDescription = _("Generated");
617             if (nCredit == 0)
618             {
619                 int64 nUnmatured = 0;
620                 foreach(const CTxOut& txout, wtx.vout)
621                     nUnmatured += txout.GetCredit();
622                 if (wtx.IsInMainChain())
623                 {
624                     strDescription = strprintf(_("Generated (%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
625
626                     // Check if the block was requested by anyone
627                     if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
628                         strDescription = _("Generated - Warning: This block was not received by any other nodes and will probably not be accepted!");
629                 }
630                 else
631                 {
632                     strDescription = _("Generated (not accepted)");
633                 }
634             }
635         }
636         else if (!mapValue["from"].empty() || !mapValue["message"].empty())
637         {
638             // Received by IP connection
639             if (!fShowReceived)
640                 return false;
641             if (!mapValue["from"].empty())
642                 strDescription += _("From: ") + mapValue["from"];
643             if (!mapValue["message"].empty())
644             {
645                 if (!strDescription.empty())
646                     strDescription += " - ";
647                 strDescription += mapValue["message"];
648             }
649         }
650         else
651         {
652             // Received by Bitcoin Address
653             if (!fShowReceived)
654                 return false;
655             foreach(const CTxOut& txout, wtx.vout)
656             {
657                 if (txout.IsMine())
658                 {
659                     vector<unsigned char> vchPubKey;
660                     if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
661                     {
662                         CRITICAL_BLOCK(cs_mapAddressBook)
663                         {
664                             //strDescription += _("Received payment to ");
665                             //strDescription += _("Received with address ");
666                             strDescription += _("Received with: ");
667                             string strAddress = PubKeyToAddress(vchPubKey);
668                             map<string, string>::iterator mi = mapAddressBook.find(strAddress);
669                             if (mi != mapAddressBook.end() && !(*mi).second.empty())
670                             {
671                                 string strLabel = (*mi).second;
672                                 strDescription += strAddress.substr(0,12) + "... ";
673                                 strDescription += "(" + strLabel + ")";
674                             }
675                             else
676                                 strDescription += strAddress;
677                         }
678                     }
679                     break;
680                 }
681             }
682         }
683
684         string strCredit = FormatMoney(nNet, true);
685         if (!fConfirmed)
686             strCredit = "[" + strCredit + "]";
687
688         InsertLine(fNew, nIndex, hash, strSort, colour,
689                    strStatus,
690                    nTime ? DateTimeStr(nTime) : "",
691                    SingleLine(strDescription),
692                    "",
693                    strCredit);
694     }
695     else
696     {
697         bool fAllFromMe = true;
698         foreach(const CTxIn& txin, wtx.vin)
699             fAllFromMe = fAllFromMe && txin.IsMine();
700
701         bool fAllToMe = true;
702         foreach(const CTxOut& txout, wtx.vout)
703             fAllToMe = fAllToMe && txout.IsMine();
704
705         if (fAllFromMe && fAllToMe)
706         {
707             // Payment to self
708             int64 nValue = wtx.vout[0].nValue;
709             InsertLine(fNew, nIndex, hash, strSort, colour,
710                        strStatus,
711                        nTime ? DateTimeStr(nTime) : "",
712                        _("Payment to yourself"),
713                        "",
714                        "");
715             /// issue: can't tell which is the payment and which is the change anymore
716             //           FormatMoney(nNet - nValue, true),
717             //           FormatMoney(nValue, true));
718         }
719         else if (fAllFromMe)
720         {
721             //
722             // Debit
723             //
724             if (!fShowSent)
725                 return false;
726
727             int64 nTxFee = nDebit - wtx.GetValueOut();
728             wtx.nLinesDisplayed = 0;
729             for (int nOut = 0; nOut < wtx.vout.size(); nOut++)
730             {
731                 const CTxOut& txout = wtx.vout[nOut];
732                 if (txout.IsMine())
733                     continue;
734
735                 string strAddress;
736                 if (!mapValue["to"].empty())
737                 {
738                     // Sent to IP
739                     strAddress = mapValue["to"];
740                 }
741                 else
742                 {
743                     // Sent to Bitcoin Address
744                     uint160 hash160;
745                     if (ExtractHash160(txout.scriptPubKey, hash160))
746                         strAddress = Hash160ToAddress(hash160);
747                 }
748
749                 string strDescription = _("To: ");
750                 CRITICAL_BLOCK(cs_mapAddressBook)
751                     if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
752                         strDescription += mapAddressBook[strAddress] + " ";
753                 strDescription += strAddress;
754                 if (!mapValue["message"].empty())
755                 {
756                     if (!strDescription.empty())
757                         strDescription += " - ";
758                     strDescription += mapValue["message"];
759                 }
760
761                 int64 nValue = txout.nValue;
762                 if (nTxFee > 0)
763                 {
764                     nValue += nTxFee;
765                     nTxFee = 0;
766                 }
767
768                 InsertLine(fNew, nIndex, hash, strprintf("%s-%d", strSort.c_str(), nOut), colour,
769                            strStatus,
770                            nTime ? DateTimeStr(nTime) : "",
771                            SingleLine(strDescription),
772                            FormatMoney(-nValue, true),
773                            "");
774                 wtx.nLinesDisplayed++;
775             }
776         }
777         else
778         {
779             //
780             // Mixed debit transaction, can't break down payees
781             //
782             bool fAllMine = true;
783             foreach(const CTxOut& txout, wtx.vout)
784                 fAllMine = fAllMine && txout.IsMine();
785             foreach(const CTxIn& txin, wtx.vin)
786                 fAllMine = fAllMine && txin.IsMine();
787
788             InsertLine(fNew, nIndex, hash, strSort, colour,
789                        strStatus,
790                        nTime ? DateTimeStr(nTime) : "",
791                        "",
792                        FormatMoney(nNet, true),
793                        "");
794         }
795     }
796
797     return true;
798 }
799
800 void CMainFrame::RefreshListCtrl()
801 {
802     fRefreshListCtrl = true;
803     ::wxWakeUpIdle();
804 }
805
806 void CMainFrame::OnIdle(wxIdleEvent& event)
807 {
808     if (fRefreshListCtrl)
809     {
810         // Collect list of wallet transactions and sort newest first
811         bool fEntered = false;
812         vector<pair<unsigned int, uint256> > vSorted;
813         TRY_CRITICAL_BLOCK(cs_mapWallet)
814         {
815             printf("RefreshListCtrl starting\n");
816             fEntered = true;
817             fRefreshListCtrl = false;
818             vWalletUpdated.clear();
819
820             // Do the newest transactions first
821             vSorted.reserve(mapWallet.size());
822             for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
823             {
824                 const CWalletTx& wtx = (*it).second;
825                 unsigned int nTime = UINT_MAX - wtx.GetTxTime();
826                 vSorted.push_back(make_pair(nTime, (*it).first));
827             }
828             m_listCtrl->DeleteAllItems();
829         }
830         if (!fEntered)
831             return;
832
833         sort(vSorted.begin(), vSorted.end());
834
835         // Fill list control
836         for (int i = 0; i < vSorted.size();)
837         {
838             if (fShutdown)
839                 return;
840             bool fEntered = false;
841             TRY_CRITICAL_BLOCK(cs_mapWallet)
842             {
843                 fEntered = true;
844                 uint256& hash = vSorted[i++].second;
845                 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
846                 if (mi != mapWallet.end())
847                     InsertTransaction((*mi).second, true);
848             }
849             if (!fEntered || i == 100 || i % 500 == 0)
850                 wxYield();
851         }
852
853         printf("RefreshListCtrl done\n");
854
855         // Update transaction total display
856         MainFrameRepaint();
857     }
858     else
859     {
860         // Check for time updates
861         static int64 nLastTime;
862         if (GetTime() > nLastTime + 30)
863         {
864             TRY_CRITICAL_BLOCK(cs_mapWallet)
865             {
866                 nLastTime = GetTime();
867                 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
868                 {
869                     CWalletTx& wtx = (*it).second;
870                     if (wtx.nTimeDisplayed && wtx.nTimeDisplayed != wtx.GetTxTime())
871                         InsertTransaction(wtx, false);
872                 }
873             }
874         }
875     }
876 }
877
878 void CMainFrame::RefreshStatusColumn()
879 {
880     static int nLastTop;
881     static CBlockIndex* pindexLastBest;
882     static unsigned int nLastRefreshed;
883
884     int nTop = max((int)m_listCtrl->GetTopItem(), 0);
885     if (nTop == nLastTop && pindexLastBest == pindexBest)
886         return;
887
888     TRY_CRITICAL_BLOCK(cs_mapWallet)
889     {
890         int nStart = nTop;
891         int nEnd = min(nStart + 100, m_listCtrl->GetItemCount());
892
893         if (pindexLastBest == pindexBest && nLastRefreshed == nListViewUpdated)
894         {
895             // If no updates, only need to do the part that moved onto the screen
896             if (nStart >= nLastTop && nStart < nLastTop + 100)
897                 nStart = nLastTop + 100;
898             if (nEnd >= nLastTop && nEnd < nLastTop + 100)
899                 nEnd = nLastTop;
900         }
901         nLastTop = nTop;
902         pindexLastBest = pindexBest;
903         nLastRefreshed = nListViewUpdated;
904
905         for (int nIndex = nStart; nIndex < min(nEnd, m_listCtrl->GetItemCount()); nIndex++)
906         {
907             uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1));
908             map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
909             if (mi == mapWallet.end())
910             {
911                 printf("CMainFrame::RefreshStatusColumn() : tx not found in mapWallet\n");
912                 continue;
913             }
914             CWalletTx& wtx = (*mi).second;
915             bool fConfirmed;
916             string strStatus = FormatTxStatus(wtx, fConfirmed);
917             if (wtx.IsCoinBase() || wtx.GetTxTime() != wtx.nTimeDisplayed || fConfirmed != wtx.fConfirmedDisplayed)
918             {
919                 if (!InsertTransaction(wtx, false, nIndex))
920                     m_listCtrl->DeleteItem(nIndex--);
921             }
922             else
923             {
924                 m_listCtrl->SetItem(nIndex, 2, strStatus);
925             }
926         }
927     }
928 }
929
930 void CMainFrame::OnPaint(wxPaintEvent& event)
931 {
932     event.Skip();
933     if (fRefresh)
934     {
935         fRefresh = false;
936         Refresh();
937     }
938 }
939
940
941 unsigned int nNeedRepaint = 0;
942 unsigned int nLastRepaint = 0;
943 int64 nLastRepaintTime = 0;
944 int64 nRepaintInterval = 500;
945
946 void ThreadDelayedRepaint(void* parg)
947 {
948     while (!fShutdown)
949     {
950         if (nLastRepaint != nNeedRepaint && GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)
951         {
952             nLastRepaint = nNeedRepaint;
953             if (pframeMain)
954             {
955                 printf("DelayedRepaint\n");
956                 wxPaintEvent event;
957                 pframeMain->fRefresh = true;
958                 pframeMain->GetEventHandler()->AddPendingEvent(event);
959             }
960         }
961         Sleep(nRepaintInterval);
962     }
963 }
964
965 void MainFrameRepaint()
966 {
967     // This is called by network code that shouldn't access pframeMain
968     // directly because it could still be running after the UI is closed.
969     if (pframeMain)
970     {
971         // Don't repaint too often
972         static int64 nLastRepaintRequest;
973         if (GetTimeMillis() - nLastRepaintRequest < 100)
974         {
975             nNeedRepaint++;
976             return;
977         }
978         nLastRepaintRequest = GetTimeMillis();
979
980         printf("MainFrameRepaint\n");
981         wxPaintEvent event;
982         pframeMain->fRefresh = true;
983         pframeMain->GetEventHandler()->AddPendingEvent(event);
984     }
985 }
986
987 void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
988 {
989     // Skip lets the listctrl do the paint, we're just hooking the message
990     event.Skip();
991
992     if (ptaskbaricon)
993         ptaskbaricon->UpdateTooltip();
994
995     //
996     // Slower stuff
997     //
998     static int nTransactionCount;
999     bool fPaintedBalance = false;
1000     if (GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)
1001     {
1002         nLastRepaint = nNeedRepaint;
1003         nLastRepaintTime = GetTimeMillis();
1004
1005         // Update listctrl contents
1006         if (!vWalletUpdated.empty())
1007         {
1008             TRY_CRITICAL_BLOCK(cs_mapWallet)
1009             {
1010                 string strTop;
1011                 if (m_listCtrl->GetItemCount())
1012                     strTop = (string)m_listCtrl->GetItemText(0);
1013                 foreach(uint256 hash, vWalletUpdated)
1014                 {
1015                     map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
1016                     if (mi != mapWallet.end())
1017                         InsertTransaction((*mi).second, false);
1018                 }
1019                 vWalletUpdated.clear();
1020                 if (m_listCtrl->GetItemCount() && strTop != (string)m_listCtrl->GetItemText(0))
1021                     m_listCtrl->ScrollList(0, INT_MIN/2);
1022             }
1023         }
1024
1025         // Balance total
1026         TRY_CRITICAL_BLOCK(cs_mapWallet)
1027         {
1028             fPaintedBalance = true;
1029             m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + "  ");
1030
1031             // Count hidden and multi-line transactions
1032             nTransactionCount = 0;
1033             for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
1034             {
1035                 CWalletTx& wtx = (*it).second;
1036                 nTransactionCount += wtx.nLinesDisplayed;
1037             }
1038         }
1039     }
1040     if (!vWalletUpdated.empty() || !fPaintedBalance)
1041         nNeedRepaint++;
1042
1043     // Update status column of visible items only
1044     RefreshStatusColumn();
1045
1046     // Update status bar
1047     static string strPrevWarning;
1048     string strWarning = GetWarnings("statusbar");
1049     if (strWarning != "")
1050         m_statusBar->SetStatusText(string("    ") + _(strWarning), 0);
1051     else if (strPrevWarning != "")
1052         m_statusBar->SetStatusText("", 0);
1053     strPrevWarning = strWarning;
1054
1055     string strGen = "";
1056     if (fGenerateBitcoins)
1057         strGen = _("    Generating");
1058     if (fGenerateBitcoins && vNodes.empty())
1059         strGen = _("(not connected)");
1060     m_statusBar->SetStatusText(strGen, 1);
1061
1062     string strStatus = strprintf(_("     %d connections     %d blocks     %d transactions"), vNodes.size(), nBestHeight, nTransactionCount);
1063     m_statusBar->SetStatusText(strStatus, 2);
1064
1065     // Update receiving address
1066     string strDefaultAddress = PubKeyToAddress(vchDefaultKey);
1067     if (m_textCtrlAddress->GetValue() != strDefaultAddress)
1068         m_textCtrlAddress->SetValue(strDefaultAddress);
1069 }
1070
1071
1072 void UIThreadCall(boost::function0<void> fn)
1073 {
1074     // Call this with a function object created with bind.
1075     // bind needs all parameters to match the function's expected types
1076     // and all default parameters specified.  Some examples:
1077     //  UIThreadCall(bind(wxBell));
1078     //  UIThreadCall(bind(wxMessageBox, wxT("Message"), wxT("Title"), wxOK, (wxWindow*)NULL, -1, -1));
1079     //  UIThreadCall(bind(&CMainFrame::OnMenuHelpAbout, pframeMain, event));
1080     if (pframeMain)
1081     {
1082         wxCommandEvent event(wxEVT_UITHREADCALL);
1083         event.SetClientData((void*)new boost::function0<void>(fn));
1084         pframeMain->GetEventHandler()->AddPendingEvent(event);
1085     }
1086 }
1087
1088 void CMainFrame::OnUIThreadCall(wxCommandEvent& event)
1089 {
1090     boost::function0<void>* pfn = (boost::function0<void>*)event.GetClientData();
1091     (*pfn)();
1092     delete pfn;
1093 }
1094
1095 void CMainFrame::OnMenuFileExit(wxCommandEvent& event)
1096 {
1097     // File->Exit
1098     Close(true);
1099 }
1100
1101 void CMainFrame::OnMenuOptionsGenerate(wxCommandEvent& event)
1102 {
1103     // Options->Generate Coins
1104     GenerateBitcoins(event.IsChecked());
1105 }
1106
1107 void CMainFrame::OnUpdateUIOptionsGenerate(wxUpdateUIEvent& event)
1108 {
1109     event.Check(fGenerateBitcoins);
1110 }
1111
1112 void CMainFrame::OnMenuOptionsChangeYourAddress(wxCommandEvent& event)
1113 {
1114     // Options->Your Receiving Addresses
1115     CAddressBookDialog dialog(this, "", CAddressBookDialog::RECEIVING, false);
1116     if (!dialog.ShowModal())
1117         return;
1118 }
1119
1120 void CMainFrame::OnMenuOptionsOptions(wxCommandEvent& event)
1121 {
1122     // Options->Options
1123     COptionsDialog dialog(this);
1124     dialog.ShowModal();
1125 }
1126
1127 void CMainFrame::OnMenuHelpAbout(wxCommandEvent& event)
1128 {
1129     // Help->About
1130     CAboutDialog dialog(this);
1131     dialog.ShowModal();
1132 }
1133
1134 void CMainFrame::OnButtonSend(wxCommandEvent& event)
1135 {
1136     // Toolbar: Send
1137     CSendDialog dialog(this);
1138     dialog.ShowModal();
1139 }
1140
1141 void CMainFrame::OnButtonAddressBook(wxCommandEvent& event)
1142 {
1143     // Toolbar: Address Book
1144     CAddressBookDialog dialogAddr(this, "", CAddressBookDialog::SENDING, false);
1145     if (dialogAddr.ShowModal() == 2)
1146     {
1147         // Send
1148         CSendDialog dialogSend(this, dialogAddr.GetSelectedAddress());
1149         dialogSend.ShowModal();
1150     }
1151 }
1152
1153 void CMainFrame::OnSetFocusAddress(wxFocusEvent& event)
1154 {
1155     // Automatically select-all when entering window
1156     event.Skip();
1157     m_textCtrlAddress->SetSelection(-1, -1);
1158     fOnSetFocusAddress = true;
1159 }
1160
1161 void CMainFrame::OnMouseEventsAddress(wxMouseEvent& event)
1162 {
1163     event.Skip();
1164     if (fOnSetFocusAddress)
1165         m_textCtrlAddress->SetSelection(-1, -1);
1166     fOnSetFocusAddress = false;
1167 }
1168
1169 void CMainFrame::OnButtonNew(wxCommandEvent& event)
1170 {
1171     // Ask name
1172     CGetTextFromUserDialog dialog(this,
1173         _("New Receiving Address"),
1174         _("You should use a new address for each payment you receive.\n\nLabel"),
1175         "");
1176     if (!dialog.ShowModal())
1177         return;
1178     string strName = dialog.GetValue();
1179
1180     // Generate new key
1181     string strAddress = PubKeyToAddress(GenerateNewKey());
1182
1183     // Save
1184     SetAddressBookName(strAddress, strName);
1185     SetDefaultReceivingAddress(strAddress);
1186 }
1187
1188 void CMainFrame::OnButtonCopy(wxCommandEvent& event)
1189 {
1190     // Copy address box to clipboard
1191     if (wxTheClipboard->Open())
1192     {
1193         wxTheClipboard->SetData(new wxTextDataObject(m_textCtrlAddress->GetValue()));
1194         wxTheClipboard->Close();
1195     }
1196 }
1197
1198 void CMainFrame::OnListItemActivated(wxListEvent& event)
1199 {
1200     uint256 hash((string)GetItemText(m_listCtrl, event.GetIndex(), 1));
1201     CWalletTx wtx;
1202     CRITICAL_BLOCK(cs_mapWallet)
1203     {
1204         map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
1205         if (mi == mapWallet.end())
1206         {
1207             printf("CMainFrame::OnListItemActivated() : tx not found in mapWallet\n");
1208             return;
1209         }
1210         wtx = (*mi).second;
1211     }
1212     CTxDetailsDialog dialog(this, wtx);
1213     dialog.ShowModal();
1214     //CTxDetailsDialog* pdialog = new CTxDetailsDialog(this, wtx);
1215     //pdialog->Show();
1216 }
1217
1218
1219
1220
1221
1222
1223 //////////////////////////////////////////////////////////////////////////////
1224 //
1225 // CTxDetailsDialog
1226 //
1227
1228 CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetailsDialogBase(parent)
1229 {
1230     CRITICAL_BLOCK(cs_mapAddressBook)
1231     {
1232         string strHTML;
1233         strHTML.reserve(4000);
1234         strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
1235
1236         int64 nTime = wtx.GetTxTime();
1237         int64 nCredit = wtx.GetCredit();
1238         int64 nDebit = wtx.GetDebit();
1239         int64 nNet = nCredit - nDebit;
1240
1241
1242
1243         strHTML += _("<b>Status:</b> ") + FormatTxStatus(wtx);
1244         int nRequests = wtx.GetRequestCount();
1245         if (nRequests != -1)
1246         {
1247             if (nRequests == 0)
1248                 strHTML += _(", has not been successfully broadcast yet");
1249             else if (nRequests == 1)
1250                 strHTML += strprintf(_(", broadcast through %d node"), nRequests);
1251             else
1252                 strHTML += strprintf(_(", broadcast through %d nodes"), nRequests);
1253         }
1254         strHTML += "<br>";
1255
1256         strHTML += _("<b>Date:</b> ") + (nTime ? DateTimeStr(nTime) : "") + "<br>";
1257
1258
1259         //
1260         // From
1261         //
1262         if (wtx.IsCoinBase())
1263         {
1264             strHTML += _("<b>Source:</b> Generated<br>");
1265         }
1266         else if (!wtx.mapValue["from"].empty())
1267         {
1268             // Online transaction
1269             if (!wtx.mapValue["from"].empty())
1270                 strHTML += _("<b>From:</b> ") + HtmlEscape(wtx.mapValue["from"]) + "<br>";
1271         }
1272         else
1273         {
1274             // Offline transaction
1275             if (nNet > 0)
1276             {
1277                 // Credit
1278                 foreach(const CTxOut& txout, wtx.vout)
1279                 {
1280                     if (txout.IsMine())
1281                     {
1282                         vector<unsigned char> vchPubKey;
1283                         if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
1284                         {
1285                             string strAddress = PubKeyToAddress(vchPubKey);
1286                             if (mapAddressBook.count(strAddress))
1287                             {
1288                                 strHTML += string() + _("<b>From:</b> ") + _("unknown") + "<br>";
1289                                 strHTML += _("<b>To:</b> ");
1290                                 strHTML += HtmlEscape(strAddress);
1291                                 if (!mapAddressBook[strAddress].empty())
1292                                     strHTML += _(" (yours, label: ") + mapAddressBook[strAddress] + ")";
1293                                 else
1294                                     strHTML += _(" (yours)");
1295                                 strHTML += "<br>";
1296                             }
1297                         }
1298                         break;
1299                     }
1300                 }
1301             }
1302         }
1303
1304
1305         //
1306         // To
1307         //
1308         string strAddress;
1309         if (!wtx.mapValue["to"].empty())
1310         {
1311             // Online transaction
1312             strAddress = wtx.mapValue["to"];
1313             strHTML += _("<b>To:</b> ");
1314             if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
1315                 strHTML += mapAddressBook[strAddress] + " ";
1316             strHTML += HtmlEscape(strAddress) + "<br>";
1317         }
1318
1319
1320         //
1321         // Amount
1322         //
1323         if (wtx.IsCoinBase() && nCredit == 0)
1324         {
1325             //
1326             // Coinbase
1327             //
1328             int64 nUnmatured = 0;
1329             foreach(const CTxOut& txout, wtx.vout)
1330                 nUnmatured += txout.GetCredit();
1331             strHTML += _("<b>Credit:</b> ");
1332             if (wtx.IsInMainChain())
1333                 strHTML += strprintf(_("(%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
1334             else
1335                 strHTML += _("(not accepted)");
1336             strHTML += "<br>";
1337         }
1338         else if (nNet > 0)
1339         {
1340             //
1341             // Credit
1342             //
1343             strHTML += _("<b>Credit:</b> ") + FormatMoney(nNet) + "<br>";
1344         }
1345         else
1346         {
1347             bool fAllFromMe = true;
1348             foreach(const CTxIn& txin, wtx.vin)
1349                 fAllFromMe = fAllFromMe && txin.IsMine();
1350
1351             bool fAllToMe = true;
1352             foreach(const CTxOut& txout, wtx.vout)
1353                 fAllToMe = fAllToMe && txout.IsMine();
1354
1355             if (fAllFromMe)
1356             {
1357                 //
1358                 // Debit
1359                 //
1360                 foreach(const CTxOut& txout, wtx.vout)
1361                 {
1362                     if (txout.IsMine())
1363                         continue;
1364
1365                     if (wtx.mapValue["to"].empty())
1366                     {
1367                         // Offline transaction
1368                         uint160 hash160;
1369                         if (ExtractHash160(txout.scriptPubKey, hash160))
1370                         {
1371                             string strAddress = Hash160ToAddress(hash160);
1372                             strHTML += _("<b>To:</b> ");
1373                             if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
1374                                 strHTML += mapAddressBook[strAddress] + " ";
1375                             strHTML += strAddress;
1376                             strHTML += "<br>";
1377                         }
1378                     }
1379
1380                     strHTML += _("<b>Debit:</b> ") + FormatMoney(-txout.nValue) + "<br>";
1381                 }
1382
1383                 if (fAllToMe)
1384                 {
1385                     // Payment to self
1386                     /// issue: can't tell which is the payment and which is the change anymore
1387                     //int64 nValue = wtx.vout[0].nValue;
1388                     //strHTML += _("<b>Debit:</b> ") + FormatMoney(-nValue) + "<br>";
1389                     //strHTML += _("<b>Credit:</b> ") + FormatMoney(nValue) + "<br>";
1390                 }
1391
1392                 int64 nTxFee = nDebit - wtx.GetValueOut();
1393                 if (nTxFee > 0)
1394                     strHTML += _("<b>Transaction fee:</b> ") + FormatMoney(-nTxFee) + "<br>";
1395             }
1396             else
1397             {
1398                 //
1399                 // Mixed debit transaction
1400                 //
1401                 foreach(const CTxIn& txin, wtx.vin)
1402                     if (txin.IsMine())
1403                         strHTML += _("<b>Debit:</b> ") + FormatMoney(-txin.GetDebit()) + "<br>";
1404                 foreach(const CTxOut& txout, wtx.vout)
1405                     if (txout.IsMine())
1406                         strHTML += _("<b>Credit:</b> ") + FormatMoney(txout.GetCredit()) + "<br>";
1407             }
1408         }
1409
1410         strHTML += _("<b>Net amount:</b> ") + FormatMoney(nNet, true) + "<br>";
1411
1412
1413         //
1414         // Message
1415         //
1416         if (!wtx.mapValue["message"].empty())
1417             strHTML += string() + "<br><b>" + _("Message:") + "</b><br>" + HtmlEscape(wtx.mapValue["message"], true) + "<br>";
1418
1419         if (wtx.IsCoinBase())
1420             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>";
1421
1422
1423         //
1424         // Debug view
1425         //
1426         if (fDebug)
1427         {
1428             strHTML += "<hr><br>debug print<br><br>";
1429             foreach(const CTxIn& txin, wtx.vin)
1430                 if (txin.IsMine())
1431                     strHTML += "<b>Debit:</b> " + FormatMoney(-txin.GetDebit()) + "<br>";
1432             foreach(const CTxOut& txout, wtx.vout)
1433                 if (txout.IsMine())
1434                     strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";
1435
1436             strHTML += "<b>Inputs:</b><br>";
1437             CRITICAL_BLOCK(cs_mapWallet)
1438             {
1439                 foreach(const CTxIn& txin, wtx.vin)
1440                 {
1441                     COutPoint prevout = txin.prevout;
1442                     map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
1443                     if (mi != mapWallet.end())
1444                     {
1445                         const CWalletTx& prev = (*mi).second;
1446                         if (prevout.n < prev.vout.size())
1447                         {
1448                             strHTML += HtmlEscape(prev.ToString(), true);
1449                             strHTML += " &nbsp;&nbsp; " + FormatTxStatus(prev) + ", ";
1450                             strHTML = strHTML + "IsMine=" + (prev.vout[prevout.n].IsMine() ? "true" : "false") + "<br>";
1451                         }
1452                     }
1453                 }
1454             }
1455
1456             strHTML += "<br><hr><br><b>Transaction:</b><br>";
1457             strHTML += HtmlEscape(wtx.ToString(), true);
1458         }
1459
1460
1461
1462         strHTML += "</font></html>";
1463         string(strHTML.begin(), strHTML.end()).swap(strHTML);
1464         m_htmlWin->SetPage(strHTML);
1465         m_buttonOK->SetFocus();
1466     }
1467 }
1468
1469 void CTxDetailsDialog::OnButtonOK(wxCommandEvent& event)
1470 {
1471     Close();
1472     //Destroy();
1473 }
1474
1475
1476
1477
1478
1479
1480 //////////////////////////////////////////////////////////////////////////////
1481 //
1482 // Startup folder
1483 //
1484
1485 #ifdef __WXMSW__
1486 string StartupShortcutPath()
1487 {
1488     return MyGetSpecialFolderPath(CSIDL_STARTUP, true) + "\\Bitcoin.lnk";
1489 }
1490
1491 bool GetStartOnSystemStartup()
1492 {
1493     return filesystem::exists(StartupShortcutPath().c_str());
1494 }
1495
1496 void SetStartOnSystemStartup(bool fAutoStart)
1497 {
1498     // If the shortcut exists already, remove it for updating
1499     remove(StartupShortcutPath().c_str());
1500
1501     if (fAutoStart)
1502     {
1503         CoInitialize(NULL);
1504
1505         // Get a pointer to the IShellLink interface.
1506         IShellLink* psl = NULL;
1507         HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
1508                                 CLSCTX_INPROC_SERVER, IID_IShellLink,
1509                                 reinterpret_cast<void**>(&psl));
1510
1511         if (SUCCEEDED(hres))
1512         {
1513             // Get the current executable path
1514             TCHAR pszExePath[MAX_PATH];
1515             GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));
1516
1517             // Set the path to the shortcut target
1518             psl->SetPath(pszExePath);
1519             PathRemoveFileSpec(pszExePath);
1520             psl->SetWorkingDirectory(pszExePath);
1521             psl->SetShowCmd(SW_SHOWMINNOACTIVE);
1522
1523             // Query IShellLink for the IPersistFile interface for
1524             // saving the shortcut in persistent storage.
1525             IPersistFile* ppf = NULL;
1526             hres = psl->QueryInterface(IID_IPersistFile,
1527                                        reinterpret_cast<void**>(&ppf));
1528             if (SUCCEEDED(hres))
1529             {
1530                 WCHAR pwsz[MAX_PATH];
1531                 // Ensure that the string is ANSI.
1532                 MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().c_str(), -1, pwsz, MAX_PATH);
1533                 // Save the link by calling IPersistFile::Save.
1534                 hres = ppf->Save(pwsz, TRUE);
1535                 ppf->Release();
1536             }
1537             psl->Release();
1538         }
1539         CoUninitialize();
1540     }
1541 }
1542
1543 #elif defined(__WXGTK__)
1544
1545 // Follow the Desktop Application Autostart Spec:
1546 //  http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
1547
1548 boost::filesystem::path GetAutostartDir()
1549 {
1550     namespace fs = boost::filesystem;
1551
1552     char* pszConfigHome = getenv("XDG_CONFIG_HOME");
1553     if (pszConfigHome) return fs::path(pszConfigHome) / fs::path("autostart");
1554     char* pszHome = getenv("HOME");
1555     if (pszHome) return fs::path(pszHome) / fs::path(".config/autostart");
1556     return fs::path();
1557 }
1558
1559 boost::filesystem::path GetAutostartFilePath()
1560 {
1561     return GetAutostartDir() / boost::filesystem::path("bitcoin.desktop");
1562 }
1563
1564 bool GetStartOnSystemStartup()
1565 {
1566     boost::filesystem::ifstream optionFile(GetAutostartFilePath());
1567     if (!optionFile.good())
1568         return false;
1569     // Scan through file for "Hidden=true":
1570     string line;
1571     while (!optionFile.eof())
1572     {
1573         getline(optionFile, line);
1574         if (line.find("Hidden") != string::npos &&
1575             line.find("true") != string::npos)
1576             return false;
1577     }
1578     optionFile.close();
1579
1580     return true;
1581 }
1582
1583 void SetStartOnSystemStartup(bool fAutoStart)
1584 {
1585     if (!fAutoStart)
1586     {
1587         unlink(GetAutostartFilePath().native_file_string().c_str());
1588     }
1589     else
1590     {
1591         char pszExePath[MAX_PATH+1];
1592         memset(pszExePath, 0, sizeof(pszExePath));
1593         if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1)
1594             return;
1595
1596         boost::filesystem::create_directories(GetAutostartDir());
1597
1598         boost::filesystem::ofstream optionFile(GetAutostartFilePath(), ios_base::out|ios_base::trunc);
1599         if (!optionFile.good())
1600         {
1601             wxMessageBox(_("Cannot write autostart/bitcoin.desktop file"), "Bitcoin");
1602             return;
1603         }
1604         // Write a bitcoin.desktop file to the autostart directory:
1605         optionFile << "[Desktop Entry]\n";
1606         optionFile << "Type=Application\n";
1607         optionFile << "Name=Bitcoin\n";
1608         optionFile << "Exec=" << pszExePath << "\n";
1609         optionFile << "Terminal=false\n";
1610         optionFile << "Hidden=false\n";
1611         optionFile.close();
1612     }
1613 }
1614 #else
1615
1616 // TODO: OSX startup stuff; see:
1617 // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html
1618
1619 bool GetStartOnSystemStartup() { return false; }
1620 void SetStartOnSystemStartup(bool fAutoStart) { }
1621
1622 #endif
1623
1624
1625
1626
1627
1628
1629 //////////////////////////////////////////////////////////////////////////////
1630 //
1631 // COptionsDialog
1632 //
1633
1634 COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent)
1635 {
1636     // Set up list box of page choices
1637     m_listBox->Append(_("Main"));
1638     //m_listBox->Append(_("Test 2"));
1639     m_listBox->SetSelection(0);
1640     SelectPage(0);
1641 #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
1642     m_checkBoxStartOnSystemStartup->SetLabel(_("&Start Bitcoin on window system startup"));
1643     if (!mapArgs.count("-minimizetotray"))
1644     {
1645         // Minimize to tray is just too buggy on Linux
1646         fMinimizeToTray = false;
1647         m_checkBoxMinimizeToTray->SetValue(false);
1648         m_checkBoxMinimizeToTray->Enable(false);
1649         m_checkBoxMinimizeOnClose->SetLabel(_("&Minimize on close"));
1650     }
1651 #endif
1652 #ifdef __WXMAC_OSX__
1653     m_checkBoxStartOnSystemStartup->Enable(false); // not implemented yet
1654 #endif
1655
1656     // Init values
1657     m_textCtrlTransactionFee->SetValue(FormatMoney(nTransactionFee));
1658     m_checkBoxLimitProcessors->SetValue(fLimitProcessors);
1659     m_spinCtrlLimitProcessors->Enable(fLimitProcessors);
1660     m_spinCtrlLimitProcessors->SetValue(nLimitProcessors);
1661     int nProcessors = wxThread::GetCPUCount();
1662     if (nProcessors < 1)
1663         nProcessors = 999;
1664     m_spinCtrlLimitProcessors->SetRange(1, nProcessors);
1665     m_checkBoxStartOnSystemStartup->SetValue(fTmpStartOnSystemStartup = GetStartOnSystemStartup());
1666     m_checkBoxMinimizeToTray->SetValue(fMinimizeToTray);
1667     m_checkBoxMinimizeOnClose->SetValue(fMinimizeOnClose);
1668     m_checkBoxUseProxy->SetValue(fUseProxy);
1669     m_textCtrlProxyIP->Enable(fUseProxy);
1670     m_textCtrlProxyPort->Enable(fUseProxy);
1671     m_staticTextProxyIP->Enable(fUseProxy);
1672     m_staticTextProxyPort->Enable(fUseProxy);
1673     m_textCtrlProxyIP->SetValue(addrProxy.ToStringIP());
1674     m_textCtrlProxyPort->SetValue(addrProxy.ToStringPort());
1675
1676     m_buttonOK->SetFocus();
1677 }
1678
1679 void COptionsDialog::SelectPage(int nPage)
1680 {
1681     m_panelMain->Show(nPage == 0);
1682     m_panelTest2->Show(nPage == 1);
1683
1684     m_scrolledWindow->Layout();
1685     m_scrolledWindow->SetScrollbars(0, 0, 0, 0, 0, 0);
1686 }
1687
1688 void COptionsDialog::OnListBox(wxCommandEvent& event)
1689 {
1690     SelectPage(event.GetSelection());
1691 }
1692
1693 void COptionsDialog::OnKillFocusTransactionFee(wxFocusEvent& event)
1694 {
1695     event.Skip();
1696     int64 nTmp = nTransactionFee;
1697     ParseMoney(m_textCtrlTransactionFee->GetValue(), nTmp);
1698     m_textCtrlTransactionFee->SetValue(FormatMoney(nTmp));
1699 }
1700
1701 void COptionsDialog::OnCheckBoxLimitProcessors(wxCommandEvent& event)
1702 {
1703     m_spinCtrlLimitProcessors->Enable(event.IsChecked());
1704 }
1705
1706 void COptionsDialog::OnCheckBoxUseProxy(wxCommandEvent& event)
1707 {
1708     m_textCtrlProxyIP->Enable(event.IsChecked());
1709     m_textCtrlProxyPort->Enable(event.IsChecked());
1710     m_staticTextProxyIP->Enable(event.IsChecked());
1711     m_staticTextProxyPort->Enable(event.IsChecked());
1712 }
1713
1714 CAddress COptionsDialog::GetProxyAddr()
1715 {
1716     // Be careful about byte order, addr.ip and addr.port are big endian
1717     CAddress addr(m_textCtrlProxyIP->GetValue() + ":" + m_textCtrlProxyPort->GetValue());
1718     if (addr.ip == INADDR_NONE)
1719         addr.ip = addrProxy.ip;
1720     int nPort = atoi(m_textCtrlProxyPort->GetValue());
1721     addr.port = htons(nPort);
1722     if (nPort <= 0 || nPort > USHRT_MAX)
1723         addr.port = addrProxy.port;
1724     return addr;
1725 }
1726
1727 void COptionsDialog::OnKillFocusProxy(wxFocusEvent& event)
1728 {
1729     event.Skip();
1730     m_textCtrlProxyIP->SetValue(GetProxyAddr().ToStringIP());
1731     m_textCtrlProxyPort->SetValue(GetProxyAddr().ToStringPort());
1732 }
1733
1734
1735 void COptionsDialog::OnButtonOK(wxCommandEvent& event)
1736 {
1737     OnButtonApply(event);
1738     Close();
1739 }
1740
1741 void COptionsDialog::OnButtonCancel(wxCommandEvent& event)
1742 {
1743     Close();
1744 }
1745
1746 void COptionsDialog::OnButtonApply(wxCommandEvent& event)
1747 {
1748     CWalletDB walletdb;
1749
1750     int64 nPrevTransactionFee = nTransactionFee;
1751     if (ParseMoney(m_textCtrlTransactionFee->GetValue(), nTransactionFee) && nTransactionFee != nPrevTransactionFee)
1752         walletdb.WriteSetting("nTransactionFee", nTransactionFee);
1753
1754     int nPrevMaxProc = (fLimitProcessors ? nLimitProcessors : INT_MAX);
1755     if (fLimitProcessors != m_checkBoxLimitProcessors->GetValue())
1756     {
1757         fLimitProcessors = m_checkBoxLimitProcessors->GetValue();
1758         walletdb.WriteSetting("fLimitProcessors", fLimitProcessors);
1759     }
1760     if (nLimitProcessors != m_spinCtrlLimitProcessors->GetValue())
1761     {
1762         nLimitProcessors = m_spinCtrlLimitProcessors->GetValue();
1763         walletdb.WriteSetting("nLimitProcessors", nLimitProcessors);
1764     }
1765     if (fGenerateBitcoins && (fLimitProcessors ? nLimitProcessors : INT_MAX) > nPrevMaxProc)
1766         GenerateBitcoins(fGenerateBitcoins);
1767
1768     if (fTmpStartOnSystemStartup != m_checkBoxStartOnSystemStartup->GetValue())
1769     {
1770         fTmpStartOnSystemStartup = m_checkBoxStartOnSystemStartup->GetValue();
1771         SetStartOnSystemStartup(fTmpStartOnSystemStartup);
1772     }
1773
1774     if (fMinimizeToTray != m_checkBoxMinimizeToTray->GetValue())
1775     {
1776         fMinimizeToTray = m_checkBoxMinimizeToTray->GetValue();
1777         walletdb.WriteSetting("fMinimizeToTray", fMinimizeToTray);
1778         ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
1779     }
1780
1781     if (fMinimizeOnClose != m_checkBoxMinimizeOnClose->GetValue())
1782     {
1783         fMinimizeOnClose = m_checkBoxMinimizeOnClose->GetValue();
1784         walletdb.WriteSetting("fMinimizeOnClose", fMinimizeOnClose);
1785     }
1786
1787     fUseProxy = m_checkBoxUseProxy->GetValue();
1788     walletdb.WriteSetting("fUseProxy", fUseProxy);
1789
1790     addrProxy = GetProxyAddr();
1791     walletdb.WriteSetting("addrProxy", addrProxy);
1792 }
1793
1794
1795
1796
1797
1798
1799 //////////////////////////////////////////////////////////////////////////////
1800 //
1801 // CAboutDialog
1802 //
1803
1804 CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent)
1805 {
1806     m_staticTextVersion->SetLabel(strprintf(_("version %s%s beta"), FormatVersion(VERSION).c_str(), pszSubVer));
1807
1808     // Change (c) into UTF-8 or ANSI copyright symbol
1809     wxString str = m_staticTextMain->GetLabel();
1810 #if wxUSE_UNICODE
1811     str.Replace("(c)", wxString::FromUTF8("\xC2\xA9"));
1812 #else
1813     str.Replace("(c)", "\xA9");
1814 #endif
1815     m_staticTextMain->SetLabel(str);
1816 #ifndef __WXMSW__
1817     // Resize on Linux to make the window fit the text.
1818     // The text was wrapped manually rather than using the Wrap setting because
1819     // the wrap would be too small on Linux and it can't be changed at this point.
1820     wxFont fontTmp = m_staticTextMain->GetFont();
1821     if (fontTmp.GetPointSize() > 8);
1822         fontTmp.SetPointSize(8);
1823     m_staticTextMain->SetFont(fontTmp);
1824     SetSize(GetSize().GetWidth() + 44, GetSize().GetHeight() + 10);
1825 #endif
1826 }
1827
1828 void CAboutDialog::OnButtonOK(wxCommandEvent& event)
1829 {
1830     Close();
1831 }
1832
1833
1834
1835
1836
1837
1838 //////////////////////////////////////////////////////////////////////////////
1839 //
1840 // CSendDialog
1841 //
1842
1843 CSendDialog::CSendDialog(wxWindow* parent, const wxString& strAddress) : CSendDialogBase(parent)
1844 {
1845     // Init
1846     m_textCtrlAddress->SetValue(strAddress);
1847     m_choiceTransferType->SetSelection(0);
1848     m_bitmapCheckMark->Show(false);
1849     fEnabledPrev = true;
1850     m_textCtrlAddress->SetFocus();
1851     //// todo: should add a display of your balance for convenience
1852 #ifndef __WXMSW__
1853     wxFont fontTmp = m_staticTextInstructions->GetFont();
1854     if (fontTmp.GetPointSize() > 9);
1855         fontTmp.SetPointSize(9);
1856     m_staticTextInstructions->SetFont(fontTmp);
1857     SetSize(725, 380);
1858 #endif
1859
1860     // Set Icon
1861     wxIcon iconSend;
1862     iconSend.CopyFromBitmap(wxBitmap(send16noshadow_xpm));
1863     SetIcon(iconSend);
1864
1865     wxCommandEvent event;
1866     OnTextAddress(event);
1867
1868     // Fixup the tab order
1869     m_buttonPaste->MoveAfterInTabOrder(m_buttonCancel);
1870     m_buttonAddress->MoveAfterInTabOrder(m_buttonPaste);
1871     this->Layout();
1872 }
1873
1874 void CSendDialog::OnTextAddress(wxCommandEvent& event)
1875 {
1876     // Check mark
1877     event.Skip();
1878     bool fBitcoinAddress = IsValidBitcoinAddress(m_textCtrlAddress->GetValue());
1879     m_bitmapCheckMark->Show(fBitcoinAddress);
1880
1881     // Grey out message if bitcoin address
1882     bool fEnable = !fBitcoinAddress;
1883     m_staticTextFrom->Enable(fEnable);
1884     m_textCtrlFrom->Enable(fEnable);
1885     m_staticTextMessage->Enable(fEnable);
1886     m_textCtrlMessage->Enable(fEnable);
1887     m_textCtrlMessage->SetBackgroundColour(wxSystemSettings::GetColour(fEnable ? wxSYS_COLOUR_WINDOW : wxSYS_COLOUR_BTNFACE));
1888     if (!fEnable && fEnabledPrev)
1889     {
1890         strFromSave    = m_textCtrlFrom->GetValue();
1891         strMessageSave = m_textCtrlMessage->GetValue();
1892         m_textCtrlFrom->SetValue(_("n/a"));
1893         m_textCtrlMessage->SetValue(_("Can't include a message when sending to a Bitcoin address"));
1894     }
1895     else if (fEnable && !fEnabledPrev)
1896     {
1897         m_textCtrlFrom->SetValue(strFromSave);
1898         m_textCtrlMessage->SetValue(strMessageSave);
1899     }
1900     fEnabledPrev = fEnable;
1901 }
1902
1903 void CSendDialog::OnKillFocusAmount(wxFocusEvent& event)
1904 {
1905     // Reformat the amount
1906     event.Skip();
1907     if (m_textCtrlAmount->GetValue().Trim().empty())
1908         return;
1909     int64 nTmp;
1910     if (ParseMoney(m_textCtrlAmount->GetValue(), nTmp))
1911         m_textCtrlAmount->SetValue(FormatMoney(nTmp));
1912 }
1913
1914 void CSendDialog::OnButtonAddressBook(wxCommandEvent& event)
1915 {
1916     // Open address book
1917     CAddressBookDialog dialog(this, m_textCtrlAddress->GetValue(), CAddressBookDialog::SENDING, true);
1918     if (dialog.ShowModal())
1919         m_textCtrlAddress->SetValue(dialog.GetSelectedAddress());
1920 }
1921
1922 void CSendDialog::OnButtonPaste(wxCommandEvent& event)
1923 {
1924     // Copy clipboard to address box
1925     if (wxTheClipboard->Open())
1926     {
1927         if (wxTheClipboard->IsSupported(wxDF_TEXT))
1928         {
1929             wxTextDataObject data;
1930             wxTheClipboard->GetData(data);
1931             m_textCtrlAddress->SetValue(data.GetText());
1932         }
1933         wxTheClipboard->Close();
1934     }
1935 }
1936
1937 void CSendDialog::OnButtonSend(wxCommandEvent& event)
1938 {
1939     CWalletTx wtx;
1940     string strAddress = (string)m_textCtrlAddress->GetValue();
1941
1942     // Parse amount
1943     int64 nValue = 0;
1944     if (!ParseMoney(m_textCtrlAmount->GetValue(), nValue) || nValue <= 0)
1945     {
1946         wxMessageBox(_("Error in amount  "), _("Send Coins"));
1947         return;
1948     }
1949     if (nValue > GetBalance())
1950     {
1951         wxMessageBox(_("Amount exceeds your balance  "), _("Send Coins"));
1952         return;
1953     }
1954     if (nValue + nTransactionFee > GetBalance())
1955     {
1956         wxMessageBox(string(_("Total exceeds your balance when the ")) + FormatMoney(nTransactionFee) + _(" transaction fee is included  "), _("Send Coins"));
1957         return;
1958     }
1959
1960     // Parse bitcoin address
1961     uint160 hash160;
1962     bool fBitcoinAddress = AddressToHash160(strAddress, hash160);
1963
1964     if (fBitcoinAddress)
1965     {
1966         // Send to bitcoin address
1967         CScript scriptPubKey;
1968         scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
1969
1970         string strError = SendMoney(scriptPubKey, nValue, wtx, true);
1971         if (strError == "")
1972             wxMessageBox(_("Payment sent  "), _("Sending..."));
1973         else if (strError != "ABORTED")
1974             wxMessageBox(strError + "  ", _("Sending..."));
1975     }
1976     else
1977     {
1978         // Parse IP address
1979         CAddress addr(strAddress);
1980         if (!addr.IsValid())
1981         {
1982             wxMessageBox(_("Invalid address  "), _("Send Coins"));
1983             return;
1984         }
1985
1986         // Message
1987         wtx.mapValue["to"] = strAddress;
1988         wtx.mapValue["from"] = m_textCtrlFrom->GetValue();
1989         wtx.mapValue["message"] = m_textCtrlMessage->GetValue();
1990
1991         // Send to IP address
1992         CSendingDialog* pdialog = new CSendingDialog(this, addr, nValue, wtx);
1993         if (!pdialog->ShowModal())
1994             return;
1995     }
1996
1997     CRITICAL_BLOCK(cs_mapAddressBook)
1998         if (!mapAddressBook.count(strAddress))
1999             SetAddressBookName(strAddress, "");
2000
2001     EndModal(true);
2002 }
2003
2004 void CSendDialog::OnButtonCancel(wxCommandEvent& event)
2005 {
2006     // Cancel
2007     EndModal(false);
2008 }
2009
2010
2011
2012
2013
2014
2015 //////////////////////////////////////////////////////////////////////////////
2016 //
2017 // CSendingDialog
2018 //
2019
2020 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
2021 {
2022     addr = addrIn;
2023     nPrice = nPriceIn;
2024     wtx = wtxIn;
2025     start = wxDateTime::UNow();
2026     memset(pszStatus, 0, sizeof(pszStatus));
2027     fCanCancel = true;
2028     fAbort = false;
2029     fSuccess = false;
2030     fUIDone = false;
2031     fWorkDone = false;
2032 #ifndef __WXMSW__
2033     SetSize(1.2 * GetSize().GetWidth(), 1.08 * GetSize().GetHeight());
2034 #endif
2035
2036     SetTitle(strprintf(_("Sending %s to %s"), FormatMoney(nPrice).c_str(), wtx.mapValue["to"].c_str()));
2037     m_textCtrlStatus->SetValue("");
2038
2039     CreateThread(SendingDialogStartTransfer, this);
2040 }
2041
2042 CSendingDialog::~CSendingDialog()
2043 {
2044     printf("~CSendingDialog()\n");
2045 }
2046
2047 void CSendingDialog::Close()
2048 {
2049     // Last one out turn out the lights.
2050     // fWorkDone signals that work side is done and UI thread should call destroy.
2051     // fUIDone signals that UI window has closed and work thread should call destroy.
2052     // This allows the window to disappear and end modality when cancelled
2053     // without making the user wait for ConnectNode to return.  The dialog object
2054     // hangs around in the background until the work thread exits.
2055     if (IsModal())
2056         EndModal(fSuccess);
2057     else
2058         Show(false);
2059     if (fWorkDone)
2060         Destroy();
2061     else
2062         fUIDone = true;
2063 }
2064
2065 void CSendingDialog::OnClose(wxCloseEvent& event)
2066 {
2067     if (!event.CanVeto() || fWorkDone || fAbort || !fCanCancel)
2068     {
2069         Close();
2070     }
2071     else
2072     {
2073         event.Veto();
2074         wxCommandEvent cmdevent;
2075         OnButtonCancel(cmdevent);
2076     }
2077 }
2078
2079 void CSendingDialog::OnButtonOK(wxCommandEvent& event)
2080 {
2081     if (fWorkDone)
2082         Close();
2083 }
2084
2085 void CSendingDialog::OnButtonCancel(wxCommandEvent& event)
2086 {
2087     if (fCanCancel)
2088         fAbort = true;
2089 }
2090
2091 void CSendingDialog::OnPaint(wxPaintEvent& event)
2092 {
2093     event.Skip();
2094     if (strlen(pszStatus) > 130)
2095         m_textCtrlStatus->SetValue(string("\n") + pszStatus);
2096     else
2097         m_textCtrlStatus->SetValue(string("\n\n") + pszStatus);
2098     m_staticTextSending->SetFocus();
2099     if (!fCanCancel)
2100         m_buttonCancel->Enable(false);
2101     if (fWorkDone)
2102     {
2103         m_buttonOK->Enable(true);
2104         m_buttonOK->SetFocus();
2105         m_buttonCancel->Enable(false);
2106     }
2107     if (fAbort && fCanCancel && IsShown())
2108     {
2109         strcpy(pszStatus, _("CANCELLED"));
2110         m_buttonOK->Enable(true);
2111         m_buttonOK->SetFocus();
2112         m_buttonCancel->Enable(false);
2113         m_buttonCancel->SetLabel(_("Cancelled"));
2114         Close();
2115         wxMessageBox(_("Transfer cancelled  "), _("Sending..."), wxOK, this);
2116     }
2117 }
2118
2119
2120 //
2121 // Everything from here on is not in the UI thread and must only communicate
2122 // with the rest of the dialog through variables and calling repaint.
2123 //
2124
2125 void CSendingDialog::Repaint()
2126 {
2127     Refresh();
2128     wxPaintEvent event;
2129     GetEventHandler()->AddPendingEvent(event);
2130 }
2131
2132 bool CSendingDialog::Status()
2133 {
2134     if (fUIDone)
2135     {
2136         Destroy();
2137         return false;
2138     }
2139     if (fAbort && fCanCancel)
2140     {
2141         memset(pszStatus, 0, 10);
2142         strcpy(pszStatus, _("CANCELLED"));
2143         Repaint();
2144         fWorkDone = true;
2145         return false;
2146     }
2147     return true;
2148 }
2149
2150 bool CSendingDialog::Status(const string& str)
2151 {
2152     if (!Status())
2153         return false;
2154
2155     // This can be read by the UI thread at any time,
2156     // so copy in a way that can be read cleanly at all times.
2157     memset(pszStatus, 0, min(str.size()+1, sizeof(pszStatus)));
2158     strlcpy(pszStatus, str.c_str(), sizeof(pszStatus));
2159
2160     Repaint();
2161     return true;
2162 }
2163
2164 bool CSendingDialog::Error(const string& str)
2165 {
2166     fCanCancel = false;
2167     fWorkDone = true;
2168     Status(string(_("Error: ")) + str);
2169     return false;
2170 }
2171
2172 void SendingDialogStartTransfer(void* parg)
2173 {
2174     ((CSendingDialog*)parg)->StartTransfer();
2175 }
2176
2177 void CSendingDialog::StartTransfer()
2178 {
2179     // Make sure we have enough money
2180     if (nPrice + nTransactionFee > GetBalance())
2181     {
2182         Error(_("Insufficient funds"));
2183         return;
2184     }
2185
2186     // We may have connected already for product details
2187     if (!Status(_("Connecting...")))
2188         return;
2189     CNode* pnode = ConnectNode(addr, 15 * 60);
2190     if (!pnode)
2191     {
2192         Error(_("Unable to connect"));
2193         return;
2194     }
2195
2196     // Send order to seller, with response going to OnReply2 via event handler
2197     if (!Status(_("Requesting public key...")))
2198         return;
2199     pnode->PushRequest("checkorder", wtx, SendingDialogOnReply2, this);
2200 }
2201
2202 void SendingDialogOnReply2(void* parg, CDataStream& vRecv)
2203 {
2204     ((CSendingDialog*)parg)->OnReply2(vRecv);
2205 }
2206
2207 void CSendingDialog::OnReply2(CDataStream& vRecv)
2208 {
2209     if (!Status(_("Received public key...")))
2210         return;
2211
2212     CScript scriptPubKey;
2213     int nRet;
2214     try
2215     {
2216         vRecv >> nRet;
2217         if (nRet > 0)
2218         {
2219             string strMessage;
2220             if (!vRecv.empty())
2221                 vRecv >> strMessage;
2222             if (nRet == 2)
2223                 Error(_("Recipient is not accepting transactions sent by IP address"));
2224             else
2225                 Error(_("Transfer was not accepted"));
2226             //// todo: enlarge the window and enable a hidden white box to put seller's message
2227             return;
2228         }
2229         vRecv >> scriptPubKey;
2230     }
2231     catch (...)
2232     {
2233         //// what do we want to do about this?
2234         Error(_("Invalid response received"));
2235         return;
2236     }
2237
2238     // Pause to give the user a chance to cancel
2239     while (wxDateTime::UNow() < start + wxTimeSpan(0, 0, 0, 2 * 1000))
2240     {
2241         Sleep(200);
2242         if (!Status())
2243             return;
2244     }
2245
2246     CRITICAL_BLOCK(cs_main)
2247     {
2248         // Pay
2249         if (!Status(_("Creating transaction...")))
2250             return;
2251         if (nPrice + nTransactionFee > GetBalance())
2252         {
2253             Error(_("Insufficient funds"));
2254             return;
2255         }
2256         CKey key;
2257         int64 nFeeRequired;
2258         if (!CreateTransaction(scriptPubKey, nPrice, wtx, key, nFeeRequired))
2259         {
2260             if (nPrice + nFeeRequired > GetBalance())
2261                 Error(strprintf(_("This is an oversized transaction that requires a transaction fee of %s"), FormatMoney(nFeeRequired).c_str()));
2262             else
2263                 Error(_("Transaction creation failed"));
2264             return;
2265         }
2266
2267         // Transaction fee
2268         if (!ThreadSafeAskFee(nFeeRequired, _("Sending..."), this))
2269         {
2270             Error(_("Transaction aborted"));
2271             return;
2272         }
2273
2274         // Make sure we're still connected
2275         CNode* pnode = ConnectNode(addr, 2 * 60 * 60);
2276         if (!pnode)
2277         {
2278             Error(_("Lost connection, transaction cancelled"));
2279             return;
2280         }
2281
2282         // Last chance to cancel
2283         Sleep(50);
2284         if (!Status())
2285             return;
2286         fCanCancel = false;
2287         if (fAbort)
2288         {
2289             fCanCancel = true;
2290             if (!Status())
2291                 return;
2292             fCanCancel = false;
2293         }
2294         if (!Status(_("Sending payment...")))
2295             return;
2296
2297         // Commit
2298         if (!CommitTransaction(wtx, key))
2299         {
2300             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."));
2301             return;
2302         }
2303
2304         // Send payment tx to seller, with response going to OnReply3 via event handler
2305         CWalletTx wtxSend = wtx;
2306         wtxSend.fFromMe = false;
2307         pnode->PushRequest("submitorder", wtxSend, SendingDialogOnReply3, this);
2308
2309         Status(_("Waiting for confirmation..."));
2310         MainFrameRepaint();
2311     }
2312 }
2313
2314 void SendingDialogOnReply3(void* parg, CDataStream& vRecv)
2315 {
2316     ((CSendingDialog*)parg)->OnReply3(vRecv);
2317 }
2318
2319 void CSendingDialog::OnReply3(CDataStream& vRecv)
2320 {
2321     int nRet;
2322     try
2323     {
2324         vRecv >> nRet;
2325         if (nRet > 0)
2326         {
2327             Error(_("The payment was sent, but the recipient was unable to verify it.\n"
2328                     "The transaction is recorded and will credit to the recipient,\n"
2329                     "but the comment information will be blank."));
2330             return;
2331         }
2332     }
2333     catch (...)
2334     {
2335         //// what do we want to do about this?
2336         Error(_("Payment was sent, but an invalid response was received"));
2337         return;
2338     }
2339
2340     fSuccess = true;
2341     fWorkDone = true;
2342     Status(_("Payment completed"));
2343 }
2344
2345
2346
2347
2348
2349
2350 //////////////////////////////////////////////////////////////////////////////
2351 //
2352 // CAddressBookDialog
2353 //
2354
2355 CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInitSelected, int nPageIn, bool fDuringSendIn) : CAddressBookDialogBase(parent)
2356 {
2357     // Set initially selected page
2358     wxNotebookEvent event;
2359     event.SetSelection(nPageIn);
2360     OnNotebookPageChanged(event);
2361     m_notebook->ChangeSelection(nPageIn);
2362
2363     fDuringSend = fDuringSendIn;
2364     if (!fDuringSend)
2365         m_buttonCancel->Show(false);
2366
2367     // Set Icon
2368     wxIcon iconAddressBook;
2369     iconAddressBook.CopyFromBitmap(wxBitmap(addressbook16_xpm));
2370     SetIcon(iconAddressBook);
2371
2372     // Init column headers
2373     m_listCtrlSending->InsertColumn(0, _("Name"), wxLIST_FORMAT_LEFT, 200);
2374     m_listCtrlSending->InsertColumn(1, _("Address"), wxLIST_FORMAT_LEFT, 350);
2375     m_listCtrlSending->SetFocus();
2376     m_listCtrlReceiving->InsertColumn(0, _("Label"), wxLIST_FORMAT_LEFT, 200);
2377     m_listCtrlReceiving->InsertColumn(1, _("Bitcoin Address"), wxLIST_FORMAT_LEFT, 350);
2378     m_listCtrlReceiving->SetFocus();
2379
2380     // Fill listctrl with address book data
2381     CRITICAL_BLOCK(cs_mapKeys)
2382     CRITICAL_BLOCK(cs_mapAddressBook)
2383     {
2384         string strDefaultReceiving = (string)pframeMain->m_textCtrlAddress->GetValue();
2385         foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
2386         {
2387             string strAddress = item.first;
2388             string strName = item.second;
2389             uint160 hash160;
2390             bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
2391             wxListCtrl* plistCtrl = fMine ? m_listCtrlReceiving : m_listCtrlSending;
2392             int nIndex = InsertLine(plistCtrl, strName, strAddress);
2393             if (strAddress == (fMine ? strDefaultReceiving : string(strInitSelected)))
2394                 plistCtrl->SetItemState(nIndex, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
2395         }
2396     }
2397 }
2398
2399 wxString CAddressBookDialog::GetSelectedAddress()
2400 {
2401     int nIndex = GetSelection(m_listCtrl);
2402     if (nIndex == -1)
2403         return "";
2404     return GetItemText(m_listCtrl, nIndex, 1);
2405 }
2406
2407 wxString CAddressBookDialog::GetSelectedSendingAddress()
2408 {
2409     int nIndex = GetSelection(m_listCtrlSending);
2410     if (nIndex == -1)
2411         return "";
2412     return GetItemText(m_listCtrlSending, nIndex, 1);
2413 }
2414
2415 wxString CAddressBookDialog::GetSelectedReceivingAddress()
2416 {
2417     int nIndex = GetSelection(m_listCtrlReceiving);
2418     if (nIndex == -1)
2419         return "";
2420     return GetItemText(m_listCtrlReceiving, nIndex, 1);
2421 }
2422
2423 void CAddressBookDialog::OnNotebookPageChanged(wxNotebookEvent& event)
2424 {
2425     event.Skip();
2426     nPage = event.GetSelection();
2427     if (nPage == SENDING)
2428         m_listCtrl = m_listCtrlSending;
2429     else if (nPage == RECEIVING)
2430         m_listCtrl = m_listCtrlReceiving;
2431     m_buttonDelete->Show(nPage == SENDING);
2432     m_buttonCopy->Show(nPage == RECEIVING);
2433     this->Layout();
2434     m_listCtrl->SetFocus();
2435 }
2436
2437 void CAddressBookDialog::OnListEndLabelEdit(wxListEvent& event)
2438 {
2439     // Update address book with edited name
2440     event.Skip();
2441     if (event.IsEditCancelled())
2442         return;
2443     string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1);
2444     SetAddressBookName(strAddress, string(event.GetText()));
2445     pframeMain->RefreshListCtrl();
2446 }
2447
2448 void CAddressBookDialog::OnListItemSelected(wxListEvent& event)
2449 {
2450     event.Skip();
2451     if (nPage == RECEIVING)
2452         SetDefaultReceivingAddress((string)GetSelectedReceivingAddress());
2453 }
2454
2455 void CAddressBookDialog::OnListItemActivated(wxListEvent& event)
2456 {
2457     event.Skip();
2458     if (fDuringSend)
2459     {
2460         // Doubleclick returns selection
2461         EndModal(GetSelectedAddress() != "" ? 2 : 0);
2462         return;
2463     }
2464
2465     // Doubleclick edits item
2466     wxCommandEvent event2;
2467     OnButtonEdit(event2);
2468 }
2469
2470 void CAddressBookDialog::OnButtonDelete(wxCommandEvent& event)
2471 {
2472     if (nPage != SENDING)
2473         return;
2474     for (int nIndex = m_listCtrl->GetItemCount()-1; nIndex >= 0; nIndex--)
2475     {
2476         if (m_listCtrl->GetItemState(nIndex, wxLIST_STATE_SELECTED))
2477         {
2478             string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
2479             CWalletDB().EraseName(strAddress);
2480             m_listCtrl->DeleteItem(nIndex);
2481         }
2482     }
2483     pframeMain->RefreshListCtrl();
2484 }
2485
2486 void CAddressBookDialog::OnButtonCopy(wxCommandEvent& event)
2487 {
2488     // Copy address box to clipboard
2489     if (wxTheClipboard->Open())
2490     {
2491         wxTheClipboard->SetData(new wxTextDataObject(GetSelectedAddress()));
2492         wxTheClipboard->Close();
2493     }
2494 }
2495
2496 bool CAddressBookDialog::CheckIfMine(const string& strAddress, const string& strTitle)
2497 {
2498     uint160 hash160;
2499     bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
2500     if (fMine)
2501         wxMessageBox(_("This is one of your own addresses for receiving payments and cannot be entered in the address book.  "), strTitle);
2502     return fMine;
2503 }
2504
2505 void CAddressBookDialog::OnButtonEdit(wxCommandEvent& event)
2506 {
2507     int nIndex = GetSelection(m_listCtrl);
2508     if (nIndex == -1)
2509         return;
2510     string strName = (string)m_listCtrl->GetItemText(nIndex);
2511     string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
2512     string strAddressOrg = strAddress;
2513
2514     if (nPage == SENDING)
2515     {
2516         // Ask name and address
2517         do
2518         {
2519             CGetTextFromUserDialog dialog(this, _("Edit Address"), _("Name"), strName, _("Address"), strAddress);
2520             if (!dialog.ShowModal())
2521                 return;
2522             strName = dialog.GetValue1();
2523             strAddress = dialog.GetValue2();
2524         }
2525         while (CheckIfMine(strAddress, _("Edit Address")));
2526
2527     }
2528     else if (nPage == RECEIVING)
2529     {
2530         // Ask name
2531         CGetTextFromUserDialog dialog(this, _("Edit Address Label"), _("Label"), strName);
2532         if (!dialog.ShowModal())
2533             return;
2534         strName = dialog.GetValue();
2535     }
2536
2537     // Write back
2538     if (strAddress != strAddressOrg)
2539         CWalletDB().EraseName(strAddressOrg);
2540     SetAddressBookName(strAddress, strName);
2541     m_listCtrl->SetItem(nIndex, 1, strAddress);
2542     m_listCtrl->SetItemText(nIndex, strName);
2543     pframeMain->RefreshListCtrl();
2544 }
2545
2546 void CAddressBookDialog::OnButtonNew(wxCommandEvent& event)
2547 {
2548     string strName;
2549     string strAddress;
2550
2551     if (nPage == SENDING)
2552     {
2553         // Ask name and address
2554         do
2555         {
2556             CGetTextFromUserDialog dialog(this, _("Add Address"), _("Name"), strName, _("Address"), strAddress);
2557             if (!dialog.ShowModal())
2558                 return;
2559             strName = dialog.GetValue1();
2560             strAddress = dialog.GetValue2();
2561         }
2562         while (CheckIfMine(strAddress, _("Add Address")));
2563     }
2564     else if (nPage == RECEIVING)
2565     {
2566         // Ask name
2567         CGetTextFromUserDialog dialog(this,
2568             _("New Receiving Address"),
2569             _("You should use a new address for each payment you receive.\n\nLabel"),
2570             "");
2571         if (!dialog.ShowModal())
2572             return;
2573         strName = dialog.GetValue();
2574
2575         // Generate new key
2576         strAddress = PubKeyToAddress(GenerateNewKey());
2577     }
2578
2579     // Add to list and select it
2580     SetAddressBookName(strAddress, strName);
2581     int nIndex = InsertLine(m_listCtrl, strName, strAddress);
2582     SetSelection(m_listCtrl, nIndex);
2583     m_listCtrl->SetFocus();
2584     if (nPage == SENDING)
2585         pframeMain->RefreshListCtrl();
2586 }
2587
2588 void CAddressBookDialog::OnButtonOK(wxCommandEvent& event)
2589 {
2590     // OK
2591     EndModal(GetSelectedAddress() != "" ? 1 : 0);
2592 }
2593
2594 void CAddressBookDialog::OnButtonCancel(wxCommandEvent& event)
2595 {
2596     // Cancel
2597     EndModal(0);
2598 }
2599
2600 void CAddressBookDialog::OnClose(wxCloseEvent& event)
2601 {
2602     // Close
2603     EndModal(0);
2604 }
2605
2606
2607
2608
2609
2610
2611 //////////////////////////////////////////////////////////////////////////////
2612 //
2613 // CMyTaskBarIcon
2614 //
2615
2616 enum
2617 {
2618     ID_TASKBAR_RESTORE = 10001,
2619     ID_TASKBAR_OPTIONS,
2620     ID_TASKBAR_GENERATE,
2621     ID_TASKBAR_EXIT,
2622 };
2623
2624 BEGIN_EVENT_TABLE(CMyTaskBarIcon, wxTaskBarIcon)
2625     EVT_TASKBAR_LEFT_DCLICK(CMyTaskBarIcon::OnLeftButtonDClick)
2626     EVT_MENU(ID_TASKBAR_RESTORE, CMyTaskBarIcon::OnMenuRestore)
2627     EVT_MENU(ID_TASKBAR_OPTIONS, CMyTaskBarIcon::OnMenuOptions)
2628     EVT_MENU(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnMenuGenerate)
2629     EVT_UPDATE_UI(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnUpdateUIGenerate)
2630     EVT_MENU(ID_TASKBAR_EXIT, CMyTaskBarIcon::OnMenuExit)
2631 END_EVENT_TABLE()
2632
2633 void CMyTaskBarIcon::Show(bool fShow)
2634 {
2635     static char pszPrevTip[200];
2636     if (fShow)
2637     {
2638         string strTooltip = _("Bitcoin");
2639         if (fGenerateBitcoins)
2640             strTooltip = _("Bitcoin - Generating");
2641         if (fGenerateBitcoins && vNodes.empty())
2642             strTooltip = _("Bitcoin - (not connected)");
2643
2644         // Optimization, only update when changed, using char array to be reentrant
2645         if (strncmp(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip)-1) != 0)
2646         {
2647             strlcpy(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip));
2648 #ifdef __WXMSW__
2649             // somehow it'll choose the wrong size and scale it down if
2650             // we use the main icon, so we hand it one with only 16x16
2651             SetIcon(wxICON(favicon), strTooltip);
2652 #else
2653             SetIcon(bitcoin80_xpm, strTooltip);
2654 #endif
2655         }
2656     }
2657     else
2658     {
2659         strlcpy(pszPrevTip, "", sizeof(pszPrevTip));
2660         RemoveIcon();
2661     }
2662 }
2663
2664 void CMyTaskBarIcon::Hide()
2665 {
2666     Show(false);
2667 }
2668
2669 void CMyTaskBarIcon::OnLeftButtonDClick(wxTaskBarIconEvent& event)
2670 {
2671     Restore();
2672 }
2673
2674 void CMyTaskBarIcon::OnMenuRestore(wxCommandEvent& event)
2675 {
2676     Restore();
2677 }
2678
2679 void CMyTaskBarIcon::OnMenuOptions(wxCommandEvent& event)
2680 {
2681     // Since it's modal, get the main window to do it
2682     wxCommandEvent event2(wxEVT_COMMAND_MENU_SELECTED, wxID_PREFERENCES);
2683     pframeMain->GetEventHandler()->AddPendingEvent(event2);
2684 }
2685
2686 void CMyTaskBarIcon::Restore()
2687 {
2688     pframeMain->Show();
2689     wxIconizeEvent event(0, false);
2690     pframeMain->GetEventHandler()->AddPendingEvent(event);
2691     pframeMain->Iconize(false);
2692     pframeMain->Raise();
2693 }
2694
2695 void CMyTaskBarIcon::OnMenuGenerate(wxCommandEvent& event)
2696 {
2697     GenerateBitcoins(event.IsChecked());
2698 }
2699
2700 void CMyTaskBarIcon::OnUpdateUIGenerate(wxUpdateUIEvent& event)
2701 {
2702     event.Check(fGenerateBitcoins);
2703 }
2704
2705 void CMyTaskBarIcon::OnMenuExit(wxCommandEvent& event)
2706 {
2707     pframeMain->Close(true);
2708 }
2709
2710 void CMyTaskBarIcon::UpdateTooltip()
2711 {
2712     if (IsIconInstalled())
2713         Show(true);
2714 }
2715
2716 wxMenu* CMyTaskBarIcon::CreatePopupMenu()
2717 {
2718     wxMenu* pmenu = new wxMenu;
2719     pmenu->Append(ID_TASKBAR_RESTORE, _("&Open Bitcoin"));
2720     pmenu->Append(ID_TASKBAR_OPTIONS, _("O&ptions..."));
2721     pmenu->AppendCheckItem(ID_TASKBAR_GENERATE, _("&Generate Coins"))->Check(fGenerateBitcoins);
2722 #ifndef __WXMAC_OSX__ // Mac has built-in quit menu
2723     pmenu->AppendSeparator();
2724     pmenu->Append(ID_TASKBAR_EXIT, _("E&xit"));
2725 #endif
2726     return pmenu;
2727 }
2728
2729
2730
2731
2732
2733
2734 //////////////////////////////////////////////////////////////////////////////
2735 //
2736 // CMyApp
2737 //
2738
2739 void CreateMainWindow()
2740 {
2741     pframeMain = new CMainFrame(NULL);
2742     if (mapArgs.count("-min"))
2743         pframeMain->Iconize(true);
2744 #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
2745     if (!mapArgs.count("-minimizetotray"))
2746         fMinimizeToTray = false;
2747 #endif
2748     pframeMain->Show(true);  // have to show first to get taskbar button to hide
2749     if (fMinimizeToTray && pframeMain->IsIconized())
2750         fClosedToTray = true;
2751     pframeMain->Show(!fClosedToTray);
2752     ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
2753     CreateThread(ThreadDelayedRepaint, NULL);
2754 }
2755
2756
2757 // Define a new application
2758 class CMyApp : public wxApp
2759 {
2760 public:
2761     CMyApp(){};
2762     ~CMyApp(){};
2763     bool OnInit();
2764     bool OnInit2();
2765     int OnExit();
2766
2767     // Hook Initialize so we can start without GUI
2768     virtual bool Initialize(int& argc, wxChar** argv);
2769
2770     // 2nd-level exception handling: we get all the exceptions occurring in any
2771     // event handler here
2772     virtual bool OnExceptionInMainLoop();
2773
2774     // 3rd, and final, level exception handling: whenever an unhandled
2775     // exception is caught, this function is called
2776     virtual void OnUnhandledException();
2777
2778     // and now for something different: this function is called in case of a
2779     // crash (e.g. dereferencing null pointer, division by 0, ...)
2780     virtual void OnFatalException();
2781 };
2782
2783 IMPLEMENT_APP(CMyApp)
2784
2785 bool CMyApp::Initialize(int& argc, wxChar** argv)
2786 {
2787     for (int i = 1; i < argc; i++)
2788         if (!IsSwitchChar(argv[i][0]))
2789             fCommandLine = true;
2790
2791     if (!fCommandLine)
2792     {
2793         // wxApp::Initialize will remove environment-specific parameters,
2794         // so it's too early to call ParseParameters yet
2795         for (int i = 1; i < argc; i++)
2796         {
2797             wxString str = argv[i];
2798             #ifdef __WXMSW__
2799             if (str.size() >= 1 && str[0] == '/')
2800                 str[0] = '-';
2801             char pszLower[MAX_PATH];
2802             strlcpy(pszLower, str.c_str(), sizeof(pszLower));
2803             strlwr(pszLower);
2804             str = pszLower;
2805             #endif
2806             if (str == "-daemon")
2807                 fDaemon = true;
2808         }
2809     }
2810
2811 #ifdef __WXGTK__
2812     if (fDaemon || fCommandLine)
2813     {
2814         // Call the original Initialize while suppressing error messages
2815         // and ignoring failure.  If unable to initialize GTK, it fails
2816         // near the end so hopefully the last few things don't matter.
2817         {
2818             wxLogNull logNo;
2819             wxApp::Initialize(argc, argv);
2820         }
2821
2822         if (fDaemon)
2823         {
2824             // Daemonize
2825             pid_t pid = fork();
2826             if (pid < 0)
2827             {
2828                 fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
2829                 return false;
2830             }
2831             if (pid > 0)
2832                 pthread_exit((void*)0);
2833         }
2834
2835         return true;
2836     }
2837 #endif
2838
2839     return wxApp::Initialize(argc, argv);
2840 }
2841
2842 bool CMyApp::OnInit()
2843 {
2844 #if defined(__WXMSW__) && defined(__WXDEBUG__) && defined(GUI)
2845     // Disable malfunctioning wxWidgets debug assertion
2846     extern int g_isPainting;
2847     g_isPainting = 10000;
2848 #endif
2849 #ifdef GUI
2850     wxImage::AddHandler(new wxPNGHandler);
2851 #endif
2852 #if defined(__WXMSW__ ) || defined(__WXMAC_OSX__)
2853     SetAppName("Bitcoin");
2854 #else
2855     SetAppName("bitcoin");
2856 #endif
2857 #ifdef __WXMSW__
2858 #if wxUSE_UNICODE
2859     // Hack to set wxConvLibc codepage to UTF-8 on Windows,
2860     // may break if wxMBConv_win32 implementation in strconv.cpp changes.
2861     class wxMBConv_win32 : public wxMBConv
2862     {
2863     public:
2864         long m_CodePage;
2865         size_t m_minMBCharWidth;
2866     };
2867     if (((wxMBConv_win32*)&wxConvLibc)->m_CodePage == CP_ACP)
2868         ((wxMBConv_win32*)&wxConvLibc)->m_CodePage = CP_UTF8;
2869 #endif
2870 #endif
2871
2872     // Load locale/<lang>/LC_MESSAGES/bitcoin.mo language file
2873     g_locale.Init(wxLANGUAGE_DEFAULT, 0);
2874     g_locale.AddCatalogLookupPathPrefix("locale");
2875 #ifndef __WXMSW__
2876     g_locale.AddCatalogLookupPathPrefix("/usr/share/locale");
2877     g_locale.AddCatalogLookupPathPrefix("/usr/local/share/locale");
2878 #endif
2879     g_locale.AddCatalog("wxstd"); // wxWidgets standard translations, if any
2880     g_locale.AddCatalog("bitcoin");
2881
2882     return AppInit(argc, argv);
2883 }
2884
2885 int CMyApp::OnExit()
2886 {
2887     Shutdown(NULL);
2888     return wxApp::OnExit();
2889 }
2890
2891 bool CMyApp::OnExceptionInMainLoop()
2892 {
2893     try
2894     {
2895         throw;
2896     }
2897     catch (std::exception& e)
2898     {
2899         PrintException(&e, "CMyApp::OnExceptionInMainLoop()");
2900         wxLogWarning("Exception %s %s", typeid(e).name(), e.what());
2901         Sleep(1000);
2902         throw;
2903     }
2904     catch (...)
2905     {
2906         PrintException(NULL, "CMyApp::OnExceptionInMainLoop()");
2907         wxLogWarning("Unknown exception");
2908         Sleep(1000);
2909         throw;
2910     }
2911     return true;
2912 }
2913
2914 void CMyApp::OnUnhandledException()
2915 {
2916     // this shows how we may let some exception propagate uncaught
2917     try
2918     {
2919         throw;
2920     }
2921     catch (std::exception& e)
2922     {
2923         PrintException(&e, "CMyApp::OnUnhandledException()");
2924         wxLogWarning("Exception %s %s", typeid(e).name(), e.what());
2925         Sleep(1000);
2926         throw;
2927     }
2928     catch (...)
2929     {
2930         PrintException(NULL, "CMyApp::OnUnhandledException()");
2931         wxLogWarning("Unknown exception");
2932         Sleep(1000);
2933         throw;
2934     }
2935 }
2936
2937 void CMyApp::OnFatalException()
2938 {
2939     wxMessageBox(_("Program has crashed and will terminate.  "), "Bitcoin", wxOK | wxICON_ERROR);
2940 }
This page took 0.181297 seconds and 4 git commands to generate.