Straw-man for dev process
[novacoin.git] / ui.cpp
diff --git a/ui.cpp b/ui.cpp
index c184fc4..1cb922f 100644 (file)
--- a/ui.cpp
+++ b/ui.cpp
@@ -14,6 +14,7 @@ DEFINE_EVENT_TYPE(wxEVT_UITHREADCALL)
 CMainFrame* pframeMain = NULL;
 CMyTaskBarIcon* ptaskbaricon = NULL;
 bool fClosedToTray = false;
+wxLocale g_locale;
 
 
 
@@ -102,6 +103,18 @@ int InsertLine(wxListCtrl* listCtrl, void* pdata, const wxString& str0, const wx
     return nIndex;
 }
 
+void SetItemTextColour(wxListCtrl* listCtrl, int nIndex, const wxColour& colour)
+{
+    // Repaint on Windows is more flickery if the colour has ever been set,
+    // so don't want to set it unless it's different.  Default colour has
+    // alpha 0 transparent, so our colours don't match using operator==.
+    wxColour c1 = listCtrl->GetItemTextColour(nIndex);
+    if (!c1.IsOk())
+        c1 = wxColour(0,0,0);
+    if (colour.Red() != c1.Red() || colour.Green() != c1.Green() || colour.Blue() != c1.Blue())
+        listCtrl->SetItemTextColour(nIndex, colour);
+}
+
 void SetSelection(wxListCtrl* listCtrl, int nIndex)
 {
     int nSize = listCtrl->GetItemCount();
@@ -183,7 +196,7 @@ int ThreadSafeMessageBox(const string& message, const string& caption, int style
 
 bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* parent)
 {
-    if (nFeeRequired == 0 || fDaemon)
+    if (nFeeRequired < CENT || nFeeRequired <= nTransactionFee || fDaemon)
         return true;
     string strMessage = strprintf(
         _("This transaction is over the size limit.  You can still send it for a fee of %s, "
@@ -195,6 +208,8 @@ bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* pa
 
 void CalledSetStatusBar(const string& strText, int nField)
 {
+    if (nField == 0 && GetWarnings("statusbar") != "")
+        return;
     if (pframeMain && pframeMain->m_statusBar)
         pframeMain->m_statusBar->SetStatusText(strText, nField);
 }
@@ -263,7 +278,7 @@ CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent)
     m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + "  ");
     m_listCtrl->SetFocus();
     ptaskbaricon = new CMyTaskBarIcon();
-#ifdef __WXMAC__
+#ifdef __WXMAC_OSX__
     // Mac automatically moves wxID_EXIT, wxID_PREFERENCES and wxID_ABOUT
     // to their standard places, leaving these menus empty.
     GetMenuBar()->Remove(2); // remove Help menu
@@ -274,7 +289,7 @@ CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent)
     int nDateWidth = DateTimeStr(1229413914).size() * 6 + 8;
     if (!strstr(DateTimeStr(1229413914).c_str(), "2008"))
         nDateWidth += 12;
-#ifdef __WXMAC__
+#ifdef __WXMAC_OSX__
     nDateWidth += 5;
     dResize -= 0.01;
 #endif
@@ -375,8 +390,8 @@ void CMainFrame::OnIconize(wxIconizeEvent& event)
     // to get rid of the deprecated warning.  Just ignore it.
     if (!event.Iconized())
         fClosedToTray = false;
-#ifdef __WXGTK__
-    if (mapArgs.count("-minimizetotray")) {
+#if defined(__WXGTK__) || defined(__WXMAC_OSX__)
+    if (GetBoolArg("-minimizetotray")) {
 #endif
     // The tray icon sometimes disappears on ubuntu karmic
     // Hiding the taskbar button doesn't work cleanly on ubuntu lucid
@@ -385,7 +400,7 @@ void CMainFrame::OnIconize(wxIconizeEvent& event)
         fClosedToTray = true;
     Show(!fClosedToTray);
     ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
-#ifdef __WXGTK__
+#if defined(__WXGTK__) || defined(__WXMAC_OSX__)
     }
 #endif
 }
@@ -431,7 +446,7 @@ int CMainFrame::GetSortIndex(const string& strSort)
 #endif
 }
 
