diff --git a/src/application.cpp b/src/application.cpp new file mode 100644 index 000000000..3fb079ec0 --- /dev/null +++ b/src/application.cpp @@ -0,0 +1,101 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2014 Vladimir Golovnev + * Copyright (C) 2006 Christophe Dumez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#include +#include +#include +#include +#include + +#include "application.h" +#include "preferences.h" + +Application::Application(const QString &id, int &argc, char **argv) +#ifndef DISABLE_GUI + : SessionApplication(id, argc, argv) +#else + : QtSingleCoreApplication(id, argc, argv) +#endif +{ +#if defined(Q_OS_MACX) && !defined(DISABLE_GUI) + if (QSysInfo::MacintoshVersion > QSysInfo::MV_10_8) { + // fix Mac OS X 10.9 (mavericks) font issue + // https://bugreports.qt-project.org/browse/QTBUG-32789 + QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande"); + } +#endif + setApplicationName("qBittorrent"); + initializeTranslation(); +#ifndef DISABLE_GUI + setStyleSheet("QStatusBar::item { border-width: 0; }"); + setQuitOnLastWindowClosed(false); +#endif +} + +void Application::initializeTranslation() +{ + Preferences* const pref = Preferences::instance(); + // Load translation + QString locale = pref->getLocale(); + if (locale.isEmpty()) { + locale = QLocale::system().name(); + pref->setLocale(locale); + } + + if (qtTranslator_.load( +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + QString::fromUtf8("qtbase_") + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath)) || + qtTranslator_.load( +#endif + QString::fromUtf8("qt_") + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) { + qDebug("Qt %s locale recognized, using translation.", qPrintable(locale)); + } + else { + qDebug("Qt %s locale unrecognized, using default (en).", qPrintable(locale)); + } + installTranslator(&qtTranslator_); + + if (translator_.load(QString::fromUtf8(":/lang/qbittorrent_") + locale)) { + qDebug("%s locale recognized, using translation.", qPrintable(locale)); + } + else { + qDebug("%s locale unrecognized, using default (en).", qPrintable(locale)); + } + installTranslator(&translator_); + +#ifndef DISABLE_GUI + if (locale.startsWith("ar") || locale.startsWith("he")) { + qDebug("Right to Left mode"); + setLayoutDirection(Qt::RightToLeft); + } + else { + setLayoutDirection(Qt::LeftToRight); + } +#endif +} diff --git a/src/application.h b/src/application.h new file mode 100644 index 000000000..f43235f6b --- /dev/null +++ b/src/application.h @@ -0,0 +1,59 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2014 Vladimir Golovnev + * Copyright (C) 2006 Christophe Dumez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#ifndef APPLICATION_H +#define APPLICATION_H + +#include +#include + +#ifndef DISABLE_GUI +#include "sessionapplication.h" +#else +#include "qtsinglecoreapplication.h" +#endif + +class Application +#ifndef DISABLE_GUI + : public SessionApplication +#else + : public QtSingleCoreApplication +#endif +{ +public: + Application(const QString &id, int &argc, char **argv); + +private: + QTranslator qtTranslator_; + QTranslator translator_; + + void initializeTranslation(); +}; + +#endif // APPLICATION_H diff --git a/src/main.cpp b/src/main.cpp index dbd6c24d1..a20162767 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,6 @@ /* - * Bittorrent Client using Qt4 and libtorrent. + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2014 Vladimir Golovnev * Copyright (C) 2006 Christophe Dumez * * This program is free software; you can redistribute it and/or @@ -28,52 +29,46 @@ * Contact : chris@qbittorrent.org */ -#include -#include -#include -#include #include #ifndef DISABLE_GUI -#if defined(QBT_STATIC_QT) +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef QBT_STATIC_QT #include #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) Q_IMPORT_PLUGIN(QICOPlugin) #else Q_IMPORT_PLUGIN(qico) #endif -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sessionapplication.h" +#endif // QBT_STATIC_QT #include "mainwindow.h" #include "ico.h" -#else -#include "qtsinglecoreapplication.h" +#else // DISABLE_GUI #include #include #include "headlessloader.h" -#endif +#endif // DISABLE_GUI -#include "preferences.h" -#if defined(Q_OS_UNIX) +#include "application.h" + +#ifdef Q_OS_UNIX #include #include #include "stacktrace.h" -#endif +#endif // Q_OS_UNIX #ifdef STACKTRACE_WIN #include #include "stacktrace_win.h" #include "stacktrace_win_dlg.h" -#endif +#endif //STACKTRACE_WIN #include #include "misc.h" @@ -83,54 +78,6 @@ Q_IMPORT_PLUGIN(qico) #error You seem to have updated QtSingleApplication without porting our custom QtSingleApplication::getRunningPid() function. Please see previous version to understate how it works. #endif -void displayUsage(char* prg_name) -{ - std::cout << qPrintable(QObject::tr("Usage:")) << std::endl; - std::cout << '\t' << prg_name << " --version: " << qPrintable(QObject::tr("displays program version")) << std::endl; -#ifndef DISABLE_GUI - std::cout << '\t' << prg_name << " --no-splash: " << qPrintable(QObject::tr("disable splash screen")) << std::endl; -#else - std::cout << '\t' << prg_name << " -d | --daemon: " << qPrintable(QObject::tr("run in daemon-mode (background)")) << std::endl; -#endif - std::cout << '\t' << prg_name << " --help: " << qPrintable(QObject::tr("displays this help message")) << std::endl; - std::cout << '\t' << prg_name << " --webui-port=x: " << qPrintable(QObject::tr("changes the webui port (current: %1)").arg(QString::number(Preferences::instance()->getWebUiPort()))) << std::endl; - std::cout << '\t' << prg_name << " " << qPrintable(QObject::tr("[files or urls]: downloads the torrents passed by the user (optional)")) << std::endl; -} - -bool userAgreesWithLegalNotice() -{ - Preferences* const pref = Preferences::instance(); - if (pref->getAcceptedLegal()) // Already accepted once - return true; -#ifdef DISABLE_GUI - std::cout << std::endl << "*** " << qPrintable(QObject::tr("Legal Notice")) << " ***" << std::endl; - std::cout << qPrintable(QObject::tr("qBittorrent is a file sharing program. When you run a torrent, its data will be made available to others by means of upload. Any content you share is your sole responsibility.\n\nNo further notices will be issued.")) << std::endl << std::endl; - std::cout << qPrintable(QObject::tr("Press %1 key to accept and continue...").arg("'y'")) << std::endl; - char ret = getchar(); // Read pressed key - if (ret == 'y' || ret == 'Y') { - // Save the answer - pref->setAcceptedLegal(true); - return true; - } - return false; -#else - QMessageBox msgBox; - msgBox.setText(QObject::tr("qBittorrent is a file sharing program. When you run a torrent, its data will be made available to others by means of upload. Any content you share is your sole responsibility.\n\nNo further notices will be issued.")); - msgBox.setWindowTitle(QObject::tr("Legal notice")); - msgBox.addButton(QObject::tr("Cancel"), QMessageBox::RejectRole); - QAbstractButton *agree_button = msgBox.addButton(QObject::tr("I Agree"), QMessageBox::AcceptRole); - msgBox.show(); // Need to be shown or to moveToCenter does not work - msgBox.move(misc::screenCenter(&msgBox)); - msgBox.exec(); - if (msgBox.clickedButton() == agree_button) { - // Save the answer - pref->setAcceptedLegal(true); - return true; - } - return false; -#endif -} - #if defined(Q_OS_UNIX) || defined(STACKTRACE_WIN) void sigintHandler(int) { @@ -185,199 +132,211 @@ void sigabrtHandler(int) } #endif -// Main -int main(int argc, char *argv[]) +#ifndef DISABLE_GUI +void showSplashScreen() { -#if defined(Q_OS_MACX) && !defined(DISABLE_GUI) - if (QSysInfo::MacintoshVersion > QSysInfo::MV_10_8) { - // fix Mac OS X 10.9 (mavericks) font issue - // https://bugreports.qt-project.org/browse/QTBUG-32789 - QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande"); - } + QPixmap splash_img(":/Icons/skin/splash.png"); + QPainter painter(&splash_img); + QString version = VERSION; + painter.setPen(QPen(Qt::white)); + painter.setFont(QFont("Arial", 22, QFont::Black)); + painter.drawText(224 - painter.fontMetrics().width(version), 270, version); + QSplashScreen *splash = new QSplashScreen(splash_img, Qt::WindowStaysOnTopHint); + QTimer::singleShot(1500, splash, SLOT(deleteLater())); + splash->show(); + qApp->processEvents(); +} #endif - // Create Application - QString uid = misc::getUserIDString(); -#ifdef DISABLE_GUI - bool shouldDaemonize = false; - for (int i = 1; i < argc; i++) { - if (strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--daemon") == 0) { - shouldDaemonize = true; - argc--; - for (int j = i; j < argc; j++) { - argv[j] = argv[j + 1]; - } - i--; - } - } - QtSingleCoreApplication app("qBittorrent-"+uid, argc, argv); +void displayVersion() +{ + std::cout << qPrintable(qApp->applicationName()) << " " << VERSION << std::endl; +} + +void displayUsage(const char *prg_name) +{ + std::cout << qPrintable(QObject::tr("Usage:")) << std::endl; + std::cout << '\t' << prg_name << " --version: " << qPrintable(QObject::tr("displays program version")) << std::endl; +#ifndef DISABLE_GUI + std::cout << '\t' << prg_name << " --no-splash: " << qPrintable(QObject::tr("disable splash screen")) << std::endl; #else - SessionApplication app("qBittorrent-"+uid, argc, argv); + std::cout << '\t' << prg_name << " -d | --daemon: " << qPrintable(QObject::tr("run in daemon-mode (background)")) << std::endl; #endif + std::cout << '\t' << prg_name << " --help: " << qPrintable(QObject::tr("displays this help message")) << std::endl; + std::cout << '\t' << prg_name << " --webui-port=x: " << qPrintable(QObject::tr("changes the webui port (current: %1)").arg(QString::number(Preferences::instance()->getWebUiPort()))) << std::endl; + std::cout << '\t' << prg_name << " " << qPrintable(QObject::tr("[files or urls]: downloads the torrents passed by the user (optional)")) << std::endl; +} - // Check if qBittorrent is already running for this user - if (app.isRunning()) { - qDebug("qBittorrent is already running for this user."); - // Read torrents given on command line -#ifdef Q_OS_WIN - DWORD pid = (DWORD)app.getRunningPid(); - if (pid > 0) { - BOOL b = AllowSetForegroundWindow(pid); - qDebug("AllowSetForegroundWindow() returns %s", b ? "TRUE" : "FALSE"); - } +void parseCommandLine( + bool& showVersion, bool& showUsage, +#ifndef DISABLE_GUI + bool& noSplash, +#else + bool& shouldDaemonize, #endif - QStringList torrentCmdLine = app.arguments(); - //Pass program parameters if any - QString message; - QFileInfo torrentPath; - for (int a = 1; a < torrentCmdLine.size(); ++a) { - if (torrentCmdLine[a].startsWith("--")) continue; - - torrentPath.setFile(torrentCmdLine[a]); - if (torrentPath.exists()) - message += torrentPath.absoluteFilePath(); - else - message += torrentCmdLine[a]; + QStringList& torrents + ) +{ + // Default values + showVersion = false; + showUsage = false; +#ifndef DISABLE_GUI + noSplash = Preferences::instance()->isSlashScreenDisabled(); +#else + shouldDaemonize = false; +#endif + torrents.clear(); - if (a < argc-1) - message += "|"; - } + QStringList appArguments = qApp->arguments(); - if (!message.isEmpty()) { - qDebug("Passing program parameters to running instance..."); - qDebug("Message: %s", qPrintable(message)); - app.sendMessage(message); + for (int i = 1; i < appArguments.size(); ++i) { + QString& arg = appArguments[i]; + + if (arg == "--version") { + showVersion = true; } - else { // Raise main window - app.sendMessage("qbt://show"); + else if (arg == "--usage") { + showUsage = true; + } + else if (arg.startsWith("--webui-port=")) { + QStringList parts = arg.split("="); + if (parts.size() == 2) { + bool ok = false; + int new_port = parts.last().toInt(&ok); + if (ok && (new_port > 0) && (new_port <= 65535)) + Preferences::instance()->setWebUiPort(new_port); + } } - - return EXIT_SUCCESS; - } - - srand(time(0)); - Preferences* const pref = Preferences::instance(); #ifndef DISABLE_GUI - bool no_splash = false; + else if (arg == "--no-splash") { + noSplash = true; + } #else - if (shouldDaemonize && daemon(1, 0) != 0) { - qCritical("Something went wrong while daemonizing, exiting..."); - return EXIT_FAILURE; - } + else if ((arg == "-d") || (arg == "--daemon")) { + shouldDaemonize = true; + } #endif + else if (!arg.startsWith("--")) { + QFileInfo torrentPath; + torrentPath.setFile(arg); - // Load translation - QString locale = pref->getLocale(); - QTranslator qtTranslator; - QTranslator translator; - if (locale.isEmpty()) { - locale = QLocale::system().name(); - pref->setLocale(locale); - } - - if (qtTranslator.load( -#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) - QString::fromUtf8("qtbase_") + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath)) || - qtTranslator.load( -#endif - QString::fromUtf8("qt_") + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) { - qDebug("Qt %s locale recognized, using translation.", qPrintable(locale)); - } - else { - qDebug("Qt %s locale unrecognized, using default (en).", qPrintable(locale)); + if (torrentPath.exists()) + torrents += torrentPath.absoluteFilePath(); + else + torrents += arg; + } } - app.installTranslator(&qtTranslator); +} - if (translator.load(QString::fromUtf8(":/lang/qbittorrent_") + locale)) { - qDebug("%s locale recognized, using translation.", qPrintable(locale)); - } - else { - qDebug("%s locale unrecognized, using default (en).", qPrintable(locale)); - } - app.installTranslator(&translator); +bool userAgreesWithLegalNotice() +{ + Preferences* const pref = Preferences::instance(); + if (pref->getAcceptedLegal()) // Already accepted once + return true; -#ifndef DISABLE_GUI - if (locale.startsWith("ar") || locale.startsWith("he")) { - qDebug("Right to Left mode"); - app.setLayoutDirection(Qt::RightToLeft); +#ifdef DISABLE_GUI + std::cout << std::endl << "*** " << qPrintable(QObject::tr("Legal Notice")) << " ***" << std::endl; + std::cout << qPrintable(QObject::tr("qBittorrent is a file sharing program. When you run a torrent, its data will be made available to others by means of upload. Any content you share is your sole responsibility.\n\nNo further notices will be issued.")) << std::endl << std::endl; + std::cout << qPrintable(QObject::tr("Press %1 key to accept and continue...").arg("'y'")) << std::endl; + char ret = getchar(); // Read pressed key + if (ret == 'y' || ret == 'Y') { + // Save the answer + pref->setAcceptedLegal(true); + return true; } - else { - app.setLayoutDirection(Qt::LeftToRight); +#else + QMessageBox msgBox; + msgBox.setText(QObject::tr("qBittorrent is a file sharing program. When you run a torrent, its data will be made available to others by means of upload. Any content you share is your sole responsibility.\n\nNo further notices will be issued.")); + msgBox.setWindowTitle(QObject::tr("Legal notice")); + msgBox.addButton(QObject::tr("Cancel"), QMessageBox::RejectRole); + QAbstractButton *agree_button = msgBox.addButton(QObject::tr("I Agree"), QMessageBox::AcceptRole); + msgBox.show(); // Need to be shown or to moveToCenter does not work + msgBox.move(misc::screenCenter(&msgBox)); + msgBox.exec(); + if (msgBox.clickedButton() == agree_button) { + // Save the answer + pref->setAcceptedLegal(true); + return true; } #endif - app.setApplicationName(QString::fromUtf8("qBittorrent")); - - // Check for executable parameters - if (argc > 1) { - if (QString::fromLocal8Bit(argv[1]) == QString::fromUtf8("--version")) { - std::cout << "qBittorrent " << VERSION << '\n'; - return EXIT_SUCCESS; - } - - if (QString::fromLocal8Bit(argv[1]) == QString::fromUtf8("--help")) { - displayUsage(argv[0]); - return EXIT_SUCCESS; - } + return false; +} - for (int i = 1; i < argc; ++i) { +// Main +int main(int argc, char *argv[]) +{ + // We must save it here because QApplication constructor may change it + bool isOneArg = (argc == 2); + bool showVersion; + bool showUsage; #ifndef DISABLE_GUI - if (QString::fromLocal8Bit(argv[i]) == QString::fromUtf8("--no-splash")) { - no_splash = true; - } - else { + bool noSplash; +#else + bool shouldDaemonize; #endif - if (QString::fromLocal8Bit(argv[i]).startsWith("--webui-port=")) { - QStringList parts = QString::fromLocal8Bit(argv[i]).split("="); - if (parts.size() == 2) { - bool ok = false; - int new_port = parts.last().toInt(&ok); - if (ok && new_port > 0 && new_port <= 65535) { - Preferences::instance()->setWebUiPort(new_port); - } - } - } + QStringList torrents; + + // Create Application + Application app("qBittorrent-" + misc::getUserIDString(), argc, argv); + #ifndef DISABLE_GUI - } + parseCommandLine(showVersion, showUsage, noSplash, torrents); +#else + parseCommandLine(showVersion, showUsage, shouldDaemonize, torrents); #endif - } - } -#ifndef DISABLE_GUI - if (pref->isSlashScreenDisabled()) { - no_splash = true; - } + if (showVersion) + displayVersion(); - QSplashScreen *splash = 0; - if (!no_splash) { - QPixmap splash_img(":/Icons/skin/splash.png"); - QPainter painter(&splash_img); - QString version = VERSION; - painter.setPen(QPen(Qt::white)); - painter.setFont(QFont("Arial", 22, QFont::Black)); - painter.drawText(224 - painter.fontMetrics().width(version), 270, version); - splash = new QSplashScreen(splash_img, Qt::WindowStaysOnTopHint); - QTimer::singleShot(1500, splash, SLOT(deleteLater())); - splash->show(); - app.processEvents(); - } -#endif + if (showUsage) + displayUsage(argv[0]); + + // If only one parameter is present and it is "--version" + // or "--help", program exits after printing appropriate message. + if (isOneArg && (showVersion || showUsage)) + return EXIT_SUCCESS; // Set environment variable if (!qputenv("QBITTORRENT", QByteArray(VERSION))) { std::cerr << "Couldn't set environment variable...\n"; } -#ifndef DISABLE_GUI - app.setStyleSheet("QStatusBar::item { border-width: 0; }"); + if (!userAgreesWithLegalNotice()) + return EXIT_SUCCESS; + + // Check if qBittorrent is already running for this user + if (app.isRunning()) { + qDebug("qBittorrent is already running for this user."); +#ifdef Q_OS_WIN + DWORD pid = (DWORD)app.getRunningPid(); + if (pid > 0) { + BOOL b = AllowSetForegroundWindow(pid); + qDebug("AllowSetForegroundWindow() returns %s", b ? "TRUE" : "FALSE"); + } #endif + if (!torrents.isEmpty()) { + QString message = torrents.join("|"); + qDebug("Passing program parameters to running instance..."); + qDebug("Message: %s", qPrintable(message)); + app.sendMessage(message); + } + else { // Raise main window + app.sendMessage("qbt://show"); + } - if (!userAgreesWithLegalNotice()) { return EXIT_SUCCESS; } -#ifndef DISABLE_GUI - app.setQuitOnLastWindowClosed(false); + srand(time(0)); +#ifdef DISABLE_GUI + if (shouldDaemonize && (daemon(1, 0) != 0)) { + qCritical("Something went wrong while daemonizing, exiting..."); + return EXIT_FAILURE; + } +#else + if (!noSplash) + showSplashScreen(); #endif #if defined(Q_OS_UNIX) || defined(STACKTRACE_WIN) @@ -387,16 +346,6 @@ int main(int argc, char *argv[]) signal(SIGSEGV, sigsegvHandler); #endif - // Read torrents given on command line - QStringList torrents; - QStringList appArguments = app.arguments(); - for (int i = 1; i < appArguments.size(); ++i) { - if (!appArguments[i].startsWith("--")) { - qDebug() << "Command line argument:" << appArguments[i]; - torrents << appArguments[i]; - } - } - #ifndef DISABLE_GUI MainWindow window(0, torrents); QObject::connect(&app, SIGNAL(messageReceived(const QString&)), diff --git a/src/src.pro b/src/src.pro index 34eb13e7b..62d5a1eaa 100644 --- a/src/src.pro +++ b/src/src.pro @@ -4,7 +4,7 @@ CONFIG += qt thread # Windows specific configuration win32 { - include(../winconf.pri) + include(../winconf.pri) } # Mac specific configuration @@ -109,7 +109,8 @@ HEADERS += misc.h \ scannedfoldersmodel.h \ qinisettings.h \ smtp.h \ - dnsupdater.h + dnsupdater.h \ + application.h SOURCES += main.cpp \ downloadthread.cpp \ @@ -118,7 +119,8 @@ SOURCES += main.cpp \ misc.cpp \ fs_utils.cpp \ smtp.cpp \ - dnsupdater.cpp + dnsupdater.cpp \ + application.cpp nox { HEADERS += headlessloader.h