|
|
|
|
// Copyright (c) 2009 Satoshi Nakamoto
|
|
|
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
|
|
|
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
|
|
|
|
|
#include "headers.h"
|
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
|
#include <crtdbg.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
DEFINE_EVENT_TYPE(wxEVT_CROSSTHREADCALL)
|
|
|
|
|
DEFINE_EVENT_TYPE(wxEVT_REPLY1)
|
|
|
|
|
DEFINE_EVENT_TYPE(wxEVT_REPLY2)
|
|
|
|
|
DEFINE_EVENT_TYPE(wxEVT_REPLY3)
|
|
|
|
|
DEFINE_EVENT_TYPE(wxEVT_TABLEADDED)
|
|
|
|
|
DEFINE_EVENT_TYPE(wxEVT_TABLEUPDATED)
|
|
|
|
|
DEFINE_EVENT_TYPE(wxEVT_TABLEDELETED)
|
|
|
|
|
|
|
|
|
|
CMainFrame* pframeMain = NULL;
|
|
|
|
|
map<string, string> mapAddressBook;
|
|
|
|
|
CBitcoinTBIcon* taskBarIcon = NULL; // Tray icon
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ThreadRequestProductDetails(void* parg);
|
|
|
|
|
void ThreadRandSendTest(void* parg);
|
|
|
|
|
bool fRandSendTest = false;
|
|
|
|
|
void RandSend();
|
|
|
|
|
extern int g_isPainting;
|
|
|
|
|
|
|
|
|
|
// UI settings and their default values
|
|
|
|
|
int minimizeToTray = 1;
|
|
|
|
|
int closeToTray = 1;
|
|
|
|
|
int startOnSysBoot = 1;
|
|
|
|
|
int askBeforeClosing = 1;
|
|
|
|
|
int alwaysShowTrayIcon = 1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Util
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
void HandleCtrlA(wxKeyEvent& event)
|
|
|
|
|
{
|
|
|
|
|
// Ctrl-a select all
|
|
|
|
|
wxTextCtrl* textCtrl = (wxTextCtrl*)event.GetEventObject();
|
|
|
|
|
if (event.GetModifiers() == wxMOD_CONTROL && event.GetKeyCode() == 'A')
|
|
|
|
|
textCtrl->SetSelection(-1, -1);
|
|
|
|
|
event.Skip();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Is24HourTime()
|
|
|
|
|
{
|
|
|
|
|
//char pszHourFormat[256];
|
|
|
|
|
//pszHourFormat[0] = '\0';
|
|
|
|
|
//GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ITIME, pszHourFormat, 256);
|
|
|
|
|
//return (pszHourFormat[0] != '0');
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string DateStr(int64 nTime)
|
|
|
|
|
{
|
|
|
|
|
return (string)wxDateTime((time_t)nTime).FormatDate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string DateTimeStr(int64 nTime)
|
|
|
|
|
{
|
|
|
|
|
wxDateTime datetime((time_t)nTime);
|
|
|
|
|
if (Is24HourTime())
|
|
|
|
|
return (string)datetime.Format("%x %H:%M");
|
|
|
|
|
else
|
|
|
|
|
return (string)datetime.Format("%x ") + itostr((datetime.GetHour() + 11) % 12 + 1) + (string)datetime.Format(":%M %p");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wxString GetItemText(wxListCtrl* listCtrl, int nIndex, int nColumn)
|
|
|
|
|
{
|
|
|
|
|
// Helper to simplify access to listctrl
|
|
|
|
|
wxListItem item;
|
|
|
|
|
item.m_itemId = nIndex;
|
|
|
|
|
item.m_col = nColumn;
|
|
|
|
|
item.m_mask = wxLIST_MASK_TEXT;
|
|
|
|
|
if (!listCtrl->GetItem(item))
|
|
|
|
|
return "";
|
|
|
|
|
return item.GetText();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1)
|
|
|
|
|
{
|
|
|
|
|
int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
|
|
|
|
|
listCtrl->SetItem(nIndex, 1, str1);
|
|
|
|
|
return nIndex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
|
|
|
|
|
{
|
|
|
|
|
int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
|
|
|
|
|
listCtrl->SetItem(nIndex, 1, str1);
|
|
|
|
|
listCtrl->SetItem(nIndex, 2, str2);
|
|
|
|
|
listCtrl->SetItem(nIndex, 3, str3);
|
|
|
|
|
listCtrl->SetItem(nIndex, 4, str4);
|
|
|
|
|
return nIndex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int InsertLine(wxListCtrl* listCtrl, void* pdata, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
|
|
|
|
|
{
|
|
|
|
|
int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
|
|
|
|
|
listCtrl->SetItemPtrData(nIndex, (wxUIntPtr)pdata);
|
|
|
|
|
listCtrl->SetItem(nIndex, 1, str1);
|
|
|
|
|
listCtrl->SetItem(nIndex, 2, str2);
|
|
|
|
|
listCtrl->SetItem(nIndex, 3, str3);
|
|
|
|
|
listCtrl->SetItem(nIndex, 4, str4);
|
|
|
|
|
return nIndex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SetSelection(wxListCtrl* listCtrl, int nIndex)
|
|
|
|
|
{
|
|
|
|
|
int nSize = listCtrl->GetItemCount();
|
|
|
|
|
long nState = (wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
|
|
|
|
|
for (int i = 0; i < nSize; i++)
|
|
|
|
|
listCtrl->SetItemState(i, (i == nIndex ? nState : 0), nState);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int GetSelection(wxListCtrl* listCtrl)
|
|
|
|
|
{
|
|
|
|
|
int nSize = listCtrl->GetItemCount();
|
|
|
|
|
for (int i = 0; i < nSize; i++)
|
|
|
|
|
if (listCtrl->GetItemState(i, wxLIST_STATE_FOCUSED))
|
|
|
|
|
return i;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string HtmlEscape(const char* psz, bool fMultiLine=false)
|
|
|
|
|
{
|
|
|
|
|
int len = 0;
|
|
|
|
|
for (const char* p = psz; *p; p++)
|
|
|
|
|
{
|
|
|
|
|
if (*p == '<') len += 4;
|
|
|
|
|
else if (*p == '>') len += 4;
|
|
|
|
|
else if (*p == '&') len += 5;
|
|
|
|
|
else if (*p == '"') len += 6;
|
|
|
|
|
else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') len += 6;
|
|
|
|
|
else if (*p == '\n' && fMultiLine) len += 5;
|
|
|
|
|
else
|
|
|
|
|
len++;
|
|
|
|
|
}
|
|
|
|
|
string str;
|
|
|
|
|
str.reserve(len);
|
|
|
|
|
for (const char* p = psz; *p; p++)
|
|
|
|
|
{
|
|
|
|
|
if (*p == '<') str += "<";
|
|
|
|
|
else if (*p == '>') str += ">";
|
|
|
|
|
else if (*p == '&') str += "&";
|
|
|
|
|
else if (*p == '"') str += """;
|
|
|
|
|
else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') str += " ";
|
|
|
|
|
else if (*p == '\n' && fMultiLine) str += "<br>\n";
|
|
|
|
|
else
|
|
|
|
|
str += *p;
|
|
|
|
|
}
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string HtmlEscape(const string& str, bool fMultiLine=false)
|
|
|
|
|
{
|
|
|
|
|
return HtmlEscape(str.c_str(), fMultiLine);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AddToMyProducts(CProduct product)
|
|
|
|
|
{
|
|
|
|
|
CProduct& productInsert = mapMyProducts[product.GetHash()];
|
|
|
|
|
productInsert = product;
|
|
|
|
|
InsertLine(pframeMain->m_listCtrlProductsSent, &productInsert,
|
|
|
|
|
product.mapValue["category"],
|
|
|
|
|
product.mapValue["title"].substr(0, 100),
|
|
|
|
|
product.mapValue["description"].substr(0, 100),
|
|
|
|
|
product.mapValue["price"],
|
|
|
|
|
"");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Custom events
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
set<void*> setCallbackAvailable;
|
|
|
|
|
CCriticalSection cs_setCallbackAvailable;
|
|
|
|
|
|
|
|
|
|
void AddCallbackAvailable(void* p)
|
|
|
|
|
{
|
|
|
|
|
CRITICAL_BLOCK(cs_setCallbackAvailable)
|
|
|
|
|
setCallbackAvailable.insert(p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RemoveCallbackAvailable(void* p)
|
|
|
|
|
{
|
|
|
|
|
CRITICAL_BLOCK(cs_setCallbackAvailable)
|
|
|
|
|
setCallbackAvailable.erase(p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IsCallbackAvailable(void* p)
|
|
|
|
|
{
|
|
|
|
|
CRITICAL_BLOCK(cs_setCallbackAvailable)
|
|
|
|
|
return setCallbackAvailable.count(p);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
|
void AddPendingCustomEvent(wxEvtHandler* pevthandler, int nEventID, const T pbeginIn, const T pendIn)
|
|
|
|
|
{
|
|
|
|
|
if (!pevthandler)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const char* pbegin = (pendIn != pbeginIn) ? &pbeginIn[0] : NULL;
|
|
|
|
|
const char* pend = pbegin + (pendIn - pbeginIn) * sizeof(pbeginIn[0]);
|
|
|
|
|
wxCommandEvent event(nEventID);
|
|
|
|
|
wxString strData(wxChar(0), (pend - pbegin) / sizeof(wxChar) + 1);
|
|
|
|
|
memcpy(&strData[0], pbegin, pend - pbegin);
|
|
|
|
|
event.SetString(strData);
|
|
|
|
|
event.SetInt(pend - pbegin);
|
|
|
|
|
|
|
|
|
|
pevthandler->AddPendingEvent(event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
|
void AddPendingCustomEvent(wxEvtHandler* pevthandler, int nEventID, const T& obj)
|
|
|
|
|
{
|
|
|
|
|
CDataStream ss;
|
|
|
|
|
ss << obj;
|
|
|
|
|
AddPendingCustomEvent(pevthandler, nEventID, ss.begin(), ss.end());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AddPendingReplyEvent1(void* pevthandler, CDataStream& vRecv)
|
|
|
|
|
{
|
|
|
|
|
if (IsCallbackAvailable(pevthandler))
|
|
|
|
|
AddPendingCustomEvent((wxEvtHandler*)pevthandler, wxEVT_REPLY1, vRecv.begin(), vRecv.end());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AddPendingReplyEvent2(void* pevthandler, CDataStream& vRecv)
|
|
|
|
|
{
|
|
|
|
|
if (IsCallbackAvailable(pevthandler))
|
|
|
|
|
AddPendingCustomEvent((wxEvtHandler*)pevthandler, wxEVT_REPLY2, vRecv.begin(), vRecv.end());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AddPendingReplyEvent3(void* pevthandler, CDataStream& vRecv)
|
|
|
|
|
{
|
|
|
|
|
if (IsCallbackAvailable(pevthandler))
|
|
|
|
|
AddPendingCustomEvent((wxEvtHandler*)pevthandler, wxEVT_REPLY3, vRecv.begin(), vRecv.end());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CDataStream GetStreamFromEvent(const wxCommandEvent& event)
|
|
|
|
|
{
|
|
|
|
|
wxString strData = event.GetString();
|
|
|
|
|
return CDataStream(strData.begin(), strData.begin() + event.GetInt(), SER_NETWORK);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// CMainFrame
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent)
|
|
|
|
|
{
|
|
|
|
|
Connect(wxEVT_CROSSTHREADCALL, wxCommandEventHandler(CMainFrame::OnCrossThreadCall), NULL, this);
|
|
|
|
|
|
|
|
|
|
// Init
|
|
|
|
|
fRefreshListCtrl = false;
|
|
|
|
|
fRefreshListCtrlRunning = false;
|
|
|
|
|
fOnSetFocusAddress = false;
|
|
|
|
|
pindexBestLast = NULL;
|
|
|
|
|
m_choiceFilter->SetSelection(0);
|
|
|
|
|
m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " ");
|
|
|
|
|
m_listCtrl->SetFocus();
|
|
|
|
|
SetIcon(wxICON(bitcoin));
|
|
|
|
|
m_menuOptions->Check(wxID_OPTIONSGENERATEBITCOINS, fGenerateBitcoins);
|
|
|
|
|
|
|
|
|
|
// Init toolbar with transparency masked bitmaps
|
|
|
|
|
m_toolBar->ClearTools();
|
|
|
|
|
|
|
|
|
|
//// shouldn't have to do mask separately anymore, bitmap alpha support added in wx 2.8.9,
|
|
|
|
|
wxBitmap bmpSend(wxT("send20"), wxBITMAP_TYPE_RESOURCE);
|
|
|
|
|
bmpSend.SetMask(new wxMask(wxBitmap(wxT("send20mask"), wxBITMAP_TYPE_RESOURCE)));
|
|
|
|
|
m_toolBar->AddTool(wxID_BUTTONSEND, wxT("&Send Coins"), bmpSend, wxNullBitmap, wxITEM_NORMAL, wxEmptyString, wxEmptyString);
|
|
|
|
|
|
|
|
|
|
wxBitmap bmpAddressBook(wxT("addressbook20"), wxBITMAP_TYPE_RESOURCE);
|
|
|
|
|
bmpAddressBook.SetMask(new wxMask(wxBitmap(wxT("addressbook20mask"), wxBITMAP_TYPE_RESOURCE)));
|
|
|
|
|
m_toolBar->AddTool(wxID_BUTTONRECEIVE, wxT("&Address Book"), bmpAddressBook, wxNullBitmap, wxITEM_NORMAL, wxEmptyString, wxEmptyString);
|
|
|
|
|
|
|
|
|
|
m_toolBar->Realize();
|
|
|
|
|
|
|
|
|
|
// Init column headers
|
|
|
|
|
int nDateWidth = DateTimeStr(1229413914).size() * 6 + 8;
|
|
|
|
|
m_listCtrl->InsertColumn(0, "", wxLIST_FORMAT_LEFT, 0);
|
|
|
|
|
m_listCtrl->InsertColumn(1, "", wxLIST_FORMAT_LEFT, 0);
|
|
|
|
|
m_listCtrl->InsertColumn(2, "Status", wxLIST_FORMAT_LEFT, 90);
|
|
|
|
|
m_listCtrl->InsertColumn(3, "Date", wxLIST_FORMAT_LEFT, nDateWidth);
|
|
|
|
|
m_listCtrl->InsertColumn(4, "Description", wxLIST_FORMAT_LEFT, 409 - nDateWidth);
|
|
|
|
|
m_listCtrl->InsertColumn(5, "Debit", wxLIST_FORMAT_RIGHT, 79);
|
|
|
|
|
m_listCtrl->InsertColumn(6, "Credit", wxLIST_FORMAT_RIGHT, 79);
|
|
|
|
|
|
|
|
|
|
//m_listCtrlProductsSent->InsertColumn(0, "Category", wxLIST_FORMAT_LEFT, 100);
|
|
|
|
|
//m_listCtrlProductsSent->InsertColumn(1, "Title", wxLIST_FORMAT_LEFT, 100);
|
|
|
|
|
//m_listCtrlProductsSent->InsertColumn(2, "Description", wxLIST_FORMAT_LEFT, 100);
|
|
|
|
|
//m_listCtrlProductsSent->InsertColumn(3, "Price", wxLIST_FORMAT_LEFT, 100);
|
|
|
|
|
//m_listCtrlProductsSent->InsertColumn(4, "", wxLIST_FORMAT_LEFT, 100);
|
|
|
|
|
|
|
|
|
|
//m_listCtrlOrdersSent->InsertColumn(0, "Time", wxLIST_FORMAT_LEFT, 100);
|
|
|
|
|
//m_listCtrlOrdersSent->InsertColumn(1, "Price", wxLIST_FORMAT_LEFT, 100);
|
|
|
|
|
//m_listCtrlOrdersSent->InsertColumn(2, "", wxLIST_FORMAT_LEFT, 100);
|
|
|
|
|
//m_listCtrlOrdersSent->InsertColumn(3, "", wxLIST_FORMAT_LEFT, 100);
|
|
|
|
|
//m_listCtrlOrdersSent->InsertColumn(4, "", wxLIST_FORMAT_LEFT, 100);
|
|
|
|
|
|
|
|
|
|
//m_listCtrlOrdersReceived->InsertColumn(0, "Time", wxLIST_FORMAT_LEFT, 100);
|
|
|
|
|
//m_listCtrlOrdersReceived->InsertColumn(1, "Price", wxLIST_FORMAT_LEFT, 100);
|
|
|
|
|
//m_listCtrlOrdersReceived->InsertColumn(2, "Payment Status", wxLIST_FORMAT_LEFT, 100);
|
|
|
|
|
//m_listCtrlOrdersReceived->InsertColumn(3, "", wxLIST_FORMAT_LEFT, 100);
|
|
|
|
|
//m_listCtrlOrdersReceived->InsertColumn(4, "", wxLIST_FORMAT_LEFT, 100);
|
|
|
|
|
|
|
|
|
|
// Init status bar
|
|
|
|
|
int pnWidths[3] = { -100, 81, 286 };
|
|
|
|
|
m_statusBar->SetFieldsCount(3, pnWidths);
|
|
|
|
|
|
|
|
|
|
// Fill your address text box
|
|
|
|
|
vector<unsigned char> vchPubKey;
|
|
|
|
|
if (CWalletDB("r").ReadDefaultKey(vchPubKey))
|
|
|
|
|
m_textCtrlAddress->SetValue(PubKeyToAddress(vchPubKey));
|
|
|
|
|
|
|
|
|
|
// Fill listctrl with wallet transactions
|
|
|
|
|
RefreshListCtrl();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CMainFrame::~CMainFrame()
|
|
|
|
|
{
|
|
|
|
|
pframeMain = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Shutdown(void* parg)
|
|
|
|
|
{
|
|
|
|
|
static CCriticalSection cs_Shutdown;
|
|
|
|
|
CRITICAL_BLOCK(cs_Shutdown)
|
|
|
|
|
{
|
|
|
|
|
fShutdown = true;
|
|
|
|
|
nTransactionsUpdated++;
|
|
|
|
|
DBFlush(false);
|
|
|
|
|
StopNode();
|
|
|
|
|
DBFlush(true);
|
|
|
|
|
|
|
|
|
|
printf("Bitcoin exiting\n");
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnClose(wxCloseEvent& event)
|
|
|
|
|
{
|
|
|
|
|
if (closeToTray && event.CanVeto()) {
|
|
|
|
|
event.Veto();
|
|
|
|
|
SendToTray();
|
|
|
|
|
}
|
|
|
|
|
else if (!event.CanVeto() || !askBeforeClosing || wxMessageBox("Quit program?", "Confirm", wxYES_NO, this) == wxYES) {
|
|
|
|
|
delete taskBarIcon;
|
|
|
|
|
Destroy();
|
|
|
|
|
_beginthread(Shutdown, 0, NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnIconize(wxIconizeEvent& event)
|
|
|
|
|
{
|
|
|
|
|
if (minimizeToTray) {
|
|
|
|
|
SendToTray();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::SendToTray()
|
|
|
|
|
{
|
|
|
|
|
Hide();
|
|
|
|
|
taskBarIcon->Show();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnMouseEvents(wxMouseEvent& event)
|
|
|
|
|
{
|
|
|
|
|
RandAddSeed();
|
|
|
|
|
RAND_add(&event.m_x, sizeof(event.m_x), 0.25);
|
|
|
|
|
RAND_add(&event.m_y, sizeof(event.m_y), 0.25);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnListColBeginDrag(wxListEvent& event)
|
|
|
|
|
{
|
|
|
|
|
// Hidden columns not resizeable
|
|
|
|
|
if (event.GetColumn() <= 1 && !fDebug)
|
|
|
|
|
event.Veto();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
string str0 = strSort;
|
|
|
|
|
long nData = *(long*)&hashKey;
|
|
|
|
|
|
|
|
|
|
if (fNew)
|
|
|
|
|
{
|
|
|
|
|
nIndex = m_listCtrl->InsertItem(0, str0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (nIndex == -1)
|
|
|
|
|
{
|
|
|
|
|
// Find item
|
|
|
|
|
while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)
|
|
|
|
|
if (GetItemText(m_listCtrl, nIndex, 1) == hashKey.ToString())
|
|
|
|
|
break;
|
|
|
|
|
if (nIndex == -1)
|
|
|
|
|
{
|
|
|
|
|
printf("CMainFrame::InsertLine : Couldn't find item to be updated\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If sort key changed, must delete and reinsert to make it relocate
|
|
|
|
|
if (GetItemText(m_listCtrl, nIndex, 0) != str0)
|
|
|
|
|
{
|
|
|
|
|
m_listCtrl->DeleteItem(nIndex);
|
|
|
|
|
nIndex = m_listCtrl->InsertItem(0, str0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_listCtrl->SetItem(nIndex, 1, hashKey.ToString());
|
|
|
|
|
m_listCtrl->SetItem(nIndex, 2, str2);
|
|
|
|
|
m_listCtrl->SetItem(nIndex, 3, str3);
|
|
|
|
|
m_listCtrl->SetItem(nIndex, 4, str4);
|
|
|
|
|
m_listCtrl->SetItem(nIndex, 5, str5);
|
|
|
|
|
m_listCtrl->SetItem(nIndex, 6, str6);
|
|
|
|
|
m_listCtrl->SetItemData(nIndex, nData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string FormatTxStatus(const CWalletTx& wtx)
|
|
|
|
|
{
|
|
|
|
|
// Status
|
|
|
|
|
int nDepth = wtx.GetDepthInMainChain();
|
|
|
|
|
if (!wtx.IsFinal())
|
|
|
|
|
return strprintf("Open for %d blocks", nBestHeight - wtx.nLockTime);
|
|
|
|
|
else if (nDepth < 6)
|
|
|
|
|
return strprintf("%d/unconfirmed", nDepth);
|
|
|
|
|
else
|
|
|
|
|
return strprintf("%d blocks", nDepth);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string SingleLine(const string& strIn)
|
|
|
|
|
{
|
|
|
|
|
string strOut;
|
|
|
|
|
bool fOneSpace = false;
|
|
|
|
|
foreach(int c, strIn)
|
|
|
|
|
{
|
|
|
|
|
if (isspace(c))
|
|
|
|
|
{
|
|
|
|
|
fOneSpace = true;
|
|
|
|
|
}
|
|
|
|
|
else if (c > ' ')
|
|
|
|
|
{
|
|
|
|
|
if (fOneSpace && !strOut.empty())
|
|
|
|
|
strOut += ' ';
|
|
|
|
|
strOut += c;
|
|
|
|
|
fOneSpace = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return strOut;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
|
|
|
|
|
{
|
|
|
|
|
int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime();
|
|
|
|
|
int64 nCredit = wtx.GetCredit();
|
|
|
|
|
int64 nDebit = wtx.GetDebit();
|
|
|
|
|
int64 nNet = nCredit - nDebit;
|
|
|
|
|
uint256 hash = wtx.GetHash();
|
|
|
|
|
string strStatus = FormatTxStatus(wtx);
|
|
|
|
|
map<string, string> mapValue = wtx.mapValue;
|
|
|
|
|
|
|
|
|
|
// Find the block the tx is in
|
|
|
|
|
CBlockIndex* pindex = NULL;
|
|
|
|
|
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(wtx.hashBlock);
|
|
|
|
|
if (mi != mapBlockIndex.end())
|
|
|
|
|
pindex = (*mi).second;
|
|
|
|
|
|
|
|
|
|
// Sort order, unrecorded transactions sort to the top
|
|
|
|
|
string strSort = strprintf("%010d-%01d-%010u",
|
|
|
|
|
(pindex ? pindex->nHeight : INT_MAX),
|
|
|
|
|
(wtx.IsCoinBase() ? 1 : 0),
|
|
|
|
|
wtx.nTimeReceived);
|
|
|
|
|
|
|
|
|
|
// Insert line
|
|
|
|
|
if (nNet > 0 || wtx.IsCoinBase())
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// Credit
|
|
|
|
|
//
|
|
|
|
|
string strDescription;
|
|
|
|
|
|
|
|
|
|
if (wtx.IsCoinBase())
|
|
|
|
|
{
|
|
|
|
|
// Coinbase
|
|
|
|
|
strDescription = "Generated";
|
|
|
|
|
if (nCredit == 0)
|
|
|
|
|
{
|
|
|
|
|
int64 nUnmatured = 0;
|
|
|
|
|
foreach(const CTxOut& txout, wtx.vout)
|
|
|
|
|
nUnmatured += txout.GetCredit();
|
|
|
|
|
if (wtx.IsInMainChain())
|
|
|
|
|
strDescription += strprintf(" (%s matures in %d more blocks)", FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
|
|
|
|
|
else
|
|
|
|
|
strDescription += " (not accepted)";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (!mapValue["from"].empty() || !mapValue["message"].empty())
|
|
|
|
|
{
|
|
|
|
|
// Online transaction
|
|
|
|
|
if (!mapValue["from"].empty())
|
|
|
|
|
strDescription += "From: " + mapValue["from"];
|
|
|
|
|
if (!mapValue["message"].empty())
|
|
|
|
|
{
|
|
|
|
|
if (!strDescription.empty())
|
|
|
|
|
strDescription += " - ";
|
|
|
|
|
strDescription += mapValue["message"];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Offline transaction
|
|
|
|
|
foreach(const CTxOut& txout, wtx.vout)
|
|
|
|
|
{
|
|
|
|
|
if (txout.IsMine())
|
|
|
|
|
{
|
|
|
|
|
vector<unsigned char> vchPubKey;
|
|
|
|
|
if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
|
|
|
|
|
{
|
|
|
|
|
string strAddress = PubKeyToAddress(vchPubKey);
|
|
|
|
|
if (mapAddressBook.count(strAddress))
|
|
|
|
|
{
|
|
|
|
|
//strDescription += "Received payment to ";
|
|
|
|
|
//strDescription += "Received with address ";
|
|
|
|
|
strDescription += "From: unknown, To: ";
|
|
|
|
|
strDescription += strAddress;
|
|
|
|
|
/// The labeling feature is just too confusing, so I hid it
|
|
|
|
|
/// by putting it at the end where it runs off the screen.
|
|
|
|
|
/// It can still be seen by widening the column, or in the
|
|
|
|
|
/// details dialog.
|
|
|
|
|
if (!mapAddressBook[strAddress].empty())
|
|
|
|
|
strDescription += " (" + mapAddressBook[strAddress] + ")";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
InsertLine(fNew, nIndex, hash, strSort,
|
|
|
|
|
strStatus,
|
|
|
|
|
nTime ? DateTimeStr(nTime) : "",
|
|
|
|
|
SingleLine(strDescription),
|
|
|
|
|
"",
|
|
|
|
|
FormatMoney(nNet, true));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bool fAllFromMe = true;
|
|
|
|
|
foreach(const CTxIn& txin, wtx.vin)
|
|
|
|
|
fAllFromMe = fAllFromMe && txin.IsMine();
|
|
|
|
|
|
|
|
|
|
bool fAllToMe = true;
|
|
|
|
|
foreach(const CTxOut& txout, wtx.vout)
|
|
|
|
|
fAllToMe = fAllToMe && txout.IsMine();
|
|
|
|
|
|
|
|
|
|
if (fAllFromMe && fAllToMe)
|
|
|
|
|
{
|
|
|
|
|
// Payment to self
|
|
|
|
|
int64 nValue = wtx.vout[0].nValue;
|
|
|
|
|
InsertLine(fNew, nIndex, hash, strSort,
|
|
|
|
|
strStatus,
|
|
|
|
|
nTime ? DateTimeStr(nTime) : "",
|
|
|
|
|
"Payment to yourself",
|
|
|
|
|
FormatMoney(nNet - nValue, true),
|
|
|
|
|
FormatMoney(nValue, true));
|
|
|
|
|
}
|
|
|
|
|
else if (fAllFromMe)
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// Debit
|
|
|
|
|
//
|
|
|
|
|
int64 nTxFee = nDebit - wtx.GetValueOut();
|
|
|
|
|
for (int nOut = 0; nOut < wtx.vout.size(); nOut++)
|
|
|
|
|
{
|
|
|
|
|
const CTxOut& txout = wtx.vout[nOut];
|
|
|
|
|
if (txout.IsMine())
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
string strAddress;
|
|
|
|
|
if (!mapValue["to"].empty())
|
|
|
|
|
{
|
|
|
|
|
// Online transaction
|
|
|
|
|
strAddress = mapValue["to"];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Offline transaction
|
|
|
|
|
uint160 hash160;
|
|
|
|
|
if (ExtractHash160(txout.scriptPubKey, hash160))
|
|
|
|
|
strAddress = Hash160ToAddress(hash160);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string strDescription = "To: ";
|
|
|
|
|
if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
|
|
|
|
|
strDescription += mapAddressBook[strAddress] + " ";
|
|
|
|
|
strDescription += strAddress;
|
|
|
|
|
if (!mapValue["message"].empty())
|
|
|
|
|
{
|
|
|
|
|
if (!strDescription.empty())
|
|
|
|
|
strDescription += " - ";
|
|
|
|
|
strDescription += mapValue["message"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int64 nValue = txout.nValue;
|
|
|
|
|
if (nOut == 0 && nTxFee > 0)
|
|
|
|
|
nValue += nTxFee;
|
|
|
|
|
|
|
|
|
|
InsertLine(fNew, nIndex, hash, strprintf("%s-%d", strSort.c_str(), nOut),
|
|
|
|
|
strStatus,
|
|
|
|
|
nTime ? DateTimeStr(nTime) : "",
|
|
|
|
|
SingleLine(strDescription),
|
|
|
|
|
FormatMoney(-nValue, true),
|
|
|
|
|
"");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// Mixed debit transaction, can't break down payees
|
|
|
|
|
//
|
|
|
|
|
bool fAllMine = true;
|
|
|
|
|
foreach(const CTxOut& txout, wtx.vout)
|
|
|
|
|
fAllMine = fAllMine && txout.IsMine();
|
|
|
|
|
foreach(const CTxIn& txin, wtx.vin)
|
|
|
|
|
fAllMine = fAllMine && txin.IsMine();
|
|
|
|
|
|
|
|
|
|
InsertLine(fNew, nIndex, hash, strSort,
|
|
|
|
|
strStatus,
|
|
|
|
|
nTime ? DateTimeStr(nTime) : "",
|
|
|
|
|
"",
|
|
|
|
|
FormatMoney(nNet, true),
|
|
|
|
|
"");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::RefreshStatus()
|
|
|
|
|
{
|
|
|
|
|
static int nLastTop;
|
|
|
|
|
int nTop = m_listCtrl->GetTopItem();
|
|
|
|
|
if (nTop == nLastTop && pindexBestLast == pindexBest)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
TRY_CRITICAL_BLOCK(cs_mapWallet)
|
|
|
|
|
{
|
|
|
|
|
int nStart = nTop;
|
|
|
|
|
int nEnd = min(nStart + 100, m_listCtrl->GetItemCount());
|
|
|
|
|
if (pindexBestLast == pindexBest)
|
|
|
|
|
{
|
|
|
|
|
if (nStart >= nLastTop && nStart < nLastTop + 100)
|
|
|
|
|
nStart = nLastTop + 100;
|
|
|
|
|
if (nEnd >= nLastTop && nEnd < nLastTop + 100)
|
|
|
|
|
nEnd = nLastTop;
|
|
|
|
|
}
|
|
|
|
|
nLastTop = nTop;
|
|
|
|
|
pindexBestLast = pindexBest;
|
|
|
|
|
|
|
|
|
|
for (int nIndex = nStart; nIndex < nEnd; nIndex++)
|
|
|
|
|
{
|
|
|
|
|
uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1));
|
|
|
|
|
map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
|
|
|
|
|
if (mi == mapWallet.end())
|
|
|
|
|
{
|
|
|
|
|
printf("CMainFrame::RefreshStatus() : tx not found in mapWallet\n");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const CWalletTx& wtx = (*mi).second;
|
|
|
|
|
if (wtx.IsCoinBase() || wtx.GetTxTime() != wtx.nTimeDisplayed)
|
|
|
|
|
InsertTransaction(wtx, false, nIndex);
|
|
|
|
|
else
|
|
|
|
|
m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::RefreshListCtrl()
|
|
|
|
|
{
|
|
|
|
|
fRefreshListCtrl = true;
|
|
|
|
|
::wxWakeUpIdle();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnIdle(wxIdleEvent& event)
|
|
|
|
|
{
|
|
|
|
|
if (fRefreshListCtrl)
|
|
|
|
|
{
|
|
|
|
|
// Collect list of wallet transactions and sort newest first
|
|
|
|
|
bool fEntered = false;
|
|
|
|
|
vector<pair<unsigned int, uint256> > vSorted;
|
|
|
|
|
TRY_CRITICAL_BLOCK(cs_mapWallet)
|
|
|
|
|
{
|
|
|
|
|
printf("RefreshListCtrl starting\n");
|
|
|
|
|
fEntered = true;
|
|
|
|
|
fRefreshListCtrl = false;
|
|
|
|
|
vWalletUpdated.clear();
|
|
|
|
|
|
|
|
|
|
// Do the newest transactions first
|
|
|
|
|
vSorted.reserve(mapWallet.size());
|
|
|
|
|
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
const CWalletTx& wtx = (*it).second;
|
|
|
|
|
unsigned int nTime = UINT_MAX - wtx.GetTxTime();
|
|
|
|
|
vSorted.push_back(make_pair(nTime, (*it).first));
|
|
|
|
|
}
|
|
|
|
|
m_listCtrl->DeleteAllItems();
|
|
|
|
|
}
|
|
|
|
|
if (!fEntered)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
sort(vSorted.begin(), vSorted.end());
|
|
|
|
|
|
|
|
|
|
// Fill list control
|
|
|
|
|
for (int i = 0; i < vSorted.size();)
|
|
|
|
|
{
|
|
|
|
|
if (fShutdown)
|
|
|
|
|
return;
|
|
|
|
|
bool fEntered = false;
|
|
|
|
|
TRY_CRITICAL_BLOCK(cs_mapWallet)
|
|
|
|
|
{
|
|
|
|
|
fEntered = true;
|
|
|
|
|
uint256& hash = vSorted[i++].second;
|
|
|
|
|
map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
|
|
|
|
|
if (mi != mapWallet.end())
|
|
|
|
|
InsertTransaction((*mi).second, true);
|
|
|
|
|
}
|
|
|
|
|
if (!fEntered || i == 100 || i % 500 == 0)
|
|
|
|
|
wxYield();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf("RefreshListCtrl done\n");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Check for time updates
|
|
|
|
|
static int64 nLastTime;
|
|
|
|
|
if (GetTime() > nLastTime + 30)
|
|
|
|
|
{
|
|
|
|
|
TRY_CRITICAL_BLOCK(cs_mapWallet)
|
|
|
|
|
{
|
|
|
|
|
nLastTime = GetTime();
|
|
|
|
|
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
CWalletTx& wtx = (*it).second;
|
|
|
|
|
if (wtx.nTimeDisplayed && wtx.nTimeDisplayed != wtx.GetTxTime())
|
|
|
|
|
InsertTransaction(wtx, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnPaint(wxPaintEvent& event)
|
|
|
|
|
{
|
|
|
|
|
event.Skip();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
|
|
|
|
|
{
|
|
|
|
|
// Update listctrl contents
|
|
|
|
|
if (!vWalletUpdated.empty())
|
|
|
|
|
{
|
|
|
|
|
TRY_CRITICAL_BLOCK(cs_mapWallet)
|
|
|
|
|
{
|
|
|
|
|
pair<uint256, bool> item;
|
|
|
|
|
foreach(item, vWalletUpdated)
|
|
|
|
|
{
|
|
|
|
|
bool fNew = item.second;
|
|
|
|
|
map<uint256, CWalletTx>::iterator mi = mapWallet.find(item.first);
|
|
|
|
|
if (mi != mapWallet.end())
|
|
|
|
|
{
|
|
|
|
|
printf("vWalletUpdated: %s %s\n", (*mi).second.GetHash().ToString().substr(0,6).c_str(), fNew ? "new" : "");
|
|
|
|
|
InsertTransaction((*mi).second, fNew);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
m_listCtrl->ScrollList(0, INT_MAX);
|
|
|
|
|
vWalletUpdated.clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update status column of visible items only
|
|
|
|
|
RefreshStatus();
|
|
|
|
|
|
|
|
|
|
// Update status bar
|
|
|
|
|
string strGen = "";
|
|
|
|
|
if (fGenerateBitcoins)
|
|
|
|
|
strGen = " Generating";
|
|
|
|
|
if (fGenerateBitcoins && vNodes.empty())
|
|
|
|
|
strGen = "(not connected)";
|
|
|
|
|
m_statusBar->SetStatusText(strGen, 1);
|
|
|
|
|
|
|
|
|
|
string strStatus = strprintf(" %d connections %d blocks %d transactions", vNodes.size(), nBestHeight + 1, m_listCtrl->GetItemCount());
|
|
|
|
|
m_statusBar->SetStatusText(strStatus, 2);
|
|
|
|
|
|
|
|
|
|
// Balance total
|
|
|
|
|
TRY_CRITICAL_BLOCK(cs_mapWallet)
|
|
|
|
|
m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " ");
|
|
|
|
|
|
|
|
|
|
m_listCtrl->OnPaint(event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CrossThreadCall(wxCommandEvent& event)
|
|
|
|
|
{
|
|
|
|
|
if (pframeMain)
|
|
|
|
|
pframeMain->GetEventHandler()->AddPendingEvent(event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CrossThreadCall(int nID, void* pdata)
|
|
|
|
|
{
|
|
|
|
|
wxCommandEvent event;
|
|
|
|
|
event.SetInt(nID);
|
|
|
|
|
event.SetClientData(pdata);
|
|
|
|
|
if (pframeMain)
|
|
|
|
|
pframeMain->GetEventHandler()->AddPendingEvent(event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnCrossThreadCall(wxCommandEvent& event)
|
|
|
|
|
{
|
|
|
|
|
void* pdata = event.GetClientData();
|
|
|
|
|
switch (event.GetInt())
|
|
|
|
|
{
|
|
|
|
|
case UICALL_ADDORDER:
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case UICALL_UPDATEORDER:
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnMenuFileExit(wxCommandEvent& event)
|
|
|
|
|
{
|
|
|
|
|
Close(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnMenuOptionsGenerate(wxCommandEvent& event)
|
|
|
|
|
{
|
|
|
|
|
GenerateBitcoins(event.IsChecked());
|
|
|
|
|
|
|
|
|
|
Refresh();
|
|
|
|
|
wxPaintEvent eventPaint;
|
|
|
|
|
AddPendingEvent(eventPaint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnMenuOptionsChangeYourAddress(wxCommandEvent& event)
|
|
|
|
|
{
|
|
|
|
|
OnButtonChange(event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnMenuOptionsOptions(wxCommandEvent& event)
|
|
|
|
|
{
|
|
|
|
|
COptionsDialog dialog(this);
|
|
|
|
|
dialog.ShowModal();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnMenuHelpAbout(wxCommandEvent& event)
|
|
|
|
|
{
|
|
|
|
|
CAboutDialog dialog(this);
|
|
|
|
|
dialog.ShowModal();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnUpdateMenuGenerate( wxUpdateUIEvent& event ) {
|
|
|
|
|
event.Check(fGenerateBitcoins);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnButtonSend(wxCommandEvent& event)
|
|
|
|
|
{
|
|
|
|
|
/// debug test
|
|
|
|
|
if (fRandSendTest)
|
|
|
|
|
{
|
|
|
|
|
RandSend();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Toolbar: Send
|
|
|
|
|
CSendDialog dialog(this);
|
|
|
|
|
dialog.ShowModal();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnButtonAddressBook(wxCommandEvent& event)
|
|
|
|
|
{
|
|
|
|
|
// Toolbar: Address Book
|
|
|
|
|
CAddressBookDialog dialogAddr(this, "", false);
|
|
|
|
|
if (dialogAddr.ShowModal() == 2)
|
|
|
|
|
{
|
|
|
|
|
// Send
|
|
|
|
|
CSendDialog dialogSend(this, dialogAddr.GetAddress());
|
|
|
|
|
dialogSend.ShowModal();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnSetFocusAddress(wxFocusEvent& event)
|
|
|
|
|
{
|
|
|
|
|
// Automatically select-all when entering window
|
|
|
|
|
m_textCtrlAddress->SetSelection(-1, -1);
|
|
|
|
|
fOnSetFocusAddress = true;
|
|
|
|
|
event.Skip();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnMouseEventsAddress(wxMouseEvent& event)
|
|
|
|
|
{
|
|
|
|
|
if (fOnSetFocusAddress)
|
|
|
|
|
m_textCtrlAddress->SetSelection(-1, -1);
|
|
|
|
|
fOnSetFocusAddress = false;
|
|
|
|
|
event.Skip();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnButtonCopy(wxCommandEvent& event)
|
|
|
|
|
{
|
|
|
|
|
// Copy address box to clipboard
|
|
|
|
|
if (wxTheClipboard->Open())
|
|
|
|
|
{
|
|
|
|
|
wxTheClipboard->SetData(new wxTextDataObject(m_textCtrlAddress->GetValue()));
|
|
|
|
|
wxTheClipboard->Close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnButtonChange(wxCommandEvent& event)
|
|
|
|
|
{
|
|
|
|
|
CYourAddressDialog dialog(this, string(m_textCtrlAddress->GetValue()));
|
|
|
|
|
if (!dialog.ShowModal())
|
|
|
|
|
return;
|
|
|
|
|
string strAddress = (string)dialog.GetAddress();
|
|
|
|
|
if (strAddress != m_textCtrlAddress->GetValue())
|
|
|
|
|
{
|
|
|
|
|
uint160 hash160;
|
|
|
|
|
if (!AddressToHash160(strAddress, hash160))
|
|
|
|
|
return;
|
|
|
|
|
if (!mapPubKeys.count(hash160))
|
|
|
|
|
return;
|
|
|
|
|
CWalletDB().WriteDefaultKey(mapPubKeys[hash160]);
|
|
|
|
|
m_textCtrlAddress->SetValue(strAddress);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnListItemActivatedAllTransactions(wxListEvent& event)
|
|
|
|
|
{
|
|
|
|
|
uint256 hash((string)GetItemText(m_listCtrl, event.GetIndex(), 1));
|
|
|
|
|
CWalletTx wtx;
|
|
|
|
|
CRITICAL_BLOCK(cs_mapWallet)
|
|
|
|
|
{
|
|
|
|
|
map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
|
|
|
|
|
if (mi == mapWallet.end())
|
|
|
|
|
{
|
|
|
|
|
printf("CMainFrame::OnListItemActivatedAllTransactions() : tx not found in mapWallet\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
wtx = (*mi).second;
|
|
|
|
|
}
|
|
|
|
|
CTxDetailsDialog dialog(this, wtx);
|
|
|
|
|
dialog.ShowModal();
|
|
|
|
|
//CTxDetailsDialog* pdialog = new CTxDetailsDialog(this, wtx);
|
|
|
|
|
//pdialog->Show();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnListItemActivatedProductsSent(wxListEvent& event)
|
|
|
|
|
{
|
|
|
|
|
CProduct& product = *(CProduct*)event.GetItem().GetData();
|
|
|
|
|
CEditProductDialog* pdialog = new CEditProductDialog(this);
|
|
|
|
|
pdialog->SetProduct(product);
|
|
|
|
|
pdialog->Show();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnListItemActivatedOrdersSent(wxListEvent& event)
|
|
|
|
|
{
|
|
|
|
|
CWalletTx& order = *(CWalletTx*)event.GetItem().GetData();
|
|
|
|
|
CViewOrderDialog* pdialog = new CViewOrderDialog(this, order, false);
|
|
|
|
|
pdialog->Show();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainFrame::OnListItemActivatedOrdersReceived(wxListEvent& event)
|
|
|
|
|
{
|
|
|
|
|
CWalletTx& order = *(CWalletTx*)event.GetItem().GetData();
|
|
|
|
|
CViewOrderDialog* pdialog = new CViewOrderDialog(this, order, true);
|
|
|
|
|
pdialog->Show();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// CTxDetailsDialog
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetailsDialogBase(parent)
|
|
|
|
|
{
|
|
|
|
|
string strHTML;
|
|
|
|
|
strHTML.reserve(4000);
|
|
|
|
|
strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
|
|
|
|
|
|
|
|
|
|
int64 nTime = wtx.GetTxTime();
|
|
|
|
|
int64 nCredit = wtx.GetCredit();
|
|
|
|
|
int64 nDebit = wtx.GetDebit();
|
|
|
|
|
int64 nNet = nCredit - nDebit;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
strHTML += "<b>Status:</b> " + FormatTxStatus(wtx) + "<br>";
|
|
|
|
|
strHTML += "<b>Date:</b> " + (nTime ? DateTimeStr(nTime) : "") + "<br>";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// From
|
|
|
|
|
//
|
|
|
|
|
if (wtx.IsCoinBase())
|
|
|
|
|
{
|
|
|
|
|
strHTML += "<b>Source:</b> Generated<br>";
|
|
|
|
|
}
|
|
|
|
|
else if (!wtx.mapValue["from"].empty())
|
|
|
|
|
{
|
|
|
|
|
// Online transaction
|
|
|
|
|
if (!wtx.mapValue["from"].empty())
|
|
|
|
|
strHTML += "<b>From:</b> " + HtmlEscape(wtx.mapValue["from"]) + "<br>";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Offline transaction
|
|
|
|
|
if (nNet > 0)
|
|
|
|
|
{
|
|
|
|
|
// Credit
|
|
|
|
|
foreach(const CTxOut& txout, wtx.vout)
|
|
|
|
|
{
|
|
|
|
|
if (txout.IsMine())
|
|
|
|
|
{
|
|
|
|
|
vector<unsigned char> vchPubKey;
|
|
|
|
|
if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
|
|
|
|
|
{
|
|
|
|
|
string strAddress = PubKeyToAddress(vchPubKey);
|
|
|
|
|
if (mapAddressBook.count(strAddress))
|
|
|
|
|
{
|
|
|
|
|
strHTML += "<b>From:</b> unknown<br>";
|
|
|
|
|
strHTML += "<b>To:</b> ";
|
|
|
|
|
strHTML += HtmlEscape(strAddress);
|
|
|
|
|
if (!mapAddressBook[strAddress].empty())
|
|
|
|
|
strHTML += " (yours, label: " + mapAddressBook[strAddress] + ")";
|
|
|
|
|
else
|
|
|
|
|
strHTML += " (yours)";
|
|
|
|
|
strHTML += "<br>";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// To
|
|
|
|
|
//
|
|
|
|
|
string strAddress;
|
|
|
|
|
if (!wtx.mapValue["to"].empty())
|
|
|
|
|
{
|
|
|
|
|
// Online transaction
|
|
|
|
|
strAddress = wtx.mapValue["to"];
|
|
|
|
|
strHTML += "<b>To:</b> ";
|
|
|
|
|
if (mapAddressBook.count |