From dd519206a684c772a4a06ceecc87c665ad09d8be Mon Sep 17 00:00:00 2001 From: s_nakamoto Date: Thu, 29 Oct 2009 02:52:48 +0000 Subject: addr relaying fixes, proxy option and privacy patches, detect connect to self, non-final tx locktime changes, fix hide unconfirmed generated git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@18 1a98c847-1fd6-4fd8-948a-caf3550aa51b --- ui.cpp | 223 +++++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 176 insertions(+), 47 deletions(-) (limited to 'ui.cpp') diff --git a/ui.cpp b/ui.cpp index 428304796e..917c64b445 100644 --- a/ui.cpp +++ b/ui.cpp @@ -497,7 +497,7 @@ string SingleLine(const string& strIn) return strOut; } -void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) +bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) { int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime(); int64 nCredit = wtx.GetCredit(); @@ -506,14 +506,11 @@ void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) uint256 hash = wtx.GetHash(); string strStatus = FormatTxStatus(wtx); map mapValue = wtx.mapValue; + wtx.nLinesDisplayed = 1; // Filter if (wtx.IsCoinBase()) { - // View->Show Generated - if (!fShowGenerated) - return; - // Don't show generated coin until confirmed by at least one block after it // so we don't get the user's hopes up until it looks like it's probably accepted. // @@ -527,10 +524,13 @@ void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) // if (wtx.GetDepthInMainChain() < 2) { - // In case it was previously displayed - DeleteLine(hash); - return; + wtx.nLinesDisplayed = 0; + return false; } + + // View->Show Generated + if (!fShowGenerated) + return false; } // Find the block the tx is in @@ -644,6 +644,7 @@ void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) // Debit // int64 nTxFee = nDebit - wtx.GetValueOut(); + wtx.nLinesDisplayed = 0; for (int nOut = 0; nOut < wtx.vout.size(); nOut++) { const CTxOut& txout = wtx.vout[nOut]; @@ -685,6 +686,7 @@ void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) SingleLine(strDescription), FormatMoney(-nValue, true), ""); + wtx.nLinesDisplayed++; } } else @@ -706,12 +708,14 @@ void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) ""); } } + + return true; } void CMainFrame::RefreshStatus() { static int nLastTop; - int nTop = m_listCtrl->GetTopItem(); + int nTop = max((int)m_listCtrl->GetTopItem(), 0); if (nTop == nLastTop && pindexBestLast == pindexBest) return; @@ -729,7 +733,7 @@ void CMainFrame::RefreshStatus() nLastTop = nTop; pindexBestLast = pindexBest; - for (int nIndex = nStart; nIndex < nEnd; nIndex++) + for (int nIndex = nStart; nIndex < min(nEnd, m_listCtrl->GetItemCount()); nIndex++) { uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1)); map::iterator mi = mapWallet.find(hash); @@ -738,9 +742,12 @@ void CMainFrame::RefreshStatus() printf("CMainFrame::RefreshStatus() : tx not found in mapWallet\n"); continue; } - const CWalletTx& wtx = (*mi).second; + CWalletTx& wtx = (*mi).second; if (wtx.IsCoinBase() || wtx.GetTxTime() != wtx.nTimeDisplayed) - InsertTransaction(wtx, false, nIndex); + { + if (!InsertTransaction(wtx, false, nIndex)) + m_listCtrl->DeleteItem(nIndex--); + } else m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx)); } @@ -801,6 +808,9 @@ void CMainFrame::OnIdle(wxIdleEvent& event) } printf("RefreshListCtrl done\n"); + + // Update transaction total display + MainFrameRepaint(); } else { @@ -834,31 +844,54 @@ void DelayedRepaint(void* parg) return; fOneThread = true; Sleep(1000); + printf("DelayedRepaint()\n"); MainFrameRepaint(); fOneThread = false; } void CMainFrame::OnPaintListCtrl(wxPaintEvent& event) { + if (ptaskbaricon) + ptaskbaricon->UpdateTooltip(); + // Update listctrl contents if (!vWalletUpdated.empty()) { TRY_CRITICAL_BLOCK(cs_mapWallet) { + bool fInserted = false; foreach(uint256 hash, vWalletUpdated) { map::iterator mi = mapWallet.find(hash); if (mi != mapWallet.end()) - InsertTransaction((*mi).second, false); + fInserted |= InsertTransaction((*mi).second, false); } - m_listCtrl->ScrollList(0, INT_MAX); vWalletUpdated.clear(); + if (fInserted) + m_listCtrl->ScrollList(0, INT_MAX); } } // Update status column of visible items only RefreshStatus(); + // Balance total + bool fRefreshed = false; + static int nTransactionCount; + TRY_CRITICAL_BLOCK(cs_mapWallet) + { + fRefreshed = true; + m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " "); + + // Count hidden and multi-line transactions + nTransactionCount = 0; + for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { + CWalletTx& wtx = (*it).second; + nTransactionCount += wtx.nLinesDisplayed; + } + } + // Update status bar string strGen = ""; if (fGenerateBitcoins) @@ -867,17 +900,9 @@ void CMainFrame::OnPaintListCtrl(wxPaintEvent& event) strGen = "(not connected)"; m_statusBar->SetStatusText(strGen, 1); - string strStatus = strprintf(" %d connections %d blocks %d transactions", vNodes.size(), nBestHeight + 1, m_listCtrl->GetItemCount()); + string strStatus = strprintf(" %d connections %d blocks %d transactions", vNodes.size(), nBestHeight + 1, nTransactionCount); m_statusBar->SetStatusText(strStatus, 2); - // Balance total - bool fRefreshed = false; - TRY_CRITICAL_BLOCK(cs_mapWallet) - { - m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " "); - fRefreshed = true; - } - // mapWallet was locked, try again later if (!vWalletUpdated.empty() || !fRefreshed) _beginthread(DelayedRepaint, 0, NULL); @@ -1350,6 +1375,14 @@ COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent) m_checkBoxMinimizeOnClose->Enable(fMinimizeToTray); m_checkBoxMinimizeOnClose->SetValue(fMinimizeToTray && fMinimizeOnClose); fTmpMinimizeOnClose = fMinimizeOnClose; + m_checkBoxUseProxy->SetValue(fUseProxy); + m_textCtrlProxyIP->Enable(fUseProxy); + m_textCtrlProxyPort->Enable(fUseProxy); + m_staticTextProxyIP->Enable(fUseProxy); + m_staticTextProxyPort->Enable(fUseProxy); + m_textCtrlProxyIP->SetValue(addrProxy.ToStringIP()); + m_textCtrlProxyPort->SetValue(addrProxy.ToStringPort()); + m_buttonOK->SetFocus(); } @@ -1395,6 +1428,34 @@ void COptionsDialog::OnCheckBoxMinimizeToTray(wxCommandEvent& event) } +void COptionsDialog::OnCheckBoxUseProxy(wxCommandEvent& event) +{ + m_textCtrlProxyIP->Enable(event.IsChecked()); + m_textCtrlProxyPort->Enable(event.IsChecked()); + m_staticTextProxyIP->Enable(event.IsChecked()); + m_staticTextProxyPort->Enable(event.IsChecked()); +} + +CAddress COptionsDialog::GetProxyAddr() +{ + // Be careful about byte order, addr.ip and addr.port are big endian + CAddress addr(m_textCtrlProxyIP->GetValue() + ":" + m_textCtrlProxyPort->GetValue()); + if (addr.ip == INADDR_NONE) + addr.ip = addrProxy.ip; + int nPort = atoi(m_textCtrlProxyPort->GetValue()); + addr.port = htons(nPort); + if (nPort <= 0 || nPort > USHRT_MAX) + addr.port = addrProxy.port; + return addr; +} + +void COptionsDialog::OnKillFocusProxy(wxFocusEvent& event) +{ + m_textCtrlProxyIP->SetValue(GetProxyAddr().ToStringIP()); + m_textCtrlProxyPort->SetValue(GetProxyAddr().ToStringPort()); +} + + void COptionsDialog::OnButtonOK(wxCommandEvent& event) { OnButtonApply(event); @@ -1446,6 +1507,18 @@ void COptionsDialog::OnButtonApply(wxCommandEvent& event) fMinimizeOnClose = (fMinimizeToTray ? m_checkBoxMinimizeOnClose->GetValue() : fTmpMinimizeOnClose); walletdb.WriteSetting("fMinimizeOnClose", fMinimizeOnClose); } + + if (fUseProxy != m_checkBoxUseProxy->GetValue()) + { + fUseProxy = m_checkBoxUseProxy->GetValue(); + walletdb.WriteSetting("fUseProxy", fUseProxy); + } + + if (addrProxy != GetProxyAddr()) + { + addrProxy = GetProxyAddr(); + walletdb.WriteSetting("addrProxy", addrProxy); + } } @@ -1657,7 +1730,7 @@ CSendingDialog::CSendingDialog(wxWindow* parent, const CAddress& addrIn, int64 n nPrice = nPriceIn; wtx = wtxIn; start = wxDateTime::UNow(); - strStatus = ""; + memset(pszStatus, 0, sizeof(pszStatus)); fCanCancel = true; fAbort = false; fSuccess = false; @@ -1721,10 +1794,10 @@ void CSendingDialog::OnButtonCancel(wxCommandEvent& event) void CSendingDialog::OnPaint(wxPaintEvent& event) { - if (strStatus.size() > 130) - m_textCtrlStatus->SetValue(string("\n") + strStatus); + if (strlen(pszStatus) > 130) + m_textCtrlStatus->SetValue(string("\n") + pszStatus); else - m_textCtrlStatus->SetValue(string("\n\n") + strStatus); + m_textCtrlStatus->SetValue(string("\n\n") + pszStatus); m_staticTextSending->SetFocus(); if (!fCanCancel) m_buttonCancel->Enable(false); @@ -1736,7 +1809,7 @@ void CSendingDialog::OnPaint(wxPaintEvent& event) } if (fAbort && fCanCancel && IsShown()) { - strStatus = "CANCELLED"; + strcpy(pszStatus, "CANCELLED"); m_buttonOK->Enable(true); m_buttonOK->SetFocus(); m_buttonCancel->Enable(false); @@ -1777,7 +1850,8 @@ bool CSendingDialog::Status() } if (fAbort && fCanCancel) { - strStatus = "CANCELLED"; + memset(pszStatus, 0, 10); + strcpy(pszStatus, "CANCELLED"); Repaint(); fWorkDone = true; return false; @@ -1789,7 +1863,12 @@ bool CSendingDialog::Status(const string& str) { if (!Status()) return false; - strStatus = str; + + // This can be read by the UI thread at any time, + // so copy in a way that can be read cleanly at all times. + memset(pszStatus, 0, min(str.size()+1, sizeof(pszStatus))); + strlcpy(pszStatus, str.c_str(), sizeof(pszStatus)); + Repaint(); return true; } @@ -1950,8 +2029,8 @@ void CSendingDialog::OnReply3(CDataStream& vRecv) if (nRet > 0) { Error("The payment was sent, but the recipient was unable to verify it.\n" - "The transaction is recorded and will credit to the recipient if it is valid,\n" - "but without comment information."); + "The transaction is recorded and will credit to the recipient,\n" + "but the comment information will be blank."); return; } } @@ -3092,6 +3171,7 @@ END_EVENT_TABLE() void CMyTaskBarIcon::Show(bool fShow) { + static char pszPrevTip[200]; if (fShow) { string strTooltip = "Bitcoin"; @@ -3099,10 +3179,17 @@ void CMyTaskBarIcon::Show(bool fShow) strTooltip = "Bitcoin - Generating"; if (fGenerateBitcoins && vNodes.empty()) strTooltip = "Bitcoin - (not connected)"; - SetIcon(wxICON(bitcoin), strTooltip); + + // Optimization, only update when changed, using char array to be reentrant + if (strncmp(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip)-1) != 0) + { + strlcpy(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip)); + SetIcon(wxICON(bitcoin), strTooltip); + } } else { + strlcpy(pszPrevTip, "", sizeof(pszPrevTip)); RemoveIcon(); } } @@ -3301,12 +3388,12 @@ bool CMyApp::OnInit2() if (mapArgs.count("/datadir")) strSetDataDir = mapArgs["/datadir"]; - if (mapArgs.count("/proxy")) - addrProxy = CAddress(mapArgs["/proxy"].c_str()); - if (mapArgs.count("/debug")) fDebug = true; + if (mapArgs.count("/printtodebugger")) + fPrintToDebugger = true; + if (mapArgs.count("/dropmessages")) { nDropMessagesTest = atoi(mapArgs["/dropmessages"]); @@ -3380,6 +3467,20 @@ bool CMyApp::OnInit2() return false; } + if (mapArgs.count("/proxy")) + { + fUseProxy = true; + addrProxy = CAddress(mapArgs["/proxy"].c_str()); + if (addrProxy.ip == INADDR_NONE) + { + wxMessageBox("Invalid /proxy address", "Bitcoin"); + OnExit(); + } + CWalletDB walletdb; + walletdb.WriteSetting("fUseProxy", fUseProxy); + walletdb.WriteSetting("addrProxy", addrProxy); + } + if (mapArgs.count("/gen")) { if (mapArgs["/gen"].empty()) @@ -3404,7 +3505,7 @@ bool CMyApp::OnInit2() return false; } - //RandAddSeedPerfmon(); + RandAddSeedPerfmon(); if (!StartNode(strErrors)) wxMessageBox(strErrors, "Bitcoin"); @@ -3514,7 +3615,7 @@ void CMyApp::OnFatalException() void MainFrameRepaint() { - // This is called by network code that shouldn't access pframeMain and ptaskbaricon + // This is called by network code that shouldn't access pframeMain // directly because it could still be running after the UI is closed. if (pframeMain) { @@ -3523,20 +3624,47 @@ void MainFrameRepaint() pframeMain->Refresh(); pframeMain->AddPendingEvent(event); } - if (ptaskbaricon) - ptaskbaricon->UpdateTooltip(); } +typedef WINSHELLAPI BOOL WINAPI (*PSHGETSPECIALFOLDERPATHA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate); + +string MyGetSpecialFolderPath(int nFolder, bool fCreate) +{ + char pszPath[MAX_PATH+100] = ""; + + // SHGetSpecialFolderPath is not usually available on NT 4.0 + HMODULE hShell32 = LoadLibrary("shell32.dll"); + if (hShell32) + { + PSHGETSPECIALFOLDERPATHA pSHGetSpecialFolderPath = + (PSHGETSPECIALFOLDERPATHA)GetProcAddress(hShell32, "SHGetSpecialFolderPathA"); + if (pSHGetSpecialFolderPath) + (*pSHGetSpecialFolderPath)(NULL, pszPath, nFolder, fCreate); + FreeModule(hShell32); + } + + // Backup option + if (pszPath[0] == '\0') + { + if (nFolder == CSIDL_STARTUP) + { + strcpy(pszPath, getenv("USERPROFILE")); + strcat(pszPath, "\\Start Menu\\Programs\\Startup"); + } + else if (nFolder == CSIDL_APPDATA) + { + strcpy(pszPath, getenv("APPDATA")); + } + } + + return pszPath; +} + string StartupShortcutPath() { - // Get the startup folder shortcut path - char pszLinkPath[MAX_PATH+100]; - pszLinkPath[0] = '\0'; - SHGetSpecialFolderPath(0, pszLinkPath, CSIDL_STARTUP, 0); - strcat(pszLinkPath, "\\Bitcoin.lnk"); - return pszLinkPath; + return MyGetSpecialFolderPath(CSIDL_STARTUP, true) + "\\Bitcoin.lnk"; } bool GetStartOnSystemStartup() @@ -3630,7 +3758,8 @@ void ThreadRandSendTest(void* parg) if (GetBalance() < nValue) { wxMessageBox("Out of money "); - return; + while (GetBalance() < 1000) + Sleep(1000); } nValue += (nRep % 100) * CENT; -- cgit v1.2.3