aboutsummaryrefslogtreecommitdiff
path: root/src/qt
diff options
context:
space:
mode:
Diffstat (limited to 'src/qt')
-rw-r--r--src/qt/bitcoin.cpp62
-rw-r--r--src/qt/bitcoingui.cpp7
-rw-r--r--src/qt/clientmodel.cpp6
-rw-r--r--src/qt/clientmodel.h1
-rw-r--r--src/qt/csvmodelwriter.cpp5
-rw-r--r--src/qt/forms/askpassphrasedialog.ui3
-rw-r--r--src/qt/forms/qrcodedialog.ui4
-rw-r--r--src/qt/forms/rpcconsole.ui148
-rw-r--r--src/qt/forms/sendcoinsdialog.ui2
-rw-r--r--src/qt/forms/transactiondescdialog.ui4
-rw-r--r--src/qt/guiutil.cpp147
-rw-r--r--src/qt/guiutil.h3
-rw-r--r--src/qt/messagepage.cpp1
-rw-r--r--src/qt/optionsmodel.cpp5
-rw-r--r--src/qt/overviewpage.cpp12
-rw-r--r--src/qt/overviewpage.h3
-rw-r--r--src/qt/qtipcserver.cpp1
-rw-r--r--src/qt/rpcconsole.cpp164
-rw-r--r--src/qt/rpcconsole.h8
-rw-r--r--src/qt/sendcoinsdialog.cpp10
-rw-r--r--src/qt/transactionview.cpp10
-rw-r--r--src/qt/transactionview.h1
22 files changed, 442 insertions, 165 deletions
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 91f6a56c82..ab0a37abff 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -129,6 +129,53 @@ static void handleRunawayException(std::exception *e)
exit(1);
}
+/** Help message for Bitcoin-Qt, shown with --help. */
+class HelpMessageBox: public QMessageBox
+{
+public:
+ HelpMessageBox(QWidget *parent = 0);
+
+ void exec();
+private:
+ QString header;
+ QString coreOptions;
+ QString uiOptions;
+};
+#include <QSpacerItem>
+#include <QGridLayout>
+HelpMessageBox::HelpMessageBox(QWidget *parent):
+ QMessageBox(parent)
+{
+ header = tr("Bitcoin-Qt") + " " + tr("version") + " " +
+ QString::fromStdString(FormatFullVersion()) + "\n\n" +
+ tr("Usage:") + "\n" +
+ " bitcoin-qt [options] " + "\n";
+ coreOptions = QString::fromStdString(HelpMessage());
+ uiOptions = tr("UI options") + ":\n" +
+ " -lang=<lang> " + tr("Set language, for example \"de_DE\" (default: system locale)") + "\n" +
+ " -min " + tr("Start minimized") + "\n" +
+ " -splash " + tr("Show splash screen on startup (default: 1)") + "\n";
+
+ setWindowTitle(tr("Bitcoin-Qt"));
+ setTextFormat(Qt::PlainText);
+ // setMinimumWidth is ignored for QMessageBox so put in nonbreaking spaces to make it wider.
+ QChar em_space(0x2003);
+ setText(header + QString(em_space).repeated(40));
+ setDetailedText(coreOptions + "\n" + uiOptions);
+}
+
+void HelpMessageBox::exec()
+{
+#if defined(WIN32)
+ // On windows, show a message box, as there is no stderr in windowed applications
+ QMessageBox::exec();
+#else
+ // On other operating systems, the expected action is to print the message to the console.
+ QString strUsage = header + "\n" + coreOptions + "\n" + uiOptions;
+ fprintf(stderr, "%s", strUsage.toStdString().c_str());
+#endif
+}
+
#ifdef WIN32
#define strncasecmp strnicmp
#endif
@@ -218,6 +265,15 @@ int main(int argc, char *argv[])
if (translator.load(lang_territory, ":/translations/"))
app.installTranslator(&translator);
+ // Show help message immediately after parsing command-line options (for "-lang") and setting locale,
+ // but before showing splash screen.
+ if (mapArgs.count("-?") || mapArgs.count("--help"))
+ {
+ HelpMessageBox help;
+ help.exec();
+ return 1;
+ }
+
QSplashScreen splash(QPixmap(":/images/splash"), 0);
if (GetBoolArg("-splash", true) && !GetBoolArg("-min"))
{
@@ -232,9 +288,13 @@ int main(int argc, char *argv[])
try
{
+ // Regenerate startup link, to fix links to old versions
+ if (GUIUtil::GetStartOnSystemStartup())
+ GUIUtil::SetStartOnSystemStartup(true);
+
BitcoinGUI window;
guiref = &window;
- if(AppInit2(argc, argv))
+ if(AppInit2())
{
{
// Put this in a block, so that the Model objects are cleaned up before
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 855fec3a8b..6b97d97656 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -1,8 +1,8 @@
/*
* Qt4 bitcoin GUI.
*
- * W.J. van der Laan 20011-2012
- * The Bitcoin Developers 20011-2012
+ * W.J. van der Laan 2011-2012
+ * The Bitcoin Developers 2011-2012
*/
#include "bitcoingui.h"
#include "transactiontablemodel.h"
@@ -72,6 +72,7 @@ BitcoinGUI::BitcoinGUI(QWidget *parent):
resize(850, 550);
setWindowTitle(tr("Bitcoin Wallet"));
#ifndef Q_WS_MAC
+ qApp->setWindowIcon(QIcon(":icons/bitcoin"));
setWindowIcon(QIcon(":icons/bitcoin"));
#else
setUnifiedTitleAndToolBarOnMac(true);
@@ -157,6 +158,7 @@ BitcoinGUI::BitcoinGUI(QWidget *parent):
// Clicking on a transaction on the overview page simply sends you to transaction history page
connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), this, SLOT(gotoHistoryPage()));
+ connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), transactionView, SLOT(focusTransaction(QModelIndex)));
// Doubleclicking on a transaction on the transaction history page shows details
connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails()));
@@ -331,6 +333,7 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
{
setWindowTitle(windowTitle() + QString(" ") + tr("[testnet]"));
#ifndef Q_WS_MAC
+ qApp->setWindowIcon(QIcon(":icons/bitcoin_testnet"));
setWindowIcon(QIcon(":icons/bitcoin_testnet"));
#else
MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet"));
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index d7172fd9cd..85ab03612d 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -5,6 +5,7 @@
#include "transactiontablemodel.h"
#include "main.h"
+static const int64 nClientStartupTime = GetTime();
#include <QDateTime>
@@ -98,3 +99,8 @@ QString ClientModel::clientName() const
{
return QString::fromStdString(CLIENT_NAME);
}
+
+QDateTime ClientModel::formatClientStartupTime() const
+{
+ return QDateTime::fromTime_t(nClientStartupTime);
+}
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 74e0c0688f..67835db727 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -39,6 +39,7 @@ public:
QString formatFullVersion() const;
QString formatBuildDate() const;
QString clientName() const;
+ QDateTime formatClientStartupTime() const;
private:
OptionsModel *optionsModel;
diff --git a/src/qt/csvmodelwriter.cpp b/src/qt/csvmodelwriter.cpp
index 84578b3322..8a50bbab3f 100644
--- a/src/qt/csvmodelwriter.cpp
+++ b/src/qt/csvmodelwriter.cpp
@@ -27,8 +27,9 @@ void CSVModelWriter::addColumn(const QString &title, int column, int role)
static void writeValue(QTextStream &f, const QString &value)
{
- // TODO: quoting if " or \n in string
- f << "\"" << value << "\"";
+ QString escaped = value;
+ escaped.replace('"', "\"\"");
+ f << "\"" << escaped << "\"";
}
static void writeSep(QTextStream &f)
diff --git a/src/qt/forms/askpassphrasedialog.ui b/src/qt/forms/askpassphrasedialog.ui
index 1383af7a70..e4d86f7cf9 100644
--- a/src/qt/forms/askpassphrasedialog.ui
+++ b/src/qt/forms/askpassphrasedialog.ui
@@ -28,9 +28,6 @@
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="warningLabel">
- <property name="text">
- <string>TextLabel</string>
- </property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
diff --git a/src/qt/forms/qrcodedialog.ui b/src/qt/forms/qrcodedialog.ui
index ef21841c26..6199b68749 100644
--- a/src/qt/forms/qrcodedialog.ui
+++ b/src/qt/forms/qrcodedialog.ui
@@ -7,11 +7,11 @@
<x>0</x>
<y>0</y>
<width>334</width>
- <height>423</height>
+ <height>425</height>
</rect>
</property>
<property name="windowTitle">
- <string>QR-Code Dialog</string>
+ <string>QR Code Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui
index 02164f76b5..cded274792 100644
--- a/src/qt/forms/rpcconsole.ui
+++ b/src/qt/forms/rpcconsole.ui
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>706</width>
- <height>382</height>
+ <height>446</height>
</rect>
</property>
<property name="windowTitle">
@@ -27,6 +27,19 @@
<property name="horizontalSpacing">
<number>12</number>
</property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_9">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Client</string>
+ </property>
+ </widget>
+ </item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
@@ -36,6 +49,9 @@
</item>
<item row="1" column="1">
<widget class="QLabel" name="clientName">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
<property name="text">
<string>N/A</string>
</property>
@@ -56,6 +72,9 @@
</item>
<item row="2" column="1">
<widget class="QLabel" name="clientVersion">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
<property name="text">
<string>N/A</string>
</property>
@@ -67,20 +86,53 @@
</property>
</widget>
</item>
- <item row="0" column="0">
- <widget class="QLabel" name="label_9">
- <property name="font">
- <font>
- <weight>75</weight>
- <bold>true</bold>
- </font>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_12">
+ <property name="text">
+ <string>Build date</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLabel" name="buildDate">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
- <string>Version</string>
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="4" column="0">
+ <widget class="QLabel" name="label_13">
+ <property name="text">
+ <string>Startup time</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLabel" name="startupTime">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
<widget class="QLabel" name="label_11">
<property name="font">
<font>
@@ -93,15 +145,18 @@
</property>
</widget>
</item>
- <item row="5" column="0">
+ <item row="6" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Number of connections</string>
</property>
</widget>
</item>
- <item row="5" column="1">
+ <item row="6" column="1">
<widget class="QLabel" name="numberOfConnections">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
<property name="text">
<string>N/A</string>
</property>
@@ -113,14 +168,14 @@
</property>
</widget>
</item>
- <item row="6" column="0">
+ <item row="7" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>On testnet</string>
</property>
</widget>
</item>
- <item row="6" column="1">
+ <item row="7" column="1">
<widget class="QCheckBox" name="isTestNet">
<property name="enabled">
<bool>false</bool>
@@ -130,7 +185,7 @@
</property>
</widget>
</item>
- <item row="7" column="0">
+ <item row="8" column="0">
<widget class="QLabel" name="label_10">
<property name="font">
<font>
@@ -143,15 +198,18 @@
</property>
</widget>
</item>
- <item row="8" column="0">
+ <item row="9" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Current number of blocks</string>
</property>
</widget>
</item>
- <item row="8" column="1">
+ <item row="9" column="1">
<widget class="QLabel" name="numberOfBlocks">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
<property name="text">
<string>N/A</string>
</property>
@@ -163,15 +221,18 @@
</property>
</widget>
</item>
- <item row="9" column="0">
+ <item row="10" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Estimated total blocks</string>
</property>
</widget>
</item>
- <item row="9" column="1">
+ <item row="10" column="1">
<widget class="QLabel" name="totalBlocks">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
<property name="text">
<string>N/A</string>
</property>
@@ -183,15 +244,18 @@
</property>
</widget>
</item>
- <item row="10" column="0">
+ <item row="11" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Last block time</string>
</property>
</widget>
</item>
- <item row="10" column="1">
+ <item row="11" column="1">
<widget class="QLabel" name="lastBlockTime">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
<property name="text">
<string>N/A</string>
</property>
@@ -203,7 +267,7 @@
</property>
</widget>
</item>
- <item row="11" column="0">
+ <item row="12" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -216,7 +280,7 @@
</property>
</spacer>
</item>
- <item row="12" column="0">
+ <item row="13" column="0">
<widget class="QLabel" name="labelDebugLogfile">
<property name="font">
<font>
@@ -229,7 +293,7 @@
</property>
</widget>
</item>
- <item row="13" column="0">
+ <item row="14" column="0">
<widget class="QPushButton" name="openDebugLogfileButton">
<property name="toolTip">
<string>Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles.</string>
@@ -239,7 +303,7 @@
</property>
</widget>
</item>
- <item row="14" column="0">
+ <item row="15" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -252,20 +316,6 @@
</property>
</spacer>
</item>
- <item row="3" column="0">
- <widget class="QLabel" name="label_12">
- <property name="text">
- <string>Build date</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QLabel" name="buildDate">
- <property name="text">
- <string>N/A</string>
- </property>
- </widget>
- </item>
</layout>
</widget>
<widget class="QWidget" name="tab_console">
@@ -277,30 +327,22 @@
<number>3</number>
</property>
<item>
- <widget class="QTableWidget" name="messagesWidget">
+ <widget class="QTextEdit" name="messagesWidget">
<property name="minimumSize">
<size>
<width>0</width>
<height>100</height>
</size>
</property>
- <property name="tabKeyNavigation">
- <bool>false</bool>
+ <property name="readOnly">
+ <bool>true</bool>
</property>
- <property name="selectionBehavior">
- <enum>QAbstractItemView::SelectRows</enum>
+ <property name="tabKeyNavigation" stdset="0">
+ <bool>false</bool>
</property>
- <property name="columnCount">
+ <property name="columnCount" stdset="0">
<number>2</number>
</property>
- <attribute name="horizontalHeaderVisible">
- <bool>false</bool>
- </attribute>
- <attribute name="verticalHeaderVisible">
- <bool>false</bool>
- </attribute>
- <column/>
- <column/>
</widget>
</item>
<item>
@@ -311,7 +353,7 @@
<item>
<widget class="QLabel" name="label">
<property name="text">
- <string>&gt;</string>
+ <string notr="true">&gt;</string>
</property>
</widget>
</item>
diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui
index 49b4580dcf..023a72ac2b 100644
--- a/src/qt/forms/sendcoinsdialog.ui
+++ b/src/qt/forms/sendcoinsdialog.ui
@@ -84,7 +84,7 @@
<string>Remove all transaction fields</string>
</property>
<property name="text">
- <string>Clear all</string>
+ <string>Clear &amp;All</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
diff --git a/src/qt/forms/transactiondescdialog.ui b/src/qt/forms/transactiondescdialog.ui
index 9a9f6db158..039cb082cc 100644
--- a/src/qt/forms/transactiondescdialog.ui
+++ b/src/qt/forms/transactiondescdialog.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>400</width>
- <height>300</height>
+ <width>600</width>
+ <height>250</height>
</rect>
</property>
<property name="windowTitle">
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 67cbc51bd0..22c0bfeebe 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -19,6 +19,7 @@
#include <QThread>
#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
#ifdef WIN32
#ifdef _WIN32_WINNT
@@ -256,7 +257,7 @@ bool ToolTipToRichTextFilter::eventFilter(QObject *obj, QEvent *evt)
{
QWidget *widget = static_cast<QWidget*>(obj);
QString tooltip = widget->toolTip();
- if(!Qt::mightBeRichText(tooltip) && tooltip.size() > size_threshold)
+ if(tooltip.size() > size_threshold && !tooltip.startsWith("<qt/>") && !Qt::mightBeRichText(tooltip))
{
// Prefix <qt/> to make sure Qt detects this as rich text
// Escape the current message as HTML and replace \n by <br>
@@ -268,5 +269,149 @@ bool ToolTipToRichTextFilter::eventFilter(QObject *obj, QEvent *evt)
return QObject::eventFilter(obj, evt);
}
+#ifdef WIN32
+boost::filesystem::path static StartupShortcutPath()
+{
+ return GetSpecialFolderPath(CSIDL_STARTUP) / "Bitcoin.lnk";
+}
+
+bool GetStartOnSystemStartup()
+{
+ // check for Bitcoin.lnk
+ return boost::filesystem::exists(StartupShortcutPath());
+}
+
+bool SetStartOnSystemStartup(bool fAutoStart)
+{
+ // If the shortcut exists already, remove it for updating
+ boost::filesystem::remove(StartupShortcutPath());
+
+ 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));
+
+ TCHAR pszArgs[5] = TEXT("-min");
+
+ // Set the path to the shortcut target
+ psl->SetPath(pszExePath);
+ PathRemoveFileSpec(pszExePath);
+ psl->SetWorkingDirectory(pszExePath);
+ psl->SetShowCmd(SW_SHOWMINNOACTIVE);
+ psl->SetArguments(pszArgs);
+
+ // 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().string().c_str(), -1, pwsz, MAX_PATH);
+ // Save the link by calling IPersistFile::Save.
+ hres = ppf->Save(pwsz, TRUE);
+ ppf->Release();
+ psl->Release();
+ CoUninitialize();
+ return true;
+ }
+ psl->Release();
+ }
+ CoUninitialize();
+ return false;
+ }
+ return true;
+}
+
+#elif defined(LINUX)
+
+// Follow the Desktop Application Autostart Spec:
+// http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
+
+boost::filesystem::path static GetAutostartDir()
+{
+ namespace fs = boost::filesystem;
+
+ char* pszConfigHome = getenv("XDG_CONFIG_HOME");
+ if (pszConfigHome) return fs::path(pszConfigHome) / "autostart";
+ char* pszHome = getenv("HOME");
+ if (pszHome) return fs::path(pszHome) / ".config" / "autostart";
+ return fs::path();
+}
+
+boost::filesystem::path static GetAutostartFilePath()
+{
+ return GetAutostartDir() / "bitcoin.desktop";
+}
+
+bool GetStartOnSystemStartup()
+{
+ boost::filesystem::ifstream optionFile(GetAutostartFilePath());
+ if (!optionFile.good())
+ return false;
+ // Scan through file for "Hidden=true":
+ std::string line;
+ while (!optionFile.eof())
+ {
+ getline(optionFile, line);
+ if (line.find("Hidden") != std::string::npos &&
+ line.find("true") != std::string::npos)
+ return false;
+ }
+ optionFile.close();
+
+ return true;
+}
+
+bool SetStartOnSystemStartup(bool fAutoStart)
+{
+ if (!fAutoStart)
+ boost::filesystem::remove(GetAutostartFilePath());
+ else
+ {
+ char pszExePath[MAX_PATH+1];
+ memset(pszExePath, 0, sizeof(pszExePath));
+ if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1)
+ return false;
+
+ boost::filesystem::create_directories(GetAutostartDir());
+
+ boost::filesystem::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out|std::ios_base::trunc);
+ if (!optionFile.good())
+ return false;
+ // Write a bitcoin.desktop file to the autostart directory:
+ optionFile << "[Desktop Entry]\n";
+ optionFile << "Type=Application\n";
+ optionFile << "Name=Bitcoin\n";
+ optionFile << "Exec=" << pszExePath << " -min\n";
+ optionFile << "Terminal=false\n";
+ optionFile << "Hidden=false\n";
+ optionFile.close();
+ }
+ return true;
+}
+#else
+
+// TODO: OSX startup stuff; see:
+// http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html
+
+bool GetStartOnSystemStartup() { return false; }
+bool SetStartOnSystemStartup(bool fAutoStart) { return false; }
+
+#endif
+
} // namespace GUIUtil
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index 8d1a01e07e..f30d5db35b 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -90,6 +90,9 @@ namespace GUIUtil
int size_threshold;
};
+ bool GetStartOnSystemStartup();
+ bool SetStartOnSystemStartup(bool fAutoStart);
+
} // namespace GUIUtil
#endif // GUIUTIL_H
diff --git a/src/qt/messagepage.cpp b/src/qt/messagepage.cpp
index c04d8b2c78..1f895e28ff 100644
--- a/src/qt/messagepage.cpp
+++ b/src/qt/messagepage.cpp
@@ -10,7 +10,6 @@
#include "main.h"
#include "wallet.h"
#include "init.h"
-#include "util.h"
#include "messagepage.h"
#include "ui_messagepage.h"
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 78448d3ee1..181dec4400 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -4,6 +4,7 @@
#include "init.h"
#include "walletdb.h"
+#include "guiutil.h"
OptionsModel::OptionsModel(QObject *parent) :
QAbstractListModel(parent)
@@ -107,7 +108,7 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
switch(index.row())
{
case StartAtStartup:
- return QVariant(GetStartOnSystemStartup());
+ return QVariant(GUIUtil::GetStartOnSystemStartup());
case MinimizeToTray:
return QVariant(fMinimizeToTray);
case MapPortUPnP:
@@ -146,7 +147,7 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
switch(index.row())
{
case StartAtStartup:
- successful = SetStartOnSystemStartup(value.toBool());
+ successful = GUIUtil::SetStartOnSystemStartup(value.toBool());
break;
case MinimizeToTray:
fMinimizeToTray = value.toBool();
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index 259f819deb..d0ba377967 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -94,7 +94,7 @@ OverviewPage::OverviewPage(QWidget *parent) :
ui(new Ui::OverviewPage),
currentBalance(-1),
currentUnconfirmedBalance(-1),
- txdelegate(new TxViewDelegate())
+ txdelegate(new TxViewDelegate()), filter(0)
{
ui->setupUi(this);
@@ -104,7 +104,13 @@ OverviewPage::OverviewPage(QWidget *parent) :
ui->listTransactions->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2));
ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false);
- connect(ui->listTransactions, SIGNAL(clicked(QModelIndex)), this, SIGNAL(transactionClicked(QModelIndex)));
+ connect(ui->listTransactions, SIGNAL(clicked(QModelIndex)), this, SLOT(handleTransactionClicked(QModelIndex)));
+}
+
+void OverviewPage::handleTransactionClicked(const QModelIndex &index)
+{
+ if(filter)
+ emit transactionClicked(filter->mapToSource(index));
}
OverviewPage::~OverviewPage()
@@ -132,7 +138,7 @@ void OverviewPage::setModel(WalletModel *model)
if(model)
{
// Set up transaction list
- TransactionFilterProxy *filter = new TransactionFilterProxy();
+ filter = new TransactionFilterProxy();
filter->setSourceModel(model->getTransactionTableModel());
filter->setLimit(NUM_ITEMS);
filter->setDynamicSortFilter(true);
diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h
index 1199227168..1acd1b7f39 100644
--- a/src/qt/overviewpage.h
+++ b/src/qt/overviewpage.h
@@ -12,6 +12,7 @@ namespace Ui {
}
class WalletModel;
class TxViewDelegate;
+class TransactionFilterProxy;
/** Overview ("home") page widget */
class OverviewPage : public QWidget
@@ -38,9 +39,11 @@ private:
qint64 currentUnconfirmedBalance;
TxViewDelegate *txdelegate;
+ TransactionFilterProxy *filter;
private slots:
void displayUnitChanged();
+ void handleTransactionClicked(const QModelIndex &index);
};
#endif // OVERVIEWPAGE_H
diff --git a/src/qt/qtipcserver.cpp b/src/qt/qtipcserver.cpp
index 102ac0ff4e..06ada5aaca 100644
--- a/src/qt/qtipcserver.cpp
+++ b/src/qt/qtipcserver.cpp
@@ -8,7 +8,6 @@
#include <boost/date_time/posix_time/posix_time.hpp>
#include "ui_interface.h"
-#include "util.h"
#include "qtipcserver.h"
using namespace boost::interprocess;
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 85f79309f3..51051f72f0 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -10,6 +10,8 @@
#include <QThread>
#include <QTextEdit>
#include <QKeyEvent>
+#include <QUrl>
+#include <QScrollBar>
#include <boost/tokenizer.hpp>
@@ -19,6 +21,19 @@
const int CONSOLE_SCROLLBACK = 50;
const int CONSOLE_HISTORY = 50;
+const QSize ICON_SIZE(24, 24);
+
+const struct {
+ const char *url;
+ const char *source;
+} ICON_MAPPING[] = {
+ {"cmd-request", ":/icons/tx_input"},
+ {"cmd-reply", ":/icons/tx_output"},
+ {"cmd-error", ":/icons/tx_output"},
+ {"misc", ":/icons/tx_inout"},
+ {NULL, NULL}
+};
+
/* Object for executing console RPC commands in a separate thread.
*/
class RPCExecutor: public QObject
@@ -41,19 +56,26 @@ void RPCExecutor::start()
void RPCExecutor::request(const QString &command)
{
// Parse shell-like command line into separate arguments
- boost::escaped_list_separator<char> els('\\',' ','\"');
- std::string strCommand = command.toStdString();
- boost::tokenizer<boost::escaped_list_separator<char> > tok(strCommand, els);
-
std::string strMethod;
std::vector<std::string> strParams;
- int n = 0;
- for(boost::tokenizer<boost::escaped_list_separator<char> >::iterator beg=tok.begin(); beg!=tok.end();++beg,++n)
+ try {
+ boost::escaped_list_separator<char> els('\\',' ','\"');
+ std::string strCommand = command.toStdString();
+ boost::tokenizer<boost::escaped_list_separator<char> > tok(strCommand, els);
+
+ int n = 0;
+ for(boost::tokenizer<boost::escaped_list_separator<char> >::iterator beg=tok.begin(); beg!=tok.end();++beg,++n)
+ {
+ if(n == 0) // First parameter is the command
+ strMethod = *beg;
+ else
+ strParams.push_back(*beg);
+ }
+ }
+ catch(boost::escaped_list_error &e)
{
- if(n == 0) // First parameter is the command
- strMethod = *beg;
- else
- strParams.push_back(*beg);
+ emit reply(RPCConsole::CMD_ERROR, QString("Parse error"));
+ return;
}
try {
@@ -83,12 +105,9 @@ void RPCExecutor::request(const QString &command)
RPCConsole::RPCConsole(QWidget *parent) :
QDialog(parent),
ui(new Ui::RPCConsole),
- firstLayout(true),
historyPtr(0)
{
ui->setupUi(this);
- ui->messagesWidget->horizontalHeader()->setResizeMode(1, QHeaderView::Stretch);
- ui->messagesWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
#ifndef WIN32
// Show Debug logfile label and Open button only for Windows
@@ -99,13 +118,6 @@ RPCConsole::RPCConsole(QWidget *parent) :
// Install event filter for up and down arrow
ui->lineEdit->installEventFilter(this);
- // Add "Copy message" to context menu explicitly
- QAction *copyMessageAction = new QAction(tr("&Copy"), this);
- copyMessageAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_C));
- copyMessageAction->setShortcutContext(Qt::WidgetShortcut);
- connect(copyMessageAction, SIGNAL(triggered()), this, SLOT(copyMessage()));
- ui->messagesWidget->addAction(copyMessageAction);
-
connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
connect(ui->openDebugLogfileButton, SIGNAL(clicked()), this, SLOT(on_openDebugLogfileButton_clicked()));
@@ -150,6 +162,7 @@ void RPCConsole::setClientModel(ClientModel *model)
ui->clientVersion->setText(model->formatFullVersion());
ui->clientName->setText(model->clientName());
ui->buildDate->setText(model->formatBuildDate());
+ ui->startupTime->setText(model->formatClientStartupTime().toString());
setNumConnections(model->getNumConnections());
ui->isTestNet->setChecked(model->isTestNet());
@@ -158,68 +171,62 @@ void RPCConsole::setClientModel(ClientModel *model)
}
}
-static QColor categoryColor(int category)
+static QString categoryClass(int category)
{
switch(category)
{
- case RPCConsole::MC_ERROR: return QColor(255,0,0); break;
- case RPCConsole::MC_DEBUG: return QColor(192,192,192); break;
- case RPCConsole::CMD_REQUEST: return QColor(128,128,128); break;
- case RPCConsole::CMD_REPLY: return QColor(128,255,128); break;
- case RPCConsole::CMD_ERROR: return QColor(255,128,128); break;
- default: return QColor(0,0,0);
+ case RPCConsole::CMD_REQUEST: return "cmd-request"; break;
+ case RPCConsole::CMD_REPLY: return "cmd-reply"; break;
+ case RPCConsole::CMD_ERROR: return "cmd-error"; break;
+ default: return "misc";
}
}
void RPCConsole::clear()
{
ui->messagesWidget->clear();
- ui->messagesWidget->setRowCount(0);
ui->lineEdit->clear();
ui->lineEdit->setFocus();
- message(CMD_REPLY, tr("Welcome to the bitcoin RPC console.")+"\n"+
- tr("Use up and down arrows to navigate history, and Ctrl-L to clear screen.")+"\n"+
- tr("Type \"help\" for an overview of available commands."));
+ // Add smoothly scaled icon images.
+ // (when using width/height on an img, Qt uses nearest instead of linear interpolation)
+ for(int i=0; ICON_MAPPING[i].url; ++i)
+ {
+ ui->messagesWidget->document()->addResource(
+ QTextDocument::ImageResource,
+ QUrl(ICON_MAPPING[i].url),
+ QImage(ICON_MAPPING[i].source).scaled(ICON_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
+ }
+
+ // Set default style sheet
+ ui->messagesWidget->document()->setDefaultStyleSheet(
+ "table { }"
+ "td.time { color: #808080; padding-top: 3px; } "
+ "td.message { font-family: Monospace; font-size: 12px; } "
+ "td.cmd-request { color: #006060; } "
+ "td.cmd-error { color: red; } "
+ "b { color: #006060; } "
+ );
+
+ message(CMD_REPLY, tr("Welcome to the Bitcoin RPC console.<br>"
+ "Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen.<br>"
+ "Type <b>help</b> for an overview of available commands."), true);
}
-void RPCConsole::message(int category, const QString &message)
+void RPCConsole::message(int category, const QString &message, bool html)
{
- // Add row to messages widget
- int row = ui->messagesWidget->rowCount();
- ui->messagesWidget->setRowCount(row+1);
-
QTime time = QTime::currentTime();
- QTableWidgetItem *newTime = new QTableWidgetItem(time.toString());
- newTime->setData(Qt::DecorationRole, categoryColor(category));
- newTime->setForeground(QColor(128,128,128));
- newTime->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); // make non-editable
-
- int numLines = message.count("\n") + 1;
- // As Qt doesn't like very tall cells (they break scrolling) keep only short messages in
- // the cell text, longer messages trigger a display widget with scroll bar
- if(numLines < 5)
- {
- QTableWidgetItem *newItem = new QTableWidgetItem(message);
- newItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); // make non-editable
- if(category == CMD_ERROR) // Coloring error messages in red
- newItem->setForeground(QColor(255,16,16));
- ui->messagesWidget->setItem(row, 1, newItem);
- } else {
- QTextEdit *newWidget = new QTextEdit;
- newWidget->setText(message);
- newWidget->setMaximumHeight(100);
- newWidget->setReadOnly(true);
- ui->messagesWidget->setCellWidget(row, 1, newWidget);
- }
-
- ui->messagesWidget->setItem(row, 0, newTime);
- ui->messagesWidget->resizeRowToContents(row);
- // Preserve only limited scrollback buffer
- while(ui->messagesWidget->rowCount() > CONSOLE_SCROLLBACK)
- ui->messagesWidget->removeRow(0);
- // Scroll to bottom after table is updated
- QTimer::singleShot(0, ui->messagesWidget, SLOT(scrollToBottom()));
+ QString timeString = time.toString();
+ QString out;
+ out += "<table><tr><td class=\"time\" width=\"65\">" + timeString + "</td>";
+ out += "<td class=\"icon\" width=\"32\"><img src=\"" + categoryClass(category) + "\"></td>";
+ out += "<td class=\"message " + categoryClass(category) + "\" valign=\"middle\">";
+ if(html)
+ out += message;
+ else
+ out += GUIUtil::HtmlEscape(message, true);
+ out += "</td></tr></table>";
+ ui->messagesWidget->append(out);
}
void RPCConsole::setNumConnections(int count)
@@ -232,7 +239,8 @@ void RPCConsole::setNumBlocks(int count)
ui->numberOfBlocks->setText(QString::number(count));
if(clientModel)
{
- ui->totalBlocks->setText(QString::number(clientModel->getNumBlocksOfPeers()));
+ // If there is no current number available display N/A instead of 0, which can't ever be true
+ ui->totalBlocks->setText(clientModel->getNumBlocksOfPeers() == 0 ? tr("N/A") : QString::number(clientModel->getNumBlocksOfPeers()));
ui->lastBlockTime->setText(clientModel->getLastBlockDate().toString());
}
}
@@ -255,6 +263,8 @@ void RPCConsole::on_lineEdit_returnPressed()
history.removeFirst();
// Set pointer to end of history
historyPtr = history.size();
+ // Scroll console view to end
+ scrollToEnd();
}
}
@@ -296,24 +306,10 @@ void RPCConsole::startExecutor()
thread->start();
}
-void RPCConsole::copyMessage()
-{
- GUIUtil::copyEntryData(ui->messagesWidget, 1, Qt::EditRole);
-}
-
void RPCConsole::on_tabWidget_currentChanged(int index)
{
if(ui->tabWidget->widget(index) == ui->tab_console)
{
- if(firstLayout)
- {
- // Work around QTableWidget issue:
- // Call resizeRowsToContents on first Layout request with widget visible,
- // to make sure multiline messages that were added before the console was shown
- // have the right height.
- firstLayout = false;
- ui->messagesWidget->resizeRowsToContents();
- }
ui->lineEdit->setFocus();
}
}
@@ -322,3 +318,9 @@ void RPCConsole::on_openDebugLogfileButton_clicked()
{
GUIUtil::openDebugLogfile();
}
+
+void RPCConsole::scrollToEnd()
+{
+ QScrollBar *scrollbar = ui->messagesWidget->verticalScrollBar();
+ scrollbar->setValue(scrollbar->maximum());
+}
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 30948eaad2..0a7b10f4a2 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -37,16 +37,15 @@ private slots:
public slots:
void clear();
- void message(int category, const QString &message);
+ void message(int category, const QString &message, bool html = false);
/** Set number of connections shown in the UI */
void setNumConnections(int count);
/** Set number of blocks shown in the UI */
void setNumBlocks(int count);
/** Go forward or back in history */
void browseHistory(int offset);
- /** Copy currently selected message to clipboard */
- void copyMessage();
-
+ /** Scroll console view to end */
+ void scrollToEnd();
signals:
// For RPC command executor
void stopExecutor();
@@ -55,7 +54,6 @@ signals:
private:
Ui::RPCConsole *ui;
ClientModel *clientModel;
- bool firstLayout;
QStringList history;
int historyPtr;
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index b4029aa0d2..f6a3047a2b 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -130,28 +130,28 @@ void SendCoinsDialog::on_sendButton_clicked()
break;
case WalletModel::AmountExceedsBalance:
QMessageBox::warning(this, tr("Send Coins"),
- tr("Amount exceeds your balance"),
+ tr("The amount exceeds your balance."),
QMessageBox::Ok, QMessageBox::Ok);
break;
case WalletModel::AmountWithFeeExceedsBalance:
QMessageBox::warning(this, tr("Send Coins"),
- tr("Total exceeds your balance when the %1 transaction fee is included").
+ tr("The total exceeds your balance when the %1 transaction fee is included.").
arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, sendstatus.fee)),
QMessageBox::Ok, QMessageBox::Ok);
break;
case WalletModel::DuplicateAddress:
QMessageBox::warning(this, tr("Send Coins"),
- tr("Duplicate address found, can only send to each address once in one send operation"),
+ tr("Duplicate address found, can only send to each address once per send operation."),
QMessageBox::Ok, QMessageBox::Ok);
break;
case WalletModel::TransactionCreationFailed:
QMessageBox::warning(this, tr("Send Coins"),
- tr("Error: Transaction creation failed "),
+ tr("Error: Transaction creation failed."),
QMessageBox::Ok, QMessageBox::Ok);
break;
case WalletModel::TransactionCommitFailed:
QMessageBox::warning(this, tr("Send Coins"),
- tr("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."),
+ tr("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."),
QMessageBox::Ok, QMessageBox::Ok);
break;
case WalletModel::Aborted: // User aborted, nothing to do
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 1c427d6fe4..a0e7dd4e77 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -417,3 +417,13 @@ void TransactionView::dateRangeChanged()
QDateTime(dateFrom->date()),
QDateTime(dateTo->date()).addDays(1));
}
+
+void TransactionView::focusTransaction(const QModelIndex &idx)
+{
+ if(!transactionProxyModel)
+ return;
+ QModelIndex targetIdx = transactionProxyModel->mapFromSource(idx);
+ transactionView->scrollTo(targetIdx);
+ transactionView->setCurrentIndex(targetIdx);
+ transactionView->setFocus();
+}
diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h
index bc6e1e4e05..4ade3ecd5f 100644
--- a/src/qt/transactionview.h
+++ b/src/qt/transactionview.h
@@ -75,6 +75,7 @@ public slots:
void changedPrefix(const QString &prefix);
void changedAmount(const QString &amount);
void exportClicked();
+ void focusTransaction(const QModelIndex&);
};