-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)
+void CMainFrame::InsertLine(bool fNew, int nIndex, uint256 hashKey, string strSort, const wxColour& colour, const wxString& str2, const wxString& str3, const wxString& str4, const wxString& str5, const wxString& str6)
 {
     strSort = " " + strSort;       // leading space to workaround wx2.9.0 ubuntu 9.10 bug
     long nData = *(long*)&hashKey; //  where first char of hidden column is displayed
@@ -467,6 +482,7 @@ void CMainFrame::InsertLine(bool fNew, int nIndex, uint256 hashKey, string strSo
     m_listCtrl->SetItem(nIndex, 5, str5);
     m_listCtrl->SetItem(nIndex, 6, str6);
     m_listCtrl->SetItemData(nIndex, nData);
+    SetItemTextColour(m_listCtrl, nIndex, colour);
 }
 
 bool CMainFrame::DeleteLine(uint256 hashKey)
@@ -512,7 +528,7 @@ string SingleLine(const string& strIn)
 {
     string strOut;
     bool fOneSpace = false;
-    foreach(int c, strIn)
+    foreach(unsigned char c, strIn)
     {
         if (isspace(c))
         {
@@ -537,6 +553,8 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
     int64 nNet = nCredit - nDebit;
     uint256 hash = wtx.GetHash();
     string strStatus = FormatTxStatus(wtx);
+    bool fConfirmed = wtx.fConfirmedDisplayed = wtx.IsConfirmed();
+    wxColour colour = (fConfirmed ? wxColour(0,0,0) : wxColour(128,128,128));
     map<string, string> mapValue = wtx.mapValue;
     wtx.nLinesDisplayed = 1;
     nListViewUpdated++;
@@ -637,7 +655,7 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
                         {
                             //strDescription += _("Received payment to ");
                             //strDescription += _("Received with address ");
-                            strDescription += _("From: unknown, Received with: ");
+                            strDescription += _("Received with: ");
                             string strAddress = PubKeyToAddress(vchPubKey);
                             map<string, string>::iterator mi = mapAddressBook.find(strAddress);
                             if (mi != mapAddressBook.end() && !(*mi).second.empty())
@@ -655,12 +673,16 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
             }
         }
 
-        InsertLine(fNew, nIndex, hash, strSort,
+        string strCredit = FormatMoney(nNet, true);
+        if (!fConfirmed)
+            strCredit = "[" + strCredit + "]";
+
+        InsertLine(fNew, nIndex, hash, strSort, colour,
                    strStatus,
                    nTime ? DateTimeStr(nTime) : "",
                    SingleLine(strDescription),
                    "",
-                   FormatMoney(nNet, true));
+                   strCredit);
     }
     else
     {
@@ -675,16 +697,13 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
         if (fAllFromMe && fAllToMe)
         {
             // Payment to self
-            int64 nValue = wtx.vout[0].nValue;
-            InsertLine(fNew, nIndex, hash, strSort,
+            int64 nChange = wtx.GetChange();
+            InsertLine(fNew, nIndex, hash, strSort, colour,
                        strStatus,
                        nTime ? DateTimeStr(nTime) : "",
                        _("Payment to yourself"),
-                       "",
-                       "");
-            /// issue: can't tell which is the payment and which is the change anymore
-            //           FormatMoney(nNet - nValue, true),
-            //           FormatMoney(nValue, true));
+                       FormatMoney(-(nDebit - nChange), true),
+                       FormatMoney(nCredit - nChange, true));
         }
         else if (fAllFromMe)
         {
@@ -727,6 +746,12 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
                         strDescription += " - ";
                     strDescription += mapValue["message"];
                 }
+                else if (!mapValue["comment"].empty())
+                {
+                    if (!strDescription.empty())
+                        strDescription += " - ";
+                    strDescription += mapValue["comment"];
+                }
 
                 int64 nValue = txout.nValue;
                 if (nTxFee > 0)
@@ -735,12 +760,13 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
                     nTxFee = 0;
                 }
 
-                InsertLine(fNew, nIndex, hash, strprintf("%s-%d", strSort.c_str(), nOut),
+                InsertLine(fNew, nIndex, hash, strprintf("%s-%d", strSort.c_str(), nOut), colour,
                            strStatus,
                            nTime ? DateTimeStr(nTime) : "",
                            SingleLine(strDescription),
                            FormatMoney(-nValue, true),
                            "");
+                nIndex = -1;
                 wtx.nLinesDisplayed++;
             }
         }
@@ -755,7 +781,7 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
             foreach(const CTxIn& txin, wtx.vin)
                 fAllMine = fAllMine && txin.IsMine();
 
-            InsertLine(fNew, nIndex, hash, strSort,
+            InsertLine(fNew, nIndex, hash, strSort, colour,
                        strStatus,
                        nTime ? DateTimeStr(nTime) : "",
                        "",
@@ -882,13 +908,17 @@ void CMainFrame::RefreshStatusColumn()
                 continue;
             }
             CWalletTx& wtx = (*mi).second;
-            if (wtx.IsCoinBase() || wtx.GetTxTime() != wtx.nTimeDisplayed)
+            if (wtx.IsCoinBase() ||
+                wtx.GetTxTime() != wtx.nTimeDisplayed ||
+                wtx.IsConfirmed() != wtx.fConfirmedDisplayed)
             {
                 if (!InsertTransaction(wtx, false, nIndex))
                     m_listCtrl->DeleteItem(nIndex--);
             }
             else
+            {
                 m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx));
+            }
         }
     }
 }
