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