diff options
Diffstat (limited to 'src/qt')
-rw-r--r-- | src/qt/bitcoin.cpp | 62 | ||||
-rw-r--r-- | src/qt/bitcoingui.cpp | 1 | ||||
-rw-r--r-- | src/qt/forms/askpassphrasedialog.ui | 3 | ||||
-rw-r--r-- | src/qt/forms/qrcodedialog.ui | 4 | ||||
-rw-r--r-- | src/qt/guiutil.cpp | 145 | ||||
-rw-r--r-- | src/qt/guiutil.h | 3 | ||||
-rw-r--r-- | src/qt/optionsmodel.cpp | 5 | ||||
-rw-r--r-- | src/qt/overviewpage.cpp | 12 | ||||
-rw-r--r-- | src/qt/overviewpage.h | 3 | ||||
-rw-r--r-- | src/qt/sendcoinsdialog.cpp | 10 | ||||
-rw-r--r-- | src/qt/transactionview.cpp | 10 | ||||
-rw-r--r-- | src/qt/transactionview.h | 1 |
12 files changed, 243 insertions, 16 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 74969fc6f3..ae9bf2a4b9 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -157,6 +157,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())); 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/guiutil.cpp b/src/qt/guiutil.cpp index 32bce88330..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 @@ -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/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/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&); }; |