@@ -1010,6 +1040,14 @@ void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
     RefreshStatusColumn();
 
     // Update status bar
+    static string strPrevWarning;
+    string strWarning = GetWarnings("statusbar");
+    if (strWarning != "")
+        m_statusBar->SetStatusText(string("    ") + _(strWarning), 0);
+    else if (strPrevWarning != "")
+        m_statusBar->SetStatusText("", 0);
+    strPrevWarning = strWarning;
+
     string strGen = "";
     if (fGenerateBitcoins)
         strGen = _("    Generating");
@@ -1017,12 +1055,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, nTransactionCount);
+    string strStatus = strprintf(_("     %d connections     %d blocks     %d transactions"), vNodes.size(), nBestHeight, nTransactionCount);
     m_statusBar->SetStatusText(strStatus, 2);
 
-    if (fDebug && GetTime() - nThreadSocketHandlerHeartbeat > 60)
-        m_statusBar->SetStatusText("     ERROR: ThreadSocketHandler has stopped", 0);
-
     // Update receiving address
     string strDefaultAddress = PubKeyToAddress(vchDefaultKey);
     if (m_textCtrlAddress->GetValue() != strDefaultAddress)
@@ -1139,7 +1174,7 @@ void CMainFrame::OnButtonNew(wxCommandEvent& event)
     string strName = dialog.GetValue();
 
     // Generate new key
-    string strAddress = PubKeyToAddress(GenerateNewKey());
+    string strAddress = PubKeyToAddress(GetKeyFromKeyPool());
 
     // Save
     SetAddressBookName(strAddress, strName);
@@ -1344,10 +1379,10 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails
                 if (fAllToMe)
                 {
                     // Payment to self
-                    /// issue: can't tell which is the payment and which is the change anymore
-                    //int64 nValue = wtx.vout[0].nValue;
-                    //strHTML += _("<b>Debit:</b> ") + FormatMoney(-nValue) + "<br>";
-                    //strHTML += _("<b>Credit:</b> ") + FormatMoney(nValue) + "<br>";
+                    int64 nChange = wtx.GetChange();
+                    int64 nValue = nCredit - nChange;
+                    strHTML += _("<b>Debit:</b> ") + FormatMoney(-nValue) + "<br>";
+                    strHTML += _("<b>Credit:</b> ") + FormatMoney(nValue) + "<br>";
                 }
 
                 int64 nTxFee = nDebit - wtx.GetValueOut();
@@ -1376,6 +1411,8 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails
         //
         if (!wtx.mapValue["message"].empty())
             strHTML += string() + "<br><b>" + _("Message:") + "</b><br>" + HtmlEscape(wtx.mapValue["message"], true) + "<br>";
+        if (!wtx.mapValue["comment"].empty())
+            strHTML += string() + "<br><b>" + _("Comment:") + "</b><br>" + HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
 
         if (wtx.IsCoinBase())
             strHTML += string() + "<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>";
@@ -1394,7 +1431,10 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails
                 if (txout.IsMine())
                     strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";
 
