forked from qt-creator/qt-creator
		
	
		
			
				
	
	
		
			287 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			287 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/***************************************************************************
 | 
						|
**
 | 
						|
** 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.3, 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 QList<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();
 | 
						|
}
 | 
						|
 |