]> Git Repo - VerusCoin.git/blob - ui.cpp
unix build merged in, bitmap resources from xpm instead of rc, better addr relay...
[VerusCoin.git] / ui.cpp
1 // Copyright (c) 2009 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 void ThreadRequestProductDetails(void* parg);\r
11 void ThreadRandSendTest(void* parg);\r
12 bool GetStartOnSystemStartup();\r
13 void SetStartOnSystemStartup(bool fAutoStart);\r
14 \r
15 \r
16 \r
17 DEFINE_EVENT_TYPE(wxEVT_CROSSTHREADCALL)\r
18 DEFINE_EVENT_TYPE(wxEVT_REPLY1)\r
19 DEFINE_EVENT_TYPE(wxEVT_REPLY2)\r
20 DEFINE_EVENT_TYPE(wxEVT_REPLY3)\r
21 DEFINE_EVENT_TYPE(wxEVT_TABLEADDED)\r
22 DEFINE_EVENT_TYPE(wxEVT_TABLEUPDATED)\r
23 DEFINE_EVENT_TYPE(wxEVT_TABLEDELETED)\r
24 \r
25 CMainFrame* pframeMain = NULL;\r
26 CMyTaskBarIcon* ptaskbaricon = NULL;\r
27 map<string, string> mapAddressBook;\r
28 bool fRandSendTest = false;\r
29 void RandSend();\r
30 extern int g_isPainting;\r
31 \r
32 // Settings\r
33 int fShowGenerated = true;\r
34 int fMinimizeToTray = true;\r
35 int fMinimizeOnClose = true;\r
36 \r
37 \r
38 \r
39 \r
40 \r
41 \r
42 \r
43 //////////////////////////////////////////////////////////////////////////////\r
44 //\r
45 // Util\r
46 //\r
47 \r
48 void HandleCtrlA(wxKeyEvent& event)\r
49 {\r
50     // Ctrl-a select all\r
51     wxTextCtrl* textCtrl = (wxTextCtrl*)event.GetEventObject();\r
52     if (event.GetModifiers() == wxMOD_CONTROL && event.GetKeyCode() == 'A')\r
53         textCtrl->SetSelection(-1, -1);\r
54     event.Skip();\r
55 }\r
56 \r
57 bool Is24HourTime()\r
58 {\r
59     //char pszHourFormat[256];\r
60     //pszHourFormat[0] = '\0';\r
61     //GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ITIME, pszHourFormat, 256);\r
62     //return (pszHourFormat[0] != '0');\r
63     return true;\r
64 }\r
65 \r
66 string DateStr(int64 nTime)\r
67 {\r
68     return (string)wxDateTime((time_t)nTime).FormatDate();\r
69 }\r
70 \r
71 string DateTimeStr(int64 nTime)\r
72 {\r
73     wxDateTime datetime((time_t)nTime);\r
74     if (Is24HourTime())\r
75         return (string)datetime.Format("%x %H:%M");\r
76     else\r
77         return (string)datetime.Format("%x ") + itostr((datetime.GetHour() + 11) % 12 + 1) + (string)datetime.Format(":%M %p");\r
78 }\r
79 \r
80 wxString GetItemText(wxListCtrl* listCtrl, int nIndex, int nColumn)\r
81 {\r
82     // Helper to simplify access to listctrl\r
83     wxListItem item;\r
84     item.m_itemId = nIndex;\r
85     item.m_col = nColumn;\r
86     item.m_mask = wxLIST_MASK_TEXT;\r
87     if (!listCtrl->GetItem(item))\r
88         return "";\r
89     return item.GetText();\r
90 }\r
91 \r
92 int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1)\r
93 {\r
94     int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);\r
95     listCtrl->SetItem(nIndex, 1, str1);\r
96     return nIndex;\r
97 }\r
98 \r
99 int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)\r
100 {\r
101     int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);\r
102     listCtrl->SetItem(nIndex, 1, str1);\r
103     listCtrl->SetItem(nIndex, 2, str2);\r
104     listCtrl->SetItem(nIndex, 3, str3);\r
105     listCtrl->SetItem(nIndex, 4, str4);\r
106     return nIndex;\r
107 }\r
108 \r
109 int InsertLine(wxListCtrl* listCtrl, void* pdata, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)\r
110 {\r
111     int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);\r
112     listCtrl->SetItemPtrData(nIndex, (wxUIntPtr)pdata);\r
113     listCtrl->SetItem(nIndex, 1, str1);\r
114     listCtrl->SetItem(nIndex, 2, str2);\r
115     listCtrl->SetItem(nIndex, 3, str3);\r
116     listCtrl->SetItem(nIndex, 4, str4);\r
117     return nIndex;\r
118 }\r
119 \r
120 void SetSelection(wxListCtrl* listCtrl, int nIndex)\r
121 {\r
122     int nSize = listCtrl->GetItemCount();\r
123     long nState = (wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);\r
124     for (int i = 0; i < nSize; i++)\r
125         listCtrl->SetItemState(i, (i == nIndex ? nState : 0), nState);\r
126 }\r
127 \r
128 int GetSelection(wxListCtrl* listCtrl)\r
129 {\r
130     int nSize = listCtrl->GetItemCount();\r
131     for (int i = 0; i < nSize; i++)\r
132         if (listCtrl->GetItemState(i, wxLIST_STATE_FOCUSED))\r
133             return i;\r
134     return -1;\r
135 }\r
136 \r
137 \r
138 string HtmlEscape(const char* psz, bool fMultiLine=false)\r
139 {\r
140     int len = 0;\r
141     for (const char* p = psz; *p; p++)\r
142     {\r
143              if (*p == '<') len += 4;\r
144         else if (*p == '>') len += 4;\r
145         else if (*p == '&') len += 5;\r
146         else if (*p == '"') len += 6;\r
147         else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') len += 6;\r
148         else if (*p == '\n' && fMultiLine) len += 5;\r
149         else\r
150             len++;\r
151     }\r
152     string str;\r
153     str.reserve(len);\r
154     for (const char* p = psz; *p; p++)\r
155     {\r
156              if (*p == '<') str += "&lt;";\r
157         else if (*p == '>') str += "&gt;";\r
158         else if (*p == '&') str += "&amp;";\r
159         else if (*p == '"') str += "&quot;";\r
160         else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') str += "&nbsp;";\r
161         else if (*p == '\n' && fMultiLine) str += "<br>\n";\r
162         else\r
163             str += *p;\r
164     }\r
165     return str;\r
166 }\r
167 \r
168 string HtmlEscape(const string& str, bool fMultiLine=false)\r
169 {\r
170     return HtmlEscape(str.c_str(), fMultiLine);\r
171 }\r
172 \r
173 void AddToMyProducts(CProduct product)\r
174 {\r
175     CProduct& productInsert = mapMyProducts[product.GetHash()];\r
176     productInsert = product;\r
177     InsertLine(pframeMain->m_listCtrlProductsSent, &productInsert,\r
178                 product.mapValue["category"],\r
179                 product.mapValue["title"].substr(0, 100),\r
180                 product.mapValue["description"].substr(0, 100),\r
181                 product.mapValue["price"],\r
182                 "");\r
183 }\r
184 \r
185 \r
186 \r
187 \r
188 \r
189 \r
190 //////////////////////////////////////////////////////////////////////////////\r
191 //\r
192 // Custom events\r
193 //\r
194 \r
195 set<void*> setCallbackAvailable;\r
196 CCriticalSection cs_setCallbackAvailable;\r
197 \r
198 void AddCallbackAvailable(void* p)\r
199 {\r
200     CRITICAL_BLOCK(cs_setCallbackAvailable)\r
201         setCallbackAvailable.insert(p);\r
202 }\r
203 \r
204 void RemoveCallbackAvailable(void* p)\r
205 {\r
206     CRITICAL_BLOCK(cs_setCallbackAvailable)\r
207         setCallbackAvailable.erase(p);\r
208 }\r
209 \r
210 bool IsCallbackAvailable(void* p)\r
211 {\r
212     CRITICAL_BLOCK(cs_setCallbackAvailable)\r
213         return setCallbackAvailable.count(p);\r
214     return false;\r
215 }\r
216 \r
217 template<typename T>\r
218 void AddPendingCustomEvent(wxEvtHandler* pevthandler, int nEventID, const T pbeginIn, const T pendIn)\r
219 {\r
220     if (!pevthandler)\r
221         return;\r
222 \r
223     const char* pbegin = (pendIn != pbeginIn) ? &pbeginIn[0] : NULL;\r
224     const char* pend = pbegin + (pendIn - pbeginIn) * sizeof(pbeginIn[0]);\r
225     wxCommandEvent event(nEventID);\r
226     wxString strData(wxChar(0), (pend - pbegin) / sizeof(wxChar) + 1);\r
227     memcpy(&strData[0], pbegin, pend - pbegin);\r
228     event.SetString(strData);\r
229     event.SetInt(pend - pbegin);\r
230 \r
231     pevthandler->AddPendingEvent(event);\r
232 }\r
233 \r
234 template<class T>\r
235 void AddPendingCustomEvent(wxEvtHandler* pevthandler, int nEventID, const T& obj)\r
236 {\r
237     CDataStream ss;\r
238     ss << obj;\r
239     AddPendingCustomEvent(pevthandler, nEventID, ss.begin(), ss.end());\r
240 }\r
241 \r
242 void AddPendingReplyEvent1(void* pevthandler, CDataStream& vRecv)\r
243 {\r
244     if (IsCallbackAvailable(pevthandler))\r
245         AddPendingCustomEvent((wxEvtHandler*)pevthandler, wxEVT_REPLY1, vRecv.begin(), vRecv.end());\r
246 }\r
247 \r
248 void AddPendingReplyEvent2(void* pevthandler, CDataStream& vRecv)\r
249 {\r
250     if (IsCallbackAvailable(pevthandler))\r
251         AddPendingCustomEvent((wxEvtHandler*)pevthandler, wxEVT_REPLY2, vRecv.begin(), vRecv.end());\r
252 }\r
253 \r
254 void AddPendingReplyEvent3(void* pevthandler, CDataStream& vRecv)\r
255 {\r
256     if (IsCallbackAvailable(pevthandler))\r
257         AddPendingCustomEvent((wxEvtHandler*)pevthandler, wxEVT_REPLY3, vRecv.begin(), vRecv.end());\r
258 }\r
259 \r
260 CDataStream GetStreamFromEvent(const wxCommandEvent& event)\r
261 {\r
262     wxString strData = event.GetString();\r
263     const char* pszBegin = strData.c_str();\r
264     return CDataStream(pszBegin, pszBegin + event.GetInt(), SER_NETWORK);\r
265 }\r
266 \r
267 \r
268 \r
269 \r
270 \r
271 \r
272 \r
273 //////////////////////////////////////////////////////////////////////////////\r
274 //\r
275 // CMainFrame\r
276 //\r
277 \r
278 CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent)\r
279 {\r
280     Connect(wxEVT_CROSSTHREADCALL, wxCommandEventHandler(CMainFrame::OnCrossThreadCall), NULL, this);\r
281 \r
282     // Init\r
283     fRefreshListCtrl = false;\r
284     fRefreshListCtrlRunning = false;\r
285     fOnSetFocusAddress = false;\r
286     m_choiceFilter->SetSelection(0);\r
287     m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + "  ");\r
288     m_listCtrl->SetFocus();\r
289     SetIcon(wxICON(bitcoin));\r
290     ptaskbaricon = new CMyTaskBarIcon();\r
291 \r
292     // Init column headers\r
293     int nDateWidth = DateTimeStr(1229413914).size() * 6 + 8;\r
294     if (!strstr(DateTimeStr(1229413914).c_str(), "2008"))\r
295         nDateWidth += 12;\r
296     m_listCtrl->InsertColumn(0, "",             wxLIST_FORMAT_LEFT,     0);\r
297     m_listCtrl->InsertColumn(1, "",             wxLIST_FORMAT_LEFT,     0);\r
298     m_listCtrl->InsertColumn(2, "Status",       wxLIST_FORMAT_LEFT,    90);\r
299     m_listCtrl->InsertColumn(3, "Date",         wxLIST_FORMAT_LEFT,   nDateWidth);\r
300     m_listCtrl->InsertColumn(4, "Description",  wxLIST_FORMAT_LEFT,   409 - nDateWidth);\r
301     m_listCtrl->InsertColumn(5, "Debit",        wxLIST_FORMAT_RIGHT,   79);\r
302     m_listCtrl->InsertColumn(6, "Credit",       wxLIST_FORMAT_RIGHT,   79);\r
303 \r
304     //m_listCtrlProductsSent->InsertColumn(0, "Category",      wxLIST_FORMAT_LEFT,  100);\r
305     //m_listCtrlProductsSent->InsertColumn(1, "Title",         wxLIST_FORMAT_LEFT,  100);\r
306     //m_listCtrlProductsSent->InsertColumn(2, "Description",   wxLIST_FORMAT_LEFT,  100);\r
307     //m_listCtrlProductsSent->InsertColumn(3, "Price",         wxLIST_FORMAT_LEFT,  100);\r
308     //m_listCtrlProductsSent->InsertColumn(4, "",              wxLIST_FORMAT_LEFT,  100);\r
309 \r
310     //m_listCtrlOrdersSent->InsertColumn(0, "Time",          wxLIST_FORMAT_LEFT,  100);\r
311     //m_listCtrlOrdersSent->InsertColumn(1, "Price",         wxLIST_FORMAT_LEFT,  100);\r
312     //m_listCtrlOrdersSent->InsertColumn(2, "",              wxLIST_FORMAT_LEFT,  100);\r
313     //m_listCtrlOrdersSent->InsertColumn(3, "",              wxLIST_FORMAT_LEFT,  100);\r
314     //m_listCtrlOrdersSent->InsertColumn(4, "",              wxLIST_FORMAT_LEFT,  100);\r
315 \r
316     //m_listCtrlOrdersReceived->InsertColumn(0, "Time",            wxLIST_FORMAT_LEFT,  100);\r
317     //m_listCtrlOrdersReceived->InsertColumn(1, "Price",           wxLIST_FORMAT_LEFT,  100);\r
318     //m_listCtrlOrdersReceived->InsertColumn(2, "Payment Status",  wxLIST_FORMAT_LEFT,  100);\r
319     //m_listCtrlOrdersReceived->InsertColumn(3, "",                wxLIST_FORMAT_LEFT,  100);\r
320     //m_listCtrlOrdersReceived->InsertColumn(4, "",                wxLIST_FORMAT_LEFT,  100);\r
321 \r
322     // Init status bar\r
323     int pnWidths[3] = { -100, 88, 290 };\r
324     m_statusBar->SetFieldsCount(3, pnWidths);\r
325 \r
326     // Fill your address text box\r
327     vector<unsigned char> vchPubKey;\r
328     if (CWalletDB("r").ReadDefaultKey(vchPubKey))\r
329         m_textCtrlAddress->SetValue(PubKeyToAddress(vchPubKey));\r
330 \r
331     // Fill listctrl with wallet transactions\r
332     RefreshListCtrl();\r
333 }\r
334 \r
335 CMainFrame::~CMainFrame()\r
336 {\r
337     pframeMain = NULL;\r
338     delete ptaskbaricon;\r
339     ptaskbaricon = NULL;\r
340 }\r
341 \r
342 void Shutdown(void* parg)\r
343 {\r
344     static CCriticalSection cs_Shutdown;\r
345     CRITICAL_BLOCK(cs_Shutdown)\r
346     {\r
347         fShutdown = true;\r
348         nTransactionsUpdated++;\r
349         DBFlush(false);\r
350         StopNode();\r
351         DBFlush(true);\r
352 \r
353         printf("Bitcoin exiting\n");\r
354         exit(0);\r
355     }\r
356 }\r
357 \r
358 void CMainFrame::OnClose(wxCloseEvent& event)\r
359 {\r
360     if (fMinimizeToTray && fMinimizeOnClose && event.CanVeto() && !IsIconized())\r
361     {\r
362         // Divert close to minimize\r
363         event.Veto();\r
364         Iconize(true);\r
365     }\r
366     else\r
367     {\r
368         Destroy();\r
369         _beginthread(Shutdown, 0, NULL);\r
370     }\r
371 }\r
372 \r
373 void CMainFrame::OnIconize(wxIconizeEvent& event)\r
374 {\r
375     // Hide the task bar button when minimized.\r
376     // Event is sent when the frame is minimized or restored.\r
377     Show(!fMinimizeToTray || !event.Iconized());\r
378 }\r
379 \r
380 void CMainFrame::OnMouseEvents(wxMouseEvent& event)\r
381 {\r
382     RandAddSeed();\r
383     RAND_add(&event.m_x, sizeof(event.m_x), 0.25);\r
384     RAND_add(&event.m_y, sizeof(event.m_y), 0.25);\r
385 }\r
386 \r
387 void CMainFrame::OnListColBeginDrag(wxListEvent& event)\r
388 {\r
389      // Hidden columns not resizeable\r
390      if (event.GetColumn() <= 1 && !fDebug)\r
391         event.Veto();\r
392 }\r
393 \r
394 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
395 {\r
396     string str0 = strSort;\r
397     long nData = *(long*)&hashKey;\r
398 \r
399     // Find item\r
400     if (!fNew && nIndex == -1)\r
401     {\r
402         while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)\r
403             if (GetItemText(m_listCtrl, nIndex, 1) == hashKey.ToString())\r
404                 break;\r
405     }\r
406 \r
407     // fNew is for blind insert, only use if you're sure it's new\r
408     if (fNew || nIndex == -1)\r
409     {\r
410         nIndex = m_listCtrl->InsertItem(0, str0);\r
411     }\r
412     else\r
413     {\r
414         // If sort key changed, must delete and reinsert to make it relocate\r
415         if (GetItemText(m_listCtrl, nIndex, 0) != str0)\r
416         {\r
417             m_listCtrl->DeleteItem(nIndex);\r
418             nIndex = m_listCtrl->InsertItem(0, str0);\r
419         }\r
420     }\r
421 \r
422     m_listCtrl->SetItem(nIndex, 1, hashKey.ToString());\r
423     m_listCtrl->SetItem(nIndex, 2, str2);\r
424     m_listCtrl->SetItem(nIndex, 3, str3);\r
425     m_listCtrl->SetItem(nIndex, 4, str4);\r
426     m_listCtrl->SetItem(nIndex, 5, str5);\r
427     m_listCtrl->SetItem(nIndex, 6, str6);\r
428     m_listCtrl->SetItemData(nIndex, nData);\r
429 }\r
430 \r
431 bool CMainFrame::DeleteLine(uint256 hashKey)\r
432 {\r
433     long nData = *(long*)&hashKey;\r
434 \r
435     // Find item\r
436     int nIndex = -1;\r
437     while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)\r
438         if (GetItemText(m_listCtrl, nIndex, 1) == hashKey.ToString())\r
439             break;\r
440 \r
441     if (nIndex != -1)\r
442         m_listCtrl->DeleteItem(nIndex);\r
443 \r
444     return nIndex != -1;\r
445 }\r
446 \r
447 string FormatTxStatus(const CWalletTx& wtx)\r
448 {\r
449     // Status\r
450     int nDepth = wtx.GetDepthInMainChain();\r
451     if (!wtx.IsFinal())\r
452     {\r
453         if (wtx.nLockTime < 500000000)\r
454             return strprintf("Open for %d blocks", nBestHeight - wtx.nLockTime);\r
455         else\r
456             return strprintf("Open until %s", DateTimeStr(wtx.nLockTime).c_str());\r
457     }\r
458     else if (nDepth < 6)\r
459         return strprintf("%d/unconfirmed", nDepth);\r
460     else\r
461         return strprintf("%d blocks", nDepth);\r
462 }\r
463 \r
464 string SingleLine(const string& strIn)\r
465 {\r
466     string strOut;\r
467     bool fOneSpace = false;\r
468     foreach(int c, strIn)\r
469     {\r
470         if (isspace(c))\r
471         {\r
472             fOneSpace = true;\r
473         }\r
474         else if (c > ' ')\r
475         {\r
476             if (fOneSpace && !strOut.empty())\r
477                 strOut += ' ';\r
478             strOut += c;\r
479             fOneSpace = false;\r
480         }\r
481     }\r
482     return strOut;\r
483 }\r
484 \r
485 bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)\r
486 {\r
487     int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime();\r
488     int64 nCredit = wtx.GetCredit();\r
489     int64 nDebit = wtx.GetDebit();\r
490     int64 nNet = nCredit - nDebit;\r
491     uint256 hash = wtx.GetHash();\r
492     string strStatus = FormatTxStatus(wtx);\r
493     map<string, string> mapValue = wtx.mapValue;\r
494     wtx.nLinesDisplayed = 1;\r
495     nListViewUpdated++;\r
496 \r
497     // Filter\r
498     if (wtx.IsCoinBase())\r
499     {\r
500         // Don't show generated coin until confirmed by at least one block after it\r
501         // so we don't get the user's hopes up until it looks like it's probably accepted.\r
502         //\r
503         // It is not an error when generated blocks are not accepted.  By design,\r
504         // some percentage of blocks, like 10% or more, will end up not accepted.\r
505         // This is the normal mechanism by which the network copes with latency.\r
506         //\r
507         // We display regular transactions right away before any confirmation\r
508         // because they can always get into some block eventually.  Generated coins\r
509         // are special because if their block is not accepted, they are not valid.\r
510         //\r
511         if (wtx.GetDepthInMainChain() < 2)\r
512         {\r
513             wtx.nLinesDisplayed = 0;\r
514             return false;\r
515         }\r
516 \r
517         // View->Show Generated\r
518         if (!fShowGenerated)\r
519             return false;\r
520     }\r
521 \r
522     // Find the block the tx is in\r
523     CBlockIndex* pindex = NULL;\r
524     map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(wtx.hashBlock);\r
525     if (mi != mapBlockIndex.end())\r
526         pindex = (*mi).second;\r
527 \r
528     // Sort order, unrecorded transactions sort to the top\r
529     string strSort = strprintf("%010d-%01d-%010u",\r
530         (pindex ? pindex->nHeight : INT_MAX),\r
531         (wtx.IsCoinBase() ? 1 : 0),\r
532         wtx.nTimeReceived);\r
533 \r
534     // Insert line\r
535     if (nNet > 0 || wtx.IsCoinBase())\r
536     {\r
537         //\r
538         // Credit\r
539         //\r
540         string strDescription;\r
541 \r
542         if (wtx.IsCoinBase())\r
543         {\r
544             // Coinbase\r
545             strDescription = "Generated";\r
546             if (nCredit == 0)\r
547             {\r
548                 int64 nUnmatured = 0;\r
549                 foreach(const CTxOut& txout, wtx.vout)\r
550                     nUnmatured += txout.GetCredit();\r
551                 if (wtx.IsInMainChain())\r
552                     strDescription += strprintf(" (%s matures in %d more blocks)", FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());\r
553                 else\r
554                     strDescription += " (not accepted)";\r
555             }\r
556         }\r
557         else if (!mapValue["from"].empty() || !mapValue["message"].empty())\r
558         {\r
559             // Online transaction\r
560             if (!mapValue["from"].empty())\r
561                 strDescription += "From: " + mapValue["from"];\r
562             if (!mapValue["message"].empty())\r
563             {\r
564                 if (!strDescription.empty())\r
565                     strDescription += " - ";\r
566                 strDescription += mapValue["message"];\r
567             }\r
568         }\r
569         else\r
570         {\r
571             // Offline transaction\r
572             foreach(const CTxOut& txout, wtx.vout)\r
573             {\r
574                 if (txout.IsMine())\r
575                 {\r
576                     vector<unsigned char> vchPubKey;\r
577                     if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))\r
578                     {\r
579                         string strAddress = PubKeyToAddress(vchPubKey);\r
580                         if (mapAddressBook.count(strAddress))\r
581                         {\r
582                             //strDescription += "Received payment to ";\r
583                             //strDescription += "Received with address ";\r
584                             strDescription += "From: unknown, To: ";\r
585                             strDescription += strAddress;\r
586                             /// The labeling feature is just too confusing, so I hid it\r
587                             /// by putting it at the end where it runs off the screen.\r
588                             /// It can still be seen by widening the column, or in the\r
589                             /// details dialog.\r
590                             if (!mapAddressBook[strAddress].empty())\r
591                                 strDescription += " (" + mapAddressBook[strAddress] + ")";\r
592                         }\r
593                     }\r
594                     break;\r
595                 }\r
596             }\r
597         }\r
598 \r
599         InsertLine(fNew, nIndex, hash, strSort,\r
600                    strStatus,\r
601                    nTime ? DateTimeStr(nTime) : "",\r
602                    SingleLine(strDescription),\r
603                    "",\r
604                    FormatMoney(nNet, true));\r
605     }\r
606     else\r
607     {\r
608         bool fAllFromMe = true;\r
609         foreach(const CTxIn& txin, wtx.vin)\r
610             fAllFromMe = fAllFromMe && txin.IsMine();\r
611 \r
612         bool fAllToMe = true;\r
613         foreach(const CTxOut& txout, wtx.vout)\r
614             fAllToMe = fAllToMe && txout.IsMine();\r
615 \r
616         if (fAllFromMe && fAllToMe)\r
617         {\r
618             // Payment to self\r
619             int64 nValue = wtx.vout[0].nValue;\r
620             InsertLine(fNew, nIndex, hash, strSort,\r
621                        strStatus,\r
622                        nTime ? DateTimeStr(nTime) : "",\r
623                        "Payment to yourself",\r
624                        FormatMoney(nNet - nValue, true),\r
625                        FormatMoney(nValue, true));\r
626         }\r
627         else if (fAllFromMe)\r
628         {\r
629             //\r
630             // Debit\r
631             //\r
632             int64 nTxFee = nDebit - wtx.GetValueOut();\r
633             wtx.nLinesDisplayed = 0;\r
634             for (int nOut = 0; nOut < wtx.vout.size(); nOut++)\r
635             {\r
636                 const CTxOut& txout = wtx.vout[nOut];\r
637                 if (txout.IsMine())\r
638                     continue;\r
639 \r
640                 string strAddress;\r
641                 if (!mapValue["to"].empty())\r
642                 {\r
643                     // Online transaction\r
644                     strAddress = mapValue["to"];\r
645                 }\r
646                 else\r
647                 {\r
648                     // Offline transaction\r
649                     uint160 hash160;\r
650                     if (ExtractHash160(txout.scriptPubKey, hash160))\r
651                         strAddress = Hash160ToAddress(hash160);\r
652                 }\r
653 \r
654                 string strDescription = "To: ";\r
655                 if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())\r
656                     strDescription += mapAddressBook[strAddress] + " ";\r
657                 strDescription += strAddress;\r
658                 if (!mapValue["message"].empty())\r
659                 {\r
660                     if (!strDescription.empty())\r
661                         strDescription += " - ";\r
662                     strDescription += mapValue["message"];\r
663                 }\r
664 \r
665                 int64 nValue = txout.nValue;\r
666                 if (nOut == 0 && nTxFee > 0)\r
667                     nValue += nTxFee;\r
668 \r
669                 InsertLine(fNew, nIndex, hash, strprintf("%s-%d", strSort.c_str(), nOut),\r
670                            strStatus,\r
671                            nTime ? DateTimeStr(nTime) : "",\r
672                            SingleLine(strDescription),\r
673                            FormatMoney(-nValue, true),\r
674                            "");\r
675                 wtx.nLinesDisplayed++;\r
676             }\r
677         }\r
678         else\r
679         {\r
680             //\r
681             // Mixed debit transaction, can't break down payees\r
682             //\r
683             bool fAllMine = true;\r
684             foreach(const CTxOut& txout, wtx.vout)\r
685                 fAllMine = fAllMine && txout.IsMine();\r
686             foreach(const CTxIn& txin, wtx.vin)\r
687                 fAllMine = fAllMine && txin.IsMine();\r
688 \r
689             InsertLine(fNew, nIndex, hash, strSort,\r
690                        strStatus,\r
691                        nTime ? DateTimeStr(nTime) : "",\r
692                        "",\r
693                        FormatMoney(nNet, true),\r
694                        "");\r
695         }\r
696     }\r
697 \r
698     return true;\r
699 }\r
700 \r
701 void CMainFrame::RefreshListCtrl()\r
702 {\r
703     fRefreshListCtrl = true;\r
704     ::wxWakeUpIdle();\r
705 }\r
706 \r
707 void CMainFrame::OnIdle(wxIdleEvent& event)\r
708 {\r
709     if (fRefreshListCtrl)\r
710     {\r
711         // Collect list of wallet transactions and sort newest first\r
712         bool fEntered = false;\r
713         vector<pair<unsigned int, uint256> > vSorted;\r
714         TRY_CRITICAL_BLOCK(cs_mapWallet)\r
715         {\r
716             printf("RefreshListCtrl starting\n");\r
717             fEntered = true;\r
718             fRefreshListCtrl = false;\r
719             vWalletUpdated.clear();\r
720 \r
721             // Do the newest transactions first\r
722             vSorted.reserve(mapWallet.size());\r
723             for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)\r
724             {\r
725                 const CWalletTx& wtx = (*it).second;\r
726                 unsigned int nTime = UINT_MAX - wtx.GetTxTime();\r
727                 vSorted.push_back(make_pair(nTime, (*it).first));\r
728             }\r
729             m_listCtrl->DeleteAllItems();\r
730         }\r
731         if (!fEntered)\r
732             return;\r
733 \r
734         sort(vSorted.begin(), vSorted.end());\r
735 \r
736         // Fill list control\r
737         for (int i = 0; i < vSorted.size();)\r
738         {\r
739             if (fShutdown)\r
740                 return;\r
741             bool fEntered = false;\r
742             TRY_CRITICAL_BLOCK(cs_mapWallet)\r
743             {\r
744                 fEntered = true;\r
745                 uint256& hash = vSorted[i++].second;\r
746                 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);\r
747                 if (mi != mapWallet.end())\r
748                     InsertTransaction((*mi).second, true);\r
749             }\r
750             if (!fEntered || i == 100 || i % 500 == 0)\r
751                 wxYield();\r
752         }\r
753 \r
754         printf("RefreshListCtrl done\n");\r
755 \r
756         // Update transaction total display\r
757         MainFrameRepaint();\r
758     }\r
759     else\r
760     {\r
761         // Check for time updates\r
762         static int64 nLastTime;\r
763         if (GetTime() > nLastTime + 30)\r
764         {\r
765             TRY_CRITICAL_BLOCK(cs_mapWallet)\r
766             {\r
767                 nLastTime = GetTime();\r
768                 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)\r
769                 {\r
770                     CWalletTx& wtx = (*it).second;\r
771                     if (wtx.nTimeDisplayed && wtx.nTimeDisplayed != wtx.GetTxTime())\r
772                         InsertTransaction(wtx, false);\r
773                 }\r
774             }\r
775         }\r
776     }\r
777 }\r
778 \r
779 void CMainFrame::RefreshStatusColumn()\r
780 {\r
781     static int nLastTop;\r
782     static CBlockIndex* pindexLastBest;\r
783     static unsigned int nLastRefreshed;\r
784 \r
785     int nTop = max((int)m_listCtrl->GetTopItem(), 0);\r
786     if (nTop == nLastTop && pindexLastBest == pindexBest)\r
787         return;\r
788 \r
789     TRY_CRITICAL_BLOCK(cs_mapWallet)\r
790     {\r
791         int nStart = nTop;\r
792         int nEnd = min(nStart + 100, m_listCtrl->GetItemCount());\r
793 \r
794         if (pindexLastBest == pindexBest && nLastRefreshed == nListViewUpdated)\r
795         {\r
796             // If no updates, only need to do the part that moved onto the screen\r
797             if (nStart >= nLastTop && nStart < nLastTop + 100)\r
798                 nStart = nLastTop + 100;\r
799             if (nEnd >= nLastTop && nEnd < nLastTop + 100)\r
800                 nEnd = nLastTop;\r
801         }\r
802         nLastTop = nTop;\r
803         pindexLastBest = pindexBest;\r
804         nLastRefreshed = nListViewUpdated;\r
805 \r
806         for (int nIndex = nStart; nIndex < min(nEnd, m_listCtrl->GetItemCount()); nIndex++)\r
807         {\r
808             uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1));\r
809             map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);\r
810             if (mi == mapWallet.end())\r
811             {\r
812                 printf("CMainFrame::RefreshStatusColumn() : tx not found in mapWallet\n");\r
813                 continue;\r
814             }\r
815             CWalletTx& wtx = (*mi).second;\r
816             if (wtx.IsCoinBase() || wtx.GetTxTime() != wtx.nTimeDisplayed)\r
817             {\r
818                 if (!InsertTransaction(wtx, false, nIndex))\r
819                     m_listCtrl->DeleteItem(nIndex--);\r
820             }\r
821             else\r
822                 m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx));\r
823         }\r
824     }\r
825 }\r
826 \r
827 void CMainFrame::OnPaint(wxPaintEvent& event)\r
828 {\r
829     event.Skip();\r
830 }\r
831 \r
832 \r
833 unsigned int nNeedRepaint = 0;\r
834 unsigned int nLastRepaint = 0;\r
835 int64 nLastRepaintTime = 0;\r
836 int64 nRepaintInterval = 500;\r
837 \r
838 void ThreadDelayedRepaint(void* parg)\r
839 {\r
840     while (!fShutdown)\r
841     {\r
842         if (nLastRepaint != nNeedRepaint && GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)\r
843         {\r
844             nLastRepaint = nNeedRepaint;\r
845             if (pframeMain)\r
846             {\r
847                 printf("DelayedRepaint\n");\r
848                 wxPaintEvent event;\r
849                 pframeMain->Refresh();\r
850                 pframeMain->AddPendingEvent(event);\r
851             }\r
852         }\r
853         Sleep(nRepaintInterval);\r
854     }\r
855 }\r
856 \r
857 void MainFrameRepaint()\r
858 {\r
859     // This is called by network code that shouldn't access pframeMain\r
860     // directly because it could still be running after the UI is closed.\r
861     if (pframeMain)\r
862     {\r
863         // Don't repaint too often\r
864         static int64 nLastRepaintRequest;\r
865         if (GetTimeMillis() - nLastRepaintRequest < 100)\r
866         {\r
867             nNeedRepaint++;\r
868             return;\r
869         }\r
870         nLastRepaintRequest = GetTimeMillis();\r
871 \r
872         printf("MainFrameRepaint\n");\r
873         wxPaintEvent event;\r
874         pframeMain->Refresh();\r
875         pframeMain->AddPendingEvent(event);\r
876     }\r
877 }\r
878 \r
879 void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)\r
880 {\r
881     if (ptaskbaricon)\r
882         ptaskbaricon->UpdateTooltip();\r
883 \r
884     //\r
885     // Slower stuff\r
886     //\r
887     static int nTransactionCount;\r
888     bool fPaintedBalance = false;\r
889     if (GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)\r
890     {\r
891         nLastRepaint = nNeedRepaint;\r
892         nLastRepaintTime = GetTimeMillis();\r
893 \r
894         // Update listctrl contents\r
895         if (!vWalletUpdated.empty())\r
896         {\r
897             TRY_CRITICAL_BLOCK(cs_mapWallet)\r
898             {\r
899                 string strTop;\r
900                 if (m_listCtrl->GetItemCount())\r
901                     strTop = (string)m_listCtrl->GetItemText(0);\r
902                 foreach(uint256 hash, vWalletUpdated)\r
903                 {\r
904                     map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);\r
905                     if (mi != mapWallet.end())\r
906                         InsertTransaction((*mi).second, false);\r
907                 }\r
908                 vWalletUpdated.clear();\r
909                 if (m_listCtrl->GetItemCount() && strTop != (string)m_listCtrl->GetItemText(0))\r
910                     m_listCtrl->ScrollList(0, INT_MAX);\r
911             }\r
912         }\r
913 \r
914         // Balance total\r
915         TRY_CRITICAL_BLOCK(cs_mapWallet)\r
916         {\r
917             fPaintedBalance = true;\r
918             m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + "  ");\r
919 \r
920             // Count hidden and multi-line transactions\r
921             nTransactionCount = 0;\r
922             for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)\r
923             {\r
924                 CWalletTx& wtx = (*it).second;\r
925                 nTransactionCount += wtx.nLinesDisplayed;\r
926             }\r
927         }\r
928     }\r
929     if (!vWalletUpdated.empty() || !fPaintedBalance)\r
930         nNeedRepaint++;\r
931 \r
932     // Update status column of visible items only\r
933     RefreshStatusColumn();\r
934 \r
935     // Update status bar\r
936     string strGen = "";\r
937     if (fGenerateBitcoins)\r
938         strGen = "    Generating";\r
939     if (fGenerateBitcoins && vNodes.empty())\r
940         strGen = "(not connected)";\r
941     m_statusBar->SetStatusText(strGen, 1);\r
942 \r
943     string strStatus = strprintf("     %d connections     %d blocks     %d transactions", vNodes.size(), nBestHeight + 1, nTransactionCount);\r
944     m_statusBar->SetStatusText(strStatus, 2);\r
945 \r
946 #ifdef __WXMSW__\r
947     m_listCtrl->OnPaint(event);\r
948 #endif\r
949 }\r
950 \r
951 \r
952 void CrossThreadCall(wxCommandEvent& event)\r
953 {\r
954     if (pframeMain)\r
955         pframeMain->GetEventHandler()->AddPendingEvent(event);\r
956 }\r
957 \r
958 void CrossThreadCall(int nID, void* pdata)\r
959 {\r
960     wxCommandEvent event;\r
961     event.SetInt(nID);\r
962     event.SetClientData(pdata);\r
963     if (pframeMain)\r
964         pframeMain->GetEventHandler()->AddPendingEvent(event);\r
965 }\r
966 \r
967 void CMainFrame::OnCrossThreadCall(wxCommandEvent& event)\r
968 {\r
969     void* pdata = event.GetClientData();\r
970     switch (event.GetInt())\r
971     {\r
972         case UICALL_ADDORDER:\r
973         {\r
974             break;\r
975         }\r
976 \r
977         case UICALL_UPDATEORDER:\r
978         {\r
979             break;\r
980         }\r
981     }\r
982 }\r
983 \r
984 void CMainFrame::OnMenuFileExit(wxCommandEvent& event)\r
985 {\r
986     // File->Exit\r
987     Close(true);\r
988 }\r
989 \r
990 void CMainFrame::OnMenuViewShowGenerated(wxCommandEvent& event)\r
991 {\r
992     // View->Show Generated\r
993     fShowGenerated = event.IsChecked();\r
994     CWalletDB().WriteSetting("fShowGenerated", fShowGenerated);\r
995     RefreshListCtrl();\r
996 }\r
997 \r
998 void CMainFrame::OnUpdateUIViewShowGenerated(wxUpdateUIEvent& event)\r
999 {\r
1000     event.Check(fShowGenerated);\r
1001 }\r
1002 \r
1003 void CMainFrame::OnMenuOptionsGenerate(wxCommandEvent& event)\r
1004 {\r
1005     // Options->Generate Coins\r
1006     GenerateBitcoins(event.IsChecked());\r
1007 }\r
1008 \r
1009 void CMainFrame::OnUpdateUIOptionsGenerate(wxUpdateUIEvent& event)\r
1010 {\r
1011     event.Check(fGenerateBitcoins);\r
1012 }\r
1013 \r
1014 void CMainFrame::OnMenuOptionsChangeYourAddress(wxCommandEvent& event)\r
1015 {\r
1016     // Options->Change Your Address\r
1017     OnButtonChange(event);\r
1018 }\r
1019 \r
1020 void CMainFrame::OnMenuOptionsOptions(wxCommandEvent& event)\r
1021 {\r
1022     // Options->Options\r
1023     COptionsDialog dialog(this);\r
1024     dialog.ShowModal();\r
1025 }\r
1026 \r
1027 void CMainFrame::OnMenuHelpAbout(wxCommandEvent& event)\r
1028 {\r
1029     // Help->About\r
1030     CAboutDialog dialog(this);\r
1031     dialog.ShowModal();\r
1032 }\r
1033 \r
1034 void CMainFrame::OnButtonSend(wxCommandEvent& event)\r
1035 {\r
1036     // Toolbar: Send\r
1037     CSendDialog dialog(this);\r
1038     dialog.ShowModal();\r
1039 }\r
1040 \r
1041 void CMainFrame::OnButtonAddressBook(wxCommandEvent& event)\r
1042 {\r
1043     // Toolbar: Address Book\r
1044     CAddressBookDialog dialogAddr(this, "", false);\r
1045     if (dialogAddr.ShowModal() == 2)\r
1046     {\r
1047         // Send\r
1048         CSendDialog dialogSend(this, dialogAddr.GetAddress());\r
1049         dialogSend.ShowModal();\r
1050     }\r
1051 }\r
1052 \r
1053 void CMainFrame::OnSetFocusAddress(wxFocusEvent& event)\r
1054 {\r
1055     // Automatically select-all when entering window\r
1056     m_textCtrlAddress->SetSelection(-1, -1);\r
1057     fOnSetFocusAddress = true;\r
1058     event.Skip();\r
1059 }\r
1060 \r
1061 void CMainFrame::OnMouseEventsAddress(wxMouseEvent& event)\r
1062 {\r
1063     if (fOnSetFocusAddress)\r
1064         m_textCtrlAddress->SetSelection(-1, -1);\r
1065     fOnSetFocusAddress = false;\r
1066     event.Skip();\r
1067 }\r
1068 \r
1069 void CMainFrame::OnButtonCopy(wxCommandEvent& event)\r
1070 {\r
1071     // Copy address box to clipboard\r
1072     if (wxTheClipboard->Open())\r
1073     {\r
1074         wxTheClipboard->SetData(new wxTextDataObject(m_textCtrlAddress->GetValue()));\r
1075         wxTheClipboard->Close();\r
1076     }\r
1077 }\r
1078 \r
1079 void CMainFrame::OnButtonChange(wxCommandEvent& event)\r
1080 {\r
1081     CYourAddressDialog dialog(this, string(m_textCtrlAddress->GetValue()));\r
1082     if (!dialog.ShowModal())\r
1083         return;\r
1084     string strAddress = (string)dialog.GetAddress();\r
1085     if (strAddress != m_textCtrlAddress->GetValue())\r
1086     {\r
1087         uint160 hash160;\r
1088         if (!AddressToHash160(strAddress, hash160))\r
1089             return;\r
1090         if (!mapPubKeys.count(hash160))\r
1091             return;\r
1092         CWalletDB().WriteDefaultKey(mapPubKeys[hash160]);\r
1093         m_textCtrlAddress->SetValue(strAddress);\r
1094     }\r
1095 }\r
1096 \r
1097 void CMainFrame::OnListItemActivatedAllTransactions(wxListEvent& event)\r
1098 {\r
1099     uint256 hash((string)GetItemText(m_listCtrl, event.GetIndex(), 1));\r
1100     CWalletTx wtx;\r
1101     CRITICAL_BLOCK(cs_mapWallet)\r
1102     {\r
1103         map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);\r
1104         if (mi == mapWallet.end())\r
1105         {\r
1106             printf("CMainFrame::OnListItemActivatedAllTransactions() : tx not found in mapWallet\n");\r
1107             return;\r
1108         }\r
1109         wtx = (*mi).second;\r
1110     }\r
1111     CTxDetailsDialog dialog(this, wtx);\r
1112     dialog.ShowModal();\r
1113     //CTxDetailsDialog* pdialog = new CTxDetailsDialog(this, wtx);\r
1114     //pdialog->Show();\r
1115 }\r
1116 \r
1117 void CMainFrame::OnListItemActivatedProductsSent(wxListEvent& event)\r
1118 {\r
1119     CProduct& product = *(CProduct*)event.GetItem().GetData();\r
1120     CEditProductDialog* pdialog = new CEditProductDialog(this);\r
1121     pdialog->SetProduct(product);\r
1122     pdialog->Show();\r
1123 }\r
1124 \r
1125 void CMainFrame::OnListItemActivatedOrdersSent(wxListEvent& event)\r
1126 {\r
1127     CWalletTx& order = *(CWalletTx*)event.GetItem().GetData();\r
1128     CViewOrderDialog* pdialog = new CViewOrderDialog(this, order, false);\r
1129     pdialog->Show();\r
1130 }\r
1131 \r
1132 void CMainFrame::OnListItemActivatedOrdersReceived(wxListEvent& event)\r
1133 {\r
1134     CWalletTx& order = *(CWalletTx*)event.GetItem().GetData();\r
1135     CViewOrderDialog* pdialog = new CViewOrderDialog(this, order, true);\r
1136     pdialog->Show();\r
1137 }\r
1138 \r
1139 \r
1140 \r
1141 \r
1142 \r
1143 \r
1144 \r
1145 //////////////////////////////////////////////////////////////////////////////\r
1146 //\r
1147 // CTxDetailsDialog\r
1148 //\r
1149 \r
1150 CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetailsDialogBase(parent)\r
1151 {\r
1152     string strHTML;\r
1153     strHTML.reserve(4000);\r
1154     strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";\r
1155 \r
1156     int64 nTime = wtx.GetTxTime();\r
1157     int64 nCredit = wtx.GetCredit();\r
1158     int64 nDebit = wtx.GetDebit();\r
1159     int64 nNet = nCredit - nDebit;\r
1160 \r
1161 \r
1162 \r
1163     strHTML += "<b>Status:</b> " + FormatTxStatus(wtx) + "<br>";\r
1164     strHTML += "<b>Date:</b> " + (nTime ? DateTimeStr(nTime) : "") + "<br>";\r
1165 \r
1166 \r
1167     //\r
1168     // From\r
1169     //\r
1170     if (wtx.IsCoinBase())\r
1171     {\r
1172         strHTML += "<b>Source:</b> Generated<br>";\r
1173     }\r
1174     else if (!wtx.mapValue["from"].empty())\r
1175     {\r
1176         // Online transaction\r
1177         if (!wtx.mapValue["from"].empty())\r
1178             strHTML += "<b>From:</b> " + HtmlEscape(wtx.mapValue["from"]) + "<br>";\r
1179     }\r
1180     else\r
1181     {\r
1182         // Offline transaction\r
1183         if (nNet > 0)\r
1184         {\r
1185             // Credit\r
1186             foreach(const CTxOut& txout, wtx.vout)\r
1187             {\r
1188                 if (txout.IsMine())\r
1189                 {\r
1190                     vector<unsigned char> vchPubKey;\r
1191                     if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))\r
1192                     {\r
1193                         string strAddress = PubKeyToAddress(vchPubKey);\r
1194                         if (mapAddressBook.count(strAddress))\r
1195                         {\r
1196                             strHTML += "<b>From:</b> unknown<br>";\r
1197                             strHTML += "<b>To:</b> ";\r
1198                             strHTML += HtmlEscape(strAddress);\r
1199                             if (!mapAddressBook[strAddress].empty())\r
1200                                 strHTML += " (yours, label: " + mapAddressBook[strAddress] + ")";\r
1201                             else\r
1202                                 strHTML += " (yours)";\r
1203                             strHTML += "<br>";\r
1204                         }\r
1205                     }\r
1206                     break;\r
1207                 }\r
1208             }\r
1209         }\r
1210     }\r
1211 \r
1212 \r
1213     //\r
1214     // To\r
1215     //\r
1216     string strAddress;\r
1217     if (!wtx.mapValue["to"].empty())\r
1218     {\r
1219         // Online transaction\r
1220         strAddress = wtx.mapValue["to"];\r
1221         strHTML += "<b>To:</b> ";\r
1222         if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())\r
1223             strHTML += mapAddressBook[strAddress] + " ";\r
1224         strHTML += HtmlEscape(strAddress) + "<br>";\r
1225     }\r
1226 \r
1227 \r
1228     //\r
1229     // Amount\r
1230     //\r
1231     if (wtx.IsCoinBase() && nCredit == 0)\r
1232     {\r
1233         //\r
1234         // Coinbase\r
1235         //\r
1236         int64 nUnmatured = 0;\r
1237         foreach(const CTxOut& txout, wtx.vout)\r
1238             nUnmatured += txout.GetCredit();\r
1239         if (wtx.IsInMainChain())\r
1240             strHTML += strprintf("<b>Credit:</b> (%s matures in %d more blocks)<br>", FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());\r
1241         else\r
1242             strHTML += "<b>Credit:</b> (not accepted)<br>";\r
1243     }\r
1244     else if (nNet > 0)\r
1245     {\r
1246         //\r
1247         // Credit\r
1248         //\r
1249         strHTML += "<b>Credit:</b> " + FormatMoney(nNet) + "<br>";\r
1250     }\r
1251     else\r
1252     {\r
1253         bool fAllFromMe = true;\r
1254         foreach(const CTxIn& txin, wtx.vin)\r
1255             fAllFromMe = fAllFromMe && txin.IsMine();\r
1256 \r
1257         bool fAllToMe = true;\r
1258         foreach(const CTxOut& txout, wtx.vout)\r
1259             fAllToMe = fAllToMe && txout.IsMine();\r
1260 \r
1261         if (fAllFromMe)\r
1262         {\r
1263             //\r
1264             // Debit\r
1265             //\r
1266             foreach(const CTxOut& txout, wtx.vout)\r
1267             {\r
1268                 if (txout.IsMine())\r
1269                     continue;\r
1270 \r
1271                 if (wtx.mapValue["to"].empty())\r
1272                 {\r
1273                     // Offline transaction\r
1274                     uint160 hash160;\r
1275                     if (ExtractHash160(txout.scriptPubKey, hash160))\r
1276                     {\r
1277                         string strAddress = Hash160ToAddress(hash160);\r
1278                         strHTML += "<b>To:</b> ";\r
1279                         if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())\r
1280                             strHTML += mapAddressBook[strAddress] + " ";\r
1281                         strHTML += strAddress;\r
1282                         strHTML += "<br>";\r
1283                     }\r
1284                 }\r
1285 \r
1286                 strHTML += "<b>Debit:</b> " + FormatMoney(-txout.nValue) + "<br>";\r
1287             }\r
1288 \r
1289             if (fAllToMe)\r
1290             {\r
1291                 // Payment to self\r
1292                 int64 nValue = wtx.vout[0].nValue;\r
1293                 strHTML += "<b>Debit:</b> " + FormatMoney(-nValue) + "<br>";\r
1294                 strHTML += "<b>Credit:</b> " + FormatMoney(nValue) + "<br>";\r
1295             }\r
1296 \r
1297             int64 nTxFee = nDebit - wtx.GetValueOut();\r
1298             if (nTxFee > 0)\r
1299                 strHTML += "<b>Transaction fee:</b> " + FormatMoney(-nTxFee) + "<br>";\r
1300         }\r
1301         else\r
1302         {\r
1303             //\r
1304             // Mixed debit transaction\r
1305             //\r
1306             foreach(const CTxIn& txin, wtx.vin)\r
1307                 if (txin.IsMine())\r
1308                     strHTML += "<b>Debit:</b> " + FormatMoney(-txin.GetDebit()) + "<br>";\r
1309             foreach(const CTxOut& txout, wtx.vout)\r
1310                 if (txout.IsMine())\r
1311                     strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";\r
1312         }\r
1313     }\r
1314 \r
1315     strHTML += "<b>Net amount:</b> " + FormatMoney(nNet, true) + "<br>";\r
1316 \r
1317 \r
1318     //\r
1319     // Message\r
1320     //\r
1321     if (!wtx.mapValue["message"].empty())\r
1322         strHTML += "<br><b>Message:</b><br>" + HtmlEscape(wtx.mapValue["message"], true) + "<br>";\r
1323 \r
1324     if (wtx.IsCoinBase())\r
1325         strHTML += "<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
1326 \r
1327 \r
1328     //\r
1329     // Debug view\r
1330     //\r
1331     if (fDebug)\r
1332     {\r
1333         strHTML += "<hr><br>debug print<br><br>";\r
1334         foreach(const CTxIn& txin, wtx.vin)\r
1335             if (txin.IsMine())\r
1336                 strHTML += "<b>Debit:</b> " + FormatMoney(-txin.GetDebit()) + "<br>";\r
1337         foreach(const CTxOut& txout, wtx.vout)\r
1338             if (txout.IsMine())\r
1339                 strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";\r
1340 \r
1341         strHTML += "<b>Inputs:</b><br>";\r
1342         CRITICAL_BLOCK(cs_mapWallet)\r
1343         {\r
1344             foreach(const CTxIn& txin, wtx.vin)\r
1345             {\r
1346                 COutPoint prevout = txin.prevout;\r
1347                 map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);\r
1348                 if (mi != mapWallet.end())\r
1349                 {\r
1350                     const CWalletTx& prev = (*mi).second;\r
1351                     if (prevout.n < prev.vout.size())\r
1352                     {\r
1353                         strHTML += HtmlEscape(prev.ToString(), true);\r
1354                         strHTML += " &nbsp;&nbsp; " + FormatTxStatus(prev) + ", ";\r
1355                         strHTML = strHTML + "IsMine=" + (prev.vout[prevout.n].IsMine() ? "true" : "false") + "<br>";\r
1356                     }\r
1357                 }\r
1358             }\r
1359         }\r
1360 \r
1361         strHTML += "<br><hr><br><b>Transaction:</b><br>";\r
1362         strHTML += HtmlEscape(wtx.ToString(), true);\r
1363     }\r
1364 \r
1365 \r
1366 \r
1367     strHTML += "</font></html>";\r
1368     string(strHTML.begin(), strHTML.end()).swap(strHTML);\r
1369     m_htmlWin->SetPage(strHTML);\r
1370     m_buttonOK->SetFocus();\r
1371 }\r
1372 \r
1373 void CTxDetailsDialog::OnButtonOK(wxCommandEvent& event)\r
1374 {\r
1375     Close();\r
1376     //Destroy();\r
1377 }\r
1378 \r
1379 \r
1380 \r
1381 \r
1382 \r
1383 //////////////////////////////////////////////////////////////////////////////\r
1384 //\r
1385 // COptionsDialog\r
1386 //\r
1387 \r
1388 COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent)\r
1389 {\r
1390     // Set up list box of page choices\r
1391     m_listBox->Append("Main");\r
1392     //m_listBox->Append("Test 2");\r
1393     m_listBox->SetSelection(0);\r
1394     SelectPage(0);\r
1395 \r
1396     // Init values\r
1397     m_textCtrlTransactionFee->SetValue(FormatMoney(nTransactionFee));\r
1398     m_checkBoxLimitProcessors->SetValue(fLimitProcessors);\r
1399     m_spinCtrlLimitProcessors->Enable(fLimitProcessors);\r
1400     m_spinCtrlLimitProcessors->SetValue(nLimitProcessors);\r
1401     int nProcessors = wxThread::GetCPUCount();\r
1402     if (nProcessors < 1)\r
1403         nProcessors = 999;\r
1404     m_spinCtrlLimitProcessors->SetRange(1, nProcessors);\r
1405     m_checkBoxStartOnSystemStartup->SetValue(fTmpStartOnSystemStartup = GetStartOnSystemStartup());\r
1406     m_checkBoxMinimizeToTray->SetValue(fMinimizeToTray);\r
1407     m_checkBoxMinimizeOnClose->Enable(fMinimizeToTray);\r
1408     m_checkBoxMinimizeOnClose->SetValue(fMinimizeToTray && fMinimizeOnClose);\r
1409     fTmpMinimizeOnClose = fMinimizeOnClose;\r
1410     m_checkBoxUseProxy->SetValue(fUseProxy);\r
1411     m_textCtrlProxyIP->Enable(fUseProxy);\r
1412     m_textCtrlProxyPort->Enable(fUseProxy);\r
1413     m_staticTextProxyIP->Enable(fUseProxy);\r
1414     m_staticTextProxyPort->Enable(fUseProxy);\r
1415     m_textCtrlProxyIP->SetValue(addrProxy.ToStringIP());\r
1416     m_textCtrlProxyPort->SetValue(addrProxy.ToStringPort());\r
1417 \r
1418     m_buttonOK->SetFocus();\r
1419 }\r
1420 \r
1421 void COptionsDialog::SelectPage(int nPage)\r
1422 {\r
1423     m_panelMain->Show(nPage == 0);\r
1424     m_panelTest2->Show(nPage == 1);\r
1425 \r
1426     m_scrolledWindow->Layout();\r
1427     m_scrolledWindow->SetScrollbars(0, 0, 0, 0, 0, 0);\r
1428 }\r
1429 \r
1430 void COptionsDialog::OnListBox(wxCommandEvent& event)\r
1431 {\r
1432     SelectPage(event.GetSelection());\r
1433 }\r
1434 \r
1435 void COptionsDialog::OnKillFocusTransactionFee(wxFocusEvent& event)\r
1436 {\r
1437     int64 nTmp = nTransactionFee;\r
1438     ParseMoney(m_textCtrlTransactionFee->GetValue(), nTmp);\r
1439     m_textCtrlTransactionFee->SetValue(FormatMoney(nTmp));\r
1440 }\r
1441 \r
1442 void COptionsDialog::OnCheckBoxLimitProcessors(wxCommandEvent& event)\r
1443 {\r
1444     m_spinCtrlLimitProcessors->Enable(event.IsChecked());\r
1445 }\r
1446 \r
1447 void COptionsDialog::OnCheckBoxMinimizeToTray(wxCommandEvent& event)\r
1448 {\r
1449     m_checkBoxMinimizeOnClose->Enable(event.IsChecked());\r
1450 \r
1451     // Save the value in fTmpMinimizeOnClose so we can\r
1452     // show the checkbox unchecked when its parent is unchecked\r
1453     if (event.IsChecked())\r
1454         m_checkBoxMinimizeOnClose->SetValue(fTmpMinimizeOnClose);\r
1455     else\r
1456     {\r
1457         fTmpMinimizeOnClose = m_checkBoxMinimizeOnClose->GetValue();\r
1458         m_checkBoxMinimizeOnClose->SetValue(false);\r
1459     }\r
1460 \r
1461 }\r
1462 \r
1463 void COptionsDialog::OnCheckBoxUseProxy(wxCommandEvent& event)\r
1464 {\r
1465     m_textCtrlProxyIP->Enable(event.IsChecked());\r
1466     m_textCtrlProxyPort->Enable(event.IsChecked());\r
1467     m_staticTextProxyIP->Enable(event.IsChecked());\r
1468     m_staticTextProxyPort->Enable(event.IsChecked());\r
1469 }\r
1470 \r
1471 CAddress COptionsDialog::GetProxyAddr()\r
1472 {\r
1473     // Be careful about byte order, addr.ip and addr.port are big endian\r
1474     CAddress addr(m_textCtrlProxyIP->GetValue() + ":" + m_textCtrlProxyPort->GetValue());\r
1475     if (addr.ip == INADDR_NONE)\r
1476         addr.ip = addrProxy.ip;\r
1477     int nPort = atoi(m_textCtrlProxyPort->GetValue());\r
1478     addr.port = htons(nPort);\r
1479     if (nPort <= 0 || nPort > USHRT_MAX)\r
1480         addr.port = addrProxy.port;\r
1481     return addr;\r
1482 }\r
1483 \r
1484 void COptionsDialog::OnKillFocusProxy(wxFocusEvent& event)\r
1485 {\r
1486     m_textCtrlProxyIP->SetValue(GetProxyAddr().ToStringIP());\r
1487     m_textCtrlProxyPort->SetValue(GetProxyAddr().ToStringPort());\r
1488 }\r
1489 \r
1490 \r
1491 void COptionsDialog::OnButtonOK(wxCommandEvent& event)\r
1492 {\r
1493     OnButtonApply(event);\r
1494     Close();\r
1495 }\r
1496 \r
1497 void COptionsDialog::OnButtonCancel(wxCommandEvent& event)\r
1498 {\r
1499     Close();\r
1500 }\r
1501 \r
1502 void COptionsDialog::OnButtonApply(wxCommandEvent& event)\r
1503 {\r
1504     CWalletDB walletdb;\r
1505 \r
1506     int64 nPrevTransactionFee = nTransactionFee;\r
1507     if (ParseMoney(m_textCtrlTransactionFee->GetValue(), nTransactionFee) && nTransactionFee != nPrevTransactionFee)\r
1508         walletdb.WriteSetting("nTransactionFee", nTransactionFee);\r
1509 \r
1510     int nPrevMaxProc = (fLimitProcessors ? nLimitProcessors : INT_MAX);\r
1511     if (fLimitProcessors != m_checkBoxLimitProcessors->GetValue())\r
1512     {\r
1513         fLimitProcessors = m_checkBoxLimitProcessors->GetValue();\r
1514         walletdb.WriteSetting("fLimitProcessors", fLimitProcessors);\r
1515     }\r
1516     if (nLimitProcessors != m_spinCtrlLimitProcessors->GetValue())\r
1517     {\r
1518         nLimitProcessors = m_spinCtrlLimitProcessors->GetValue();\r
1519         walletdb.WriteSetting("nLimitProcessors", nLimitProcessors);\r
1520     }\r
1521     if (fGenerateBitcoins && (fLimitProcessors ? nLimitProcessors : INT_MAX) > nPrevMaxProc)\r
1522         GenerateBitcoins(fGenerateBitcoins);\r
1523 \r
1524     if (fTmpStartOnSystemStartup != m_checkBoxStartOnSystemStartup->GetValue())\r
1525     {\r
1526         fTmpStartOnSystemStartup = m_checkBoxStartOnSystemStartup->GetValue();\r
1527         SetStartOnSystemStartup(fTmpStartOnSystemStartup);\r
1528     }\r
1529 \r
1530     if (fMinimizeToTray != m_checkBoxMinimizeToTray->GetValue())\r
1531     {\r
1532         fMinimizeToTray = m_checkBoxMinimizeToTray->GetValue();\r
1533         walletdb.WriteSetting("fMinimizeToTray", fMinimizeToTray);\r
1534         ptaskbaricon->Show(fMinimizeToTray);\r
1535     }\r
1536 \r
1537     if (fMinimizeOnClose != (fMinimizeToTray ? m_checkBoxMinimizeOnClose->GetValue() : fTmpMinimizeOnClose))\r
1538     {\r
1539         fMinimizeOnClose = (fMinimizeToTray ? m_checkBoxMinimizeOnClose->GetValue() : fTmpMinimizeOnClose);\r
1540         walletdb.WriteSetting("fMinimizeOnClose", fMinimizeOnClose);\r
1541     }\r
1542 \r
1543     fUseProxy = m_checkBoxUseProxy->GetValue();\r
1544     walletdb.WriteSetting("fUseProxy", fUseProxy);\r
1545 \r
1546     addrProxy = GetProxyAddr();\r
1547     walletdb.WriteSetting("addrProxy", addrProxy);\r
1548 }\r
1549 \r
1550 \r
1551 \r
1552 \r
1553 \r
1554 \r
1555 //////////////////////////////////////////////////////////////////////////////\r
1556 //\r
1557 // CAboutDialog\r
1558 //\r
1559 \r
1560 CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent)\r
1561 {\r
1562     m_staticTextVersion->SetLabel(strprintf("version 0.%d.%d Beta", VERSION/100, VERSION%100));\r
1563 \r
1564     // Workaround until upgrade to wxWidgets supporting UTF-8\r
1565     wxString str = m_staticTextMain->GetLabel();\r
1566     if (str.Find('Â') != wxNOT_FOUND)\r
1567         str.Remove(str.Find('Â'), 1);\r
1568     m_staticTextMain->SetLabel(str);\r
1569 }\r
1570 \r
1571 void CAboutDialog::OnButtonOK(wxCommandEvent& event)\r
1572 {\r
1573     Close();\r
1574 }\r
1575 \r
1576 \r
1577 \r
1578 \r
1579 \r
1580 \r
1581 //////////////////////////////////////////////////////////////////////////////\r
1582 //\r
1583 // CSendDialog\r
1584 //\r
1585 \r
1586 CSendDialog::CSendDialog(wxWindow* parent, const wxString& strAddress) : CSendDialogBase(parent)\r
1587 {\r
1588     // Init\r
1589     m_textCtrlAddress->SetValue(strAddress);\r
1590     m_choiceTransferType->SetSelection(0);\r
1591     m_bitmapCheckMark->Show(false);\r
1592     fEnabledPrev = true;\r
1593     //// todo: should add a display of your balance for convenience\r
1594 \r
1595     // Set Icon\r
1596     wxIcon iconSend;\r
1597     iconSend.CopyFromBitmap(wxBitmap(send16noshadow_xpm));\r
1598     SetIcon(iconSend);\r
1599 \r
1600     wxCommandEvent event;\r
1601     OnTextAddress(event);\r
1602 \r
1603     // Fixup the tab order\r
1604     m_buttonPaste->MoveAfterInTabOrder(m_buttonCancel);\r
1605     m_buttonAddress->MoveAfterInTabOrder(m_buttonPaste);\r
1606     this->Layout();\r
1607 }\r
1608 \r
1609 void CSendDialog::OnTextAddress(wxCommandEvent& event)\r
1610 {\r
1611     // Check mark\r
1612     bool fBitcoinAddress = IsValidBitcoinAddress(m_textCtrlAddress->GetValue());\r
1613     m_bitmapCheckMark->Show(fBitcoinAddress);\r
1614 \r
1615     // Grey out message if bitcoin address\r
1616     bool fEnable = !fBitcoinAddress;\r
1617     m_staticTextFrom->Enable(fEnable);\r
1618     m_textCtrlFrom->Enable(fEnable);\r
1619     m_staticTextMessage->Enable(fEnable);\r
1620     m_textCtrlMessage->Enable(fEnable);\r
1621     m_textCtrlMessage->SetBackgroundColour(wxSystemSettings::GetColour(fEnable ? wxSYS_COLOUR_WINDOW : wxSYS_COLOUR_BTNFACE));\r
1622     if (!fEnable && fEnabledPrev)\r
1623     {\r
1624         strFromSave    = m_textCtrlFrom->GetValue();\r
1625         strMessageSave = m_textCtrlMessage->GetValue();\r
1626         m_textCtrlFrom->SetValue("Will appear as \"From: Unknown\"");\r
1627         m_textCtrlMessage->SetValue("Can't include a message when sending to a Bitcoin address");\r
1628     }\r
1629     else if (fEnable && !fEnabledPrev)\r
1630     {\r
1631         m_textCtrlFrom->SetValue(strFromSave);\r
1632         m_textCtrlMessage->SetValue(strMessageSave);\r
1633     }\r
1634     fEnabledPrev = fEnable;\r
1635 }\r
1636 \r
1637 void CSendDialog::OnKillFocusAmount(wxFocusEvent& event)\r
1638 {\r
1639     // Reformat the amount\r
1640     if (m_textCtrlAmount->GetValue().Trim().empty())\r
1641         return;\r
1642     int64 nTmp;\r
1643     if (ParseMoney(m_textCtrlAmount->GetValue(), nTmp))\r
1644         m_textCtrlAmount->SetValue(FormatMoney(nTmp));\r
1645 }\r
1646 \r
1647 void CSendDialog::OnButtonAddressBook(wxCommandEvent& event)\r
1648 {\r
1649     // Open address book\r
1650     CAddressBookDialog dialog(this, m_textCtrlAddress->GetValue(), true);\r
1651     if (dialog.ShowModal())\r
1652         m_textCtrlAddress->SetValue(dialog.GetAddress());\r
1653 }\r
1654 \r
1655 void CSendDialog::OnButtonPaste(wxCommandEvent& event)\r
1656 {\r
1657     // Copy clipboard to address box\r
1658     if (wxTheClipboard->Open())\r
1659     {\r
1660         if (wxTheClipboard->IsSupported(wxDF_TEXT))\r
1661         {\r
1662             wxTextDataObject data;\r
1663             wxTheClipboard->GetData(data);\r
1664             m_textCtrlAddress->SetValue(data.GetText());\r
1665         }\r
1666         wxTheClipboard->Close();\r
1667     }\r
1668 }\r
1669 \r
1670 void CSendDialog::OnButtonSend(wxCommandEvent& event)\r
1671 {\r
1672     CWalletTx wtx;\r
1673     string strAddress = (string)m_textCtrlAddress->GetValue();\r
1674 \r
1675     // Parse amount\r
1676     int64 nValue = 0;\r
1677     if (!ParseMoney(m_textCtrlAmount->GetValue(), nValue) || nValue <= 0)\r
1678     {\r
1679         wxMessageBox("Error in amount  ", "Send Coins");\r
1680         return;\r
1681     }\r
1682     if (nValue > GetBalance())\r
1683     {\r
1684         wxMessageBox("Amount exceeds your balance  ", "Send Coins");\r
1685         return;\r
1686     }\r
1687     if (nValue + nTransactionFee > GetBalance())\r
1688     {\r
1689         wxMessageBox(string("Total exceeds your balance when the ") + FormatMoney(nTransactionFee) + " transaction fee is included  ", "Send Coins");\r
1690         return;\r
1691     }\r
1692 \r
1693     // Parse bitcoin address\r
1694     uint160 hash160;\r
1695     bool fBitcoinAddress = AddressToHash160(strAddress, hash160);\r
1696 \r
1697     if (fBitcoinAddress)\r
1698     {\r
1699         // Send to bitcoin address\r
1700         CScript scriptPubKey;\r
1701         scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;\r
1702 \r
1703         if (!SendMoney(scriptPubKey, nValue, wtx))\r
1704             return;\r
1705 \r
1706         wxMessageBox("Payment sent  ", "Sending...");\r
1707     }\r
1708     else\r
1709     {\r
1710         // Parse IP address\r
1711         CAddress addr(strAddress);\r
1712         if (!addr.IsValid())\r
1713         {\r
1714             wxMessageBox("Invalid address  ", "Send Coins");\r
1715             return;\r
1716         }\r
1717 \r
1718         // Message\r
1719         wtx.mapValue["to"] = strAddress;\r
1720         wtx.mapValue["from"] = m_textCtrlFrom->GetValue();\r
1721         wtx.mapValue["message"] = m_textCtrlMessage->GetValue();\r
1722 \r
1723         // Send to IP address\r
1724         CSendingDialog* pdialog = new CSendingDialog(this, addr, nValue, wtx);\r
1725         if (!pdialog->ShowModal())\r
1726             return;\r
1727     }\r
1728 \r
1729     if (!mapAddressBook.count(strAddress))\r
1730         SetAddressBookName(strAddress, "");\r
1731 \r
1732     EndModal(true);\r
1733 }\r
1734 \r
1735 void CSendDialog::OnButtonCancel(wxCommandEvent& event)\r
1736 {\r
1737     // Cancel\r
1738     EndModal(false);\r
1739 }\r
1740 \r
1741 \r
1742 \r
1743 \r
1744 \r
1745 \r
1746 //////////////////////////////////////////////////////////////////////////////\r
1747 //\r
1748 // CSendingDialog\r
1749 //\r
1750 \r
1751 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
1752 {\r
1753     addr = addrIn;\r
1754     nPrice = nPriceIn;\r
1755     wtx = wtxIn;\r
1756     start = wxDateTime::UNow();\r
1757     memset(pszStatus, 0, sizeof(pszStatus));\r
1758     fCanCancel = true;\r
1759     fAbort = false;\r
1760     fSuccess = false;\r
1761     fUIDone = false;\r
1762     fWorkDone = false;\r
1763 \r
1764     SetTitle(strprintf("Sending %s to %s...", FormatMoney(nPrice).c_str(), wtx.mapValue["to"].c_str()));\r
1765     m_textCtrlStatus->SetValue("");\r
1766 \r
1767     _beginthread(SendingDialogStartTransfer, 0, this);\r
1768 }\r
1769 \r
1770 CSendingDialog::~CSendingDialog()\r
1771 {\r
1772     printf("~CSendingDialog()\n");\r
1773 }\r
1774 \r
1775 void CSendingDialog::Close()\r
1776 {\r
1777     // Last one out turn out the lights.\r
1778     // fWorkDone signals that work side is done and UI thread should call destroy.\r
1779     // fUIDone signals that UI window has closed and work thread should call destroy.\r
1780     // This allows the window to disappear and end modality when cancelled\r
1781     // without making the user wait for ConnectNode to return.  The dialog object\r
1782     // hangs around in the background until the work thread exits.\r
1783     if (IsModal())\r
1784         EndModal(fSuccess);\r
1785     else\r
1786         Show(false);\r
1787     if (fWorkDone)\r
1788         Destroy();\r
1789     else\r
1790         fUIDone = true;\r
1791 }\r
1792 \r
1793 void CSendingDialog::OnClose(wxCloseEvent& event)\r
1794 {\r
1795     if (!event.CanVeto() || fWorkDone || fAbort || !fCanCancel)\r
1796     {\r
1797         Close();\r
1798     }\r
1799     else\r
1800     {\r
1801         event.Veto();\r
1802         wxCommandEvent cmdevent;\r
1803         OnButtonCancel(cmdevent);\r
1804     }\r
1805 }\r
1806 \r
1807 void CSendingDialog::OnButtonOK(wxCommandEvent& event)\r
1808 {\r
1809     if (fWorkDone)\r
1810         Close();\r
1811 }\r
1812 \r
1813 void CSendingDialog::OnButtonCancel(wxCommandEvent& event)\r
1814 {\r
1815     if (fCanCancel)\r
1816         fAbort = true;\r
1817 }\r
1818 \r
1819 void CSendingDialog::OnPaint(wxPaintEvent& event)\r
1820 {\r
1821     if (strlen(pszStatus) > 130)\r
1822         m_textCtrlStatus->SetValue(string("\n") + pszStatus);\r
1823     else\r
1824         m_textCtrlStatus->SetValue(string("\n\n") + pszStatus);\r
1825     m_staticTextSending->SetFocus();\r
1826     if (!fCanCancel)\r
1827         m_buttonCancel->Enable(false);\r
1828     if (fWorkDone)\r
1829     {\r
1830         m_buttonOK->Enable(true);\r
1831         m_buttonOK->SetFocus();\r
1832         m_buttonCancel->Enable(false);\r
1833     }\r
1834     if (fAbort && fCanCancel && IsShown())\r
1835     {\r
1836         strcpy(pszStatus, "CANCELLED");\r
1837         m_buttonOK->Enable(true);\r
1838         m_buttonOK->SetFocus();\r
1839         m_buttonCancel->Enable(false);\r
1840         m_buttonCancel->SetLabel("Cancelled");\r
1841         Close();\r
1842         wxMessageBox("Transfer cancelled  ", "Sending...", wxOK, this);\r
1843     }\r
1844     event.Skip();\r
1845 }\r
1846 \r
1847 \r
1848 //\r
1849 // Everything from here on is not in the UI thread and must only communicate\r
1850 // with the rest of the dialog through variables and calling repaint.\r
1851 //\r
1852 \r
1853 void CSendingDialog::Repaint()\r
1854 {\r
1855     Refresh();\r
1856     wxPaintEvent event;\r
1857     AddPendingEvent(event);\r
1858 }\r
1859 \r
1860 bool CSendingDialog::Status()\r
1861 {\r
1862     if (fUIDone)\r
1863     {\r
1864         Destroy();\r
1865         return false;\r
1866     }\r
1867     if (fAbort && fCanCancel)\r
1868     {\r
1869         memset(pszStatus, 0, 10);\r
1870         strcpy(pszStatus, "CANCELLED");\r
1871         Repaint();\r
1872         fWorkDone = true;\r
1873         return false;\r
1874     }\r
1875     return true;\r
1876 }\r
1877 \r
1878 bool CSendingDialog::Status(const string& str)\r
1879 {\r
1880     if (!Status())\r
1881         return false;\r
1882 \r
1883     // This can be read by the UI thread at any time,\r
1884     // so copy in a way that can be read cleanly at all times.\r
1885     memset(pszStatus, 0, min(str.size()+1, sizeof(pszStatus)));\r
1886     strlcpy(pszStatus, str.c_str(), sizeof(pszStatus));\r
1887 \r
1888     Repaint();\r
1889     return true;\r
1890 }\r
1891 \r
1892 bool CSendingDialog::Error(const string& str)\r
1893 {\r
1894     fCanCancel = false;\r
1895     fWorkDone = true;\r
1896     Status(string("Error: ") + str);\r
1897     return false;\r
1898 }\r
1899 \r
1900 void SendingDialogStartTransfer(void* parg)\r
1901 {\r
1902     ((CSendingDialog*)parg)->StartTransfer();\r
1903 }\r
1904 \r
1905 void CSendingDialog::StartTransfer()\r
1906 {\r
1907     // Make sure we have enough money\r
1908     if (nPrice + nTransactionFee > GetBalance())\r
1909     {\r
1910         Error("You don't have enough money");\r
1911         return;\r
1912     }\r
1913 \r
1914     // We may have connected already for product details\r
1915     if (!Status("Connecting..."))\r
1916         return;\r
1917     CNode* pnode = ConnectNode(addr, 5 * 60);\r
1918     if (!pnode)\r
1919     {\r
1920         Error("Unable to connect");\r
1921         return;\r
1922     }\r
1923 \r
1924     // Send order to seller, with response going to OnReply2 via event handler\r
1925     if (!Status("Requesting public key..."))\r
1926         return;\r
1927     pnode->PushRequest("checkorder", wtx, SendingDialogOnReply2, this);\r
1928 }\r
1929 \r
1930 void SendingDialogOnReply2(void* parg, CDataStream& vRecv)\r
1931 {\r
1932     ((CSendingDialog*)parg)->OnReply2(vRecv);\r
1933 }\r
1934 \r
1935 void CSendingDialog::OnReply2(CDataStream& vRecv)\r
1936 {\r
1937     if (!Status("Received public key..."))\r
1938         return;\r
1939 \r
1940     CScript scriptPubKey;\r
1941     int nRet;\r
1942     try\r
1943     {\r
1944         vRecv >> nRet;\r
1945         if (nRet > 0)\r
1946         {\r
1947             string strMessage;\r
1948             vRecv >> strMessage;\r
1949             Error("Transfer was not accepted");\r
1950             //// todo: enlarge the window and enable a hidden white box to put seller's message\r
1951             return;\r
1952         }\r
1953         vRecv >> scriptPubKey;\r
1954     }\r
1955     catch (...)\r
1956     {\r
1957         //// what do we want to do about this?\r
1958         Error("Invalid response received");\r
1959         return;\r
1960     }\r
1961 \r
1962     // Should already be connected\r
1963     CNode* pnode = ConnectNode(addr, 5 * 60);\r
1964     if (!pnode)\r
1965     {\r
1966         Error("Lost connection");\r
1967         return;\r
1968     }\r
1969 \r
1970     // Pause to give the user a chance to cancel\r
1971     while (wxDateTime::UNow() < start + wxTimeSpan(0, 0, 0, 2 * 1000))\r
1972     {\r
1973         Sleep(200);\r
1974         if (!Status())\r
1975             return;\r
1976     }\r
1977 \r
1978     CRITICAL_BLOCK(cs_main)\r
1979     {\r
1980         // Pay\r
1981         if (!Status("Creating transaction..."))\r
1982             return;\r
1983         if (nPrice + nTransactionFee > GetBalance())\r
1984         {\r
1985             Error("You don't have enough money");\r
1986             return;\r
1987         }\r
1988         CKey key;\r
1989         int64 nFeeRequired;\r
1990         if (!CreateTransaction(scriptPubKey, nPrice, wtx, key, nFeeRequired))\r
1991         {\r
1992             if (nPrice + nFeeRequired > GetBalance())\r
1993                 Error(strprintf("This is an oversized transaction that requires a transaction fee of %s", FormatMoney(nFeeRequired).c_str()));\r
1994             else\r
1995                 Error("Transaction creation failed");\r
1996             return;\r
1997         }\r
1998 \r
1999         // Last chance to cancel\r
2000         Sleep(50);\r
2001         if (!Status())\r
2002             return;\r
2003         fCanCancel = false;\r
2004         if (fAbort)\r
2005         {\r
2006             fCanCancel = true;\r
2007             if (!Status())\r
2008                 return;\r
2009             fCanCancel = false;\r
2010         }\r
2011         if (!Status("Sending payment..."))\r
2012             return;\r
2013 \r
2014         // Commit\r
2015         if (!CommitTransactionSpent(wtx, key))\r
2016         {\r
2017             Error("Error finalizing payment");\r
2018             return;\r
2019         }\r
2020 \r
2021         // Send payment tx to seller, with response going to OnReply3 via event handler\r
2022         pnode->PushRequest("submitorder", wtx, SendingDialogOnReply3, this);\r
2023 \r
2024         // Accept and broadcast transaction\r
2025         if (!wtx.AcceptTransaction())\r
2026             printf("ERROR: CSendingDialog : wtxNew.AcceptTransaction() %s failed\n", wtx.GetHash().ToString().c_str());\r
2027         wtx.RelayWalletTransaction();\r
2028 \r
2029         Status("Waiting for confirmation...");\r
2030         MainFrameRepaint();\r
2031     }\r
2032 }\r
2033 \r
2034 void SendingDialogOnReply3(void* parg, CDataStream& vRecv)\r
2035 {\r
2036     ((CSendingDialog*)parg)->OnReply3(vRecv);\r
2037 }\r
2038 \r
2039 void CSendingDialog::OnReply3(CDataStream& vRecv)\r
2040 {\r
2041     int nRet;\r
2042     try\r
2043     {\r
2044         vRecv >> nRet;\r
2045         if (nRet > 0)\r
2046         {\r
2047             Error("The payment was sent, but the recipient was unable to verify it.\n"\r
2048                   "The transaction is recorded and will credit to the recipient,\n"\r
2049                   "but the comment information will be blank.");\r
2050             return;\r
2051         }\r
2052     }\r
2053     catch (...)\r
2054     {\r
2055         //// what do we want to do about this?\r
2056         Error("Payment was sent, but an invalid response was received");\r
2057         return;\r
2058     }\r
2059 \r
2060     fSuccess = true;\r
2061     fWorkDone = true;\r
2062     Status("Payment completed");\r
2063 }\r
2064 \r
2065 \r
2066 \r
2067 \r
2068 \r
2069 \r
2070 //////////////////////////////////////////////////////////////////////////////\r
2071 //\r
2072 // CYourAddressDialog\r
2073 //\r
2074 \r
2075 CYourAddressDialog::CYourAddressDialog(wxWindow* parent, const string& strInitSelected) : CYourAddressDialogBase(parent)\r
2076 {\r
2077     // Init column headers\r
2078     m_listCtrl->InsertColumn(0, "Label", wxLIST_FORMAT_LEFT, 200);\r
2079     m_listCtrl->InsertColumn(1, "Bitcoin Address", wxLIST_FORMAT_LEFT, 350);\r
2080     m_listCtrl->SetFocus();\r
2081 \r
2082     // Fill listctrl with address book data\r
2083     CRITICAL_BLOCK(cs_mapKeys)\r
2084     {\r
2085         foreach(const PAIRTYPE(string, string)& item, mapAddressBook)\r
2086         {\r
2087             string strAddress = item.first;\r
2088             string strName = item.second;\r
2089             uint160 hash160;\r
2090             bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));\r
2091             if (fMine)\r
2092             {\r
2093                 int nIndex = InsertLine(m_listCtrl, strName, strAddress);\r
2094                 if (strAddress == strInitSelected)\r
2095                     m_listCtrl->SetItemState(nIndex, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);\r
2096             }\r
2097         }\r
2098     }\r
2099 }\r
2100 \r
2101 wxString CYourAddressDialog::GetAddress()\r
2102 {\r
2103     int nIndex = GetSelection(m_listCtrl);\r
2104     if (nIndex == -1)\r
2105         return "";\r
2106     return GetItemText(m_listCtrl, nIndex, 1);\r
2107 }\r
2108 \r
2109 void CYourAddressDialog::OnListEndLabelEdit(wxListEvent& event)\r
2110 {\r
2111     // Update address book with edited name\r
2112     if (event.IsEditCancelled())\r
2113         return;\r
2114     string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1);\r
2115     SetAddressBookName(strAddress, string(event.GetText()));\r
2116     pframeMain->RefreshListCtrl();\r
2117 }\r
2118 \r
2119 void CYourAddressDialog::OnListItemSelected(wxListEvent& event)\r
2120 {\r
2121 }\r
2122 \r
2123 void CYourAddressDialog::OnListItemActivated(wxListEvent& event)\r
2124 {\r
2125     // Doubleclick edits item\r
2126     wxCommandEvent event2;\r
2127     OnButtonRename(event2);\r
2128 }\r
2129 \r
2130 void CYourAddressDialog::OnButtonRename(wxCommandEvent& event)\r
2131 {\r
2132     // Ask new name\r
2133     int nIndex = GetSelection(m_listCtrl);\r
2134     if (nIndex == -1)\r
2135         return;\r
2136     string strName = (string)m_listCtrl->GetItemText(nIndex);\r
2137     string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);\r
2138     CGetTextFromUserDialog dialog(this, "Edit Address Label", "New Label", strName);\r
2139     if (!dialog.ShowModal())\r
2140         return;\r
2141     strName = dialog.GetValue();\r
2142 \r
2143     // Change name\r
2144     SetAddressBookName(strAddress, strName);\r
2145     m_listCtrl->SetItemText(nIndex, strName);\r
2146     pframeMain->RefreshListCtrl();\r
2147 }\r
2148 \r
2149 void CYourAddressDialog::OnButtonNew(wxCommandEvent& event)\r
2150 {\r
2151     // Ask name\r
2152     CGetTextFromUserDialog dialog(this, "New Bitcoin Address", "Label", "");\r
2153     if (!dialog.ShowModal())\r
2154         return;\r
2155     string strName = dialog.GetValue();\r
2156 \r
2157     // Generate new key\r
2158     string strAddress = PubKeyToAddress(GenerateNewKey());\r
2159     SetAddressBookName(strAddress, strName);\r
2160 \r
2161     // Add to list and select it\r
2162     int nIndex = InsertLine(m_listCtrl, strName, strAddress);\r
2163     SetSelection(m_listCtrl, nIndex);\r
2164     m_listCtrl->SetFocus();\r
2165 }\r
2166 \r
2167 void CYourAddressDialog::OnButtonCopy(wxCommandEvent& event)\r
2168 {\r
2169     // Copy address box to clipboard\r
2170     if (wxTheClipboard->Open())\r
2171     {\r
2172         wxTheClipboard->SetData(new wxTextDataObject(GetAddress()));\r
2173         wxTheClipboard->Close();\r
2174     }\r
2175 }\r
2176 \r
2177 void CYourAddressDialog::OnButtonOK(wxCommandEvent& event)\r
2178 {\r
2179     // OK\r
2180     EndModal(true);\r
2181 }\r
2182 \r
2183 void CYourAddressDialog::OnButtonCancel(wxCommandEvent& event)\r
2184 {\r
2185     // Cancel\r
2186     EndModal(false);\r
2187 }\r
2188 \r
2189 void CYourAddressDialog::OnClose(wxCloseEvent& event)\r
2190 {\r
2191     // Close\r
2192     EndModal(false);\r
2193 }\r
2194 \r
2195 \r
2196 \r
2197 \r
2198 \r
2199 \r
2200 //////////////////////////////////////////////////////////////////////////////\r
2201 //\r
2202 // CAddressBookDialog\r
2203 //\r
2204 \r
2205 CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInitSelected, bool fSendingIn) : CAddressBookDialogBase(parent)\r
2206 {\r
2207     fSending = fSendingIn;\r
2208     if (!fSending)\r
2209         m_buttonCancel->Show(false);\r
2210 \r
2211     // Init column headers\r
2212     m_listCtrl->InsertColumn(0, "Name", wxLIST_FORMAT_LEFT, 200);\r
2213     m_listCtrl->InsertColumn(1, "Address", wxLIST_FORMAT_LEFT, 350);\r
2214     m_listCtrl->SetFocus();\r
2215 \r
2216     // Set Icon\r
2217     wxIcon iconAddressBook;\r
2218     iconAddressBook.CopyFromBitmap(wxBitmap(addressbook16_xpm));\r
2219     SetIcon(iconAddressBook);\r
2220 \r
2221     // Fill listctrl with address book data\r
2222     CRITICAL_BLOCK(cs_mapKeys)\r
2223     {\r
2224         foreach(const PAIRTYPE(string, string)& item, mapAddressBook)\r
2225         {\r
2226             string strAddress = item.first;\r
2227             string strName = item.second;\r
2228             uint160 hash160;\r
2229             bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));\r
2230             if (!fMine)\r
2231             {\r
2232                 int nIndex = InsertLine(m_listCtrl, strName, strAddress);\r
2233                 if (strAddress == strInitSelected)\r
2234                     m_listCtrl->SetItemState(nIndex, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);\r
2235             }\r
2236         }\r
2237     }\r
2238 }\r
2239 \r
2240 wxString CAddressBookDialog::GetAddress()\r
2241 {\r
2242     int nIndex = GetSelection(m_listCtrl);\r
2243     if (nIndex == -1)\r
2244         return "";\r
2245     return GetItemText(m_listCtrl, nIndex, 1);\r
2246 }\r
2247 \r
2248 void CAddressBookDialog::OnListEndLabelEdit(wxListEvent& event)\r
2249 {\r
2250     // Update address book with edited name\r
2251     if (event.IsEditCancelled())\r
2252         return;\r
2253     string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1);\r
2254     SetAddressBookName(strAddress, string(event.GetText()));\r
2255     pframeMain->RefreshListCtrl();\r
2256 }\r
2257 \r
2258 void CAddressBookDialog::OnListItemSelected(wxListEvent& event)\r
2259 {\r
2260 }\r
2261 \r
2262 void CAddressBookDialog::OnListItemActivated(wxListEvent& event)\r
2263 {\r
2264     if (fSending)\r
2265     {\r
2266         // Doubleclick returns selection\r
2267         EndModal(GetAddress() != "" ? 2 : 0);\r
2268     }\r
2269     else\r
2270     {\r
2271         // Doubleclick edits item\r
2272         wxCommandEvent event2;\r
2273         OnButtonEdit(event2);\r
2274     }\r
2275 }\r
2276 \r
2277 bool CAddressBookDialog::CheckIfMine(const string& strAddress, const string& strTitle)\r
2278 {\r
2279     uint160 hash160;\r
2280     bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));\r
2281     if (fMine)\r
2282         wxMessageBox("This is one of your own addresses for receiving payments and cannot be entered in the address book.  ", strTitle);\r
2283     return fMine;\r
2284 }\r
2285 \r
2286 void CAddressBookDialog::OnButtonEdit(wxCommandEvent& event)\r
2287 {\r
2288     // Ask new name\r
2289     int nIndex = GetSelection(m_listCtrl);\r
2290     if (nIndex == -1)\r
2291         return;\r
2292     string strName = (string)m_listCtrl->GetItemText(nIndex);\r
2293     string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);\r
2294     string strAddressOrg = strAddress;\r
2295     do\r
2296     {\r
2297         CGetTextFromUserDialog dialog(this, "Edit Address", "Name", strName, "Address", strAddress);\r
2298         if (!dialog.ShowModal())\r
2299             return;\r
2300         strName = dialog.GetValue1();\r
2301         strAddress = dialog.GetValue2();\r
2302     }\r
2303     while (CheckIfMine(strAddress, "Edit Address"));\r
2304 \r
2305     // Change name\r
2306     if (strAddress != strAddressOrg)\r
2307         CWalletDB().EraseName(strAddressOrg);\r
2308     SetAddressBookName(strAddress, strName);\r
2309     m_listCtrl->SetItem(nIndex, 1, strAddress);\r
2310     m_listCtrl->SetItemText(nIndex, strName);\r
2311     pframeMain->RefreshListCtrl();\r
2312 }\r
2313 \r
2314 void CAddressBookDialog::OnButtonNew(wxCommandEvent& event)\r
2315 {\r
2316     // Ask name\r
2317     string strName;\r
2318     string strAddress;\r
2319     do\r
2320     {\r
2321         CGetTextFromUserDialog dialog(this, "New Address", "Name", strName, "Address", strAddress);\r
2322         if (!dialog.ShowModal())\r
2323             return;\r
2324         strName = dialog.GetValue1();\r
2325         strAddress = dialog.GetValue2();\r
2326     }\r
2327     while (CheckIfMine(strAddress, "New Address"));\r
2328 \r
2329     // Add to list and select it\r
2330     SetAddressBookName(strAddress, strName);\r
2331     int nIndex = InsertLine(m_listCtrl, strName, strAddress);\r
2332     SetSelection(m_listCtrl, nIndex);\r
2333     m_listCtrl->SetFocus();\r
2334     pframeMain->RefreshListCtrl();\r
2335 }\r
2336 \r
2337 void CAddressBookDialog::OnButtonDelete(wxCommandEvent& event)\r
2338 {\r
2339     for (int nIndex = m_listCtrl->GetItemCount()-1; nIndex >= 0; nIndex--)\r
2340     {\r
2341         if (m_listCtrl->GetItemState(nIndex, wxLIST_STATE_SELECTED))\r
2342         {\r
2343             string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);\r
2344             CWalletDB().EraseName(strAddress);\r
2345             m_listCtrl->DeleteItem(nIndex);\r
2346         }\r
2347     }\r
2348     pframeMain->RefreshListCtrl();\r
2349 }\r
2350 \r
2351 void CAddressBookDialog::OnButtonCopy(wxCommandEvent& event)\r
2352 {\r
2353     // Copy address box to clipboard\r
2354     if (wxTheClipboard->Open())\r
2355     {\r
2356         wxTheClipboard->SetData(new wxTextDataObject(GetAddress()));\r
2357         wxTheClipboard->Close();\r
2358     }\r
2359 }\r
2360 \r
2361 void CAddressBookDialog::OnButtonOK(wxCommandEvent& event)\r
2362 {\r
2363     // OK\r
2364     EndModal(GetAddress() != "" ? 1 : 0);\r
2365 }\r
2366 \r
2367 void CAddressBookDialog::OnButtonCancel(wxCommandEvent& event)\r
2368 {\r
2369     // Cancel\r
2370     EndModal(0);\r
2371 }\r
2372 \r
2373 void CAddressBookDialog::OnClose(wxCloseEvent& event)\r
2374 {\r
2375     // Close\r
2376     EndModal(0);\r
2377 }\r
2378 \r
2379 \r
2380 \r
2381 \r
2382 \r
2383 \r
2384 //////////////////////////////////////////////////////////////////////////////\r
2385 //\r
2386 // CProductsDialog\r
2387 //\r
2388 \r
2389 bool CompareIntStringPairBestFirst(const pair<int, string>& item1, const pair<int, string>& item2)\r
2390 {\r
2391     return (item1.first > item2.first);\r
2392 }\r
2393 \r
2394 CProductsDialog::CProductsDialog(wxWindow* parent) : CProductsDialogBase(parent)\r
2395 {\r
2396     // Init column headers\r
2397     m_listCtrl->InsertColumn(0, "Title",  wxLIST_FORMAT_LEFT, 200);\r
2398     m_listCtrl->InsertColumn(1, "Price",  wxLIST_FORMAT_LEFT, 80);\r
2399     m_listCtrl->InsertColumn(2, "Seller", wxLIST_FORMAT_LEFT, 80);\r
2400     m_listCtrl->InsertColumn(3, "Stars",  wxLIST_FORMAT_LEFT, 50);\r
2401     m_listCtrl->InsertColumn(4, "Power",  wxLIST_FORMAT_LEFT, 50);\r
2402 \r
2403     // Tally top categories\r
2404     map<string, int> mapTopCategories;\r
2405     CRITICAL_BLOCK(cs_mapProducts)\r
2406         for (map<uint256, CProduct>::iterator mi = mapProducts.begin(); mi != mapProducts.end(); ++mi)\r
2407             mapTopCategories[(*mi).second.mapValue["category"]]++;\r
2408 \r
2409     // Sort top categories\r
2410     vector<pair<int, string> > vTopCategories;\r
2411     for (map<string, int>::iterator mi = mapTopCategories.begin(); mi != mapTopCategories.end(); ++mi)\r
2412         vTopCategories.push_back(make_pair((*mi).second, (*mi).first));\r
2413     sort(vTopCategories.begin(), vTopCategories.end(), CompareIntStringPairBestFirst);\r
2414 \r
2415     // Fill categories combo box\r
2416     int nLimit = 250;\r
2417     for (vector<pair<int, string> >::iterator it = vTopCategories.begin(); it != vTopCategories.end() && nLimit-- > 0; ++it)\r
2418         m_comboBoxCategory->Append((*it).second);\r
2419 \r
2420     // Fill window with initial search\r
2421     //wxCommandEvent event;\r
2422     //OnButtonSearch(event);\r
2423 }\r
2424 \r
2425 void CProductsDialog::OnCombobox(wxCommandEvent& event)\r
2426 {\r
2427     OnButtonSearch(event);\r
2428 }\r
2429 \r
2430 bool CompareProductsBestFirst(const CProduct* p1, const CProduct* p2)\r
2431 {\r
2432     return (p1->nAtoms > p2->nAtoms);\r
2433 }\r
2434 \r
2435 void CProductsDialog::OnButtonSearch(wxCommandEvent& event)\r
2436 {\r
2437     string strCategory = (string)m_comboBoxCategory->GetValue();\r
2438     string strSearch = (string)m_textCtrlSearch->GetValue();\r
2439 \r
2440     // Search products\r
2441     vector<CProduct*> vProductsFound;\r
2442     CRITICAL_BLOCK(cs_mapProducts)\r
2443     {\r
2444         for (map<uint256, CProduct>::iterator mi = mapProducts.begin(); mi != mapProducts.end(); ++mi)\r
2445         {\r
2446             CProduct& product = (*mi).second;\r
2447             if (product.mapValue["category"].find(strCategory) != -1)\r
2448             {\r
2449                 if (product.mapValue["title"].find(strSearch) != -1 ||\r
2450                     product.mapValue["description"].find(strSearch) != -1 ||\r
2451                     product.mapValue["seller"].find(strSearch) != -1)\r
2452                 {\r
2453                     vProductsFound.push_back(&product);\r
2454                 }\r
2455             }\r
2456         }\r
2457     }\r
2458 \r
2459     // Sort\r
2460     sort(vProductsFound.begin(), vProductsFound.end(), CompareProductsBestFirst);\r
2461 \r
2462     // Display\r
2463     foreach(CProduct* pproduct, vProductsFound)\r
2464     {\r
2465         InsertLine(m_listCtrl,\r
2466                    pproduct->mapValue["title"],\r
2467                    pproduct->mapValue["price"],\r
2468                    pproduct->mapValue["seller"],\r
2469                    pproduct->mapValue["stars"],\r
2470                    itostr(pproduct->nAtoms));\r
2471     }\r
2472 }\r
2473 \r
2474 void CProductsDialog::OnListItemActivated(wxListEvent& event)\r
2475 {\r
2476     // Doubleclick opens product\r
2477     CViewProductDialog* pdialog = new CViewProductDialog(this, m_vProduct[event.GetIndex()]);\r
2478     pdialog->Show();\r
2479 }\r
2480 \r
2481 \r
2482 \r
2483 \r
2484 \r
2485 \r
2486 \r
2487 //////////////////////////////////////////////////////////////////////////////\r
2488 //\r
2489 // CEditProductDialog\r
2490 //\r
2491 \r
2492 CEditProductDialog::CEditProductDialog(wxWindow* parent) : CEditProductDialogBase(parent)\r
2493 {\r
2494     m_textCtrlLabel[0 ] = m_textCtrlLabel0;\r
2495     m_textCtrlLabel[1 ] = m_textCtrlLabel1;\r
2496     m_textCtrlLabel[2 ] = m_textCtrlLabel2;\r
2497     m_textCtrlLabel[3 ] = m_textCtrlLabel3;\r
2498     m_textCtrlLabel[4 ] = m_textCtrlLabel4;\r
2499     m_textCtrlLabel[5 ] = m_textCtrlLabel5;\r
2500     m_textCtrlLabel[6 ] = m_textCtrlLabel6;\r
2501     m_textCtrlLabel[7 ] = m_textCtrlLabel7;\r
2502     m_textCtrlLabel[8 ] = m_textCtrlLabel8;\r
2503     m_textCtrlLabel[9 ] = m_textCtrlLabel9;\r
2504     m_textCtrlLabel[10] = m_textCtrlLabel10;\r
2505     m_textCtrlLabel[11] = m_textCtrlLabel11;\r
2506     m_textCtrlLabel[12] = m_textCtrlLabel12;\r
2507     m_textCtrlLabel[13] = m_textCtrlLabel13;\r
2508     m_textCtrlLabel[14] = m_textCtrlLabel14;\r
2509     m_textCtrlLabel[15] = m_textCtrlLabel15;\r
2510     m_textCtrlLabel[16] = m_textCtrlLabel16;\r
2511     m_textCtrlLabel[17] = m_textCtrlLabel17;\r
2512     m_textCtrlLabel[18] = m_textCtrlLabel18;\r
2513     m_textCtrlLabel[19] = m_textCtrlLabel19;\r
2514 \r
2515     m_textCtrlField[0 ] = m_textCtrlField0;\r
2516     m_textCtrlField[1 ] = m_textCtrlField1;\r
2517     m_textCtrlField[2 ] = m_textCtrlField2;\r
2518     m_textCtrlField[3 ] = m_textCtrlField3;\r
2519     m_textCtrlField[4 ] = m_textCtrlField4;\r
2520     m_textCtrlField[5 ] = m_textCtrlField5;\r
2521     m_textCtrlField[6 ] = m_textCtrlField6;\r
2522     m_textCtrlField[7 ] = m_textCtrlField7;\r
2523     m_textCtrlField[8 ] = m_textCtrlField8;\r
2524     m_textCtrlField[9 ] = m_textCtrlField9;\r
2525     m_textCtrlField[10] = m_textCtrlField10;\r
2526     m_textCtrlField[11] = m_textCtrlField11;\r
2527     m_textCtrlField[12] = m_textCtrlField12;\r
2528     m_textCtrlField[13] = m_textCtrlField13;\r
2529     m_textCtrlField[14] = m_textCtrlField14;\r
2530     m_textCtrlField[15] = m_textCtrlField15;\r
2531     m_textCtrlField[16] = m_textCtrlField16;\r
2532     m_textCtrlField[17] = m_textCtrlField17;\r
2533     m_textCtrlField[18] = m_textCtrlField18;\r
2534     m_textCtrlField[19] = m_textCtrlField19;\r
2535 \r
2536     m_buttonDel[0 ] = m_buttonDel0;\r
2537     m_buttonDel[1 ] = m_buttonDel1;\r
2538     m_buttonDel[2 ] = m_buttonDel2;\r
2539     m_buttonDel[3 ] = m_buttonDel3;\r
2540     m_buttonDel[4 ] = m_buttonDel4;\r
2541     m_buttonDel[5 ] = m_buttonDel5;\r
2542     m_buttonDel[6 ] = m_buttonDel6;\r
2543     m_buttonDel[7 ] = m_buttonDel7;\r
2544     m_buttonDel[8 ] = m_buttonDel8;\r
2545     m_buttonDel[9 ] = m_buttonDel9;\r
2546     m_buttonDel[10] = m_buttonDel10;\r
2547     m_buttonDel[11] = m_buttonDel11;\r
2548     m_buttonDel[12] = m_buttonDel12;\r
2549     m_buttonDel[13] = m_buttonDel13;\r
2550     m_buttonDel[14] = m_buttonDel14;\r
2551     m_buttonDel[15] = m_buttonDel15;\r
2552     m_buttonDel[16] = m_buttonDel16;\r
2553     m_buttonDel[17] = m_buttonDel17;\r
2554     m_buttonDel[18] = m_buttonDel18;\r
2555     m_buttonDel[19] = m_buttonDel19;\r
2556 \r
2557     for (int i = 1; i < FIELDS_MAX; i++)\r
2558         ShowLine(i, false);\r
2559 \r
2560     LayoutAll();\r
2561 }\r
2562 \r
2563 void CEditProductDialog::LayoutAll()\r
2564 {\r
2565     m_scrolledWindow->Layout();\r
2566     m_scrolledWindow->GetSizer()->Fit(m_scrolledWindow);\r
2567     this->Layout();\r
2568 }\r
2569 \r
2570 void CEditProductDialog::ShowLine(int i, bool fShow)\r
2571 {\r
2572     m_textCtrlLabel[i]->Show(fShow);\r
2573     m_textCtrlField[i]->Show(fShow);\r
2574     m_buttonDel[i]->Show(fShow);\r
2575 }\r
2576 \r
2577 void CEditProductDialog::OnButtonDel0(wxCommandEvent& event)  { OnButtonDel(event, 0); }\r
2578 void CEditProductDialog::OnButtonDel1(wxCommandEvent& event)  { OnButtonDel(event, 1); }\r
2579 void CEditProductDialog::OnButtonDel2(wxCommandEvent& event)  { OnButtonDel(event, 2); }\r
2580 void CEditProductDialog::OnButtonDel3(wxCommandEvent& event)  { OnButtonDel(event, 3); }\r
2581 void CEditProductDialog::OnButtonDel4(wxCommandEvent& event)  { OnButtonDel(event, 4); }\r
2582 void CEditProductDialog::OnButtonDel5(wxCommandEvent& event)  { OnButtonDel(event, 5); }\r
2583 void CEditProductDialog::OnButtonDel6(wxCommandEvent& event)  { OnButtonDel(event, 6); }\r
2584 void CEditProductDialog::OnButtonDel7(wxCommandEvent& event)  { OnButtonDel(event, 7); }\r
2585 void CEditProductDialog::OnButtonDel8(wxCommandEvent& event)  { OnButtonDel(event, 8); }\r
2586 void CEditProductDialog::OnButtonDel9(wxCommandEvent& event)  { OnButtonDel(event, 9); }\r
2587 void CEditProductDialog::OnButtonDel10(wxCommandEvent& event) { OnButtonDel(event, 10); }\r
2588 void CEditProductDialog::OnButtonDel11(wxCommandEvent& event) { OnButtonDel(event, 11); }\r
2589 void CEditProductDialog::OnButtonDel12(wxCommandEvent& event) { OnButtonDel(event, 12); }\r
2590 void CEditProductDialog::OnButtonDel13(wxCommandEvent& event) { OnButtonDel(event, 13); }\r
2591 void CEditProductDialog::OnButtonDel14(wxCommandEvent& event) { OnButtonDel(event, 14); }\r
2592 void CEditProductDialog::OnButtonDel15(wxCommandEvent& event) { OnButtonDel(event, 15); }\r
2593 void CEditProductDialog::OnButtonDel16(wxCommandEvent& event) { OnButtonDel(event, 16); }\r
2594 void CEditProductDialog::OnButtonDel17(wxCommandEvent& event) { OnButtonDel(event, 17); }\r
2595 void CEditProductDialog::OnButtonDel18(wxCommandEvent& event) { OnButtonDel(event, 18); }\r
2596 void CEditProductDialog::OnButtonDel19(wxCommandEvent& event) { OnButtonDel(event, 19); }\r
2597 \r
2598 void CEditProductDialog::OnButtonDel(wxCommandEvent& event, int n)\r
2599 {\r
2600     Freeze();\r
2601     int x, y;\r
2602     m_scrolledWindow->GetViewStart(&x, &y);\r
2603     int i;\r
2604     for (i = n; i < FIELDS_MAX-1; i++)\r
2605     {\r
2606         m_textCtrlLabel[i]->SetValue(m_textCtrlLabel[i+1]->GetValue());\r
2607         m_textCtrlField[i]->SetValue(m_textCtrlField[i+1]->GetValue());\r
2608         if (!m_buttonDel[i+1]->IsShown())\r
2609             break;\r
2610     }\r
2611     m_textCtrlLabel[i]->SetValue("");\r
2612     m_textCtrlField[i]->SetValue("");\r
2613     ShowLine(i, false);\r
2614     m_buttonAddField->Enable(true);\r
2615     LayoutAll();\r
2616     m_scrolledWindow->Scroll(0, y);\r
2617     Thaw();\r
2618 }\r
2619 \r
2620 void CEditProductDialog::OnButtonAddField(wxCommandEvent& event)\r
2621 {\r
2622     for (int i = 0; i < FIELDS_MAX; i++)\r
2623     {\r
2624         if (!m_buttonDel[i]->IsShown())\r
2625         {\r
2626             Freeze();\r
2627             ShowLine(i, true);\r
2628             if (i == FIELDS_MAX-1)\r
2629                 m_buttonAddField->Enable(false);\r
2630             LayoutAll();\r
2631             m_scrolledWindow->Scroll(0, 99999);\r
2632             Thaw();\r
2633             break;\r
2634         }\r
2635     }\r
2636 }\r
2637 \r
2638 void CEditProductDialog::OnButtonSend(wxCommandEvent& event)\r
2639 {\r
2640     CProduct product;\r
2641     GetProduct(product);\r
2642 \r
2643     // Sign the detailed product\r
2644     product.vchPubKeyFrom = keyUser.GetPubKey();\r
2645     if (!keyUser.Sign(product.GetSigHash(), product.vchSig))\r
2646     {\r
2647         wxMessageBox("Error digitally signing the product  ");\r
2648         return;\r
2649     }\r
2650 \r
2651     // Save detailed product\r
2652     AddToMyProducts(product);\r
2653 \r
2654     // Strip down to summary product\r
2655     product.mapDetails.clear();\r
2656     product.vOrderForm.clear();\r
2657 \r
2658     // Sign the summary product\r
2659     if (!keyUser.Sign(product.GetSigHash(), product.vchSig))\r
2660     {\r
2661         wxMessageBox("Error digitally signing the product  ");\r
2662         return;\r
2663     }\r
2664 \r
2665     // Verify\r
2666     if (!product.CheckProduct())\r
2667     {\r
2668         wxMessageBox("Errors found in product  ");\r
2669         return;\r
2670     }\r
2671 \r
2672     // Broadcast\r
2673     AdvertStartPublish(pnodeLocalHost, MSG_PRODUCT, 0, product);\r
2674 \r
2675     Destroy();\r
2676 }\r
2677 \r
2678 void CEditProductDialog::OnButtonPreview(wxCommandEvent& event)\r
2679 {\r
2680     CProduct product;\r
2681     GetProduct(product);\r
2682     CViewProductDialog* pdialog = new CViewProductDialog(this, product);\r
2683     pdialog->Show();\r
2684 }\r
2685 \r
2686 void CEditProductDialog::OnButtonCancel(wxCommandEvent& event)\r
2687 {\r
2688     Destroy();\r
2689 }\r
2690 \r
2691 void CEditProductDialog::SetProduct(const CProduct& productIn)\r
2692 {\r
2693     CProduct product = productIn;\r
2694 \r
2695     m_comboBoxCategory->SetValue(product.mapValue["category"]);\r
2696     m_textCtrlTitle->SetValue(product.mapValue["title"]);\r
2697     m_textCtrlPrice->SetValue(product.mapValue["price"]);\r
2698     m_textCtrlDescription->SetValue(product.mapValue["description"]);\r
2699     m_textCtrlInstructions->SetValue(product.mapValue["instructions"]);\r
2700 \r
2701     for (int i = 0; i < FIELDS_MAX; i++)\r
2702     {\r
2703         bool fUsed = i < product.vOrderForm.size();\r
2704         m_buttonDel[i]->Show(fUsed);\r
2705         m_textCtrlLabel[i]->Show(fUsed);\r
2706         m_textCtrlField[i]->Show(fUsed);\r
2707         if (!fUsed)\r
2708             continue;\r
2709 \r
2710         m_textCtrlLabel[i]->SetValue(product.vOrderForm[i].first);\r
2711         string strControl = product.vOrderForm[i].second;\r
2712         if (strControl.substr(0, 5) == "text=")\r
2713             m_textCtrlField[i]->SetValue("");\r
2714         else if (strControl.substr(0, 7) == "choice=")\r
2715             m_textCtrlField[i]->SetValue(strControl.substr(7));\r
2716         else\r
2717             m_textCtrlField[i]->SetValue(strControl);\r
2718     }\r
2719 }\r
2720 \r
2721 void CEditProductDialog::GetProduct(CProduct& product)\r
2722 {\r
2723     // map<string, string> mapValue;\r
2724     // vector<pair<string, string> > vOrderForm;\r
2725 \r
2726     product.mapValue["category"]     = m_comboBoxCategory->GetValue().Trim();\r
2727     product.mapValue["title"]        = m_textCtrlTitle->GetValue().Trim();\r
2728     product.mapValue["price"]        = m_textCtrlPrice->GetValue().Trim();\r
2729     product.mapValue["description"]  = m_textCtrlDescription->GetValue().Trim();\r
2730     product.mapValue["instructions"] = m_textCtrlInstructions->GetValue().Trim();\r
2731 \r
2732     for (int i = 0; i < FIELDS_MAX; i++)\r
2733     {\r
2734         if (m_buttonDel[i]->IsShown())\r
2735         {\r
2736             string strLabel = (string)m_textCtrlLabel[i]->GetValue().Trim();\r
2737             string strControl = (string)m_textCtrlField[i]->GetValue();\r
2738             if (strControl.empty())\r
2739                 strControl = "text=";\r
2740             else\r
2741                 strControl = "choice=" + strControl;\r
2742             product.vOrderForm.push_back(make_pair(strLabel, strControl));\r
2743         }\r
2744     }\r
2745 }\r
2746 \r
2747 \r
2748 \r
2749 \r
2750 \r
2751 \r
2752 \r
2753 //////////////////////////////////////////////////////////////////////////////\r
2754 //\r
2755 // CViewProductDialog\r
2756 //\r
2757 \r
2758 CViewProductDialog::CViewProductDialog(wxWindow* parent, const CProduct& productIn) : CViewProductDialogBase(parent)\r
2759 {\r
2760     Connect(wxEVT_REPLY1, wxCommandEventHandler(CViewProductDialog::OnReply1), NULL, this);\r
2761     AddCallbackAvailable(GetEventHandler());\r
2762 \r
2763     // Fill display with product summary while waiting for details\r
2764     product = productIn;\r
2765     UpdateProductDisplay(false);\r
2766 \r
2767     m_buttonBack->Enable(false);\r
2768     m_buttonNext->Enable(!product.vOrderForm.empty());\r
2769     m_htmlWinReviews->Show(true);\r
2770     m_scrolledWindow->Show(false);\r
2771     this->Layout();\r
2772 \r
2773     // Request details from seller\r
2774     _beginthread(ThreadRequestProductDetails, 0, new pair<CProduct, wxEvtHandler*>(product, GetEventHandler()));\r
2775 }\r
2776 \r
2777 CViewProductDialog::~CViewProductDialog()\r
2778 {\r
2779     RemoveCallbackAvailable(GetEventHandler());\r
2780 }\r
2781 \r
2782 void ThreadRequestProductDetails(void* parg)\r
2783 {\r
2784     // Extract parameters\r
2785     pair<CProduct, wxEvtHandler*>* pitem = (pair<CProduct, wxEvtHandler*>*)parg;\r
2786     CProduct product = pitem->first;\r
2787     wxEvtHandler* pevthandler = pitem->second;\r
2788     delete pitem;\r
2789 \r
2790     // Connect to seller\r
2791     CNode* pnode = ConnectNode(product.addr, 5 * 60);\r
2792     if (!pnode)\r
2793     {\r
2794         CDataStream ssEmpty;\r
2795         AddPendingReplyEvent1(pevthandler, ssEmpty);\r
2796         return;\r
2797     }\r
2798 \r
2799     // Request detailed product, with response going to OnReply1 via dialog's event handler\r
2800     pnode->PushRequest("getdetails", product.GetHash(), AddPendingReplyEvent1, (void*)pevthandler);\r
2801 }\r
2802 \r
2803 void CViewProductDialog::OnReply1(wxCommandEvent& event)\r
2804 {\r
2805     CDataStream ss = GetStreamFromEvent(event);\r
2806     if (ss.empty())\r
2807     {\r
2808         product.mapValue["description"] = "-- CAN'T CONNECT TO SELLER --\n";\r
2809         UpdateProductDisplay(true);\r
2810         return;\r
2811     }\r
2812 \r
2813     int nRet;\r
2814     CProduct product2;\r
2815     try\r
2816     {\r
2817         ss >> nRet;\r
2818         if (nRet > 0)\r
2819             throw false;\r
2820         ss >> product2;\r
2821         if (product2.GetHash() != product.GetHash())\r
2822             throw false;\r
2823         if (!product2.CheckSignature())\r
2824             throw false;\r
2825     }\r
2826     catch (...)\r
2827     {\r
2828         product.mapValue["description"] = "-- INVALID RESPONSE --\n";\r
2829         UpdateProductDisplay(true);\r
2830         return;\r
2831     }\r
2832 \r
2833     product = product2;\r
2834     UpdateProductDisplay(true);\r
2835 }\r
2836 \r
2837 bool CompareReviewsBestFirst(const CReview* p1, const CReview* p2)\r
2838 {\r
2839     return (p1->nAtoms > p2->nAtoms);\r
2840 }\r
2841 \r
2842 void CViewProductDialog::UpdateProductDisplay(bool fDetails)\r
2843 {\r
2844     // Product and reviews\r
2845     string strHTML;\r
2846     strHTML.reserve(4000);\r
2847     strHTML += "<html>\n"\r
2848                "<head>\n"\r
2849                "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"\r
2850                "</head>\n"\r
2851                "<body>\n";\r
2852     strHTML += "<b>Category:</b> " + HtmlEscape(product.mapValue["category"]) + "<br>\n";\r
2853     strHTML += "<b>Title:</b> "    + HtmlEscape(product.mapValue["title"])    + "<br>\n";\r
2854     strHTML += "<b>Price:</b> "    + HtmlEscape(product.mapValue["price"])    + "<br>\n";\r
2855 \r
2856     if (!fDetails)\r
2857         strHTML += "<b>Loading details...</b><br>\n<br>\n";\r
2858     else\r
2859         strHTML += HtmlEscape(product.mapValue["description"], true) + "<br>\n<br>\n";\r
2860 \r
2861     strHTML += "<b>Reviews:</b><br>\n<br>\n";\r
2862 \r
2863     if (!product.vchPubKeyFrom.empty())\r
2864     {\r
2865         CReviewDB reviewdb("r");\r
2866 \r
2867         // Get reviews\r
2868         vector<CReview> vReviews;\r
2869         reviewdb.ReadReviews(product.GetUserHash(), vReviews);\r
2870 \r
2871         // Get reviewer's number of atoms\r
2872         vector<CReview*> vSortedReviews;\r
2873         vSortedReviews.reserve(vReviews.size());\r
2874         for (vector<CReview>::reverse_iterator it = vReviews.rbegin(); it != vReviews.rend(); ++it)\r
2875         {\r
2876             CReview& review = *it;\r
2877             CUser user;\r
2878             reviewdb.ReadUser(review.GetUserHash(), user);\r
2879             review.nAtoms = user.GetAtomCount();\r
2880             vSortedReviews.push_back(&review);\r
2881         }\r
2882 \r
2883         reviewdb.Close();\r
2884 \r
2885         // Sort\r
2886         stable_sort(vSortedReviews.begin(), vSortedReviews.end(), CompareReviewsBestFirst);\r
2887 \r
2888         // Format reviews\r
2889         foreach(CReview* preview, vSortedReviews)\r
2890         {\r
2891             CReview& review = *preview;\r
2892             int nStars = atoi(review.mapValue["stars"].c_str());\r
2893             if (nStars < 1 || nStars > 5)\r
2894                 continue;\r
2895 \r
2896             strHTML += "<b>" + itostr(nStars) + (nStars == 1 ? " star" : " stars") + "</b>";\r
2897             strHTML += " &nbsp;&nbsp;&nbsp; ";\r
2898             strHTML += DateStr(atoi64(review.mapValue["date"])) + "<br>\n";\r
2899             strHTML += HtmlEscape(review.mapValue["review"], true);\r
2900             strHTML += "<br>\n<br>\n";\r
2901         }\r
2902     }\r
2903 \r
2904     strHTML += "</body>\n</html>\n";\r
2905 \r
2906     // Shrink capacity to fit\r
2907     string(strHTML.begin(), strHTML.end()).swap(strHTML);\r
2908 \r
2909     m_htmlWinReviews->SetPage(strHTML);\r
2910 \r
2911     ///// need to find some other indicator to use so can allow empty order form\r
2912     if (product.vOrderForm.empty())\r
2913         return;\r
2914 \r
2915     // Order form\r
2916     m_staticTextInstructions->SetLabel(product.mapValue["instructions"]);\r
2917     for (int i = 0; i < FIELDS_MAX; i++)\r
2918     {\r
2919         m_staticTextLabel[i] = NULL;\r
2920         m_textCtrlField[i] = NULL;\r
2921         m_choiceField[i] = NULL;\r
2922     }\r
2923 \r
2924     // Construct flexgridsizer\r
2925     wxBoxSizer* bSizer21 = (wxBoxSizer*)m_scrolledWindow->GetSizer();\r
2926     wxFlexGridSizer* fgSizer;\r
2927     fgSizer = new wxFlexGridSizer(0, 2, 0, 0);\r
2928     fgSizer->AddGrowableCol(1);\r
2929     fgSizer->SetFlexibleDirection(wxBOTH);\r
2930     fgSizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\r
2931 \r
2932     // Construct order form fields\r
2933     wxWindow* windowLast = NULL;\r
2934     for (int i = 0; i < product.vOrderForm.size(); i++)\r
2935     {\r
2936         string strLabel = product.vOrderForm[i].first;\r
2937         string strControl = product.vOrderForm[i].second;\r
2938 \r
2939         if (strLabel.size() < 20)\r
2940             strLabel.insert(strLabel.begin(), 20 - strLabel.size(), ' ');\r
2941 \r
2942         m_staticTextLabel[i] = new wxStaticText(m_scrolledWindow, wxID_ANY, strLabel, wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);\r
2943         m_staticTextLabel[i]->Wrap(-1);\r
2944         fgSizer->Add(m_staticTextLabel[i], 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5);\r
2945 \r
2946         if (strControl.substr(0, 5) == "text=")\r
2947         {\r
2948             m_textCtrlField[i] = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0);\r
2949             fgSizer->Add(m_textCtrlField[i], 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5);\r
2950             windowLast = m_textCtrlField[i];\r
2951         }\r
2952         else if (strControl.substr(0, 7) == "choice=")\r
2953         {\r
2954             vector<string> vChoices;\r
2955             ParseString(strControl.substr(7), ',', vChoices);\r
2956 \r
2957             wxArrayString arraystring;\r
2958             foreach(const string& str, vChoices)\r
2959                 arraystring.Add(str);\r
2960 \r
2961             m_choiceField[i] = new wxChoice(m_scrolledWindow, wxID_ANY, wxDefaultPosition, wxDefaultSize, arraystring, 0);\r
2962             fgSizer->Add(m_choiceField[i], 0, wxALL|wxALIGN_CENTER_VERTICAL, 5);\r
2963             windowLast = m_choiceField[i];\r
2964         }\r
2965         else\r
2966         {\r
2967             m_textCtrlField[i] = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0);\r
2968             fgSizer->Add(m_textCtrlField[i], 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5);\r
2969             m_staticTextLabel[i]->Show(false);\r
2970             m_textCtrlField[i]->Show(false);\r
2971         }\r
2972     }\r
2973 \r
2974     // Insert after instructions and before submit/cancel buttons\r
2975     bSizer21->Insert(2, fgSizer, 0, wxEXPAND|wxRIGHT|wxLEFT, 5);\r
2976     m_scrolledWindow->Layout();\r
2977     bSizer21->Fit(m_scrolledWindow);\r
2978     this->Layout();\r
2979 \r
2980     // Fixup the tab order\r
2981     m_buttonSubmitForm->MoveAfterInTabOrder(windowLast);\r
2982     m_buttonCancelForm->MoveAfterInTabOrder(m_buttonSubmitForm);\r
2983     //m_buttonBack->MoveAfterInTabOrder(m_buttonCancelForm);\r
2984     //m_buttonNext->MoveAfterInTabOrder(m_buttonBack);\r
2985     //m_buttonCancel->MoveAfterInTabOrder(m_buttonNext);\r
2986     this->Layout();\r
2987 }\r
2988 \r
2989 void CViewProductDialog::GetOrder(CWalletTx& wtx)\r
2990 {\r
2991     wtx.SetNull();\r
2992     for (int i = 0; i < product.vOrderForm.size(); i++)\r
2993     {\r
2994         string strValue;\r
2995         if (m_textCtrlField[i])\r
2996             strValue = m_textCtrlField[i]->GetValue().Trim();\r
2997         else\r
2998             strValue = m_choiceField[i]->GetStringSelection();\r
2999         wtx.vOrderForm.push_back(make_pair(m_staticTextLabel[i]->GetLabel(), strValue));\r
3000     }\r
3001 }\r
3002 \r
3003 void CViewProductDialog::OnButtonSubmitForm(wxCommandEvent& event)\r
3004 {\r
3005     m_buttonSubmitForm->Enable(false);\r
3006     m_buttonCancelForm->Enable(false);\r
3007 \r
3008     CWalletTx wtx;\r
3009     GetOrder(wtx);\r
3010 \r
3011     CSendingDialog* pdialog = new CSendingDialog(this, product.addr, atoi64(product.mapValue["price"]), wtx);\r
3012     if (!pdialog->ShowModal())\r
3013     {\r
3014         m_buttonSubmitForm->Enable(true);\r
3015         m_buttonCancelForm->Enable(true);\r
3016         return;\r
3017     }\r
3018 }\r
3019 \r
3020 void CViewProductDialog::OnButtonCancelForm(wxCommandEvent& event)\r
3021 {\r
3022     Destroy();\r
3023 }\r
3024 \r
3025 void CViewProductDialog::OnButtonBack(wxCommandEvent& event)\r
3026 {\r
3027     Freeze();\r
3028     m_htmlWinReviews->Show(true);\r
3029     m_scrolledWindow->Show(false);\r
3030     m_buttonBack->Enable(false);\r
3031     m_buttonNext->Enable(!product.vOrderForm.empty());\r
3032     this->Layout();\r
3033     Thaw();\r
3034 }\r
3035 \r
3036 void CViewProductDialog::OnButtonNext(wxCommandEvent& event)\r
3037 {\r
3038     if (!product.vOrderForm.empty())\r
3039     {\r
3040         Freeze();\r
3041         m_htmlWinReviews->Show(false);\r
3042         m_scrolledWindow->Show(true);\r
3043         m_buttonBack->Enable(true);\r
3044         m_buttonNext->Enable(false);\r
3045         this->Layout();\r
3046         Thaw();\r
3047     }\r
3048 }\r
3049 \r
3050 void CViewProductDialog::OnButtonCancel(wxCommandEvent& event)\r
3051 {\r
3052     Destroy();\r
3053 }\r
3054 \r
3055 \r
3056 \r
3057 \r
3058 \r
3059 \r
3060 \r
3061 //////////////////////////////////////////////////////////////////////////////\r
3062 //\r
3063 // CViewOrderDialog\r
3064 //\r
3065 \r
3066 CViewOrderDialog::CViewOrderDialog(wxWindow* parent, CWalletTx order, bool fReceived) : CViewOrderDialogBase(parent)\r
3067 {\r
3068     int64 nPrice = (fReceived ? order.GetCredit() : order.GetDebit());\r
3069 \r
3070     string strHTML;\r
3071     strHTML.reserve(4000);\r
3072     strHTML += "<html>\n"\r
3073                "<head>\n"\r
3074                "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"\r
3075                "</head>\n"\r
3076                "<body>\n";\r
3077     strHTML += "<b>Time:</b> "   + HtmlEscape(DateTimeStr(order.nTimeReceived)) + "<br>\n";\r
3078     strHTML += "<b>Price:</b> "  + HtmlEscape(FormatMoney(nPrice)) + "<br>\n";\r
3079     strHTML += "<b>Status:</b> " + HtmlEscape(FormatTxStatus(order)) + "<br>\n";\r
3080 \r
3081     strHTML += "<table>\n";\r
3082     for (int i = 0; i < order.vOrderForm.size(); i++)\r
3083     {\r
3084         strHTML += " <tr><td><b>" + HtmlEscape(order.vOrderForm[i].first) + ":</b></td>";\r
3085         strHTML += "<td>" + HtmlEscape(order.vOrderForm[i].second) + "</td></tr>\n";\r
3086     }\r
3087     strHTML += "</table>\n";\r
3088 \r
3089     strHTML += "</body>\n</html>\n";\r
3090 \r
3091     // Shrink capacity to fit\r
3092     // (strings are ref counted, so it may live on in SetPage)\r
3093     string(strHTML.begin(), strHTML.end()).swap(strHTML);\r
3094 \r
3095     m_htmlWin->SetPage(strHTML);\r
3096 }\r
3097 \r
3098 void CViewOrderDialog::OnButtonOK(wxCommandEvent& event)\r
3099 {\r
3100     Destroy();\r
3101 }\r
3102 \r
3103 \r
3104 \r
3105 \r
3106 \r
3107 \r
3108 \r
3109 //////////////////////////////////////////////////////////////////////////////\r
3110 //\r
3111 // CEditReviewDialog\r
3112 //\r
3113 \r
3114 CEditReviewDialog::CEditReviewDialog(wxWindow* parent) : CEditReviewDialogBase(parent)\r
3115 {\r
3116 }\r
3117 \r
3118 void CEditReviewDialog::OnButtonSubmit(wxCommandEvent& event)\r
3119 {\r
3120     if (m_choiceStars->GetSelection() == -1)\r
3121     {\r
3122         wxMessageBox("Please select a rating  ");\r
3123         return;\r
3124     }\r
3125 \r
3126     CReview review;\r
3127     GetReview(review);\r
3128 \r
3129     // Sign the review\r
3130     review.vchPubKeyFrom = keyUser.GetPubKey();\r
3131     if (!keyUser.Sign(review.GetSigHash(), review.vchSig))\r
3132     {\r
3133         wxMessageBox("Unable to digitally sign the review  ");\r
3134         return;\r
3135     }\r
3136 \r
3137     // Broadcast\r
3138     if (!review.AcceptReview())\r
3139     {\r
3140         wxMessageBox("Save failed  ");\r
3141         return;\r
3142     }\r
3143     RelayMessage(CInv(MSG_REVIEW, review.GetHash()), review);\r
3144 \r
3145     Destroy();\r
3146 }\r
3147 \r
3148 void CEditReviewDialog::OnButtonCancel(wxCommandEvent& event)\r
3149 {\r
3150     Destroy();\r
3151 }\r
3152 \r
3153 void CEditReviewDialog::GetReview(CReview& review)\r
3154 {\r
3155     review.mapValue["time"]   = i64tostr(GetAdjustedTime());\r
3156     review.mapValue["stars"]  = itostr(m_choiceStars->GetSelection()+1);\r
3157     review.mapValue["review"] = m_textCtrlReview->GetValue();\r
3158 }\r
3159 \r
3160 \r
3161 \r
3162 \r
3163 \r
3164 \r
3165 \r
3166 //////////////////////////////////////////////////////////////////////////////\r
3167 //\r
3168 // CMyTaskBarIcon\r
3169 //\r
3170 \r
3171 enum\r
3172 {\r
3173     ID_TASKBAR_RESTORE = 10001,\r
3174     ID_TASKBAR_GENERATE,\r
3175     ID_TASKBAR_EXIT,\r
3176 };\r
3177 \r
3178 BEGIN_EVENT_TABLE(CMyTaskBarIcon, wxTaskBarIcon)\r
3179     EVT_TASKBAR_LEFT_DCLICK(CMyTaskBarIcon::OnLeftButtonDClick)\r
3180     EVT_MENU(ID_TASKBAR_RESTORE, CMyTaskBarIcon::OnMenuRestore)\r
3181     EVT_MENU(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnMenuGenerate)\r
3182     EVT_UPDATE_UI(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnUpdateUIGenerate)\r
3183     EVT_MENU(ID_TASKBAR_EXIT, CMyTaskBarIcon::OnMenuExit)\r
3184 END_EVENT_TABLE()\r
3185 \r
3186 void CMyTaskBarIcon::Show(bool fShow)\r
3187 {\r
3188     static char pszPrevTip[200];\r
3189     if (fShow)\r
3190     {\r
3191         string strTooltip = "Bitcoin";\r
3192         if (fGenerateBitcoins)\r
3193             strTooltip = "Bitcoin - Generating";\r
3194         if (fGenerateBitcoins && vNodes.empty())\r
3195             strTooltip = "Bitcoin - (not connected)";\r
3196 \r
3197         // Optimization, only update when changed, using char array to be reentrant\r
3198         if (strncmp(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip)-1) != 0)\r
3199         {\r
3200             strlcpy(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip));\r
3201             SetIcon(wxICON(bitcoin), strTooltip);\r
3202         }\r
3203     }\r
3204     else\r
3205     {\r
3206         strlcpy(pszPrevTip, "", sizeof(pszPrevTip));\r
3207         RemoveIcon();\r
3208     }\r
3209 }\r
3210 \r
3211 void CMyTaskBarIcon::Hide()\r
3212 {\r
3213     Show(false);\r
3214 }\r
3215 \r
3216 void CMyTaskBarIcon::OnLeftButtonDClick(wxTaskBarIconEvent& event)\r
3217 {\r
3218     Restore();\r
3219 }\r
3220 \r
3221 void CMyTaskBarIcon::OnMenuRestore(wxCommandEvent& event)\r
3222 {\r
3223     Restore();\r
3224 }\r
3225 \r
3226 void CMyTaskBarIcon::Restore()\r
3227 {\r
3228     pframeMain->Show();\r
3229     pframeMain->Iconize(false);\r
3230     pframeMain->Raise();\r
3231 }\r
3232 \r
3233 void CMyTaskBarIcon::OnMenuGenerate(wxCommandEvent& event)\r
3234 {\r
3235     GenerateBitcoins(event.IsChecked());\r
3236 }\r
3237 \r
3238 void CMyTaskBarIcon::OnUpdateUIGenerate(wxUpdateUIEvent& event)\r
3239 {\r
3240     event.Check(fGenerateBitcoins);\r
3241 }\r
3242 \r
3243 void CMyTaskBarIcon::OnMenuExit(wxCommandEvent& event)\r
3244 {\r
3245     pframeMain->Close(true);\r
3246 }\r
3247 \r
3248 void CMyTaskBarIcon::UpdateTooltip()\r
3249 {\r
3250     if (IsIconInstalled())\r
3251         Show(true);\r
3252 }\r
3253 \r
3254 wxMenu* CMyTaskBarIcon::CreatePopupMenu()\r
3255 {\r
3256     wxMenu* pmenu = new wxMenu;\r
3257     pmenu->Append(ID_TASKBAR_RESTORE, "&Open Bitcoin");\r
3258     pmenu->AppendCheckItem(ID_TASKBAR_GENERATE, "&Generate Coins")->Check(fGenerateBitcoins);\r
3259 #ifndef __WXMAC_OSX__ // Mac has built-in quit menu\r
3260     pmenu->AppendSeparator();\r
3261     pmenu->Append(ID_TASKBAR_EXIT, "E&xit");\r
3262 #endif\r
3263     return pmenu;\r
3264 }\r
3265 \r
3266 \r
3267 \r
3268 \r
3269 \r
3270 \r
3271 \r
3272 \r
3273 \r
3274 \r
3275 \r
3276 \r
3277 \r
3278 //////////////////////////////////////////////////////////////////////////////\r
3279 //\r
3280 // CMyApp\r
3281 //\r
3282 \r
3283 // Define a new application\r
3284 class CMyApp: public wxApp\r
3285 {\r
3286   public:\r
3287     CMyApp(){};\r
3288     ~CMyApp(){};\r
3289     bool OnInit();\r
3290     bool OnInit2();\r
3291     int OnExit();\r
3292 \r
3293     // 2nd-level exception handling: we get all the exceptions occurring in any\r
3294     // event handler here\r
3295     virtual bool OnExceptionInMainLoop();\r
3296 \r
3297     // 3rd, and final, level exception handling: whenever an unhandled\r
3298     // exception is caught, this function is called\r
3299     virtual void OnUnhandledException();\r
3300 \r
3301     // and now for something different: this function is called in case of a\r
3302     // crash (e.g. dereferencing null pointer, division by 0, ...)\r
3303     virtual void OnFatalException();\r
3304 };\r
3305 \r
3306 IMPLEMENT_APP(CMyApp)\r
3307 \r
3308 bool CMyApp::OnInit()\r
3309 {\r
3310     try\r
3311     {\r
3312         return OnInit2();\r
3313     }\r
3314     catch (std::exception& e) {\r
3315         PrintException(&e, "OnInit()");\r
3316     } catch (...) {\r
3317         PrintException(NULL, "OnInit()");\r
3318     }\r
3319     return false;\r
3320 }\r
3321 \r
3322 bool CMyApp::OnInit2()\r
3323 {\r
3324 #ifdef _MSC_VER\r
3325     // Turn off microsoft heap dump noise for now\r
3326     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);\r
3327     _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));\r
3328 #endif\r
3329 #if defined(__WXMSW__) && defined(__WXDEBUG__)\r
3330     // Disable malfunctioning wxWidgets debug assertion\r
3331     g_isPainting = 10000;\r
3332 #endif\r
3333     wxImage::AddHandler(new wxPNGHandler);\r
3334     SetAppName("Bitcoin");\r
3335 \r
3336     ParseParameters(argc, argv);\r
3337     if (mapArgs.count("-?") || mapArgs.count("--help"))\r
3338     {\r
3339         string strUsage =\r
3340             "Usage: bitcoin [options]\t\t\t\t\t\t\n"\r
3341             "Options:\n"\r
3342             "  -gen\t\t  Generate coins\n"\r
3343             "  -gen=0\t\t  Don't generate coins\n"\r
3344             "  -min\t\t  Start minimized\n"\r
3345             "  -datadir=<dir>\t  Specify data directory\n"\r
3346             "  -proxy=<ip:port>\t  Connect through socks4 proxy\n"\r
3347             "  -addnode=<ip>\t  Add a node to connect to\n"\r
3348             "  -connect=<ip>\t  Connect only to the specified node\n"\r
3349             "  -?\t\t  This help message\n";\r
3350         wxMessageBox(strUsage, "Bitcoin", wxOK);\r
3351         exit(0);\r
3352     }\r
3353 \r
3354     //\r
3355     // Limit to single instance per user\r
3356     // Required to protect the database files if we're going to keep deleting log.*\r
3357     //\r
3358     wxString strMutexName = wxString("Bitcoin.") + getenv("HOMEPATH");\r
3359     for (int i = 0; i < strMutexName.size(); i++)\r
3360         if (!isalnum(strMutexName[i]))\r
3361             strMutexName[i] = '.';\r
3362     wxSingleInstanceChecker* psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);\r
3363     if (psingleinstancechecker->IsAnotherRunning())\r
3364     {\r
3365         printf("Existing instance found\n");\r
3366         unsigned int nStart = GetTime();\r
3367         loop\r
3368         {\r
3369             // TODO: find out how to do this in Linux, or replace with wxWidgets commands\r
3370 #ifdef __WXMSW__\r
3371             // Show the previous instance and exit\r
3372             HWND hwndPrev = FindWindow("wxWindowClassNR", "Bitcoin");\r
3373             if (hwndPrev)\r
3374             {\r
3375                 if (IsIconic(hwndPrev))\r
3376                     ShowWindow(hwndPrev, SW_RESTORE);\r
3377                 SetForegroundWindow(hwndPrev);\r
3378                 return false;\r
3379             }\r
3380 #endif\r
3381 \r
3382             if (GetTime() > nStart + 60)\r
3383                 return false;\r
3384 \r
3385             // Resume this instance if the other exits\r
3386             delete psingleinstancechecker;\r
3387             Sleep(1000);\r
3388             psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);\r
3389             if (!psingleinstancechecker->IsAnotherRunning())\r
3390                 break;\r
3391         }\r
3392     }\r
3393 \r
3394     //\r
3395     // Parameters\r
3396     //\r
3397     if (mapArgs.count("-datadir"))\r
3398         strlcpy(pszSetDataDir, mapArgs["-datadir"].c_str(), sizeof(pszSetDataDir));\r
3399 \r
3400     if (mapArgs.count("-debug"))\r
3401         fDebug = true;\r
3402 \r
3403     if (mapArgs.count("-printtodebugger"))\r
3404         fPrintToDebugger = true;\r
3405 \r
3406     printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");\r
3407     printf("Bitcoin version %d, OS version %s\n", VERSION, wxGetOsDescription().mb_str());\r
3408 \r
3409     if (mapArgs.count("-dropmessages"))\r
3410     {\r
3411         nDropMessagesTest = atoi(mapArgs["-dropmessages"]);\r
3412         if (nDropMessagesTest == 0)\r
3413             nDropMessagesTest = 20;\r
3414     }\r
3415 \r
3416     if (mapArgs.count("-loadblockindextest"))\r
3417     {\r
3418         CTxDB txdb("r");\r
3419         txdb.LoadBlockIndex();\r
3420         PrintBlockTree();\r
3421         exit(0);\r
3422     }\r
3423 \r
3424     //\r
3425     // Load data files\r
3426     //\r
3427     bool fFirstRun;\r
3428     string strErrors;\r
3429     int64 nStart;\r
3430 \r
3431     printf("Loading addresses...\n");\r
3432     nStart = GetTimeMillis();\r
3433     if (!LoadAddresses())\r
3434         strErrors += "Error loading addr.dat      \n";\r
3435     printf(" addresses   %15"PRI64d"ms\n", GetTimeMillis() - nStart);\r
3436 \r
3437     printf("Loading block index...\n");\r
3438     nStart = GetTimeMillis();\r
3439     if (!LoadBlockIndex())\r
3440         strErrors += "Error loading blkindex.dat      \n";\r
3441     printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);\r
3442 \r
3443     printf("Loading wallet...\n");\r
3444     nStart = GetTimeMillis();\r
3445     if (!LoadWallet(fFirstRun))\r
3446         strErrors += "Error loading wallet.dat      \n";\r
3447     printf(" wallet      %15"PRI64d"ms\n", GetTimeMillis() - nStart);\r
3448 \r
3449     printf("Done loading\n");\r
3450 \r
3451         //// debug print\r
3452         printf("mapBlockIndex.size() = %d\n",   mapBlockIndex.size());\r
3453         printf("nBestHeight = %d\n",            nBestHeight);\r
3454         printf("mapKeys.size() = %d\n",         mapKeys.size());\r
3455         printf("mapPubKeys.size() = %d\n",      mapPubKeys.size());\r
3456         printf("mapWallet.size() = %d\n",       mapWallet.size());\r
3457         printf("mapAddressBook.size() = %d\n",  mapAddressBook.size());\r
3458 \r
3459     if (!strErrors.empty())\r
3460     {\r
3461         wxMessageBox(strErrors, "Bitcoin");\r
3462         OnExit();\r
3463         return false;\r
3464     }\r
3465 \r
3466     // Add wallet transactions that aren't already in a block to mapTransactions\r
3467     ReacceptWalletTransactions();\r
3468 \r
3469     //\r
3470     // Parameters\r
3471     //\r
3472     if (mapArgs.count("-printblockindex") || mapArgs.count("-printblocktree"))\r
3473     {\r
3474         PrintBlockTree();\r
3475         OnExit();\r
3476         return false;\r
3477     }\r
3478 \r
3479     if (mapArgs.count("-printblock"))\r
3480     {\r
3481         string strMatch = mapArgs["-printblock"];\r
3482         int nFound = 0;\r
3483         for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)\r
3484         {\r
3485             uint256 hash = (*mi).first;\r
3486             if (strncmp(hash.ToString().c_str(), strMatch.c_str(), strMatch.size()) == 0)\r
3487             {\r
3488                 CBlockIndex* pindex = (*mi).second;\r
3489                 CBlock block;\r
3490                 block.ReadFromDisk(pindex, true);\r
3491                 block.BuildMerkleTree();\r
3492                 block.print();\r
3493                 printf("\n");\r
3494                 nFound++;\r
3495             }\r
3496         }\r
3497         if (nFound == 0)\r
3498             printf("No blocks matching %s were found\n", strMatch.c_str());\r
3499         OnExit();\r
3500         return false;\r
3501     }\r
3502 \r
3503     if (mapArgs.count("-gen"))\r
3504     {\r
3505         if (mapArgs["-gen"].empty())\r
3506             fGenerateBitcoins = true;\r
3507         else\r
3508             fGenerateBitcoins = (atoi(mapArgs["-gen"].c_str()) != 0);\r
3509     }\r
3510 \r
3511     if (mapArgs.count("-proxy"))\r
3512     {\r
3513         fUseProxy = true;\r
3514         addrProxy = CAddress(mapArgs["-proxy"]);\r
3515         if (!addrProxy.IsValid())\r
3516         {\r
3517             wxMessageBox("Invalid -proxy address", "Bitcoin");\r
3518             OnExit();\r
3519             return false;\r
3520         }\r
3521     }\r
3522 \r
3523     if (mapArgs.count("-addnode"))\r
3524     {\r
3525         CAddrDB addrdb;\r
3526         foreach(string strAddr, mapMultiArgs["-addnode"])\r
3527         {\r
3528             CAddress addr(strAddr, NODE_NETWORK);\r
3529             addr.nTime = 0; // so it won't relay unless successfully connected\r
3530             if (addr.IsValid())\r
3531                 AddAddress(addrdb, addr);\r
3532         }\r
3533     }\r
3534 \r
3535     //\r
3536     // Create the main frame window\r
3537     //\r
3538     pframeMain = new CMainFrame(NULL);\r
3539     if (mapArgs.count("-min"))\r
3540         pframeMain->Iconize(true);\r
3541     pframeMain->Show(true);  // have to show first to get taskbar button to hide\r
3542     pframeMain->Show(!fMinimizeToTray || !pframeMain->IsIconized());\r
3543     ptaskbaricon->Show(fMinimizeToTray);\r
3544 \r
3545     _beginthread(ThreadDelayedRepaint, 0, NULL);\r
3546 \r
3547     if (!CheckDiskSpace())\r
3548     {\r
3549         OnExit();\r
3550         return false;\r
3551     }\r
3552 \r
3553     RandAddSeedPerfmon();\r
3554 \r
3555     if (!StartNode(strErrors))\r
3556         wxMessageBox(strErrors, "Bitcoin");\r
3557 \r
3558     GenerateBitcoins(fGenerateBitcoins);\r
3559 \r
3560     if (fFirstRun)\r
3561         SetStartOnSystemStartup(true);\r
3562 \r
3563 \r
3564     //\r
3565     // Tests\r
3566     //\r
3567 #ifdef __WXMSW__\r
3568     if (argc >= 2 && stricmp(argv[1], "-send") == 0)\r
3569 #else\r
3570     if (argc >= 2 && strcmp(argv[1], "-send") == 0)\r
3571 #endif\r
3572     {\r
3573         int64 nValue = 1;\r
3574         if (argc >= 3)\r
3575             ParseMoney(argv[2], nValue);\r
3576 \r
3577         string strAddress;\r
3578         if (argc >= 4)\r
3579             strAddress = argv[3];\r
3580         CAddress addr(strAddress);\r
3581 \r
3582         CWalletTx wtx;\r
3583         wtx.mapValue["to"] = strAddress;\r
3584         wtx.mapValue["from"] = addrLocalHost.ToString();\r
3585         wtx.mapValue["message"] = "command line send";\r
3586 \r
3587         // Send to IP address\r
3588         CSendingDialog* pdialog = new CSendingDialog(pframeMain, addr, nValue, wtx);\r
3589         if (!pdialog->ShowModal())\r
3590             return false;\r
3591     }\r
3592 \r
3593     return true;\r
3594 }\r
3595 \r
3596 int CMyApp::OnExit()\r
3597 {\r
3598     Shutdown(NULL);\r
3599     return wxApp::OnExit();\r
3600 }\r
3601 \r
3602 bool CMyApp::OnExceptionInMainLoop()\r
3603 {\r
3604     try\r
3605     {\r
3606         throw;\r
3607     }\r
3608     catch (std::exception& e)\r
3609     {\r
3610         PrintException(&e, "CMyApp::OnExceptionInMainLoop()");\r
3611         wxLogWarning("Exception %s %s", typeid(e).name(), e.what());\r
3612         Sleep(1000);\r
3613         throw;\r
3614     }\r
3615     catch (...)\r
3616     {\r
3617         PrintException(NULL, "CMyApp::OnExceptionInMainLoop()");\r
3618         wxLogWarning("Unknown exception");\r
3619         Sleep(1000);\r
3620         throw;\r
3621     }\r
3622 \r
3623     return true;\r
3624 }\r
3625 \r
3626 void CMyApp::OnUnhandledException()\r
3627 {\r
3628     // this shows how we may let some exception propagate uncaught\r
3629     try\r
3630     {\r
3631         throw;\r
3632     }\r
3633     catch (std::exception& e)\r
3634     {\r
3635         PrintException(&e, "CMyApp::OnUnhandledException()");\r
3636         wxLogWarning("Exception %s %s", typeid(e).name(), e.what());\r
3637         Sleep(1000);\r
3638         throw;\r
3639     }\r
3640     catch (...)\r
3641     {\r
3642         PrintException(NULL, "CMyApp::OnUnhandledException()");\r
3643         wxLogWarning("Unknown exception");\r
3644         Sleep(1000);\r
3645         throw;\r
3646     }\r
3647 }\r
3648 \r
3649 void CMyApp::OnFatalException()\r
3650 {\r
3651     wxMessageBox("Program has crashed and will terminate.  ", "Bitcoin", wxOK | wxICON_ERROR);\r
3652 }\r
3653 \r
3654 \r
3655 \r
3656 \r
3657 \r
3658 #ifdef __WXMSW__\r
3659 typedef WINSHELLAPI BOOL (WINAPI *PSHGETSPECIALFOLDERPATHA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);\r
3660 \r
3661 string MyGetSpecialFolderPath(int nFolder, bool fCreate)\r
3662 {\r
3663     char pszPath[MAX_PATH+100] = "";\r
3664 \r
3665     // SHGetSpecialFolderPath is not usually available on NT 4.0\r
3666     HMODULE hShell32 = LoadLibrary("shell32.dll");\r
3667     if (hShell32)\r
3668     {\r
3669         PSHGETSPECIALFOLDERPATHA pSHGetSpecialFolderPath =\r
3670             (PSHGETSPECIALFOLDERPATHA)GetProcAddress(hShell32, "SHGetSpecialFolderPathA");\r
3671         if (pSHGetSpecialFolderPath)\r
3672             (*pSHGetSpecialFolderPath)(NULL, pszPath, nFolder, fCreate);\r
3673         FreeModule(hShell32);\r
3674     }\r
3675 \r
3676     // Backup option\r
3677     if (pszPath[0] == '\0')\r
3678     {\r
3679         if (nFolder == CSIDL_STARTUP)\r
3680         {\r
3681             strcpy(pszPath, getenv("USERPROFILE"));\r
3682             strcat(pszPath, "\\Start Menu\\Programs\\Startup");\r
3683         }\r
3684         else if (nFolder == CSIDL_APPDATA)\r
3685         {\r
3686             strcpy(pszPath, getenv("APPDATA"));\r
3687         }\r
3688     }\r
3689 \r
3690     return pszPath;\r
3691 }\r
3692 \r
3693 string StartupShortcutPath()\r
3694 {\r
3695     return MyGetSpecialFolderPath(CSIDL_STARTUP, true) + "\\Bitcoin.lnk";\r
3696 }\r
3697 \r
3698 bool GetStartOnSystemStartup()\r
3699 {\r
3700     return wxFileExists(StartupShortcutPath());\r
3701 }\r
3702 \r
3703 void SetStartOnSystemStartup(bool fAutoStart)\r
3704 {\r
3705     // If the shortcut exists already, remove it for updating\r
3706     remove(StartupShortcutPath().c_str());\r
3707 \r
3708     if (fAutoStart)\r
3709     {\r
3710         CoInitialize(NULL);\r
3711 \r
3712         // Get a pointer to the IShellLink interface.\r
3713         HRESULT hres = NULL;\r
3714         IShellLink* psl = NULL;\r
3715         hres = CoCreateInstance(CLSID_ShellLink, NULL,\r
3716                                 CLSCTX_INPROC_SERVER, IID_IShellLink,\r
3717                                 reinterpret_cast<void**>(&psl));\r
3718 \r
3719         if (SUCCEEDED(hres))\r
3720         {\r
3721             // Get the current executable path\r
3722             char pszExePath[MAX_PATH];\r
3723             GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));\r
3724 \r
3725             // Set the path to the shortcut target\r
3726             psl->SetPath(pszExePath);\r
3727             PathRemoveFileSpec(pszExePath);\r
3728             psl->SetWorkingDirectory(pszExePath);\r
3729             psl->SetShowCmd(SW_SHOWMINNOACTIVE);\r
3730 \r
3731             // Query IShellLink for the IPersistFile interface for\r
3732             // saving the shortcut in persistent storage.\r
3733             IPersistFile* ppf = NULL;\r
3734             hres = psl->QueryInterface(IID_IPersistFile,\r
3735                                        reinterpret_cast<void**>(&ppf));\r
3736             if (SUCCEEDED(hres))\r
3737             {\r
3738                 WCHAR pwsz[MAX_PATH];\r
3739                 // Ensure that the string is ANSI.\r
3740                 MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().c_str(), -1, pwsz, MAX_PATH);\r
3741                 // Save the link by calling IPersistFile::Save.\r
3742                 hres = ppf->Save(pwsz, TRUE);\r
3743                 ppf->Release();\r
3744             }\r
3745             psl->Release();\r
3746         }\r
3747         CoUninitialize();\r
3748     }\r
3749 }\r
3750 #else\r
3751 bool GetStartOnSystemStartup() { return false; }\r
3752 void SetStartOnSystemStartup(bool fAutoStart) { }\r
3753 #endif\r
3754 \r
3755 \r
3756 \r
3757 \r
3758 \r
3759 \r
3760 \r
3761 \r
3762 \r
3763 \r
This page took 0.266498 seconds and 4 git commands to generate.