]> Git Repo - VerusCoin.git/blame - ui.cpp
misc exit code, updated setup.nsi
[VerusCoin.git] / ui.cpp
CommitLineData
4405b78d 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
52109986 10void ThreadRequestProductDetails(void* parg);\r
11void ThreadRandSendTest(void* parg);\r
12bool GetStartOnSystemStartup();\r
13void SetStartOnSystemStartup(bool fAutoStart);\r
14\r
15\r
16\r
85c33b96 17DEFINE_EVENT_TYPE(wxEVT_UITHREADCALL)\r
4405b78d 18DEFINE_EVENT_TYPE(wxEVT_REPLY1)\r
19DEFINE_EVENT_TYPE(wxEVT_REPLY2)\r
20DEFINE_EVENT_TYPE(wxEVT_REPLY3)\r
4405b78d 21\r
22CMainFrame* pframeMain = NULL;\r
52109986 23CMyTaskBarIcon* ptaskbaricon = NULL;\r
4405b78d 24map<string, string> mapAddressBook;\r
4405b78d 25bool fRandSendTest = false;\r
26void RandSend();\r
27extern int g_isPainting;\r
31e6ea7f 28bool fClosedToTray = false;\r
4405b78d 29\r
52109986 30// Settings\r
31int fShowGenerated = true;\r
32int fMinimizeToTray = true;\r
33int fMinimizeOnClose = true;\r
34\r
35\r
36\r
37\r
4405b78d 38\r
39\r
40\r
41//////////////////////////////////////////////////////////////////////////////\r
42//\r
43// Util\r
44//\r
45\r
46void HandleCtrlA(wxKeyEvent& event)\r
47{\r
48 // Ctrl-a select all\r
49 wxTextCtrl* textCtrl = (wxTextCtrl*)event.GetEventObject();\r
50 if (event.GetModifiers() == wxMOD_CONTROL && event.GetKeyCode() == 'A')\r
51 textCtrl->SetSelection(-1, -1);\r
52 event.Skip();\r
53}\r
54\r
55bool Is24HourTime()\r
56{\r
57 //char pszHourFormat[256];\r
58 //pszHourFormat[0] = '\0';\r
59 //GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ITIME, pszHourFormat, 256);\r
60 //return (pszHourFormat[0] != '0');\r
61 return true;\r
62}\r
63\r
64string DateStr(int64 nTime)\r
65{\r
93cfb02a 66 // Can only be used safely here in the UI\r
4405b78d 67 return (string)wxDateTime((time_t)nTime).FormatDate();\r
68}\r
69\r
70string DateTimeStr(int64 nTime)\r
71{\r
93cfb02a 72 // Can only be used safely here in the UI\r
4405b78d 73 wxDateTime datetime((time_t)nTime);\r
74 if (Is24HourTime())\r
75 return (string)datetime.Format("%x %H:%M");\r
76 else\r
77 return (string)datetime.Format("%x ") + itostr((datetime.GetHour() + 11) % 12 + 1) + (string)datetime.Format(":%M %p");\r
78}\r
79\r
80wxString GetItemText(wxListCtrl* listCtrl, int nIndex, int nColumn)\r
81{\r
82 // Helper to simplify access to listctrl\r
83 wxListItem item;\r
84 item.m_itemId = nIndex;\r
85 item.m_col = nColumn;\r
86 item.m_mask = wxLIST_MASK_TEXT;\r
87 if (!listCtrl->GetItem(item))\r
88 return "";\r
89 return item.GetText();\r
90}\r
91\r
92int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1)\r
93{\r
94 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);\r
95 listCtrl->SetItem(nIndex, 1, str1);\r
96 return nIndex;\r
97}\r
98\r
99int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)\r
100{\r
101 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);\r
102 listCtrl->SetItem(nIndex, 1, str1);\r
103 listCtrl->SetItem(nIndex, 2, str2);\r
104 listCtrl->SetItem(nIndex, 3, str3);\r
105 listCtrl->SetItem(nIndex, 4, str4);\r
106 return nIndex;\r
107}\r
108\r
109int InsertLine(wxListCtrl* listCtrl, void* pdata, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)\r
110{\r
111 int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);\r
112 listCtrl->SetItemPtrData(nIndex, (wxUIntPtr)pdata);\r
113 listCtrl->SetItem(nIndex, 1, str1);\r
114 listCtrl->SetItem(nIndex, 2, str2);\r
115 listCtrl->SetItem(nIndex, 3, str3);\r
116 listCtrl->SetItem(nIndex, 4, str4);\r
117 return nIndex;\r
118}\r
119\r
120void SetSelection(wxListCtrl* listCtrl, int nIndex)\r
121{\r
122 int nSize = listCtrl->GetItemCount();\r
123 long nState = (wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);\r
124 for (int i = 0; i < nSize; i++)\r
125 listCtrl->SetItemState(i, (i == nIndex ? nState : 0), nState);\r
126}\r
127\r
128int GetSelection(wxListCtrl* listCtrl)\r
129{\r
130 int nSize = listCtrl->GetItemCount();\r
131 for (int i = 0; i < nSize; i++)\r
132 if (listCtrl->GetItemState(i, wxLIST_STATE_FOCUSED))\r
133 return i;\r
134 return -1;\r
135}\r
136\r
137\r
138string HtmlEscape(const char* psz, bool fMultiLine=false)\r
139{\r
140 int len = 0;\r
141 for (const char* p = psz; *p; p++)\r
142 {\r
143 if (*p == '<') len += 4;\r
144 else if (*p == '>') len += 4;\r
145 else if (*p == '&') len += 5;\r
146 else if (*p == '"') len += 6;\r
147 else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') len += 6;\r
148 else if (*p == '\n' && fMultiLine) len += 5;\r
149 else\r
150 len++;\r
151 }\r
152 string str;\r
153 str.reserve(len);\r
154 for (const char* p = psz; *p; p++)\r
155 {\r
156 if (*p == '<') str += "&lt;";\r
157 else if (*p == '>') str += "&gt;";\r
158 else if (*p == '&') str += "&amp;";\r
159 else if (*p == '"') str += "&quot;";\r
160 else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') str += "&nbsp;";\r
161 else if (*p == '\n' && fMultiLine) str += "<br>\n";\r
162 else\r
163 str += *p;\r
164 }\r
165 return str;\r
166}\r
167\r
168string HtmlEscape(const string& str, bool fMultiLine=false)\r
169{\r
170 return HtmlEscape(str.c_str(), fMultiLine);\r
171}\r
172\r
173void AddToMyProducts(CProduct product)\r
174{\r
175 CProduct& productInsert = mapMyProducts[product.GetHash()];\r
176 productInsert = product;\r
177 InsertLine(pframeMain->m_listCtrlProductsSent, &productInsert,\r
178 product.mapValue["category"],\r
179 product.mapValue["title"].substr(0, 100),\r
180 product.mapValue["description"].substr(0, 100),\r
181 product.mapValue["price"],\r
182 "");\r
183}\r
184\r
1a01afab 185void CalledMessageBox(const string& message, const string& caption, int style, wxWindow* parent, int x, int y, int* pnRet, bool* pfDone)\r
85c33b96 186{\r
1a01afab 187 *pnRet = wxMessageBox(message, caption, style, parent, x, y);\r
188 *pfDone = true;\r
85c33b96 189}\r
190\r
191int ThreadSafeMessageBox(const string& message, const string& caption, int style, wxWindow* parent, int x, int y)\r
192{\r
193#ifdef __WXMSW__\r
1a01afab 194 return wxMessageBox(message, caption, style, parent, x, y);\r
85c33b96 195#else\r
1a01afab 196 if (wxThread::IsMain())\r
197 {\r
198 return wxMessageBox(message, caption, style, parent, x, y);\r
199 }\r
200 else\r
201 {\r
202 int nRet = 0;\r
203 bool fDone = false;\r
204 UIThreadCall(bind(CalledMessageBox, message, caption, style, parent, x, y, &nRet, &fDone));\r
205 while (!fDone)\r
206 Sleep(100);\r
207 return nRet;\r
208 }\r
85c33b96 209#endif\r
210}\r
211\r
212\r
213\r
214\r
215\r
4405b78d 216\r
217\r
218\r
219\r
220\r
221//////////////////////////////////////////////////////////////////////////////\r
222//\r
223// Custom events\r
224//\r
85c33b96 225// If this code gets used again, it should be replaced with something like UIThreadCall\r
4405b78d 226\r
227set<void*> setCallbackAvailable;\r
228CCriticalSection cs_setCallbackAvailable;\r
229\r
230void AddCallbackAvailable(void* p)\r
231{\r
232 CRITICAL_BLOCK(cs_setCallbackAvailable)\r
233 setCallbackAvailable.insert(p);\r
234}\r
235\r
236void RemoveCallbackAvailable(void* p)\r
237{\r
238 CRITICAL_BLOCK(cs_setCallbackAvailable)\r
239 setCallbackAvailable.erase(p);\r
240}\r
241\r
242bool IsCallbackAvailable(void* p)\r
243{\r
244 CRITICAL_BLOCK(cs_setCallbackAvailable)\r
245 return setCallbackAvailable.count(p);\r
246 return false;\r
247}\r
248\r
249template<typename T>\r
250void AddPendingCustomEvent(wxEvtHandler* pevthandler, int nEventID, const T pbeginIn, const T pendIn)\r
251{\r
252 if (!pevthandler)\r
253 return;\r
254\r
255 const char* pbegin = (pendIn != pbeginIn) ? &pbeginIn[0] : NULL;\r
256 const char* pend = pbegin + (pendIn - pbeginIn) * sizeof(pbeginIn[0]);\r
257 wxCommandEvent event(nEventID);\r
258 wxString strData(wxChar(0), (pend - pbegin) / sizeof(wxChar) + 1);\r
259 memcpy(&strData[0], pbegin, pend - pbegin);\r
260 event.SetString(strData);\r
261 event.SetInt(pend - pbegin);\r
262\r
263 pevthandler->AddPendingEvent(event);\r
264}\r
265\r
266template<class T>\r
267void AddPendingCustomEvent(wxEvtHandler* pevthandler, int nEventID, const T& obj)\r
268{\r
269 CDataStream ss;\r
270 ss << obj;\r
271 AddPendingCustomEvent(pevthandler, nEventID, ss.begin(), ss.end());\r
272}\r
273\r
274void AddPendingReplyEvent1(void* pevthandler, CDataStream& vRecv)\r
275{\r
276 if (IsCallbackAvailable(pevthandler))\r
277 AddPendingCustomEvent((wxEvtHandler*)pevthandler, wxEVT_REPLY1, vRecv.begin(), vRecv.end());\r
278}\r
279\r
280void AddPendingReplyEvent2(void* pevthandler, CDataStream& vRecv)\r
281{\r
282 if (IsCallbackAvailable(pevthandler))\r
283 AddPendingCustomEvent((wxEvtHandler*)pevthandler, wxEVT_REPLY2, vRecv.begin(), vRecv.end());\r
284}\r
285\r
286void AddPendingReplyEvent3(void* pevthandler, CDataStream& vRecv)\r
287{\r
288 if (IsCallbackAvailable(pevthandler))\r
289 AddPendingCustomEvent((wxEvtHandler*)pevthandler, wxEVT_REPLY3, vRecv.begin(), vRecv.end());\r
290}\r
291\r
292CDataStream GetStreamFromEvent(const wxCommandEvent& event)\r
293{\r
294 wxString strData = event.GetString();\r
fba40889 295 const char* pszBegin = strData.c_str();\r
296 return CDataStream(pszBegin, pszBegin + event.GetInt(), SER_NETWORK);\r
4405b78d 297}\r
298\r
299\r
300\r
301\r
302\r
303\r
304\r
305//////////////////////////////////////////////////////////////////////////////\r
306//\r
307// CMainFrame\r
308//\r
309\r
310CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent)\r
311{\r
85c33b96 312 Connect(wxEVT_UITHREADCALL, wxCommandEventHandler(CMainFrame::OnUIThreadCall), NULL, this);\r
4405b78d 313\r
314 // Init\r
315 fRefreshListCtrl = false;\r
316 fRefreshListCtrlRunning = false;\r
317 fOnSetFocusAddress = false;\r
93cfb02a 318 fRefresh = false;\r
4405b78d 319 m_choiceFilter->SetSelection(0);\r
0bbbee96 320 double dResize = 1.0;\r
158ea66c 321#ifdef __WXMSW__\r
322 SetIcon(wxICON(bitcoin));\r
323#else\r
324 SetIcon(bitcoin16_xpm);\r
325 wxFont fontTmp = m_staticText41->GetFont();\r
1a01afab 326 fontTmp.SetFamily(wxFONTFAMILY_TELETYPE);\r
327 m_staticTextBalance->SetFont(fontTmp);\r
328 m_staticTextBalance->SetSize(140, 17);\r
158ea66c 329 // & underlines don't work on the toolbar buttons on gtk\r
1a01afab 330 m_toolBar->ClearTools();\r
331 m_toolBar->AddTool(wxID_BUTTONSEND, "Send Coins", wxBitmap(send20_xpm), wxNullBitmap, wxITEM_NORMAL, wxEmptyString, wxEmptyString);\r
332 m_toolBar->AddTool(wxID_BUTTONRECEIVE, "Address Book", wxBitmap(addressbook20_xpm), wxNullBitmap, wxITEM_NORMAL, wxEmptyString, wxEmptyString);\r
333 m_toolBar->Realize();\r
0bbbee96 334 // resize to fit ubuntu's huge default font\r
335 dResize = 1.19;\r
336 SetSize(dResize * GetSize().GetWidth(), 1.1 * GetSize().GetHeight());\r
337 dResize = 1.20;\r
1a01afab 338#endif\r
4405b78d 339 m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " ");\r
340 m_listCtrl->SetFocus();\r
52109986 341 ptaskbaricon = new CMyTaskBarIcon();\r
4405b78d 342\r
4405b78d 343 // Init column headers\r
344 int nDateWidth = DateTimeStr(1229413914).size() * 6 + 8;\r
6ccefea6 345 if (!strstr(DateTimeStr(1229413914).c_str(), "2008"))\r
346 nDateWidth += 12;\r
0bbbee96 347 m_listCtrl->InsertColumn(0, "", wxLIST_FORMAT_LEFT, dResize * 0);\r
348 m_listCtrl->InsertColumn(1, "", wxLIST_FORMAT_LEFT, dResize * 0);\r
349 m_listCtrl->InsertColumn(2, "Status", wxLIST_FORMAT_LEFT, dResize * 90);\r
350 m_listCtrl->InsertColumn(3, "Date", wxLIST_FORMAT_LEFT, dResize * nDateWidth);\r
351 m_listCtrl->InsertColumn(4, "Description", wxLIST_FORMAT_LEFT, dResize * 409 - nDateWidth);\r
352 m_listCtrl->InsertColumn(5, "Debit", wxLIST_FORMAT_RIGHT, dResize * 79);\r
353 m_listCtrl->InsertColumn(6, "Credit", wxLIST_FORMAT_RIGHT, dResize * 79);\r
4405b78d 354\r
355 //m_listCtrlProductsSent->InsertColumn(0, "Category", wxLIST_FORMAT_LEFT, 100);\r
356 //m_listCtrlProductsSent->InsertColumn(1, "Title", wxLIST_FORMAT_LEFT, 100);\r
357 //m_listCtrlProductsSent->InsertColumn(2, "Description", wxLIST_FORMAT_LEFT, 100);\r
358 //m_listCtrlProductsSent->InsertColumn(3, "Price", wxLIST_FORMAT_LEFT, 100);\r
359 //m_listCtrlProductsSent->InsertColumn(4, "", wxLIST_FORMAT_LEFT, 100);\r
360\r
361 //m_listCtrlOrdersSent->InsertColumn(0, "Time", wxLIST_FORMAT_LEFT, 100);\r
362 //m_listCtrlOrdersSent->InsertColumn(1, "Price", wxLIST_FORMAT_LEFT, 100);\r
363 //m_listCtrlOrdersSent->InsertColumn(2, "", wxLIST_FORMAT_LEFT, 100);\r
364 //m_listCtrlOrdersSent->InsertColumn(3, "", wxLIST_FORMAT_LEFT, 100);\r
365 //m_listCtrlOrdersSent->InsertColumn(4, "", wxLIST_FORMAT_LEFT, 100);\r
366\r
367 //m_listCtrlOrdersReceived->InsertColumn(0, "Time", wxLIST_FORMAT_LEFT, 100);\r
368 //m_listCtrlOrdersReceived->InsertColumn(1, "Price", wxLIST_FORMAT_LEFT, 100);\r
369 //m_listCtrlOrdersReceived->InsertColumn(2, "Payment Status", wxLIST_FORMAT_LEFT, 100);\r
370 //m_listCtrlOrdersReceived->InsertColumn(3, "", wxLIST_FORMAT_LEFT, 100);\r
371 //m_listCtrlOrdersReceived->InsertColumn(4, "", wxLIST_FORMAT_LEFT, 100);\r
372\r
373 // Init status bar\r
52109986 374 int pnWidths[3] = { -100, 88, 290 };\r
0bbbee96 375#ifndef __WXMSW__\r
376 pnWidths[1] = pnWidths[1] * 1.1 * dResize;\r
377 pnWidths[2] = pnWidths[2] * 1.1 * dResize;\r
378#endif\r
4405b78d 379 m_statusBar->SetFieldsCount(3, pnWidths);\r
380\r
381 // Fill your address text box\r
382 vector<unsigned char> vchPubKey;\r
383 if (CWalletDB("r").ReadDefaultKey(vchPubKey))\r
384 m_textCtrlAddress->SetValue(PubKeyToAddress(vchPubKey));\r
385\r
386 // Fill listctrl with wallet transactions\r
387 RefreshListCtrl();\r
388}\r
389\r
390CMainFrame::~CMainFrame()\r
391{\r
392 pframeMain = NULL;\r
52109986 393 delete ptaskbaricon;\r
394 ptaskbaricon = NULL;\r
4405b78d 395}\r
396\r
25b12b88 397void ExitTimeout(void* parg)\r
398{\r
399#ifdef __WXMSW__\r
400 Sleep(5000);\r
401 ExitProcess(0);\r
402#endif\r
403}\r
404\r
4405b78d 405void Shutdown(void* parg)\r
406{\r
407 static CCriticalSection cs_Shutdown;\r
e9c2b5c8 408 static bool fTaken;\r
409 bool fFirstThread;\r
4405b78d 410 CRITICAL_BLOCK(cs_Shutdown)\r
e9c2b5c8 411 {\r
412 fFirstThread = !fTaken;\r
413 fTaken = true;\r
414 }\r
25b12b88 415 static bool fExit;\r
e9c2b5c8 416 if (fFirstThread)\r
4405b78d 417 {\r
418 fShutdown = true;\r
419 nTransactionsUpdated++;\r
420 DBFlush(false);\r
421 StopNode();\r
422 DBFlush(true);\r
25b12b88 423 CreateThread(ExitTimeout, NULL);\r
424 Sleep(10);\r
93cfb02a 425 printf("Bitcoin exiting\n\n");\r
25b12b88 426 fExit = true;\r
4405b78d 427 exit(0);\r
428 }\r
e9c2b5c8 429 else\r
430 {\r
25b12b88 431 while (!fExit)\r
432 Sleep(500);\r
433 Sleep(100);\r
434 ExitThread(0);\r
e9c2b5c8 435 }\r
4405b78d 436}\r
437\r
438void CMainFrame::OnClose(wxCloseEvent& event)\r
439{\r
31e6ea7f 440 if (fMinimizeOnClose && event.CanVeto() && !IsIconized())\r
52109986 441 {\r
442 // Divert close to minimize\r
443 event.Veto();\r
31e6ea7f 444 fClosedToTray = true;\r
52109986 445 Iconize(true);\r
446 }\r
447 else\r
448 {\r
449 Destroy();\r
31e6ea7f 450 CreateThread(Shutdown, NULL);\r
52109986 451 }\r
d1b70ffa 452}\r
453\r
454void CMainFrame::OnIconize(wxIconizeEvent& event)\r
455{\r
52109986 456 // Hide the task bar button when minimized.\r
457 // Event is sent when the frame is minimized or restored.\r
31e6ea7f 458 if (!event.Iconized())\r
459 fClosedToTray = false;\r
460#ifndef __WXMSW__\r
461 // Tray is not reliable on Linux gnome\r
462 fClosedToTray = false;\r
463#endif\r
464 if (fMinimizeToTray && event.Iconized())\r
465 fClosedToTray = true;\r
466 Show(!fClosedToTray);\r
467 ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);\r
4405b78d 468}\r
469\r
470void CMainFrame::OnMouseEvents(wxMouseEvent& event)\r
471{\r
472 RandAddSeed();\r
473 RAND_add(&event.m_x, sizeof(event.m_x), 0.25);\r
474 RAND_add(&event.m_y, sizeof(event.m_y), 0.25);\r
475}\r
476\r
477void CMainFrame::OnListColBeginDrag(wxListEvent& event)\r
478{\r
479 // Hidden columns not resizeable\r
480 if (event.GetColumn() <= 1 && !fDebug)\r
481 event.Veto();\r
482}\r
483\r
93cfb02a 484int CMainFrame::GetSortIndex(const string& strSort)\r
485{\r
486#ifdef __WXMSW__\r
487 return 0;\r
488#else\r
489 // The wx generic listctrl implementation used on GTK doesn't sort,\r
490 // so we have to do it ourselves. Remember, we sort in reverse order.\r
491 // In the wx generic implementation, they store the list of items\r
492 // in a vector, so indexed lookups are fast, but inserts are slower\r
493 // the closer they are to the top.\r
494 int low = 0;\r
495 int high = m_listCtrl->GetItemCount();\r
496 while (low < high)\r
497 {\r
498 int mid = low + ((high - low) / 2);\r
499 if (strSort.compare(m_listCtrl->GetItemText(mid).c_str()) >= 0)\r
500 high = mid;\r
501 else\r
502 low = mid + 1;\r
503 }\r
504 return low;\r
505#endif\r
506}\r
507\r
4405b78d 508void 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
509{\r
510 string str0 = strSort;\r
511 long nData = *(long*)&hashKey;\r
512\r
52109986 513 // Find item\r
514 if (!fNew && nIndex == -1)\r
515 {\r
516 while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)\r
517 if (GetItemText(m_listCtrl, nIndex, 1) == hashKey.ToString())\r
518 break;\r
519 }\r
520\r
521 // fNew is for blind insert, only use if you're sure it's new\r
522 if (fNew || nIndex == -1)\r
4405b78d 523 {\r
93cfb02a 524 nIndex = m_listCtrl->InsertItem(GetSortIndex(strSort), str0);\r
4405b78d 525 }\r
526 else\r
527 {\r
4405b78d 528 // If sort key changed, must delete and reinsert to make it relocate\r
529 if (GetItemText(m_listCtrl, nIndex, 0) != str0)\r
530 {\r
531 m_listCtrl->DeleteItem(nIndex);\r
93cfb02a 532 nIndex = m_listCtrl->InsertItem(GetSortIndex(strSort), str0);\r
4405b78d 533 }\r
534 }\r
535\r
536 m_listCtrl->SetItem(nIndex, 1, hashKey.ToString());\r
537 m_listCtrl->SetItem(nIndex, 2, str2);\r
538 m_listCtrl->SetItem(nIndex, 3, str3);\r
539 m_listCtrl->SetItem(nIndex, 4, str4);\r
540 m_listCtrl->SetItem(nIndex, 5, str5);\r
541 m_listCtrl->SetItem(nIndex, 6, str6);\r
542 m_listCtrl->SetItemData(nIndex, nData);\r
543}\r
544\r
6ccefea6 545bool CMainFrame::DeleteLine(uint256 hashKey)\r
546{\r
547 long nData = *(long*)&hashKey;\r
548\r
549 // Find item\r
550 int nIndex = -1;\r
551 while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)\r
552 if (GetItemText(m_listCtrl, nIndex, 1) == hashKey.ToString())\r
553 break;\r
554\r
555 if (nIndex != -1)\r
556 m_listCtrl->DeleteItem(nIndex);\r
557\r
558 return nIndex != -1;\r
559}\r
560\r
4405b78d 561string FormatTxStatus(const CWalletTx& wtx)\r
562{\r
563 // Status\r
4405b78d 564 if (!wtx.IsFinal())\r
6ccefea6 565 {\r
566 if (wtx.nLockTime < 500000000)\r
567 return strprintf("Open for %d blocks", nBestHeight - wtx.nLockTime);\r
568 else\r
569 return strprintf("Open until %s", DateTimeStr(wtx.nLockTime).c_str());\r
570 }\r
4405b78d 571 else\r
31e6ea7f 572 {\r
573 int nDepth = wtx.GetDepthInMainChain();\r
574 if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)\r
575 return strprintf("%d/offline?", nDepth);\r
576 else if (nDepth < 6)\r
577 return strprintf("%d/unconfirmed", nDepth);\r
578 else\r
579 return strprintf("%d blocks", nDepth);\r
580 }\r
4405b78d 581}\r
582\r
583string SingleLine(const string& strIn)\r
584{\r
585 string strOut;\r
586 bool fOneSpace = false;\r
587 foreach(int c, strIn)\r
588 {\r
589 if (isspace(c))\r
590 {\r
591 fOneSpace = true;\r
592 }\r
593 else if (c > ' ')\r
594 {\r
595 if (fOneSpace && !strOut.empty())\r
596 strOut += ' ';\r
597 strOut += c;\r
598 fOneSpace = false;\r
599 }\r
600 }\r
601 return strOut;\r
602}\r
603\r
cc0b4c3b 604bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)\r
4405b78d 605{\r
606 int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime();\r
607 int64 nCredit = wtx.GetCredit();\r
608 int64 nDebit = wtx.GetDebit();\r
609 int64 nNet = nCredit - nDebit;\r
610 uint256 hash = wtx.GetHash();\r
611 string strStatus = FormatTxStatus(wtx);\r
612 map<string, string> mapValue = wtx.mapValue;\r
cc0b4c3b 613 wtx.nLinesDisplayed = 1;\r
e66ec79b 614 nListViewUpdated++;\r
4405b78d 615\r
52109986 616 // Filter\r
617 if (wtx.IsCoinBase())\r
618 {\r
52109986 619 // Don't show generated coin until confirmed by at least one block after it\r
620 // so we don't get the user's hopes up until it looks like it's probably accepted.\r
621 //\r
622 // It is not an error when generated blocks are not accepted. By design,\r
623 // some percentage of blocks, like 10% or more, will end up not accepted.\r
624 // This is the normal mechanism by which the network copes with latency.\r
625 //\r
626 // We display regular transactions right away before any confirmation\r
627 // because they can always get into some block eventually. Generated coins\r
628 // are special because if their block is not accepted, they are not valid.\r
629 //\r
630 if (wtx.GetDepthInMainChain() < 2)\r
6ccefea6 631 {\r
cc0b4c3b 632 wtx.nLinesDisplayed = 0;\r
633 return false;\r
6ccefea6 634 }\r
cc0b4c3b 635\r
636 // View->Show Generated\r
637 if (!fShowGenerated)\r
638 return false;\r
52109986 639 }\r
640\r
4405b78d 641 // Find the block the tx is in\r
642 CBlockIndex* pindex = NULL;\r
643 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(wtx.hashBlock);\r
644 if (mi != mapBlockIndex.end())\r
645 pindex = (*mi).second;\r
646\r
647 // Sort order, unrecorded transactions sort to the top\r
648 string strSort = strprintf("%010d-%01d-%010u",\r
649 (pindex ? pindex->nHeight : INT_MAX),\r
650 (wtx.IsCoinBase() ? 1 : 0),\r
651 wtx.nTimeReceived);\r
652\r
653 // Insert line\r
654 if (nNet > 0 || wtx.IsCoinBase())\r
655 {\r
656 //\r
657 // Credit\r
658 //\r
659 string strDescription;\r
660\r
661 if (wtx.IsCoinBase())\r
662 {\r
663 // Coinbase\r
664 strDescription = "Generated";\r
665 if (nCredit == 0)\r
666 {\r
667 int64 nUnmatured = 0;\r
668 foreach(const CTxOut& txout, wtx.vout)\r
669 nUnmatured += txout.GetCredit();\r
670 if (wtx.IsInMainChain())\r
31e6ea7f 671 {\r
672 strDescription = strprintf("Generated (%s matures in %d more blocks)", FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());\r
673\r
674 // Check if the block was requested by anyone\r
675 if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)\r
676 strDescription = "Generated - Warning: This block was not received by any other nodes and will probably not be accepted!";\r
677 }\r
4405b78d 678 else\r
31e6ea7f 679 {\r
680 strDescription = "Generated (not accepted)";\r
681 }\r
4405b78d 682 }\r
683 }\r
684 else if (!mapValue["from"].empty() || !mapValue["message"].empty())\r
685 {\r
686 // Online transaction\r
687 if (!mapValue["from"].empty())\r
688 strDescription += "From: " + mapValue["from"];\r
689 if (!mapValue["message"].empty())\r
690 {\r
691 if (!strDescription.empty())\r
692 strDescription += " - ";\r
693 strDescription += mapValue["message"];\r
694 }\r
695 }\r
696 else\r
697 {\r
698 // Offline transaction\r
699 foreach(const CTxOut& txout, wtx.vout)\r
700 {\r
701 if (txout.IsMine())\r
702 {\r
703 vector<unsigned char> vchPubKey;\r
704 if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))\r
705 {\r
706 string strAddress = PubKeyToAddress(vchPubKey);\r
707 if (mapAddressBook.count(strAddress))\r
708 {\r
709 //strDescription += "Received payment to ";\r
710 //strDescription += "Received with address ";\r
711 strDescription += "From: unknown, To: ";\r
712 strDescription += strAddress;\r
713 /// The labeling feature is just too confusing, so I hid it\r
714 /// by putting it at the end where it runs off the screen.\r
715 /// It can still be seen by widening the column, or in the\r
716 /// details dialog.\r
717 if (!mapAddressBook[strAddress].empty())\r
718 strDescription += " (" + mapAddressBook[strAddress] + ")";\r
719 }\r
720 }\r
721 break;\r
722 }\r
723 }\r
724 }\r
725\r
726 InsertLine(fNew, nIndex, hash, strSort,\r
727 strStatus,\r
728 nTime ? DateTimeStr(nTime) : "",\r
729 SingleLine(strDescription),\r
730 "",\r
731 FormatMoney(nNet, true));\r
732 }\r
733 else\r
734 {\r
735 bool fAllFromMe = true;\r
736 foreach(const CTxIn& txin, wtx.vin)\r
737 fAllFromMe = fAllFromMe && txin.IsMine();\r
738\r
739 bool fAllToMe = true;\r
740 foreach(const CTxOut& txout, wtx.vout)\r
741 fAllToMe = fAllToMe && txout.IsMine();\r
742\r
743 if (fAllFromMe && fAllToMe)\r
744 {\r
745 // Payment to self\r
746 int64 nValue = wtx.vout[0].nValue;\r
747 InsertLine(fNew, nIndex, hash, strSort,\r
748 strStatus,\r
749 nTime ? DateTimeStr(nTime) : "",\r
750 "Payment to yourself",\r
31e6ea7f 751 "",\r
752 "");\r
753 /// issue: can't tell which is the payment and which is the change anymore\r
754 // FormatMoney(nNet - nValue, true),\r
755 // FormatMoney(nValue, true));\r
4405b78d 756 }\r
757 else if (fAllFromMe)\r
758 {\r
759 //\r
760 // Debit\r
761 //\r
762 int64 nTxFee = nDebit - wtx.GetValueOut();\r
cc0b4c3b 763 wtx.nLinesDisplayed = 0;\r
4405b78d 764 for (int nOut = 0; nOut < wtx.vout.size(); nOut++)\r
765 {\r
766 const CTxOut& txout = wtx.vout[nOut];\r
767 if (txout.IsMine())\r
768 continue;\r
769\r
770 string strAddress;\r
771 if (!mapValue["to"].empty())\r
772 {\r
773 // Online transaction\r
774 strAddress = mapValue["to"];\r
775 }\r
776 else\r
777 {\r
778 // Offline transaction\r
779 uint160 hash160;\r
780 if (ExtractHash160(txout.scriptPubKey, hash160))\r
781 strAddress = Hash160ToAddress(hash160);\r
782 }\r
783\r
784 string strDescription = "To: ";\r
785 if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())\r
786 strDescription += mapAddressBook[strAddress] + " ";\r
787 strDescription += strAddress;\r
788 if (!mapValue["message"].empty())\r
789 {\r
790 if (!strDescription.empty())\r
791 strDescription += " - ";\r
792 strDescription += mapValue["message"];\r
793 }\r
794\r
795 int64 nValue = txout.nValue;\r
796 if (nOut == 0 && nTxFee > 0)\r
797 nValue += nTxFee;\r
798\r
799 InsertLine(fNew, nIndex, hash, strprintf("%s-%d", strSort.c_str(), nOut),\r
800 strStatus,\r
801 nTime ? DateTimeStr(nTime) : "",\r
802 SingleLine(strDescription),\r
803 FormatMoney(-nValue, true),\r
804 "");\r
cc0b4c3b 805 wtx.nLinesDisplayed++;\r
4405b78d 806 }\r
807 }\r
808 else\r
809 {\r
810 //\r
811 // Mixed debit transaction, can't break down payees\r
812 //\r
813 bool fAllMine = true;\r
814 foreach(const CTxOut& txout, wtx.vout)\r
815 fAllMine = fAllMine && txout.IsMine();\r
816 foreach(const CTxIn& txin, wtx.vin)\r
817 fAllMine = fAllMine && txin.IsMine();\r
818\r
819 InsertLine(fNew, nIndex, hash, strSort,\r
820 strStatus,\r
821 nTime ? DateTimeStr(nTime) : "",\r
822 "",\r
823 FormatMoney(nNet, true),\r
824 "");\r
825 }\r
826 }\r
cc0b4c3b 827\r
828 return true;\r
4405b78d 829}\r
830\r
4405b78d 831void CMainFrame::RefreshListCtrl()\r
832{\r
833 fRefreshListCtrl = true;\r
834 ::wxWakeUpIdle();\r
835}\r
836\r
837void CMainFrame::OnIdle(wxIdleEvent& event)\r
838{\r
839 if (fRefreshListCtrl)\r
840 {\r
841 // Collect list of wallet transactions and sort newest first\r
842 bool fEntered = false;\r
843 vector<pair<unsigned int, uint256> > vSorted;\r
844 TRY_CRITICAL_BLOCK(cs_mapWallet)\r
845 {\r
846 printf("RefreshListCtrl starting\n");\r
847 fEntered = true;\r
848 fRefreshListCtrl = false;\r
849 vWalletUpdated.clear();\r
850\r
851 // Do the newest transactions first\r
852 vSorted.reserve(mapWallet.size());\r
853 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)\r
854 {\r
855 const CWalletTx& wtx = (*it).second;\r
856 unsigned int nTime = UINT_MAX - wtx.GetTxTime();\r
857 vSorted.push_back(make_pair(nTime, (*it).first));\r
858 }\r
859 m_listCtrl->DeleteAllItems();\r
860 }\r
861 if (!fEntered)\r
862 return;\r
863\r
864 sort(vSorted.begin(), vSorted.end());\r
865\r
866 // Fill list control\r
867 for (int i = 0; i < vSorted.size();)\r
868 {\r
869 if (fShutdown)\r
870 return;\r
871 bool fEntered = false;\r
872 TRY_CRITICAL_BLOCK(cs_mapWallet)\r
873 {\r
874 fEntered = true;\r
875 uint256& hash = vSorted[i++].second;\r
876 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);\r
877 if (mi != mapWallet.end())\r
878 InsertTransaction((*mi).second, true);\r
879 }\r
880 if (!fEntered || i == 100 || i % 500 == 0)\r
881 wxYield();\r
882 }\r
883\r
884 printf("RefreshListCtrl done\n");\r
cc0b4c3b 885\r
886 // Update transaction total display\r
887 MainFrameRepaint();\r
4405b78d 888 }\r
889 else\r
890 {\r
891 // Check for time updates\r
892 static int64 nLastTime;\r
893 if (GetTime() > nLastTime + 30)\r
894 {\r
895 TRY_CRITICAL_BLOCK(cs_mapWallet)\r
896 {\r
897 nLastTime = GetTime();\r
898 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)\r
899 {\r
900 CWalletTx& wtx = (*it).second;\r
901 if (wtx.nTimeDisplayed && wtx.nTimeDisplayed != wtx.GetTxTime())\r
902 InsertTransaction(wtx, false);\r
903 }\r
904 }\r
905 }\r
906 }\r
907}\r
908\r
e66ec79b 909void CMainFrame::RefreshStatusColumn()\r
910{\r
911 static int nLastTop;\r
912 static CBlockIndex* pindexLastBest;\r
913 static unsigned int nLastRefreshed;\r
914\r
915 int nTop = max((int)m_listCtrl->GetTopItem(), 0);\r
916 if (nTop == nLastTop && pindexLastBest == pindexBest)\r
917 return;\r
918\r
919 TRY_CRITICAL_BLOCK(cs_mapWallet)\r
920 {\r
921 int nStart = nTop;\r
922 int nEnd = min(nStart + 100, m_listCtrl->GetItemCount());\r
923\r
924 if (pindexLastBest == pindexBest && nLastRefreshed == nListViewUpdated)\r
925 {\r
926 // If no updates, only need to do the part that moved onto the screen\r
927 if (nStart >= nLastTop && nStart < nLastTop + 100)\r
928 nStart = nLastTop + 100;\r
929 if (nEnd >= nLastTop && nEnd < nLastTop + 100)\r
930 nEnd = nLastTop;\r
931 }\r
932 nLastTop = nTop;\r
933 pindexLastBest = pindexBest;\r
934 nLastRefreshed = nListViewUpdated;\r
935\r
936 for (int nIndex = nStart; nIndex < min(nEnd, m_listCtrl->GetItemCount()); nIndex++)\r
937 {\r
938 uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1));\r
939 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);\r
940 if (mi == mapWallet.end())\r
941 {\r
942 printf("CMainFrame::RefreshStatusColumn() : tx not found in mapWallet\n");\r
943 continue;\r
944 }\r
945 CWalletTx& wtx = (*mi).second;\r
946 if (wtx.IsCoinBase() || wtx.GetTxTime() != wtx.nTimeDisplayed)\r
947 {\r
948 if (!InsertTransaction(wtx, false, nIndex))\r
949 m_listCtrl->DeleteItem(nIndex--);\r
950 }\r
951 else\r
952 m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx));\r
953 }\r
954 }\r
955}\r
956\r
4405b78d 957void CMainFrame::OnPaint(wxPaintEvent& event)\r
958{\r
93cfb02a 959 if (fRefresh)\r
960 {\r
961 fRefresh = false;\r
962 Refresh();\r
963 }\r
4405b78d 964 event.Skip();\r
965}\r
966\r
e66ec79b 967\r
968unsigned int nNeedRepaint = 0;\r
969unsigned int nLastRepaint = 0;\r
970int64 nLastRepaintTime = 0;\r
971int64 nRepaintInterval = 500;\r
972\r
973void ThreadDelayedRepaint(void* parg)\r
6ccefea6 974{\r
e66ec79b 975 while (!fShutdown)\r
976 {\r
977 if (nLastRepaint != nNeedRepaint && GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)\r
978 {\r
979 nLastRepaint = nNeedRepaint;\r
980 if (pframeMain)\r
981 {\r
982 printf("DelayedRepaint\n");\r
983 wxPaintEvent event;\r
93cfb02a 984 pframeMain->fRefresh = true;\r
e66ec79b 985 pframeMain->AddPendingEvent(event);\r
986 }\r
987 }\r
988 Sleep(nRepaintInterval);\r
989 }\r
990}\r
991\r
992void MainFrameRepaint()\r
993{\r
994 // This is called by network code that shouldn't access pframeMain\r
995 // directly because it could still be running after the UI is closed.\r
996 if (pframeMain)\r
997 {\r
998 // Don't repaint too often\r
999 static int64 nLastRepaintRequest;\r
1000 if (GetTimeMillis() - nLastRepaintRequest < 100)\r
1001 {\r
1002 nNeedRepaint++;\r
1003 return;\r
1004 }\r
1005 nLastRepaintRequest = GetTimeMillis();\r
1006\r
1007 printf("MainFrameRepaint\n");\r
1008 wxPaintEvent event;\r
93cfb02a 1009 pframeMain->fRefresh = true;\r
e66ec79b 1010 pframeMain->AddPendingEvent(event);\r
1011 }\r
6ccefea6 1012}\r
1013\r
4405b78d 1014void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)\r
1015{\r
cc0b4c3b 1016 if (ptaskbaricon)\r
1017 ptaskbaricon->UpdateTooltip();\r
1018\r
e66ec79b 1019 //\r
1020 // Slower stuff\r
1021 //\r
1022 static int nTransactionCount;\r
1023 bool fPaintedBalance = false;\r
1024 if (GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)\r
4405b78d 1025 {\r
e66ec79b 1026 nLastRepaint = nNeedRepaint;\r
1027 nLastRepaintTime = GetTimeMillis();\r
1028\r
1029 // Update listctrl contents\r
1030 if (!vWalletUpdated.empty())\r
4405b78d 1031 {\r
e66ec79b 1032 TRY_CRITICAL_BLOCK(cs_mapWallet)\r
4405b78d 1033 {\r
fba40889 1034 string strTop;\r
1035 if (m_listCtrl->GetItemCount())\r
1036 strTop = (string)m_listCtrl->GetItemText(0);\r
e66ec79b 1037 foreach(uint256 hash, vWalletUpdated)\r
1038 {\r
1039 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);\r
1040 if (mi != mapWallet.end())\r
fba40889 1041 InsertTransaction((*mi).second, false);\r
e66ec79b 1042 }\r
1043 vWalletUpdated.clear();\r
fba40889 1044 if (m_listCtrl->GetItemCount() && strTop != (string)m_listCtrl->GetItemText(0))\r
93cfb02a 1045 m_listCtrl->ScrollList(0, INT_MIN/2);\r
4405b78d 1046 }\r
4405b78d 1047 }\r
cc0b4c3b 1048\r
e66ec79b 1049 // Balance total\r
1050 TRY_CRITICAL_BLOCK(cs_mapWallet)\r
cc0b4c3b 1051 {\r
e66ec79b 1052 fPaintedBalance = true;\r
1053 m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " ");\r
1054\r
1055 // Count hidden and multi-line transactions\r
1056 nTransactionCount = 0;\r
1057 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)\r
1058 {\r
1059 CWalletTx& wtx = (*it).second;\r
1060 nTransactionCount += wtx.nLinesDisplayed;\r
1061 }\r
cc0b4c3b 1062 }\r
1063 }\r
e66ec79b 1064 if (!vWalletUpdated.empty() || !fPaintedBalance)\r
1065 nNeedRepaint++;\r
1066\r
1067 // Update status column of visible items only\r
1068 RefreshStatusColumn();\r
cc0b4c3b 1069\r
4405b78d 1070 // Update status bar\r
1071 string strGen = "";\r
1072 if (fGenerateBitcoins)\r
6ccefea6 1073 strGen = " Generating";\r
4405b78d 1074 if (fGenerateBitcoins && vNodes.empty())\r
1075 strGen = "(not connected)";\r
1076 m_statusBar->SetStatusText(strGen, 1);\r
1077\r
cc0b4c3b 1078 string strStatus = strprintf(" %d connections %d blocks %d transactions", vNodes.size(), nBestHeight + 1, nTransactionCount);\r
4405b78d 1079 m_statusBar->SetStatusText(strStatus, 2);\r
1080\r
31e6ea7f 1081 if (fDebug && GetTime() - nThreadSocketHandlerHeartbeat > 60)\r
1082 m_statusBar->SetStatusText(" ERROR: ThreadSocketHandler has stopped", 0);\r
1083\r
93cfb02a 1084 // Pass through to listctrl to actually do the paint, we're just hooking the message\r
1085 m_listCtrl->Disconnect(wxEVT_PAINT, (wxObjectEventFunction)NULL, NULL, this);\r
1086 m_listCtrl->GetEventHandler()->ProcessEvent(event);\r
1087 m_listCtrl->Connect(wxEVT_PAINT, wxPaintEventHandler(CMainFrame::OnPaintListCtrl), NULL, this);\r
4405b78d 1088}\r
1089\r
e66ec79b 1090\r
1a01afab 1091void UIThreadCall(boost::function0<void> fn)\r
4405b78d 1092{\r
85c33b96 1093 // Call this with a function object created with bind.\r
1094 // bind needs all parameters to match the function's expected types\r
1095 // and all default parameters specified. Some examples:\r
1096 // UIThreadCall(bind(wxBell));\r
1097 // UIThreadCall(bind(wxMessageBox, wxT("Message"), wxT("Title"), wxOK, (wxWindow*)NULL, -1, -1));\r
1098 // UIThreadCall(bind(&CMainFrame::OnMenuHelpAbout, pframeMain, event));\r
4405b78d 1099 if (pframeMain)\r
85c33b96 1100 {\r
1101 wxCommandEvent event(wxEVT_UITHREADCALL);\r
1a01afab 1102 event.SetClientData((void*)new boost::function0<void>(fn));\r
4405b78d 1103 pframeMain->GetEventHandler()->AddPendingEvent(event);\r
85c33b96 1104 }\r
4405b78d 1105}\r
1106\r
85c33b96 1107void CMainFrame::OnUIThreadCall(wxCommandEvent& event)\r
4405b78d 1108{\r
1a01afab 1109 boost::function0<void>* pfn = (boost::function0<void>*)event.GetClientData();\r
85c33b96 1110 (*pfn)();\r
1111 delete pfn;\r
4405b78d 1112}\r
1113\r
1114void CMainFrame::OnMenuFileExit(wxCommandEvent& event)\r
1115{\r
52109986 1116 // File->Exit\r
4405b78d 1117 Close(true);\r
1118}\r
1119\r
52109986 1120void CMainFrame::OnMenuViewShowGenerated(wxCommandEvent& event)\r
1121{\r
1122 // View->Show Generated\r
1123 fShowGenerated = event.IsChecked();\r
1124 CWalletDB().WriteSetting("fShowGenerated", fShowGenerated);\r
1125 RefreshListCtrl();\r
1126}\r
1127\r
1128void CMainFrame::OnUpdateUIViewShowGenerated(wxUpdateUIEvent& event)\r
1129{\r
1130 event.Check(fShowGenerated);\r
1131}\r
1132\r
d1b70ffa 1133void CMainFrame::OnMenuOptionsGenerate(wxCommandEvent& event)\r
1134{\r
52109986 1135 // Options->Generate Coins\r
d1b70ffa 1136 GenerateBitcoins(event.IsChecked());\r
52109986 1137}\r
d1b70ffa 1138\r
52109986 1139void CMainFrame::OnUpdateUIOptionsGenerate(wxUpdateUIEvent& event)\r
1140{\r
1141 event.Check(fGenerateBitcoins);\r
4405b78d 1142}\r
1143\r
1144void CMainFrame::OnMenuOptionsChangeYourAddress(wxCommandEvent& event)\r
1145{\r
52109986 1146 // Options->Change Your Address\r
4405b78d 1147 OnButtonChange(event);\r
1148}\r
1149\r
1150void CMainFrame::OnMenuOptionsOptions(wxCommandEvent& event)\r
1151{\r
52109986 1152 // Options->Options\r
4405b78d 1153 COptionsDialog dialog(this);\r
1154 dialog.ShowModal();\r
1155}\r
1156\r
1157void CMainFrame::OnMenuHelpAbout(wxCommandEvent& event)\r
1158{\r
52109986 1159 // Help->About\r
4405b78d 1160 CAboutDialog dialog(this);\r
1161 dialog.ShowModal();\r
1162}\r
1163\r
1164void CMainFrame::OnButtonSend(wxCommandEvent& event)\r
1165{\r
4405b78d 1166 // Toolbar: Send\r
1167 CSendDialog dialog(this);\r
1168 dialog.ShowModal();\r
1169}\r
1170\r
1171void CMainFrame::OnButtonAddressBook(wxCommandEvent& event)\r
1172{\r
1173 // Toolbar: Address Book\r
1174 CAddressBookDialog dialogAddr(this, "", false);\r
1175 if (dialogAddr.ShowModal() == 2)\r
1176 {\r
1177 // Send\r
1178 CSendDialog dialogSend(this, dialogAddr.GetAddress());\r
1179 dialogSend.ShowModal();\r
1180 }\r
1181}\r
1182\r
1183void CMainFrame::OnSetFocusAddress(wxFocusEvent& event)\r
1184{\r
1185 // Automatically select-all when entering window\r
1186 m_textCtrlAddress->SetSelection(-1, -1);\r
1187 fOnSetFocusAddress = true;\r
1188 event.Skip();\r
1189}\r
1190\r
1191void CMainFrame::OnMouseEventsAddress(wxMouseEvent& event)\r
1192{\r
1193 if (fOnSetFocusAddress)\r
1194 m_textCtrlAddress->SetSelection(-1, -1);\r
1195 fOnSetFocusAddress = false;\r
1196 event.Skip();\r
1197}\r
1198\r
1199void CMainFrame::OnButtonCopy(wxCommandEvent& event)\r
1200{\r
1201 // Copy address box to clipboard\r
1202 if (wxTheClipboard->Open())\r
1203 {\r
1204 wxTheClipboard->SetData(new wxTextDataObject(m_textCtrlAddress->GetValue()));\r
1205 wxTheClipboard->Close();\r
1206 }\r
1207}\r
1208\r
1209void CMainFrame::OnButtonChange(wxCommandEvent& event)\r
1210{\r
1211 CYourAddressDialog dialog(this, string(m_textCtrlAddress->GetValue()));\r
1212 if (!dialog.ShowModal())\r
1213 return;\r
1214 string strAddress = (string)dialog.GetAddress();\r
1215 if (strAddress != m_textCtrlAddress->GetValue())\r
1216 {\r
1217 uint160 hash160;\r
1218 if (!AddressToHash160(strAddress, hash160))\r
1219 return;\r
1220 if (!mapPubKeys.count(hash160))\r
1221 return;\r
1222 CWalletDB().WriteDefaultKey(mapPubKeys[hash160]);\r
1223 m_textCtrlAddress->SetValue(strAddress);\r
1224 }\r
1225}\r
1226\r
1227void CMainFrame::OnListItemActivatedAllTransactions(wxListEvent& event)\r
1228{\r
1229 uint256 hash((string)GetItemText(m_listCtrl, event.GetIndex(), 1));\r
1230 CWalletTx wtx;\r
1231 CRITICAL_BLOCK(cs_mapWallet)\r
1232 {\r
1233 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);\r
1234 if (mi == mapWallet.end())\r
1235 {\r
1236 printf("CMainFrame::OnListItemActivatedAllTransactions() : tx not found in mapWallet\n");\r
1237 return;\r
1238 }\r
1239 wtx = (*mi).second;\r
1240 }\r
1241 CTxDetailsDialog dialog(this, wtx);\r
1242 dialog.ShowModal();\r
1243 //CTxDetailsDialog* pdialog = new CTxDetailsDialog(this, wtx);\r
1244 //pdialog->Show();\r
1245}\r
1246\r
1247void CMainFrame::OnListItemActivatedProductsSent(wxListEvent& event)\r
1248{\r
1249 CProduct& product = *(CProduct*)event.GetItem().GetData();\r
1250 CEditProductDialog* pdialog = new CEditProductDialog(this);\r
1251 pdialog->SetProduct(product);\r
1252 pdialog->Show();\r
1253}\r
1254\r
1255void CMainFrame::OnListItemActivatedOrdersSent(wxListEvent& event)\r
1256{\r
1257 CWalletTx& order = *(CWalletTx*)event.GetItem().GetData();\r
1258 CViewOrderDialog* pdialog = new CViewOrderDialog(this, order, false);\r
1259 pdialog->Show();\r
1260}\r
1261\r
1262void CMainFrame::OnListItemActivatedOrdersReceived(wxListEvent& event)\r
1263{\r
1264 CWalletTx& order = *(CWalletTx*)event.GetItem().GetData();\r
1265 CViewOrderDialog* pdialog = new CViewOrderDialog(this, order, true);\r
1266 pdialog->Show();\r
1267}\r
1268\r
1269\r
1270\r
1271\r
1272\r
1273\r
1274\r
1275//////////////////////////////////////////////////////////////////////////////\r
1276//\r
1277// CTxDetailsDialog\r
1278//\r
1279\r
1280CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetailsDialogBase(parent)\r
1281{\r
1282 string strHTML;\r
1283 strHTML.reserve(4000);\r
1284 strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";\r
1285\r
1286 int64 nTime = wtx.GetTxTime();\r
1287 int64 nCredit = wtx.GetCredit();\r
1288 int64 nDebit = wtx.GetDebit();\r
1289 int64 nNet = nCredit - nDebit;\r
1290\r
1291\r
1292\r
31e6ea7f 1293 strHTML += "<b>Status:</b> " + FormatTxStatus(wtx);\r
1294 int nRequests = wtx.GetRequestCount();\r
1295 if (nRequests != -1)\r
1296 {\r
1297 if (nRequests == 0)\r
1298 strHTML += ", has not been successfully broadcast yet";\r
1299 else if (nRequests == 1)\r
1300 strHTML += strprintf(", broadcast through %d node", nRequests);\r
1301 else\r
1302 strHTML += strprintf(", broadcast through %d nodes", nRequests);\r
1303 }\r
1304 strHTML += "<br>";\r
1305\r
4405b78d 1306 strHTML += "<b>Date:</b> " + (nTime ? DateTimeStr(nTime) : "") + "<br>";\r
1307\r
1308\r
1309 //\r
1310 // From\r
1311 //\r
1312 if (wtx.IsCoinBase())\r
1313 {\r
1314 strHTML += "<b>Source:</b> Generated<br>";\r
1315 }\r
1316 else if (!wtx.mapValue["from"].empty())\r
1317 {\r
1318 // Online transaction\r
1319 if (!wtx.mapValue["from"].empty())\r
1320 strHTML += "<b>From:</b> " + HtmlEscape(wtx.mapValue["from"]) + "<br>";\r
1321 }\r
1322 else\r
1323 {\r
1324 // Offline transaction\r
1325 if (nNet > 0)\r
1326 {\r
1327 // Credit\r
1328 foreach(const CTxOut& txout, wtx.vout)\r
1329 {\r
1330 if (txout.IsMine())\r
1331 {\r
1332 vector<unsigned char> vchPubKey;\r
1333 if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))\r
1334 {\r
1335 string strAddress = PubKeyToAddress(vchPubKey);\r
1336 if (mapAddressBook.count(strAddress))\r
1337 {\r
1338 strHTML += "<b>From:</b> unknown<br>";\r
1339 strHTML += "<b>To:</b> ";\r
1340 strHTML += HtmlEscape(strAddress);\r
1341 if (!mapAddressBook[strAddress].empty())\r
1342 strHTML += " (yours, label: " + mapAddressBook[strAddress] + ")";\r
1343 else\r
1344 strHTML += " (yours)";\r
1345 strHTML += "<br>";\r
1346 }\r
1347 }\r
1348 break;\r
1349 }\r
1350 }\r
1351 }\r
1352 }\r
1353\r
1354\r
1355 //\r
1356 // To\r
1357 //\r
1358 string strAddress;\r
1359 if (!wtx.mapValue["to"].empty())\r
1360 {\r
1361 // Online transaction\r
1362 strAddress = wtx.mapValue["to"];\r
1363 strHTML += "<b>To:</b> ";\r
1364 if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())\r
1365 strHTML += mapAddressBook[strAddress] + " ";\r
1366 strHTML += HtmlEscape(strAddress) + "<br>";\r
1367 }\r
1368\r
1369\r
1370 //\r
1371 // Amount\r
1372 //\r
1373 if (wtx.IsCoinBase() && nCredit == 0)\r
1374 {\r
1375 //\r
1376 // Coinbase\r
1377 //\r
1378 int64 nUnmatured = 0;\r
1379 foreach(const CTxOut& txout, wtx.vout)\r
1380 nUnmatured += txout.GetCredit();\r
1381 if (wtx.IsInMainChain())\r
1382 strHTML += strprintf("<b>Credit:</b> (%s matures in %d more blocks)<br>", FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());\r
1383 else\r
1384 strHTML += "<b>Credit:</b> (not accepted)<br>";\r
1385 }\r
1386 else if (nNet > 0)\r
1387 {\r
1388 //\r
1389 // Credit\r
1390 //\r
1391 strHTML += "<b>Credit:</b> " + FormatMoney(nNet) + "<br>";\r
1392 }\r
1393 else\r
1394 {\r
1395 bool fAllFromMe = true;\r
1396 foreach(const CTxIn& txin, wtx.vin)\r
1397 fAllFromMe = fAllFromMe && txin.IsMine();\r
1398\r
1399 bool fAllToMe = true;\r
1400 foreach(const CTxOut& txout, wtx.vout)\r
1401 fAllToMe = fAllToMe && txout.IsMine();\r
1402\r
1403 if (fAllFromMe)\r
1404 {\r
1405 //\r
1406 // Debit\r
1407 //\r
1408 foreach(const CTxOut& txout, wtx.vout)\r
1409 {\r
1410 if (txout.IsMine())\r
1411 continue;\r
1412\r
1413 if (wtx.mapValue["to"].empty())\r
1414 {\r
1415 // Offline transaction\r
1416 uint160 hash160;\r
1417 if (ExtractHash160(txout.scriptPubKey, hash160))\r
1418 {\r
1419 string strAddress = Hash160ToAddress(hash160);\r
1420 strHTML += "<b>To:</b> ";\r
1421 if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())\r
1422 strHTML += mapAddressBook[strAddress] + " ";\r
1423 strHTML += strAddress;\r
1424 strHTML += "<br>";\r
1425 }\r
1426 }\r
1427\r
1428 strHTML += "<b>Debit:</b> " + FormatMoney(-txout.nValue) + "<br>";\r
1429 }\r
1430\r
1431 if (fAllToMe)\r
1432 {\r
1433 // Payment to self\r
31e6ea7f 1434 /// issue: can't tell which is the payment and which is the change anymore\r
1435 //int64 nValue = wtx.vout[0].nValue;\r
1436 //strHTML += "<b>Debit:</b> " + FormatMoney(-nValue) + "<br>";\r
1437 //strHTML += "<b>Credit:</b> " + FormatMoney(nValue) + "<br>";\r
4405b78d 1438 }\r
1439\r
1440 int64 nTxFee = nDebit - wtx.GetValueOut();\r
1441 if (nTxFee > 0)\r
1442 strHTML += "<b>Transaction fee:</b> " + FormatMoney(-nTxFee) + "<br>";\r
1443 }\r
1444 else\r
1445 {\r
1446 //\r
1447 // Mixed debit transaction\r
1448 //\r
1449 foreach(const CTxIn& txin, wtx.vin)\r
1450 if (txin.IsMine())\r
1451 strHTML += "<b>Debit:</b> " + FormatMoney(-txin.GetDebit()) + "<br>";\r
1452 foreach(const CTxOut& txout, wtx.vout)\r
1453 if (txout.IsMine())\r
1454 strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";\r
1455 }\r
1456 }\r
1457\r
1458 strHTML += "<b>Net amount:</b> " + FormatMoney(nNet, true) + "<br>";\r
1459\r
1460\r
1461 //\r
1462 // Message\r
1463 //\r
1464 if (!wtx.mapValue["message"].empty())\r
1465 strHTML += "<br><b>Message:</b><br>" + HtmlEscape(wtx.mapValue["message"], true) + "<br>";\r
1466\r
1467 if (wtx.IsCoinBase())\r
1468 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
1469\r
1470\r
1471 //\r
1472 // Debug view\r
1473 //\r
1474 if (fDebug)\r
1475 {\r
1476 strHTML += "<hr><br>debug print<br><br>";\r
1477 foreach(const CTxIn& txin, wtx.vin)\r
1478 if (txin.IsMine())\r
1479 strHTML += "<b>Debit:</b> " + FormatMoney(-txin.GetDebit()) + "<br>";\r
1480 foreach(const CTxOut& txout, wtx.vout)\r
1481 if (txout.IsMine())\r
1482 strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";\r
1483\r
1484 strHTML += "<b>Inputs:</b><br>";\r
1485 CRITICAL_BLOCK(cs_mapWallet)\r
1486 {\r
1487 foreach(const CTxIn& txin, wtx.vin)\r
1488 {\r
1489 COutPoint prevout = txin.prevout;\r
1490 map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);\r
1491 if (mi != mapWallet.end())\r
1492 {\r
1493 const CWalletTx& prev = (*mi).second;\r
1494 if (prevout.n < prev.vout.size())\r
1495 {\r
1496 strHTML += HtmlEscape(prev.ToString(), true);\r
1497 strHTML += " &nbsp;&nbsp; " + FormatTxStatus(prev) + ", ";\r
1498 strHTML = strHTML + "IsMine=" + (prev.vout[prevout.n].IsMine() ? "true" : "false") + "<br>";\r
1499 }\r
1500 }\r
1501 }\r
1502 }\r
1503\r
1504 strHTML += "<br><hr><br><b>Transaction:</b><br>";\r
1505 strHTML += HtmlEscape(wtx.ToString(), true);\r
1506 }\r
1507\r
1508\r
1509\r
1510 strHTML += "</font></html>";\r
1511 string(strHTML.begin(), strHTML.end()).swap(strHTML);\r
1512 m_htmlWin->SetPage(strHTML);\r
1513 m_buttonOK->SetFocus();\r
1514}\r
1515\r
1516void CTxDetailsDialog::OnButtonOK(wxCommandEvent& event)\r
1517{\r
1518 Close();\r
1519 //Destroy();\r
1520}\r
1521\r
1522\r
1523\r
1524\r
1525\r
1526//////////////////////////////////////////////////////////////////////////////\r
1527//\r
1528// COptionsDialog\r
1529//\r
1530\r
1531COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent)\r
1532{\r
52109986 1533 // Set up list box of page choices\r
1534 m_listBox->Append("Main");\r
1535 //m_listBox->Append("Test 2");\r
1536 m_listBox->SetSelection(0);\r
1537 SelectPage(0);\r
31e6ea7f 1538#ifndef __WXMSW__\r
1539 m_checkBoxMinimizeOnClose->SetLabel("&Minimize on close");\r
0bbbee96 1540 m_checkBoxStartOnSystemStartup->Enable(false); // not implemented yet\r
31e6ea7f 1541#endif\r
52109986 1542\r
1543 // Init values\r
1544 m_textCtrlTransactionFee->SetValue(FormatMoney(nTransactionFee));\r
1545 m_checkBoxLimitProcessors->SetValue(fLimitProcessors);\r
1546 m_spinCtrlLimitProcessors->Enable(fLimitProcessors);\r
1547 m_spinCtrlLimitProcessors->SetValue(nLimitProcessors);\r
fba40889 1548 int nProcessors = wxThread::GetCPUCount();\r
52109986 1549 if (nProcessors < 1)\r
1550 nProcessors = 999;\r
1551 m_spinCtrlLimitProcessors->SetRange(1, nProcessors);\r
1552 m_checkBoxStartOnSystemStartup->SetValue(fTmpStartOnSystemStartup = GetStartOnSystemStartup());\r
1553 m_checkBoxMinimizeToTray->SetValue(fMinimizeToTray);\r
31e6ea7f 1554 m_checkBoxMinimizeOnClose->SetValue(fMinimizeOnClose);\r
cc0b4c3b 1555 m_checkBoxUseProxy->SetValue(fUseProxy);\r
1556 m_textCtrlProxyIP->Enable(fUseProxy);\r
1557 m_textCtrlProxyPort->Enable(fUseProxy);\r
1558 m_staticTextProxyIP->Enable(fUseProxy);\r
1559 m_staticTextProxyPort->Enable(fUseProxy);\r
1560 m_textCtrlProxyIP->SetValue(addrProxy.ToStringIP());\r
1561 m_textCtrlProxyPort->SetValue(addrProxy.ToStringPort());\r
1562\r
4405b78d 1563 m_buttonOK->SetFocus();\r
52109986 1564}\r
d1b70ffa 1565\r
52109986 1566void COptionsDialog::SelectPage(int nPage)\r
1567{\r
1568 m_panelMain->Show(nPage == 0);\r
1569 m_panelTest2->Show(nPage == 1);\r
d1b70ffa 1570\r
52109986 1571 m_scrolledWindow->Layout();\r
1572 m_scrolledWindow->SetScrollbars(0, 0, 0, 0, 0, 0);\r
1573}\r
d1b70ffa 1574\r
52109986 1575void COptionsDialog::OnListBox(wxCommandEvent& event)\r
1576{\r
1577 SelectPage(event.GetSelection());\r
4405b78d 1578}\r
1579\r
52109986 1580void COptionsDialog::OnKillFocusTransactionFee(wxFocusEvent& event)\r
4405b78d 1581{\r
52109986 1582 int64 nTmp = nTransactionFee;\r
1583 ParseMoney(m_textCtrlTransactionFee->GetValue(), nTmp);\r
1584 m_textCtrlTransactionFee->SetValue(FormatMoney(nTmp));\r
4405b78d 1585}\r
1586\r
52109986 1587void COptionsDialog::OnCheckBoxLimitProcessors(wxCommandEvent& event)\r
4405b78d 1588{\r
52109986 1589 m_spinCtrlLimitProcessors->Enable(event.IsChecked());\r
1590}\r
d1b70ffa 1591\r
cc0b4c3b 1592void COptionsDialog::OnCheckBoxUseProxy(wxCommandEvent& event)\r
1593{\r
1594 m_textCtrlProxyIP->Enable(event.IsChecked());\r
1595 m_textCtrlProxyPort->Enable(event.IsChecked());\r
1596 m_staticTextProxyIP->Enable(event.IsChecked());\r
1597 m_staticTextProxyPort->Enable(event.IsChecked());\r
1598}\r
1599\r
1600CAddress COptionsDialog::GetProxyAddr()\r
1601{\r
1602 // Be careful about byte order, addr.ip and addr.port are big endian\r
1603 CAddress addr(m_textCtrlProxyIP->GetValue() + ":" + m_textCtrlProxyPort->GetValue());\r
1604 if (addr.ip == INADDR_NONE)\r
1605 addr.ip = addrProxy.ip;\r
1606 int nPort = atoi(m_textCtrlProxyPort->GetValue());\r
1607 addr.port = htons(nPort);\r
1608 if (nPort <= 0 || nPort > USHRT_MAX)\r
1609 addr.port = addrProxy.port;\r
1610 return addr;\r
1611}\r
1612\r
1613void COptionsDialog::OnKillFocusProxy(wxFocusEvent& event)\r
1614{\r
1615 m_textCtrlProxyIP->SetValue(GetProxyAddr().ToStringIP());\r
1616 m_textCtrlProxyPort->SetValue(GetProxyAddr().ToStringPort());\r
1617}\r
1618\r
1619\r
52109986 1620void COptionsDialog::OnButtonOK(wxCommandEvent& event)\r
1621{\r
1622 OnButtonApply(event);\r
4405b78d 1623 Close();\r
1624}\r
1625\r
1626void COptionsDialog::OnButtonCancel(wxCommandEvent& event)\r
1627{\r
1628 Close();\r
1629}\r
1630\r
52109986 1631void COptionsDialog::OnButtonApply(wxCommandEvent& event)\r
d1b70ffa 1632{\r
52109986 1633 CWalletDB walletdb;\r
d1b70ffa 1634\r
52109986 1635 int64 nPrevTransactionFee = nTransactionFee;\r
1636 if (ParseMoney(m_textCtrlTransactionFee->GetValue(), nTransactionFee) && nTransactionFee != nPrevTransactionFee)\r
1637 walletdb.WriteSetting("nTransactionFee", nTransactionFee);\r
d1b70ffa 1638\r
52109986 1639 int nPrevMaxProc = (fLimitProcessors ? nLimitProcessors : INT_MAX);\r
1640 if (fLimitProcessors != m_checkBoxLimitProcessors->GetValue())\r
1641 {\r
1642 fLimitProcessors = m_checkBoxLimitProcessors->GetValue();\r
1643 walletdb.WriteSetting("fLimitProcessors", fLimitProcessors);\r
1644 }\r
1645 if (nLimitProcessors != m_spinCtrlLimitProcessors->GetValue())\r
1646 {\r
1647 nLimitProcessors = m_spinCtrlLimitProcessors->GetValue();\r
1648 walletdb.WriteSetting("nLimitProcessors", nLimitProcessors);\r
1649 }\r
1650 if (fGenerateBitcoins && (fLimitProcessors ? nLimitProcessors : INT_MAX) > nPrevMaxProc)\r
1651 GenerateBitcoins(fGenerateBitcoins);\r
d1b70ffa 1652\r
52109986 1653 if (fTmpStartOnSystemStartup != m_checkBoxStartOnSystemStartup->GetValue())\r
1654 {\r
1655 fTmpStartOnSystemStartup = m_checkBoxStartOnSystemStartup->GetValue();\r
1656 SetStartOnSystemStartup(fTmpStartOnSystemStartup);\r
1657 }\r
d1b70ffa 1658\r
52109986 1659 if (fMinimizeToTray != m_checkBoxMinimizeToTray->GetValue())\r
1660 {\r
1661 fMinimizeToTray = m_checkBoxMinimizeToTray->GetValue();\r
1662 walletdb.WriteSetting("fMinimizeToTray", fMinimizeToTray);\r
31e6ea7f 1663 ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);\r
52109986 1664 }\r
1665\r
31e6ea7f 1666 if (fMinimizeOnClose != m_checkBoxMinimizeOnClose->GetValue())\r
52109986 1667 {\r
31e6ea7f 1668 fMinimizeOnClose = m_checkBoxMinimizeOnClose->GetValue();\r
52109986 1669 walletdb.WriteSetting("fMinimizeOnClose", fMinimizeOnClose);\r
1670 }\r
cc0b4c3b 1671\r
fba40889 1672 fUseProxy = m_checkBoxUseProxy->GetValue();\r
1673 walletdb.WriteSetting("fUseProxy", fUseProxy);\r
cc0b4c3b 1674\r
fba40889 1675 addrProxy = GetProxyAddr();\r
1676 walletdb.WriteSetting("addrProxy", addrProxy);\r
d1b70ffa 1677}\r
1678\r
1679\r
4405b78d 1680\r
1681\r
1682\r
52109986 1683\r
4405b78d 1684//////////////////////////////////////////////////////////////////////////////\r
1685//\r
1686// CAboutDialog\r
1687//\r
1688\r
1689CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent)\r
1690{\r
e4db3744 1691 m_staticTextVersion->SetLabel(strprintf("version 0.%d.%d beta", VERSION/100, VERSION%100));\r
4405b78d 1692\r
1693 // Workaround until upgrade to wxWidgets supporting UTF-8\r
1694 wxString str = m_staticTextMain->GetLabel();\r
1695