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