-            strHTML += "<b>Inputs:</b><br>";
+            strHTML += "<br><b>Transaction:</b><br>";
+            strHTML += HtmlEscape(wtx.ToString(), true);
+
+            strHTML += "<br><b>Inputs:</b><br>";
             CRITICAL_BLOCK(cs_mapWallet)
             {
                 foreach(const CTxIn& txin, wtx.vin)
@@ -1413,9 +1453,6 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails
                     }
                 }
             }
-
-            strHTML += "<br><hr><br><b>Transaction:</b><br>";
-            strHTML += HtmlEscape(wtx.ToString(), true);
         }
 
 
@@ -1437,6 +1474,156 @@ void CTxDetailsDialog::OnButtonOK(wxCommandEvent& event)
 
 
 
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Startup folder
+//
+
+#ifdef __WXMSW__
+string StartupShortcutPath()
+{
+    return MyGetSpecialFolderPath(CSIDL_STARTUP, true) + "\\Bitcoin.lnk";
+}
+
+bool GetStartOnSystemStartup()
+{
+    return filesystem::exists(StartupShortcutPath().c_str());
+}
+
+void SetStartOnSystemStartup(bool fAutoStart)
+{
+    // If the shortcut exists already, remove it for updating
+    remove(StartupShortcutPath().c_str());
+
+    if (fAutoStart)
+    {
+        CoInitialize(NULL);
+
+        // Get a pointer to the IShellLink interface.
+        IShellLink* psl = NULL;
+        HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
+                                CLSCTX_INPROC_SERVER, IID_IShellLink,
+                                reinterpret_cast<void**>(&psl));
+
+        if (SUCCEEDED(hres))
+        {
+            // Get the current executable path
+            TCHAR pszExePath[MAX_PATH];
+            GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));
+
+            // Set the path to the shortcut target
+            psl->SetPath(pszExePath);
+            PathRemoveFileSpec(pszExePath);
+            psl->SetWorkingDirectory(pszExePath);
+            psl->SetShowCmd(SW_SHOWMINNOACTIVE);
+
+            // Query IShellLink for the IPersistFile interface for
+            // saving the shortcut in persistent storage.
+            IPersistFile* ppf = NULL;
+            hres = psl->QueryInterface(IID_IPersistFile,
+                                       reinterpret_cast<void**>(&ppf));
+            if (SUCCEEDED(hres))
+            {
+                WCHAR pwsz[MAX_PATH];
+                // Ensure that the string is ANSI.
+                MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().c_str(), -1, pwsz, MAX_PATH);
+                // Save the link by calling IPersistFile::Save.
+                hres = ppf->Save(pwsz, TRUE);
+                ppf->Release();
+            }
+            psl->Release();
+        }
+        CoUninitialize();
+    }
+}
+
+#elif defined(__WXGTK__)
+
+// Follow the Desktop Application Autostart Spec:
+//  http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
+
+boost::filesystem::path GetAutostartDir()
+{
+    namespace fs = boost::filesystem;
+
+    char* pszConfigHome = getenv("XDG_CONFIG_HOME");
+    if (pszConfigHome) return fs::path(pszConfigHome) / fs::path("autostart");
+    char* pszHome = getenv("HOME");
+    if (pszHome) return fs::path(pszHome) / fs::path(".config/autostart");
+    return fs::path();
+}
+
+boost::filesystem::path GetAutostartFilePath()
+{
+    return GetAutostartDir() / boost::filesystem::path("bitcoin.desktop");
+}
+
+bool GetStartOnSystemStartup()
+{
+    boost::filesystem::ifstream optionFile(GetAutostartFilePath());
+    if (!optionFile.good())
+        return false;
+    // Scan through file for "Hidden=true":
+    string line;
+    while (!optionFile.eof())
+    {
+        getline(optionFile, line);
+        if (line.find("Hidden") != string::npos &&
+            line.find("true") != string::npos)
+            return false;
+    }
+    optionFile.close();
+
+    return true;
+}
+
+void SetStartOnSystemStartup(bool fAutoStart)
+{
+    if (!fAutoStart)
+    {
+        unlink(GetAutostartFilePath().native_file_string().c_str());
+    }
+    else
+    {
+        char pszExePath[MAX_PATH+1];
+        memset(pszExePath, 0, sizeof(pszExePath));
+        if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1)
+            return;
+
+        boost::filesystem::create_directories(GetAutostartDir());
+
+        boost::filesystem::ofstream optionFile(GetAutostartFilePath(), ios_base::out|ios_base::trunc);
+        if (!optionFile.good())
+        {
+            wxMessageBox(_("Cannot write autostart/bitcoin.desktop file"), "Bitcoin");
+            return;
+        }
+        // Write a bitcoin.desktop file to the autostart directory:
+        optionFile << "[Desktop Entry]\n";
+        optionFile << "Type=Application\n";
+        optionFile << "Name=Bitcoin\n";
+        optionFile << "Exec=" << pszExePath << "\n";
+        optionFile << "Terminal=false\n";
+        optionFile << "Hidden=false\n";
+        optionFile.close();
+    }
+}
+#else
+
+// TODO: OSX startup stuff; see:
+// http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html
+
+bool GetStartOnSystemStartup() { return false; }
+void SetStartOnSystemStartup(bool fAutoStart) { }
+
+#endif
+
+
+
+
+
+
 //////////////////////////////////////////////////////////////////////////////
 //
 // COptionsDialog
