aboutsummaryrefslogtreecommitdiff
path: root/src/qt/guiutil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qt/guiutil.cpp')
-rw-r--r--src/qt/guiutil.cpp292
1 files changed, 220 insertions, 72 deletions
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index d4e73adf9..7e1831f03 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -1,26 +1,17 @@
+// Copyright (c) 2011-2013 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
#include "guiutil.h"
+
#include "bitcoinaddressvalidator.h"
-#include "walletmodel.h"
#include "bitcoinunits.h"
-#include "util.h"
-#include "init.h"
-
-#include <QString>
-#include <QDateTime>
-#include <QDoubleValidator>
-#include <QFont>
-#include <QLineEdit>
-#include <QUrl>
-#include <QTextDocument> // For Qt::escape
-#include <QAbstractItemView>
-#include <QApplication>
-#include <QClipboard>
-#include <QFileDialog>
-#include <QDesktopServices>
-#include <QThread>
+#include "qvalidatedlineedit.h"
+#include "walletmodel.h"
-#include <boost/filesystem.hpp>
-#include <boost/filesystem/fstream.hpp>
+#include "core.h"
+#include "init.h"
+#include "util.h"
#ifdef WIN32
#ifdef _WIN32_WINNT
@@ -35,9 +26,32 @@
#ifndef NOMINMAX
#define NOMINMAX
#endif
-#include "shlwapi.h"
-#include "shlobj.h"
#include "shellapi.h"
+#include "shlobj.h"
+#include "shlwapi.h"
+#endif
+
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+
+#include <QAbstractItemView>
+#include <QApplication>
+#include <QClipboard>
+#include <QDateTime>
+#include <QDesktopServices>
+#include <QDesktopWidget>
+#include <QDoubleValidator>
+#include <QFileDialog>
+#include <QFont>
+#include <QLineEdit>
+#include <QSettings>
+#include <QTextDocument> // for Qt::mightBeRichText
+#include <QThread>
+
+#if QT_VERSION < 0x050000
+#include <QUrl>
+#else
+#include <QUrlQuery>
#endif
namespace GUIUtil {
@@ -59,11 +73,16 @@ QFont bitcoinAddressFont()
return font;
}
-void setupAddressWidget(QLineEdit *widget, QWidget *parent)
+void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent)
{
- widget->setMaxLength(BitcoinAddressValidator::MaxAddressLength);
- widget->setValidator(new BitcoinAddressValidator(parent));
+ parent->setFocusProxy(widget);
+
widget->setFont(bitcoinAddressFont());
+#if QT_VERSION >= 0x040700
+ widget->setPlaceholderText(QObject::tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)"));
+#endif
+ widget->setValidator(new BitcoinAddressEntryValidator(parent));
+ widget->setCheckValidator(new BitcoinAddressCheckValidator(parent));
}
void setupAmountWidget(QLineEdit *widget, QWidget *parent)
@@ -77,14 +96,20 @@ void setupAmountWidget(QLineEdit *widget, QWidget *parent)
bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
{
- // return if URI is not valid or is no bitcoin URI
+ // return if URI is not valid or is no bitcoin: URI
if(!uri.isValid() || uri.scheme() != QString("bitcoin"))
return false;
SendCoinsRecipient rv;
rv.address = uri.path();
rv.amount = 0;
+
+#if QT_VERSION < 0x050000
QList<QPair<QString, QString> > items = uri.queryItems();
+#else
+ QUrlQuery uriQuery(uri);
+ QList<QPair<QString, QString> > items = uriQuery.queryItems();
+#endif
for (QList<QPair<QString, QString> >::iterator i = items.begin(); i != items.end(); i++)
{
bool fShouldReturnFalse = false;
@@ -99,6 +124,11 @@ bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
rv.label = i->second;
fShouldReturnFalse = false;
}
+ if (i->first == "message")
+ {
+ rv.message = i->second;
+ fShouldReturnFalse = false;
+ }
else if (i->first == "amount")
{
if(!i->second.isEmpty())
@@ -127,7 +157,7 @@ bool parseBitcoinURI(QString uri, SendCoinsRecipient *out)
//
// Cannot handle this later, because bitcoin:// will cause Qt to see the part after // as host,
// which will lower-case it (and thus invalidate the address).
- if(uri.startsWith("bitcoin://"))
+ if(uri.startsWith("bitcoin://", Qt::CaseInsensitive))
{
uri.replace(0, 10, "bitcoin:");
}
@@ -135,9 +165,49 @@ bool parseBitcoinURI(QString uri, SendCoinsRecipient *out)
return parseBitcoinURI(uriInstance, out);
}
+QString formatBitcoinURI(const SendCoinsRecipient &info)
+{
+ QString ret = QString("bitcoin:%1").arg(info.address);
+ int paramCount = 0;
+
+ if (info.amount)
+ {
+ ret += QString("?amount=%1").arg(BitcoinUnits::format(BitcoinUnits::BTC, info.amount));
+ paramCount++;
+ }
+
+ if (!info.label.isEmpty())
+ {
+ QString lbl(QUrl::toPercentEncoding(info.label));
+ ret += QString("%1label=%2").arg(paramCount == 0 ? "?" : "&").arg(lbl);
+ paramCount++;
+ }
+
+ if (!info.message.isEmpty())
+ {
+ QString msg(QUrl::toPercentEncoding(info.message));;
+ ret += QString("%1message=%2").arg(paramCount == 0 ? "?" : "&").arg(msg);
+ paramCount++;
+ }
+
+ return ret;
+}
+
+bool isDust(const QString& address, qint64 amount)
+{
+ CTxDestination dest = CBitcoinAddress(address.toStdString()).Get();
+ CScript script; script.SetDestination(dest);
+ CTxOut txOut(amount, script);
+ return txOut.IsDust(CTransaction::nMinRelayTxFee);
+}
+
QString HtmlEscape(const QString& str, bool fMultiLine)
{
+#if QT_VERSION < 0x050000
QString escaped = Qt::escape(str);
+#else
+ QString escaped = str.toHtmlEscaped();
+#endif
if(fMultiLine)
{
escaped = escaped.replace("\n", "<br>\n");
@@ -159,26 +229,30 @@ void copyEntryData(QAbstractItemView *view, int column, int role)
if(!selection.isEmpty())
{
// Copy first item
- QApplication::clipboard()->setText(selection.at(0).data(role).toString());
+ setClipboard(selection.at(0).data(role).toString());
}
}
-QString getSaveFileName(QWidget *parent, const QString &caption,
- const QString &dir,
- const QString &filter,
- QString *selectedSuffixOut)
+QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir,
+ const QString &filter,
+ QString *selectedSuffixOut)
{
QString selectedFilter;
QString myDir;
if(dir.isEmpty()) // Default to user documents location
{
+#if QT_VERSION < 0x050000
myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
+#else
+ myDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
+#endif
}
else
{
myDir = dir;
}
- QString result = QFileDialog::getSaveFileName(parent, caption, myDir, filter, &selectedFilter);
+ /* Directly convert path to native OS path separators */
+ QString result = QDir::toNativeSeparators(QFileDialog::getSaveFileName(parent, caption, myDir, filter, &selectedFilter));
/* Extract first suffix from filter pattern "Description (*.foo)" or "Description (*.foo *.bar ...) */
QRegExp filter_re(".* \\(\\*\\.(.*)[ \\)]");
@@ -209,9 +283,44 @@ QString getSaveFileName(QWidget *parent, const QString &caption,
return result;
}
+QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir,
+ const QString &filter,
+ QString *selectedSuffixOut)
+{
+ QString selectedFilter;
+ QString myDir;
+ if(dir.isEmpty()) // Default to user documents location
+ {
+#if QT_VERSION < 0x050000
+ myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
+#else
+ myDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
+#endif
+ }
+ else
+ {
+ myDir = dir;
+ }
+ /* Directly convert path to native OS path separators */
+ QString result = QDir::toNativeSeparators(QFileDialog::getOpenFileName(parent, caption, myDir, filter, &selectedFilter));
+
+ if(selectedSuffixOut)
+ {
+ /* Extract first suffix from filter pattern "Description (*.foo)" or "Description (*.foo *.bar ...) */
+ QRegExp filter_re(".* \\(\\*\\.(.*)[ \\)]");
+ QString selectedSuffix;
+ if(filter_re.exactMatch(selectedFilter))
+ {
+ selectedSuffix = filter_re.cap(1);
+ }
+ *selectedSuffixOut = selectedSuffix;
+ }
+ return result;
+}
+
Qt::ConnectionType blockingGUIThreadConnection()
{
- if(QThread::currentThread() != QCoreApplication::instance()->thread())
+ if(QThread::currentThread() != qApp->thread())
{
return Qt::BlockingQueuedConnection;
}
@@ -223,7 +332,7 @@ Qt::ConnectionType blockingGUIThreadConnection()
bool checkPoint(const QPoint &p, const QWidget *w)
{
- QWidget *atW = qApp->widgetAt(w->mapToGlobal(p));
+ QWidget *atW = QApplication::widgetAt(w->mapToGlobal(p));
if (!atW) return false;
return atW->topLevelWidget() == w;
}
@@ -258,11 +367,11 @@ bool ToolTipToRichTextFilter::eventFilter(QObject *obj, QEvent *evt)
{
QWidget *widget = static_cast<QWidget*>(obj);
QString tooltip = widget->toolTip();
- if(tooltip.size() > size_threshold && !tooltip.startsWith("<qt/>") && !Qt::mightBeRichText(tooltip))
+ if(tooltip.size() > size_threshold && !tooltip.startsWith("<qt") && !Qt::mightBeRichText(tooltip))
{
- // Prefix <qt/> to make sure Qt detects this as rich text
+ // Envelop with <qt></qt> to make sure Qt detects this as rich text
// Escape the current message as HTML and replace \n by <br>
- tooltip = "<qt/>" + HtmlEscape(tooltip, true);
+ tooltip = "<qt>" + HtmlEscape(tooltip, true) + "</qt>";
widget->setToolTip(tooltip);
return true;
}
@@ -404,55 +513,94 @@ bool SetStartOnSystemStartup(bool fAutoStart)
}
return true;
}
-#else
-// TODO: OSX startup stuff; see:
-// https://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html
-bool GetStartOnSystemStartup() { return false; }
-bool SetStartOnSystemStartup(bool fAutoStart) { return false; }
+#elif defined(Q_OS_MAC)
+// based on: https://github.com/Mozketo/LaunchAtLoginController/blob/master/LaunchAtLoginController.m
-#endif
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreServices/CoreServices.h>
-HelpMessageBox::HelpMessageBox(QWidget *parent) :
- QMessageBox(parent)
+LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl);
+LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl)
{
- header = tr("Bitcoin-Qt") + " " + tr("version") + " " +
- QString::fromStdString(FormatFullVersion()) + "\n\n" +
- tr("Usage:") + "\n" +
- " bitcoin-qt [" + tr("command-line options") + "] " + "\n";
+ // loop through the list of startup items and try to find the bitcoin app
+ CFArrayRef listSnapshot = LSSharedFileListCopySnapshot(list, NULL);
+ for(int i = 0; i < CFArrayGetCount(listSnapshot); i++) {
+ LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(listSnapshot, i);
+ UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
+ CFURLRef currentItemURL = NULL;
+ LSSharedFileListItemResolve(item, resolutionFlags, &currentItemURL, NULL);
+ if(currentItemURL && CFEqual(currentItemURL, findUrl)) {
+ // found
+ CFRelease(currentItemURL);
+ return item;
+ }
+ if(currentItemURL) {
+ CFRelease(currentItemURL);
+ }
+ }
+ return NULL;
+}
- coreOptions = QString::fromStdString(HelpMessage());
+bool GetStartOnSystemStartup()
+{
+ CFURLRef bitcoinAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
+ LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
+ LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl);
+ return !!foundItem; // return boolified object
+}
- 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";
+bool SetStartOnSystemStartup(bool fAutoStart)
+{
+ CFURLRef bitcoinAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
+ LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
+ LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl);
- setWindowTitle(tr("Bitcoin-Qt"));
- setTextFormat(Qt::PlainText);
- // setMinimumWidth is ignored for QMessageBox so put in non-breaking spaces to make it wider.
- setText(header + QString(QChar(0x2003)).repeated(50));
- setDetailedText(coreOptions + "\n" + uiOptions);
+ if(fAutoStart && !foundItem) {
+ // add bitcoin app to startup item list
+ LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst, NULL, NULL, bitcoinAppUrl, NULL, NULL);
+ }
+ else if(!fAutoStart && foundItem) {
+ // remove item
+ LSSharedFileListItemRemove(loginItems, foundItem);
+ }
+ return true;
}
+#else
+
+bool GetStartOnSystemStartup() { return false; }
+bool SetStartOnSystemStartup(bool fAutoStart) { return false; }
+
+#endif
-void HelpMessageBox::printToConsole()
+void saveWindowGeometry(const QString& strSetting, QWidget *parent)
{
- // On other operating systems, the expected action is to print the message to the console.
- QString strUsage = header + "\n" + coreOptions + "\n" + uiOptions;
- fprintf(stdout, "%s", strUsage.toStdString().c_str());
+ QSettings settings;
+ settings.setValue(strSetting + "Pos", parent->pos());
+ settings.setValue(strSetting + "Size", parent->size());
}
-void HelpMessageBox::showOrPrint()
+void restoreWindowGeometry(const QString& strSetting, const QSize& defaultSize, QWidget *parent)
{
-#if defined(WIN32)
- // On Windows, show a message box, as there is no stderr/stdout in windowed applications
- exec();
-#else
- // On other operating systems, print help text to console
- printToConsole();
-#endif
+ QSettings settings;
+ QPoint pos = settings.value(strSetting + "Pos").toPoint();
+ QSize size = settings.value(strSetting + "Size", defaultSize).toSize();
+
+ if (!pos.x() && !pos.y()) {
+ QRect screen = QApplication::desktop()->screenGeometry();
+ pos.setX((screen.width() - size.width()) / 2);
+ pos.setY((screen.height() - size.height()) / 2);
+ }
+
+ parent->resize(size);
+ parent->move(pos);
}
-} // namespace GUIUtil
+void setClipboard(const QString& str)
+{
+ QApplication::clipboard()->setText(str, QClipboard::Clipboard);
+ QApplication::clipboard()->setText(str, QClipboard::Selection);
+}
+} // namespace GUIUtil