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