@@ -1449,9 +1636,12 @@ COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent)
     //m_listBox->Append(_("Test 2"));
     m_listBox->SetSelection(0);
     SelectPage(0);
-#ifdef __WXGTK__
+#ifndef __WXMSW__
+    SetSize(1.0 * GetSize().GetWidth(), 1.2 * GetSize().GetHeight());
+#endif
+#if defined(__WXGTK__) || defined(__WXMAC_OSX__)
     m_checkBoxStartOnSystemStartup->SetLabel(_("&Start Bitcoin on window system startup"));
-    if (!mapArgs.count("-minimizetotray"))
+    if (!GetBoolArg("-minimizetotray"))
     {
         // Minimize to tray is just too buggy on Linux
         fMinimizeToTray = false;
@@ -1606,6 +1796,7 @@ void COptionsDialog::OnButtonApply(wxCommandEvent& event)
 
 
 
+
 //////////////////////////////////////////////////////////////////////////////
 //
 // CAboutDialog
@@ -1613,7 +1804,7 @@ void COptionsDialog::OnButtonApply(wxCommandEvent& event)
 
 CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent)
 {
-    m_staticTextVersion->SetLabel(strprintf(_("version %d.%d.%d beta"), VERSION/10000, (VERSION/100)%100, VERSION%100));
+    m_staticTextVersion->SetLabel(strprintf(_("version %s%s BETA"), FormatVersion(VERSION).c_str(), pszSubVer));
 
     // Change (c) into UTF-8 or ANSI copyright symbol
     wxString str = m_staticTextMain->GetLabel();
@@ -1699,7 +1890,7 @@ void CSendDialog::OnTextAddress(wxCommandEvent& event)
     {
         strFromSave    = m_textCtrlFrom->GetValue();
         strMessageSave = m_textCtrlMessage->GetValue();
-        m_textCtrlFrom->SetValue(_("Will appear as \"From: Unknown\""));
+        m_textCtrlFrom->SetValue(_("n/a"));
         m_textCtrlMessage->SetValue(_("Can't include a message when sending to a Bitcoin address"));
     }
     else if (fEnable && !fEnabledPrev)
@@ -1746,69 +1937,78 @@ void CSendDialog::OnButtonPaste(wxCommandEvent& event)
 
 void CSendDialog::OnButtonSend(wxCommandEvent& event)
 {
-    CWalletTx wtx;
-    string strAddress = (string)m_textCtrlAddress->GetValue();
-
-    // Parse amount
-    int64 nValue = 0;
-    if (!ParseMoney(m_textCtrlAmount->GetValue(), nValue) || nValue <= 0)
-    {
-        wxMessageBox(_("Error in amount  "), _("Send Coins"));
-        return;
-    }
-    if (nValue > GetBalance())
+    static CCriticalSection cs_sendlock;
+    TRY_CRITICAL_BLOCK(cs_sendlock)
     {
-        wxMessageBox(_("Amount exceeds your balance  "), _("Send Coins"));
-        return;
-    }
-    if (nValue + nTransactionFee > GetBalance())
-    {
-        wxMessageBox(string(_("Total exceeds your balance when the ")) + FormatMoney(nTransactionFee) + _(" transaction fee is included  "), _("Send Coins"));
-        return;
-    }
+        CWalletTx wtx;
+        string strAddress = (string)m_textCtrlAddress->GetValue();
 
-    // Parse bitcoin address
-    uint160 hash160;
-    bool fBitcoinAddress = AddressToHash160(strAddress, hash160);
+        // Parse amount
+        int64 nValue = 0;
+        if (!ParseMoney(m_textCtrlAmount->GetValue(), nValue) || nValue <= 0)
+        {
+            wxMessageBox(_("Error in amount  "), _("Send Coins"));
+            return;
+        }
+        if (nValue > GetBalance())
+        {
+            wxMessageBox(_("Amount exceeds your balance  "), _("Send Coins"));
+            return;
+        }
+        if (nValue + nTransactionFee > GetBalance())
+        {
+            wxMessageBox(string(_("Total exceeds your balance when the ")) + FormatMoney(nTransactionFee) + _(" transaction fee is included  "), _("Send Coins"));
+            return;
+        }
 
-    if (fBitcoinAddress)
-    {
-        // Send to bitcoin address
-        CScript scriptPubKey;
-        scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
+        // Parse bitcoin address
+        uint160 hash160;
+        bool fBitcoinAddress = AddressToHash160(strAddress, hash160);
 
-        string strError = SendMoney(scriptPubKey, nValue, wtx, true);
-        if (strError == "")
-            wxMessageBox(_("Payment sent  "), _("Sending..."));
-        else if (strError != "ABORTED")
-            wxMessageBox(strError + "  ", _("Sending..."));
-    }
-    else
-    {
-        // Parse IP address
-        CAddress addr(strAddress);
-        if (!addr.IsValid())
+        if (fBitcoinAddress)
         {
-            wxMessageBox(_("Invalid address  "), _("Send Coins"));
-            return;
+            // Send to bitcoin address
+            CScript scriptPubKey;
+            scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
+
+            string strError = SendMoney(scriptPubKey, nValue, wtx, true);
+            if (strError == "")
+                wxMessageBox(_("Payment sent  "), _("Sending..."));
+            else if (strError == "ABORTED")
+                return; // leave send dialog open
+            else
+            {
+                wxMessageBox(strError + "  ", _("Sending..."));
+                EndModal(false);
+            }
         }
+        else
+        {
+            // Parse IP address
+            CAddress addr(strAddress);
+            if (!addr.IsValid())
+            {
+                wxMessageBox(_("Invalid address  "), _("Send Coins"));
+                return;
+            }
 
-        // Message
-        wtx.mapValue["to"] = strAddress;
-        wtx.mapValue["from"] = m_textCtrlFrom->GetValue();
-        wtx.mapValue["message"] = m_textCtrlMessage->GetValue();
+            // Message
+            wtx.mapValue["to"] = strAddress;
+            wtx.mapValue["from"] = m_textCtrlFrom->GetValue();
+            wtx.mapValue["message"] = m_textCtrlMessage->GetValue();
 
-        // Send to IP address
-        CSendingDialog* pdialog = new CSendingDialog(this, addr, nValue, wtx);
-        if (!pdialog->ShowModal())
-            return;
-    }
+            // Send to IP address
+            CSendingDialog* pdialog = new CSendingDialog(this, addr, nValue, wtx);
+            if (!pdialog->ShowModal())
+                return;
+        }
 
-    CRITICAL_BLOCK(cs_mapAddressBook)
-        if (!mapAddressBook.count(strAddress))
-            SetAddressBookName(strAddress, "");
+        CRITICAL_BLOCK(cs_mapAddressBook)
+            if (!mapAddressBook.count(strAddress))
+                SetAddressBookName(strAddress, "");
 
-    EndModal(true);
+        EndModal(true);
+    }
 }
 
 void CSendDialog::OnButtonCancel(wxCommandEvent& event)
