diff options
Diffstat (limited to 'src/app/main.cpp')
-rw-r--r-- | src/app/main.cpp | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/src/app/main.cpp b/src/app/main.cpp new file mode 100644 index 0000000000..0247b1dde3 --- /dev/null +++ b/src/app/main.cpp @@ -0,0 +1,285 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ + +#include "qtsingleapplication.h" + +#include <extensionsystem/pluginmanager.h> +#include <extensionsystem/pluginspec.h> +#include <extensionsystem/iplugin.h> + +#include <QtCore/QDir> +#include <QtCore/QTextStream> +#include <QtCore/QFileInfo> +#include <QtCore/QDebug> +#include <QtCore/QTimer> + +#include <QtGui/QMessageBox> +#include <QtGui/QApplication> +#include <QtGui/QMainWindow> + +#ifdef Q_OS_DARWIN +# include <sys/resource.h> +#endif + +enum { OptionIndent =4, DescriptionIndent = 24 }; + +static const char *appNameC = "Qt Creator"; +static const char *corePluginNameC = "Core"; +static const char *fixedOptionsC = +" [OPTION]... [FILE]...\n" +"Options:\n" +" -help Display this help\n" +" -version Display program version\n" +" -client Attempt to connect to already running instance\n"; + +static const char *HELP_OPTION1 = "-h"; +static const char *HELP_OPTION2 = "-help"; +static const char *HELP_OPTION3 = "/h"; +static const char *HELP_OPTION4 = "--help"; +static const char *VERSION_OPTION = "-version"; +static const char *CLIENT_OPTION = "-client"; + +typedef QSet<ExtensionSystem::PluginSpec *> PluginSpecSet; + +// Helpers for displaying messages. Note that there is no console on Windows. +#ifdef Q_WS_WIN +// Format as <pre> HTML +static inline void toHtml(QString &t) +{ + t.replace(QLatin1Char('&'), QLatin1String("&")); + t.replace(QLatin1Char('<'), QLatin1String("<")); + t.replace(QLatin1Char('>'), QLatin1String(">")); + t.insert(0, QLatin1String("<html><pre>")); + t.append(QLatin1String("</pre></html>")); +} + +static void displayHelpText(QString t) // No console on Windows. +{ + toHtml(t); + QMessageBox::information(0, QLatin1String(appNameC), t); +} + +static void displayError(const QString &t) // No console on Windows. +{ + QMessageBox::critical(0, QLatin1String(appNameC), t); +} + +#else + +static void displayHelpText(const QString &t) +{ + qWarning(t.toUtf8().constData()); +} + +static void displayError(const QString &t) +{ + qCritical(t.toUtf8().constData()); +} + +#endif + +static void printVersion(const ExtensionSystem::PluginSpec *coreplugin, + const ExtensionSystem::PluginManager &pm) +{ + QString version; + QTextStream str(&version); + str << '\n' << appNameC << ' ' << coreplugin->version()<< " based on Qt " << qVersion() << "\n\n"; + pm.formatPluginVersions(str); + str << '\n' << coreplugin->copyright() << '\n'; + displayHelpText(version); +} + +static void printHelp(const QString &a0, const ExtensionSystem::PluginManager &pm) +{ + QString help; + QTextStream str(&help); + str << "Usage: " << a0 << fixedOptionsC; + ExtensionSystem::PluginManager::formatOptions(str, OptionIndent, DescriptionIndent); + pm.formatPluginOptions(str, OptionIndent, DescriptionIndent); + displayHelpText(help); +} + +static inline QString msgCoreLoadFailure(const QString &why) +{ + return QCoreApplication::translate("Application", "Failed to load core: %1").arg(why); +} + +static inline QString msgSendArgumentFailed() +{ + return QCoreApplication::translate("Application", "Unable to send command line arguments to the already running instance. It appears to be not responding."); +} + +// Prepare a remote argument: If it is a relative file, add the current directory +// since the the central instance might be running in a different directory. + +static inline QString prepareRemoteArgument(const QString &a) +{ + QFileInfo fi(a); + if (!fi.exists()) + return a; + if (fi.isRelative()) + return fi.absoluteFilePath(); + return a; +} + +// Send the arguments to an already running instance of Qt Creator +static bool sendArguments(SharedTools::QtSingleApplication &app, const QStringList &arguments) +{ + if (!arguments.empty()) { + // Send off arguments + const QStringList::const_iterator acend = arguments.constEnd(); + for (QStringList::const_iterator it = arguments.constBegin(); it != acend; ++it) { + if (!app.sendMessage(prepareRemoteArgument(*it))) { + displayError(msgSendArgumentFailed()); + return false; + } + } + } + // Special empty argument means: Show and raise (the slot just needs to be triggered) + if (!app.sendMessage(QString())) { + displayError(msgSendArgumentFailed()); + return false; + } + return true; +} + +static inline QStringList getPluginPaths() +{ + QStringList rc; + // Figure out root: Up one from 'bin' + QDir rootDir = QApplication::applicationDirPath(); + rootDir.cdUp(); + const QString rootDirPath = rootDir.canonicalPath(); + // 1) "lib" dir + QString pluginPath = rootDirPath; + pluginPath += QDir::separator(); + pluginPath += QLatin1String("lib"); + rc.push_back(pluginPath); + // 2) "PlugIns" + pluginPath = rootDirPath; + pluginPath += QDir::separator(); + pluginPath += QLatin1String("PlugIns"); + rc.push_back(pluginPath); + return rc; +} + +int main(int argc, char **argv) +{ +#ifdef Q_OS_DARWIN + // increase the number of file that can be opened in Qt Creator. + struct rlimit rl; + getrlimit(RLIMIT_NOFILE, &rl); + rl.rlim_cur = rl.rlim_max; + setrlimit(RLIMIT_NOFILE, &rl); +#endif + + SharedTools::QtSingleApplication app((QLatin1String(appNameC)), argc, argv); + // Load + ExtensionSystem::PluginManager pluginManager; + pluginManager.setFileExtension(QLatin1String("pluginspec")); + + const QStringList pluginPaths = getPluginPaths(); + pluginManager.setPluginPaths(pluginPaths); + + const QStringList arguments = app.arguments(); + QMap<QString,QString> foundAppOptions; + if (arguments.size() > 1) { + QMap<QString,bool> appOptions; + appOptions.insert(QLatin1String(HELP_OPTION1), false); + appOptions.insert(QLatin1String(HELP_OPTION2), false); + appOptions.insert(QLatin1String(HELP_OPTION3), false); + appOptions.insert(QLatin1String(HELP_OPTION4), false); + appOptions.insert(QLatin1String(VERSION_OPTION), false); + appOptions.insert(QLatin1String(CLIENT_OPTION), false); + QString errorMessage; + if (!pluginManager.parseOptions(arguments, + appOptions, + &foundAppOptions, + &errorMessage)) { + displayError(errorMessage); + printHelp(QFileInfo(app.applicationFilePath()).baseName(), pluginManager); + return -1; + } + } + + const PluginSpecSet plugins = pluginManager.plugins(); + ExtensionSystem::PluginSpec *coreplugin = 0; + foreach (ExtensionSystem::PluginSpec *spec, plugins) { + if (spec->name() == QLatin1String(corePluginNameC)) { + coreplugin = spec; + break; + } + } + if (!coreplugin) { + const QString reason = QCoreApplication::translate("Application", "Couldn't find 'Core.pluginspec' in %1").arg(pluginPaths.join(QLatin1String(","))); + displayError(msgCoreLoadFailure(reason)); + return 1; + } + if (coreplugin->hasError()) { + displayError(msgCoreLoadFailure(coreplugin->errorString())); + return 1; + } + if (foundAppOptions.contains(QLatin1String(VERSION_OPTION))) { + printVersion(coreplugin, pluginManager); + return 0; + } + if (foundAppOptions.contains(QLatin1String(HELP_OPTION1)) + || foundAppOptions.contains(QLatin1String(HELP_OPTION2)) + || foundAppOptions.contains(QLatin1String(HELP_OPTION3)) + || foundAppOptions.contains(QLatin1String(HELP_OPTION4))) { + printHelp(QFileInfo(app.applicationFilePath()).baseName(), pluginManager); + return 0; + } + + const bool isFirstInstance = !app.isRunning(); + if (!isFirstInstance && foundAppOptions.contains(QLatin1String(CLIENT_OPTION))) + return sendArguments(app, pluginManager.arguments()) ? 0 : -1; + + pluginManager.loadPlugins(); + if (coreplugin->hasError()) { + displayError(msgCoreLoadFailure(coreplugin->errorString())); + return 1; + } + if (isFirstInstance) { + // Set up lock and remote arguments for the first instance only. + // Silently fallback to unconnected instances for any subsequent + // instances. + app.initialize(); + QObject::connect(&app, SIGNAL(messageReceived(QString)), coreplugin->plugin(), SLOT(remoteArgument(QString))); + } + QObject::connect(&app, SIGNAL(fileOpenRequest(QString)), coreplugin->plugin(), SLOT(remoteArgument(QString))); + + // Do this after the event loop has started + QTimer::singleShot(100, &pluginManager, SLOT(startTests())); + return app.exec(); +} |