@@ -2027,8 +2227,12 @@ void CSendingDialog::OnReply2(CDataStream& vRecv)
         if (nRet > 0)
         {
             string strMessage;
-            vRecv >> strMessage;
-            Error(_("Transfer was not accepted"));
+            if (!vRecv.empty())
+                vRecv >> strMessage;
+            if (nRet == 2)
+                Error(_("Recipient is not accepting transactions sent by IP address"));
+            else
+                Error(_("Transfer was not accepted"));
             //// todo: enlarge the window and enable a hidden white box to put seller's message
             return;
         }
@@ -2059,9 +2263,9 @@ void CSendingDialog::OnReply2(CDataStream& vRecv)
             Error(_("Insufficient funds"));
             return;
         }
-        CKey key;
+        CReserveKey reservekey;
         int64 nFeeRequired;
-        if (!CreateTransaction(scriptPubKey, nPrice, wtx, key, nFeeRequired))
+        if (!CreateTransaction(scriptPubKey, nPrice, wtx, reservekey, nFeeRequired))
         {
             if (nPrice + nFeeRequired > GetBalance())
                 Error(strprintf(_("This is an oversized transaction that requires a transaction fee of %s"), FormatMoney(nFeeRequired).c_str()));
@@ -2101,7 +2305,7 @@ void CSendingDialog::OnReply2(CDataStream& vRecv)
             return;
 
         // Commit
-        if (!CommitTransaction(wtx, key))
+        if (!CommitTransaction(wtx, reservekey))
         {
             Error(_("The transaction was rejected.  This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."));
             return;
@@ -2379,7 +2583,7 @@ void CAddressBookDialog::OnButtonNew(wxCommandEvent& event)
         strName = dialog.GetValue();
 
         // Generate new key
-        strAddress = PubKeyToAddress(GenerateNewKey());
+        strAddress = PubKeyToAddress(GetKeyFromKeyPool());
     }
 
     // Add to list and select it
@@ -2537,20 +2741,18 @@ wxMenu* CMyTaskBarIcon::CreatePopupMenu()
 
 
 
-
-
-
-
-
-
+//////////////////////////////////////////////////////////////////////////////
+//
+// CMyApp
+//
 
 void CreateMainWindow()
 {
     pframeMain = new CMainFrame(NULL);
-    if (mapArgs.count("-min"))
+    if (GetBoolArg("-min"))
         pframeMain->Iconize(true);
-#ifdef __WXGTK__
-    if (!mapArgs.count("-minimizetotray"))
+#if defined(__WXGTK__) || defined(__WXMAC_OSX__)
+    if (!GetBoolArg("-minimizetotray"))
         fMinimizeToTray = false;
 #endif
     pframeMain->Show(true);  // have to show first to get taskbar button to hide
@@ -2560,3 +2762,189 @@ void CreateMainWindow()
     ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
     CreateThread(ThreadDelayedRepaint, NULL);
 }
+
+
+// Define a new application
+class CMyApp : public wxApp
+{
+public:
+    CMyApp(){};
+    ~CMyApp(){};
+    bool OnInit();
+    bool OnInit2();
+    int OnExit();
+
+    // Hook Initialize so we can start without GUI
+    virtual bool Initialize(int& argc, wxChar** argv);
+
+    // 2nd-level exception handling: we get all the exceptions occurring in any
+    // event handler here
+    virtual bool OnExceptionInMainLoop();
+
+    // 3rd, and final, level exception handling: whenever an unhandled
+    // exception is caught, this function is called
+    virtual void OnUnhandledException();
+
+    // and now for something different: this function is called in case of a
+    // crash (e.g. dereferencing null pointer, division by 0, ...)
+    virtual void OnFatalException();
+};
+
+IMPLEMENT_APP(CMyApp)
+
+bool CMyApp::Initialize(int& argc, wxChar** argv)
+{
+    for (int i = 1; i < argc; i++)
+        if (!IsSwitchChar(argv[i][0]))
+            fCommandLine = true;
+
+    if (!fCommandLine)
+    {
+        // wxApp::Initialize will remove environment-specific parameters,
+        // so it's too early to call ParseParameters yet
+        for (int i = 1; i < argc; i++)
+        {
+            wxString str = argv[i];
+            #ifdef __WXMSW__
+            if (str.size() >= 1 && str[0] == '/')
+                str[0] = '-';
+            char pszLower[MAX_PATH];
+            strlcpy(pszLower, str.c_str(), sizeof(pszLower));
+            strlwr(pszLower);
+            str = pszLower;
+            #endif
+            if (str == "-daemon")
+                fDaemon = true;
+        }
+    }
+
+#ifdef __WXGTK__
+    if (fDaemon || fCommandLine)
+    {
+        // Call the original Initialize while suppressing error messages
+        // and ignoring failure.  If unable to initialize GTK, it fails
+        // near the end so hopefully the last few things don't matter.
+        {
+            wxLogNull logNo;
+            wxApp::Initialize(argc, argv);
+        }
+
+        if (fDaemon)
+        {
+            // Daemonize
+            pid_t pid = fork();
+            if (pid < 0)
+            {
+                fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
+                return false;
+            }
+            if (pid > 0)
+                pthread_exit((void*)0);
+        }
+
+        return true;
+    }
+#endif
+
+    return wxApp::Initialize(argc, argv);
+}
+
+bool CMyApp::OnInit()
+{
+#if defined(__WXMSW__) && defined(__WXDEBUG__) && defined(GUI)
+    // Disable malfunctioning wxWidgets debug assertion
+    extern int g_isPainting;
+    g_isPainting = 10000;
+#endif
+#ifdef GUI
+    wxImage::AddHandler(new wxPNGHandler);
+#endif
+#if defined(__WXMSW__ ) || defined(__WXMAC_OSX__)
+    SetAppName("Bitcoin");
+#else
+    SetAppName("bitcoin");
+#endif
+#ifdef __WXMSW__
+#if wxUSE_UNICODE
+    // Hack to set wxConvLibc codepage to UTF-8 on Windows,
+    // may break if wxMBConv_win32 implementation in strconv.cpp changes.
+    class wxMBConv_win32 : public wxMBConv
+    {
+    public:
+        long m_CodePage;
+        size_t m_minMBCharWidth;
+    };
+    if (((wxMBConv_win32*)&wxConvLibc)->m_CodePage == CP_ACP)
+        ((wxMBConv_win32*)&wxConvLibc)->m_CodePage = CP_UTF8;
+#endif
+#endif
+
+    // Load locale/<lang>/LC_MESSAGES/bitcoin.mo language file
+    g_locale.Init(wxLANGUAGE_DEFAULT, 0);
+    g_locale.AddCatalogLookupPathPrefix("locale");
+#ifndef __WXMSW__
+    g_locale.AddCatalogLookupPathPrefix("/usr/share/locale");
+    g_locale.AddCatalogLookupPathPrefix("/usr/local/share/locale");
+#endif
+    g_locale.AddCatalog("wxstd"); // wxWidgets standard translations, if any
+    g_locale.AddCatalog("bitcoin");
+
+    return AppInit(argc, argv);
+}
+
+int CMyApp::OnExit()
+{
+    Shutdown(NULL);
+    return wxApp::OnExit();
+}
+
+bool CMyApp::OnExceptionInMainLoop()
+{
+    try
+    {
+        throw;
+    }
+    catch (std::exception& e)
+    {
+        PrintException(&e, "CMyApp::OnExceptionInMainLoop()");
+        wxLogWarning("Exception %s %s", typeid(e).name(), e.what());
+        Sleep(1000);
+        throw;
+    }
+    catch (...)
+    {
+        PrintException(NULL, "CMyApp::OnExceptionInMainLoop()");
+        wxLogWarning("Unknown exception");
+        Sleep(1000);
+        throw;
+    }
+    return true;
+}
+
+void CMyApp::OnUnhandledException()
+{
+    // this shows how we may let some exception propagate uncaught
+    try
+    {
+        throw;
+    }
+    catch (std::exception& e)
+    {
+        PrintException(&e, "CMyApp::OnUnhandledException()");
+        wxLogWarning("Exception %s %s", typeid(e).name(), e.what());
+        Sleep(1000);
+        throw;
+    }
+    catch (...)
+    {
+        PrintException(NULL, "CMyApp::OnUnhandledException()");
+        wxLogWarning("Unknown exception");
+        Sleep(1000);
+        throw;
+    }
+}
+
+void CMyApp::OnFatalException()
+{
+    wxMessageBox(_("Program has crashed and will terminate.  "), "Bitcoin", wxOK | wxICON_ERROR);
+}