<commit_before>/* This file is part of Zanshin

   Copyright 2014 Kevin Ottens <ervin@kde.org>

   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) version 3 or any later version
   accepted by the membership of KDE e.V. (or its successor approved
   by the membership of KDE e.V.), which shall act as a proxy
   defined in Section 14 of version 3 of the license.

   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.
*/

#include <QApplication>
#include <QBoxLayout>
#include <QDockWidget>
#include <QMenu>
#include <QProcess>
#include <QToolBar>
#include <QToolButton>

#include <KConfigGroup>
#include <KSharedConfig>

#include <KDE/KConfigGroup>
#include <KDE/KMainWindow>

#include "widgets/applicationcomponents.h"
#include "widgets/availablepagesview.h"
#include "widgets/availablesourcesview.h"
#include "widgets/datasourcecombobox.h"
#include "widgets/editorview.h"
#include "widgets/pageview.h"

#include "presentation/applicationmodel.h"

#include "dependencies.h"

#include <iostream>

int main(int argc, char **argv)
{
    App::initializeDependencies();

    QApplication app(argc, argv);

    KSharedConfig::Ptr config = KSharedConfig::openConfig("zanshin-migratorrc");
    KConfigGroup group = config->group("Migrations");
    if (!group.readEntry("Migrated021Projects", false)) {
        std::cerr << "Migrating data from zanshin 0.2, please wait..." << std::endl;
        QProcess proc;
        proc.start("zanshin-migrator");
        proc.waitForFinished();
        std::cerr << "Migration done" << std::endl;
    }

    auto widget = new QWidget;
    auto components = new Widgets::ApplicationComponents(widget);
    components->setModel(new Presentation::ApplicationModel(components));

    QVBoxLayout *layout = new QVBoxLayout;

    QHBoxLayout *hbox = new QHBoxLayout;
    hbox->addWidget(components->defaultTaskSourceCombo());
    hbox->addWidget(components->defaultNoteSourceCombo());

    layout->addLayout(hbox);
    layout->addWidget(components->pageView());

    widget->setLayout(layout);

    auto sourcesDock = new QDockWidget(QObject::tr("Sources"));
    sourcesDock->setObjectName("sourcesDock");
    sourcesDock->setWidget(components->availableSourcesView());

    auto pagesDock = new QDockWidget(QObject::tr("Pages"));
    pagesDock->setObjectName("pagesDock");
    pagesDock->setWidget(components->availablePagesView());

    auto editorDock = new QDockWidget(QObject::tr("Editor"));
    editorDock->setObjectName("editorDock");
    editorDock->setWidget(components->editorView());

    auto configureMenu = new QMenu(widget);
    foreach (QAction *action, components->configureActions()) {
        configureMenu->addAction(action);
    }

    auto configureButton = new QToolButton(widget);
    configureButton->setIcon(QIcon::fromTheme("configure"));
    configureButton->setText(QObject::tr("Settings"));
    configureButton->setToolTip(configureButton ->text());
    configureButton->setPopupMode(QToolButton::InstantPopup);
    configureButton->setMenu(configureMenu);

    auto window = new KMainWindow;
    window->resize(1024, 600);
    window->setAutoSaveSettings("MainWindow");
    window->setCentralWidget(widget);

    QToolBar *mainToolBar = window->addToolBar(QObject::tr("Main"));
    mainToolBar->setObjectName("mainToolBar");
    mainToolBar->addWidget(configureButton);

    window->addDockWidget(Qt::RightDockWidgetArea, editorDock);
    window->addDockWidget(Qt::LeftDockWidgetArea, pagesDock);
    window->addDockWidget(Qt::LeftDockWidgetArea, sourcesDock);

    window->show();

    return app.exec();
}
<commit_msg>Create main component data, to avoid warning in KGlobal::locale() later.<commit_after>/* This file is part of Zanshin

   Copyright 2014 Kevin Ottens <ervin@kde.org>

   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) version 3 or any later version
   accepted by the membership of KDE e.V. (or its successor approved
   by the membership of KDE e.V.), which shall act as a proxy
   defined in Section 14 of version 3 of the license.

   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.
*/

#include <QApplication>
#include <QBoxLayout>
#include <QDockWidget>
#include <QMenu>
#include <QProcess>
#include <QToolBar>
#include <QToolButton>

#include <KConfigGroup>
#include <KSharedConfig>
#include <KComponentData>
#include <KMainWindow>

#include "widgets/applicationcomponents.h"
#include "widgets/availablepagesview.h"
#include "widgets/availablesourcesview.h"
#include "widgets/datasourcecombobox.h"
#include "widgets/editorview.h"
#include "widgets/pageview.h"

#include "presentation/applicationmodel.h"

#include "dependencies.h"

#include <iostream>

int main(int argc, char **argv)
{
    App::initializeDependencies();

    QApplication app(argc, argv);

    KComponentData mainComponentData("zanshin");

    KSharedConfig::Ptr config = KSharedConfig::openConfig("zanshin-migratorrc");
    KConfigGroup group = config->group("Migrations");
    if (!group.readEntry("Migrated021Projects", false)) {
        std::cerr << "Migrating data from zanshin 0.2, please wait..." << std::endl;
        QProcess proc;
        proc.start("zanshin-migrator");
        proc.waitForFinished();
        std::cerr << "Migration done" << std::endl;
    }

    auto widget = new QWidget;
    auto components = new Widgets::ApplicationComponents(widget);
    components->setModel(new Presentation::ApplicationModel(components));

    QVBoxLayout *layout = new QVBoxLayout;

    QHBoxLayout *hbox = new QHBoxLayout;
    hbox->addWidget(components->defaultTaskSourceCombo());
    hbox->addWidget(components->defaultNoteSourceCombo());

    layout->addLayout(hbox);
    layout->addWidget(components->pageView());

    widget->setLayout(layout);

    auto sourcesDock = new QDockWidget(QObject::tr("Sources"));
    sourcesDock->setObjectName("sourcesDock");
    sourcesDock->setWidget(components->availableSourcesView());

    auto pagesDock = new QDockWidget(QObject::tr("Pages"));
    pagesDock->setObjectName("pagesDock");
    pagesDock->setWidget(components->availablePagesView());

    auto editorDock = new QDockWidget(QObject::tr("Editor"));
    editorDock->setObjectName("editorDock");
    editorDock->setWidget(components->editorView());

    auto configureMenu = new QMenu(widget);
    foreach (QAction *action, components->configureActions()) {
        configureMenu->addAction(action);
    }

    auto configureButton = new QToolButton(widget);
    configureButton->setIcon(QIcon::fromTheme("configure"));
    configureButton->setText(QObject::tr("Settings"));
    configureButton->setToolTip(configureButton ->text());
    configureButton->setPopupMode(QToolButton::InstantPopup);
    configureButton->setMenu(configureMenu);

    auto window = new KMainWindow;
    window->resize(1024, 600);
    window->setAutoSaveSettings("MainWindow");
    window->setCentralWidget(widget);

    QToolBar *mainToolBar = window->addToolBar(QObject::tr("Main"));
    mainToolBar->setObjectName("mainToolBar");
    mainToolBar->addWidget(configureButton);

    window->addDockWidget(Qt::RightDockWidgetArea, editorDock);
    window->addDockWidget(Qt::LeftDockWidgetArea, pagesDock);
    window->addDockWidget(Qt::LeftDockWidgetArea, sourcesDock);

    window->show();

    return app.exec();
}
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#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 <QtCore/QLibraryInfo>
#include <QtCore/QTranslator>
#include <QtCore/QSettings>
#include <QtCore/QVariant>

#include <QtNetwork/QNetworkProxyFactory>

#include <QtGui/QMessageBox>
#include <QtGui/QApplication>
#include <QtGui/QMainWindow>

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_OS_WIN
// Format as
 HTML
static inline void toHtml(QString &t)
{
    t.replace(QLatin1Char('&'), QLatin1String("&"));
    t.replace(QLatin1Char('<'), QLatin1String("<"));
    t.replace(QLatin1Char('>'), QLatin1String(">"));
    t.insert(0, QLatin1String("
"));
    t.append(QLatin1String("
"));
}

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("%s", qPrintable(t));
}

static void displayError(const QString &t)
{
    qCritical("%s", qPrintable(t));
}

#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.");
}

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) "plugins" (Win/Linux)
    QString pluginPath = rootDirPath;
    pluginPath += QLatin1Char('/');
    pluginPath += QLatin1String(IDE_LIBRARY_BASENAME);
    pluginPath += QLatin1Char('/');
    pluginPath += QLatin1String("qtcreator");
    pluginPath += QLatin1Char('/');
    pluginPath += QLatin1String("plugins");
    rc.push_back(pluginPath);
    // 2) "PlugIns" (OS X)
    pluginPath = rootDirPath;
    pluginPath += QLatin1Char('/');
    pluginPath += QLatin1String("PlugIns");
    rc.push_back(pluginPath);
    return rc;
}

#ifdef Q_OS_MAC
#  define SHARE_PATH "/../Resources"
#else
#  define SHARE_PATH "/../share/qtcreator"
#endif

int main(int argc, char **argv)
{
#ifdef Q_OS_MAC
    // 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);

    QTranslator translator;
    QTranslator qtTranslator;
    QString locale = QLocale::system().name();

    // Must be done before any QSettings class is created
    QSettings::setPath(QSettings::IniFormat, QSettings::SystemScope,
            QCoreApplication::applicationDirPath()+QLatin1String(SHARE_PATH));

    // Work around bug in QSettings which gets triggered on Windows & Mac only
#ifdef Q_OS_MAC
    QSettings::setPath(QSettings::IniFormat, QSettings::UserScope,
            QDir::homePath()+"/.config");
#endif
#ifdef Q_OS_WIN
    QSettings::setPath(QSettings::IniFormat, QSettings::UserScope,
            qgetenv("appdata"));
#endif

    // keep this in sync with the MainWindow ctor in coreplugin/mainwindow.cpp
    const QSettings settings(QSettings::IniFormat, QSettings::UserScope,
                                 QLatin1String("Nokia"), QLatin1String("QtCreator"));
    locale = settings.value("General/OverrideLanguage", locale).toString();

    const QString &creatorTrPath = QCoreApplication::applicationDirPath()
                        + QLatin1String(SHARE_PATH "/translations");
    if (translator.load(QLatin1String("qtcreator_") + locale, creatorTrPath)) {
        const QString &qtTrPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
        const QString &qtTrFile = QLatin1String("qt_") + locale;
        // Binary installer puts Qt tr files into creatorTrPath
        if (qtTranslator.load(qtTrFile, qtTrPath) || qtTranslator.load(qtTrFile, creatorTrPath)) {
            app.installTranslator(&translator);
            app.installTranslator(&qtTranslator);
            app.setProperty("qtc_locale", locale);
        } else {
            translator.load(QString()); // unload()
        }
    }

    // Make sure we honor the system's proxy settings
    QNetworkProxyFactory::setUseSystemConfiguration(true);

    // 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) {
        QString nativePaths = QDir::toNativeSeparators(pluginPaths.join(QLatin1String(",")));
        const QString reason = QCoreApplication::translate("Application", "Could not find 'Core.pluginspec' in %1").arg(nativePaths);
        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))) {
        if (!app.sendMessage(pluginManager.serializedArguments())) {
            displayError(msgSendArgumentFailed());
            return -1;
        }
        return 0;
    }

    pluginManager.loadPlugins();
    if (coreplugin->hasError()) {
        displayError(msgCoreLoadFailure(coreplugin->errorString()));
        return 1;
    }
    {
        QStringList errors;
        foreach (ExtensionSystem::PluginSpec *p, pluginManager.plugins())
            if (p->hasError())
                errors.append(p->errorString());
        if (!errors.isEmpty())
            QMessageBox::warning(0,
                QCoreApplication::translate("Application", "Qt Creator - Plugin loader messages"),
                errors.join(QString::fromLatin1("\n\n")));
    }

    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)),
                         &pluginManager, SLOT(remoteArguments(QString)));
    }
    QObject::connect(&app, SIGNAL(fileOpenRequest(QString)), coreplugin->plugin(), SLOT(fileOpenRequest(QString)));

    // Do this after the event loop has started
    QTimer::singleShot(100, &pluginManager, SLOT(startTests()));
    return app.exec();
}

<commit_msg>remove startup error messages from plugins that are disabled by user User can still see errors in About Plugins for disabled ones, too<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#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 <QtCore/QLibraryInfo>
#include <QtCore/QTranslator>
#include <QtCore/QSettings>
#include <QtCore/QVariant>

#include <QtNetwork/QNetworkProxyFactory>

#include <QtGui/QMessageBox>
#include <QtGui/QApplication>
#include <QtGui/QMainWindow>

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_OS_WIN
// Format as
 HTML
static inline void toHtml(QString &t)
{
    t.replace(QLatin1Char('&'), QLatin1String("&"));
    t.replace(QLatin1Char('<'), QLatin1String("<"));
    t.replace(QLatin1Char('>'), QLatin1String(">"));
    t.insert(0, QLatin1String("
"));
    t.append(QLatin1String("
"));
}

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("%s", qPrintable(t));
}

static void displayError(const QString &t)
{
    qCritical("%s", qPrintable(t));
}

#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.");
}

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) "plugins" (Win/Linux)
    QString pluginPath = rootDirPath;
    pluginPath += QLatin1Char('/');
    pluginPath += QLatin1String(IDE_LIBRARY_BASENAME);
    pluginPath += QLatin1Char('/');
    pluginPath += QLatin1String("qtcreator");
    pluginPath += QLatin1Char('/');
    pluginPath += QLatin1String("plugins");
    rc.push_back(pluginPath);
    // 2) "PlugIns" (OS X)
    pluginPath = rootDirPath;
    pluginPath += QLatin1Char('/');
    pluginPath += QLatin1String("PlugIns");
    rc.push_back(pluginPath);
    return rc;
}

#ifdef Q_OS_MAC
#  define SHARE_PATH "/../Resources"
#else
#  define SHARE_PATH "/../share/qtcreator"
#endif

int main(int argc, char **argv)
{
#ifdef Q_OS_MAC
    // 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);

    QTranslator translator;
    QTranslator qtTranslator;
    QString locale = QLocale::system().name();

    // Must be done before any QSettings class is created
    QSettings::setPath(QSettings::IniFormat, QSettings::SystemScope,
            QCoreApplication::applicationDirPath()+QLatin1String(SHARE_PATH));

    // Work around bug in QSettings which gets triggered on Windows & Mac only
#ifdef Q_OS_MAC
    QSettings::setPath(QSettings::IniFormat, QSettings::UserScope,
            QDir::homePath()+"/.config");
#endif
#ifdef Q_OS_WIN
    QSettings::setPath(QSettings::IniFormat, QSettings::UserScope,
            qgetenv("appdata"));
#endif

    // keep this in sync with the MainWindow ctor in coreplugin/mainwindow.cpp
    const QSettings settings(QSettings::IniFormat, QSettings::UserScope,
                                 QLatin1String("Nokia"), QLatin1String("QtCreator"));
    locale = settings.value("General/OverrideLanguage", locale).toString();

    const QString &creatorTrPath = QCoreApplication::applicationDirPath()
                        + QLatin1String(SHARE_PATH "/translations");
    if (translator.load(QLatin1String("qtcreator_") + locale, creatorTrPath)) {
        const QString &qtTrPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
        const QString &qtTrFile = QLatin1String("qt_") + locale;
        // Binary installer puts Qt tr files into creatorTrPath
        if (qtTranslator.load(qtTrFile, qtTrPath) || qtTranslator.load(qtTrFile, creatorTrPath)) {
            app.installTranslator(&translator);
            app.installTranslator(&qtTranslator);
            app.setProperty("qtc_locale", locale);
        } else {
            translator.load(QString()); // unload()
        }
    }

    // Make sure we honor the system's proxy settings
    QNetworkProxyFactory::setUseSystemConfiguration(true);

    // 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) {
        QString nativePaths = QDir::toNativeSeparators(pluginPaths.join(QLatin1String(",")));
        const QString reason = QCoreApplication::translate("Application", "Could not find 'Core.pluginspec' in %1").arg(nativePaths);
        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))) {
        if (!app.sendMessage(pluginManager.serializedArguments())) {
            displayError(msgSendArgumentFailed());
            return -1;
        }
        return 0;
    }

    pluginManager.loadPlugins();
    if (coreplugin->hasError()) {
        displayError(msgCoreLoadFailure(coreplugin->errorString()));
        return 1;
    }
    {
        QStringList errors;
        foreach (ExtensionSystem::PluginSpec *p, pluginManager.plugins())
            // only show errors on startup if plugin is enabled.
            if (p->hasError() && p->isEnabled() && !p->isDisabledByDependency())
                errors.append(p->name() + "\n" + p->errorString());
        if (!errors.isEmpty())
            QMessageBox::warning(0,
                QCoreApplication::translate("Application", "Qt Creator - Plugin loader messages"),
                errors.join(QString::fromLatin1("\n\n")));
    }

    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)),
                         &pluginManager, SLOT(remoteArguments(QString)));
    }
    QObject::connect(&app, SIGNAL(fileOpenRequest(QString)), coreplugin->plugin(), SLOT(fileOpenRequest(QString)));

    // Do this after the event loop has started
    QTimer::singleShot(100, &pluginManager, SLOT(startTests()));
    return app.exec();
}

<|endoftext|>


<commit_before>#include <stdio.h>
#include <node.h>
#include <v8.h>
#include <string>
#include "Types.h"
#include "JuliaExecEnv.h"

using namespace std;
using namespace v8;

static JuliaExecEnv *J = 0;

void returnNull(const FunctionCallbackInfo<Value> &args,Isolate *I)
{
   args.GetReturnValue().SetNull();
}

void returnString(const FunctionCallbackInfo<Value> &args,Isolate *I,const string &s)
{
   args.GetReturnValue().Set(String::NewFromUtf8(I,s.c_str()));
}

void callback(const FunctionCallbackInfo<Value>& args,Isolate *I,const Local<Function> &cb,int argc,Local<Value> *argv)
{
  cb->Call(I->GetCurrentContext()->Global(),argc,argv);
}

void buildPrimitive(Isolate *I,const nj::Primitive &primitive,int index,Local<Value> *argv)
{
   switch(primitive.type()->getId())
   {
      case nj::null_type:
printf("arg is null\n");
         argv[index] = Null(I);
      break;
      case nj::boolean_type:
printf("arg is %d\n",primitive.toBoolean());
         argv[index] = Boolean::New(I,primitive.toBoolean());
      break;
      case nj::int_type:
printf("arg is %lld\n",primitive.toInt());
         argv[index] = Number::New(I,primitive.toInt());
      break;
      case nj::float_type:
printf("arg is %f\n",primitive.toFloat());
         argv[index] = Number::New(I,primitive.toFloat());
      break;
      case nj::string_type:
printf("arg is %s\n",primitive.toString().c_str());
         argv[index] = String::NewFromUtf8(I,primitive.toString().c_str());
      break;
   }
}

void buildArray(Isolate *I,const shared_ptr<nj::Value> &value,Local<Value> &arg)
{
   const nj::Array_t *array_type = static_cast<const nj::Array_t*>(value->type());
   const nj::Type *element_type = array_type->getElementType();

   switch(element_type->getId())
   {
      case nj::float_type:
      {
         const nj::Array<double,nj::Float_t> &array = static_cast<const nj::Array<double,nj::Float_t>&>(*value);

         if(array.dims().size() == 1)
         {
            size_t size0 = array.dims()[0];
            double *p = array.ptr();
            Local<Array> dest = Array::New(I,size0);

            for(size_t i = 0;i < size0;i++) dest->Set(i,Number::New(I,p[i]));
            arg = dest;
         }
         else if(array.dims().size() == 2)
         {
            size_t size0 = array.dims()[0];
            size_t size1 = array.dims()[1];
            double *p = array.ptr();
            Local<Array> dest = Array::New(I,size0);

            for(size_t i = 0;i < size0;i++)
            {
               Local<Array> row  = Array::New(I,size1);

               dest->Set(i,row);
               for(size_t j = 0;j < size1;j++) row->Set(j,Number::New(I,*(p + size0*j + i)));
            }
            arg = dest;
         }
      }
   }

   //arg = Array::New(I,array);
}

int buildArgs(Isolate *I,const shared_ptr<vector<shared_ptr<nj::Value>>> &res,int argc,Local<Value> *argv)
{
   int index = 0;

   for(shared_ptr<nj::Value> value: *res)
   {
      if(value.get())
      {
printf("building arg %d\n",index);
         if(value->isPrimitive())
         {
            const nj::Primitive &primitive = static_cast<const nj::Primitive&>(*value);

            buildPrimitive(I,primitive,index++,argv);
         }
         else
         {
            buildArray(I,value,argv[index++]);
         }
      }
   }
   return index;
}

void doEval(const FunctionCallbackInfo<Value> &args)
{
   Isolate *I = Isolate::GetCurrent();
   HandleScope scope(I);
   int numArgs = args.Length();

   if(numArgs < 2 || !J)
   {
      returnNull(args,I);
      return;
   }

   Local<String> arg0 = args[0]->ToString();
   String::Utf8Value text(arg0);
   Local<Function> cb = Local<Function>::Cast(args[1]);
   JMain *engine;

   if(text.length() > 0 && (engine = J->getEngine()))
   {
      engine->evalQueuePut(*text);
      shared_ptr<vector<shared_ptr<nj::Value>>> res = engine->resultQueueGet();

      if(res.get())
      {
         int argc = res->size();
         Local<Value> *argv = new Local<Value>[argc];
         argc = buildArgs(I,res,argc,argv);
         callback(args,I,cb,argc,argv);
      }
   }
   else
   {
      const unsigned argc = 1;
      Local<Value> argv[argc] = { String::NewFromUtf8(I,"") };
      callback(args,I,cb,argc,argv);
   }
}

void doStart(const FunctionCallbackInfo<Value> &args)
{
   Isolate *I = Isolate::GetCurrent();
   HandleScope scope(I);
   int numArgs = args.Length();

   if(numArgs == 0)
   {
      returnString(args,I,"");
      return;
   }

   Local<String> arg0 = args[0]->ToString();
   String::Utf8Value plainText_av(arg0);

   if(plainText_av.length() > 0)
   {
      if(!J) J = new JuliaExecEnv(*plainText_av);

      returnString(args,I,"Julia Started");
   }
   else returnString(args,I,"");
}

void init(Handle<Object> exports)
{
  NODE_SET_METHOD(exports,"start",doStart);
  NODE_SET_METHOD(exports,"eval",doEval);
}

NODE_MODULE(nj,init)
<commit_msg>Debugging<commit_after>#include <stdio.h>
#include <node.h>
#include <v8.h>
#include <string>
#include "Types.h"
#include "JuliaExecEnv.h"

using namespace std;
using namespace v8;

static JuliaExecEnv *J = 0;

void returnNull(const FunctionCallbackInfo<Value> &args,Isolate *I)
{
   args.GetReturnValue().SetNull();
}

void returnString(const FunctionCallbackInfo<Value> &args,Isolate *I,const string &s)
{
   args.GetReturnValue().Set(String::NewFromUtf8(I,s.c_str()));
}

void callback(const FunctionCallbackInfo<Value>& args,Isolate *I,const Local<Function> &cb,int argc,Local<Value> *argv)
{
  cb->Call(I->GetCurrentContext()->Global(),argc,argv);
}

void buildPrimitive(Isolate *I,const nj::Primitive &primitive,int index,Local<Value> *argv)
{
   switch(primitive.type()->getId())
   {
      case nj::null_type:
printf("arg is null\n");
         argv[index] = Null(I);
      break;
      case nj::boolean_type:
printf("arg is %d\n",primitive.toBoolean());
         argv[index] = Boolean::New(I,primitive.toBoolean());
      break;
      case nj::int_type:
printf("arg is %lld\n",primitive.toInt());
         argv[index] = Number::New(I,primitive.toInt());
      break;
      case nj::float_type:
printf("arg is %f\n",primitive.toFloat());
         argv[index] = Number::New(I,primitive.toFloat());
      break;
      case nj::string_type:
printf("arg is %s\n",primitive.toString().c_str());
         argv[index] = String::NewFromUtf8(I,primitive.toString().c_str());
      break;
   }
}

void buildArray(Isolate *I,const shared_ptr<nj::Value> &value,Local<Value> &arg)
{
   const nj::Array_t *array_type = static_cast<const nj::Array_t*>(value->type());
   const nj::Type *element_type = array_type->getElementType();

   switch(element_type->getId())
   {
      case nj::float_type:
      {
         const nj::Array<double,nj::Float_t> &array = static_cast<const nj::Array<double,nj::Float_t>&>(*value);

         if(array.dims().size() == 1)
         {
            size_t size0 = array.dims()[0];
            double *p = array.ptr();
            Local<Array> dest = Array::New(I,size0);

            for(size_t i = 0;i < size0;i++) dest->Set(i,Number::New(I,p[i]));
            arg = dest;
         }
         else if(array.dims().size() == 2)
         {
            size_t size0 = array.dims()[0];
            size_t size1 = array.dims()[1];
            double *p = array.ptr();
            Local<Array> dest = Array::New(I,size0);

            for(size_t i = 0;i < size0;i++)
            {
               Local<Array> row  = Array::New(I,size1);

               dest->Set(i,row);
               for(size_t j = 0;j < size1;j++)
               {
                  printf("Storing X(%zu,%zu) = %f\n",i,j,p[size0*j + i]);
                  row->Set(j,Number::New(I,*(p + size0*j + i)));
               }
            }
            arg = dest;
         }
      }
   }

   //arg = Array::New(I,array);
}

int buildArgs(Isolate *I,const shared_ptr<vector<shared_ptr<nj::Value>>> &res,int argc,Local<Value> *argv)
{
   int index = 0;

   for(shared_ptr<nj::Value> value: *res)
   {
      if(value.get())
      {
printf("building arg %d\n",index);
         if(value->isPrimitive())
         {
            const nj::Primitive &primitive = static_cast<const nj::Primitive&>(*value);

            buildPrimitive(I,primitive,index++,argv);
         }
         else
         {
            buildArray(I,value,argv[index++]);
         }
      }
   }
   return index;
}

void doEval(const FunctionCallbackInfo<Value> &args)
{
   Isolate *I = Isolate::GetCurrent();
   HandleScope scope(I);
   int numArgs = args.Length();

   if(numArgs < 2 || !J)
   {
      returnNull(args,I);
      return;
   }

   Local<String> arg0 = args[0]->ToString();
   String::Utf8Value text(arg0);
   Local<Function> cb = Local<Function>::Cast(args[1]);
   JMain *engine;

   if(text.length() > 0 && (engine = J->getEngine()))
   {
      engine->evalQueuePut(*text);
      shared_ptr<vector<shared_ptr<nj::Value>>> res = engine->resultQueueGet();

      if(res.get())
      {
         int argc = res->size();
         Local<Value> *argv = new Local<Value>[argc];
         argc = buildArgs(I,res,argc,argv);
         callback(args,I,cb,argc,argv);
      }
   }
   else
   {
      const unsigned argc = 1;
      Local<Value> argv[argc] = { String::NewFromUtf8(I,"") };
      callback(args,I,cb,argc,argv);
   }
}

void doStart(const FunctionCallbackInfo<Value> &args)
{
   Isolate *I = Isolate::GetCurrent();
   HandleScope scope(I);
   int numArgs = args.Length();

   if(numArgs == 0)
   {
      returnString(args,I,"");
      return;
   }

   Local<String> arg0 = args[0]->ToString();
   String::Utf8Value plainText_av(arg0);

   if(plainText_av.length() > 0)
   {
      if(!J) J = new JuliaExecEnv(*plainText_av);

      returnString(args,I,"Julia Started");
   }
   else returnString(args,I,"");
}

void init(Handle<Object> exports)
{
  NODE_SET_METHOD(exports,"start",doStart);
  NODE_SET_METHOD(exports,"eval",doEval);
}

NODE_MODULE(nj,init)
<|endoftext|>


<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

#include "DebugOperatorNew.h"

#include "UiAPI.h"
#include "UiMainWindow.h"
#include "UiGraphicsView.h"
#include "QtUiAsset.h"
#include "UiProxyWidget.h"
#include "Application.h"

#include "Framework.h"
#include "AssetAPI.h"
#include "GenericAssetFactory.h"
#include "NullAssetFactory.h"
#include "LoggingFunctions.h"

#include <QEvent>
#include <QLayout>
#include <QVBoxLayout>
#include <QScrollBar>
#include <QUiLoader>
#include <QFile>
#include <QDir>

#include "MemoryLeakCheck.h"

/// The SuppressedPaintWidget is used as a viewport for the main QGraphicsView.
/** Its purpose is to disable all automatic drawing of the QGraphicsView to screen so that
    we can composite an Ogre 3D render with the Qt widgets added to a QGraphicsScene. */
class SuppressedPaintWidget : public QWidget {
public:
    SuppressedPaintWidget(QWidget *parent = 0, Qt::WindowFlags f = 0);
    virtual ~SuppressedPaintWidget() {}

protected:
    virtual bool event(QEvent *event);
    virtual void paintEvent(QPaintEvent *event);
};

SuppressedPaintWidget::SuppressedPaintWidget(QWidget *parent, Qt::WindowFlags f)
:QWidget(parent, f)
{
    setAttribute(Qt::WA_PaintOnScreen);
    setAttribute(Qt::WA_NoSystemBackground);
    setAttribute(Qt::WA_OpaquePaintEvent, true);
}

bool SuppressedPaintWidget::event(QEvent *event)
{
    switch(event->type())
    {
    case QEvent::UpdateRequest:
    case QEvent::Paint:
    case QEvent::Wheel:
    case QEvent::Resize:
        return true;
    default:
        return QWidget::event(event);
    }
}

void SuppressedPaintWidget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
}

UiAPI::UiAPI(Framework *owner_) :
    owner(owner_),
    mainWindow(0),
    graphicsView(0),
    graphicsScene(0)
{

    if (owner_->IsHeadless())
    {
        owner_->Asset()->RegisterAssetTypeFactory(AssetTypeFactoryPtr(new NullAssetFactory("QtUiFile")));
        return;
    }

    owner_->Asset()->RegisterAssetTypeFactory(AssetTypeFactoryPtr(new GenericAssetFactory<QtUiAsset>("QtUiFile")));

    mainWindow = new UiMainWindow(owner);
    mainWindow->setAutoFillBackground(false);
    mainWindow->setWindowIcon(QIcon(Application::InstallationDirectory() + "data/ui/images/icon/naali_logo_32px_RC1.ico"));
    connect(mainWindow, SIGNAL(WindowCloseEvent()), owner, SLOT(Exit()));

    // Prepare graphics view and scene
    graphicsView = new UiGraphicsView(mainWindow);

    ///\todo Memory leak below, see very end of ~Renderer() for comments.

    // QMainWindow has a layout by default. It will not let you set another.
    // Leave this check here if the window type changes to for example QWidget so we dont crash then.
    if (!mainWindow->layout())
        mainWindow->setLayout(new QVBoxLayout());
    mainWindow->layout()->setMargin(0);
    mainWindow->layout()->setContentsMargins(0,0,0,0);
    mainWindow->layout()->addWidget(graphicsView);

    viewportWidget = new SuppressedPaintWidget();
    graphicsView->setViewport(viewportWidget);
//    viewportWidget->setAttribute(Qt::WA_DontShowOnScreen, true);
    viewportWidget->setGeometry(0, 0, graphicsView->width(), graphicsView->height());
    viewportWidget->setContentsMargins(0,0,0,0);

    mainWindow->setContentsMargins(0,0,0,0);
    graphicsView->setContentsMargins(0,0,0,0);

    graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    graphicsView->horizontalScrollBar()->setValue(0);
    graphicsView->horizontalScrollBar()->setRange(0, 0);

    graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    graphicsView->verticalScrollBar()->setValue(0);
    graphicsView->verticalScrollBar()->setRange(0, 0);

    graphicsScene = new QGraphicsScene(this);

    graphicsView->setScene(graphicsScene);
    graphicsView->scene()->setSceneRect(graphicsView->rect());

    connect(graphicsScene, SIGNAL(changed(const QList<QRectF> &)), graphicsView, SLOT(HandleSceneChanged(const QList<QRectF> &)));
    connect(graphicsScene, SIGNAL(sceneRectChanged(const QRectF &)), SLOT(OnSceneRectChanged(const QRectF &)));
    connect(mainWindow, SIGNAL(WindowResizeEvent(int,int)), graphicsView, SLOT(Resize(int,int)));

    mainWindow->LoadWindowSettingsFromFile();
    graphicsView->Resize(mainWindow->width(), mainWindow->height());

    graphicsView->show();
    mainWindow->show();
    viewportWidget->show();

    /// Do a full repaint of the view now that we've shown it.
    graphicsView->MarkViewUndirty();
}

UiAPI::~UiAPI()
{
    // If we have a mainwindow delete it, note this will be null on headless mode
    // so this if check needs to be here.
    if (mainWindow)
    {
        mainWindow->close();
        delete mainWindow.data();
    }
    // viewportWidget will be null after main window is deleted above
    // as it is inside the main window (is a child so gets deleted)
    if (!viewportWidget.isNull())
    {
        viewportWidget->close();
        delete viewportWidget.data();
    }
}

UiMainWindow *UiAPI::MainWindow() const
{
    return mainWindow;
}

UiGraphicsView *UiAPI::GraphicsView() const
{
    return graphicsView;
}

QGraphicsScene *UiAPI::GraphicsScene() const
{
    return graphicsScene;
}

UiProxyWidget *UiAPI::AddWidgetToScene(QWidget *widget, Qt::WindowFlags flags)
{
    if (!widget)
    {
        LogError("AddWidgetToScene called with a null proxy widget!");
        return 0;
    }

    // QGraphicsProxyWidget maintains symmetry for the following states:
    // state, enabled, visible, geometry, layoutDirection, style, palette,
    // font, cursor, sizeHint, getContentsMargins and windowTitle

    UiProxyWidget *proxy = new UiProxyWidget(widget, flags);
    assert(proxy->widget() == widget);

    // Synchronize windowState flags
    proxy->widget()->setWindowState(widget->windowState());

    AddProxyWidgetToScene(proxy);

    // If the widget has WA_DeleteOnClose on, connect its proxy's visibleChanged()
    // signal to a slot which handles the deletion. This must be done because closing
    // proxy window in our system doesn't yield closeEvent, but hideEvent instead.
    if (widget->testAttribute(Qt::WA_DeleteOnClose))
        connect(proxy, SIGNAL(visibleChanged()), SLOT(DeleteCallingWidgetOnClose()));

    return proxy;
}

bool UiAPI::AddProxyWidgetToScene(UiProxyWidget *widget)
{
    if (!widget)
    {
        LogError("AddWidgetToScene called with a null proxy widget!");
        return false;
    }

    if (!widget->widget())
    {
        LogError("AddWidgetToScene called for proxy widget that does not embed a widget!");
        return false;
    }

    if (widgets.contains(widget))
    {
        LogWarning("AddWidgetToScene: Scene already contains the given widget!");
        return false;
    }

    connect(widget, SIGNAL(destroyed(QObject *)), this, SLOT(OnProxyDestroyed(QObject *)));

    widgets.append(widget);

    if (widget->isVisible())
        widget->hide();

    // If no position has been set for Qt::Dialog widget, use default one so that the window's title
    // bar - or any other critical part, doesn't go outside the view.
    if ((widget->windowFlags() & Qt::Dialog) && widget->pos() == QPointF() && !(widget->widget()->windowState() & Qt::WindowFullScreen))
        widget->setPos(10.0, 200.0);

    // Resize full screen widgets to fit the scene rect.
    if (widget->widget()->windowState() & Qt::WindowFullScreen)
    {
        fullScreenWidgets << widget;
        widget->setGeometry(graphicsScene->sceneRect().toRect());
    }

    graphicsScene->addItem(widget);
    return true;
}

void UiAPI::RemoveWidgetFromScene(QWidget *widget)
{
    if (!widget)
        return;

    if (graphicsScene)
        graphicsScene->removeItem(widget->graphicsProxyWidget());
    widgets.removeOne(widget->graphicsProxyWidget());
    fullScreenWidgets.removeOne(widget->graphicsProxyWidget());
}

void UiAPI::RemoveWidgetFromScene(QGraphicsProxyWidget *widget)
{
    if (!widget)
        return;

    if (graphicsScene)
        graphicsScene->removeItem(widget);
    widgets.removeOne(widget);
    fullScreenWidgets.removeOne(widget);
}

void UiAPI::OnProxyDestroyed(QObject* obj)
{
    // Make sure we don't get dangling pointers
    // Note: at this point it's a QObject, not a QGraphicsProxyWidget anymore
    QGraphicsProxyWidget* proxy = static_cast<QGraphicsProxyWidget*>(obj);
    widgets.removeOne(proxy);
    fullScreenWidgets.removeOne(proxy);
}

QWidget *UiAPI::LoadFromFile(const QString &filePath, bool addToScene, QWidget *parent)
{
    QWidget *widget = 0;

    AssetAPI::AssetRefType refType = AssetAPI::ParseAssetRef(filePath);
    if (refType != AssetAPI::AssetRefLocalPath && refType != AssetAPI::AssetRefRelativePath)
    {
        AssetPtr asset = owner->Asset()->GetAsset(filePath);
        if (!asset)
        {
            LogError(("LoadFromFile: Asset \"" + filePath + "\" is not loaded to the asset system. Call RequestAsset prior to use!").toStdString());
            return 0;
        }

        QtUiAsset *uiAsset = dynamic_cast<QtUiAsset*>(asset.get());
        if (!uiAsset)
        {
            LogError(("LoadFromFile: Asset \"" + filePath + "\" is not of type QtUiFile!").toStdString());
            return 0;
        }
        if (!uiAsset->IsLoaded())
        {
            LogError(("LoadFromFile: Asset \"" + filePath + "\" data is not valid!").toStdString());
            return 0;
        }

        // Get the asset data with the assetrefs replaced to point to the disk sources on the current local system.
        QByteArray data = uiAsset->GetRefReplacedAssetData();

        QUiLoader loader;
        QDataStream dataStream(&data, QIODevice::ReadOnly);
        widget = loader.load(dataStream.device(), parent);
    }
    else // The file is from absolute source location.
    {
        QString path = filePath;
        // If the user submitted a relative path, try to lookup whether a path relative to cwd or the application installation directory was meant.
        if (QDir::isRelativePath(path))
        {
            QString cwdPath = Application::CurrentWorkingDirectory() + filePath;
            if (QFile::exists(cwdPath))
                path = cwdPath;
            else
                path = Application::InstallationDirectory() + filePath;
        }
        QFile file(path);
        QUiLoader loader;
        file.open(QFile::ReadOnly);
        widget = loader.load(&file, parent);
    }

    if (!widget)
    {
        LogError(("LoadFromFile: Failed to load widget from file \"" + filePath + "\"!").toStdString());
        return 0;
    }

    if (addToScene && widget)
        AddWidgetToScene(widget);

    return widget;
}

void UiAPI::EmitContextMenuAboutToOpen(QMenu *menu, QList<QObject *> targets)
{
    emit ContextMenuAboutToOpen(menu,targets);
}

void UiAPI::ShowWidget(QWidget *widget) const
{
    if (!widget)
    {
        LogError("ShowWidget called on a null widget!");
        return;
    }

    if (widget->graphicsProxyWidget())
        widget->graphicsProxyWidget()->show();
    else
        widget->show();
}

void UiAPI::HideWidget(QWidget *widget) const
{
    if (!widget)
    {
        LogError("HideWidget called on a null widget!");
        return;
    }

    if (widget->graphicsProxyWidget())
        widget->graphicsProxyWidget()->hide();
    else
        widget->hide();
}

void UiAPI::BringWidgetToFront(QWidget *widget) const
{
    if (!widget)
    {
        LogError("BringWidgetToFront called on a null widget!");
        return;
    }

    ShowWidget(widget);
    graphicsScene->setActiveWindow(widget->graphicsProxyWidget());
    graphicsScene->setFocusItem(widget->graphicsProxyWidget(), Qt::ActiveWindowFocusReason);
}

void UiAPI::BringProxyWidgetToFront(QGraphicsProxyWidget *widget) const
{
    if (!widget)
    {
        LogError("BringWidgetToFront called on a null QGraphicsProxyWidget!");
        return;
    }

    graphicsScene->setActiveWindow(widget);
    graphicsScene->setFocusItem(widget, Qt::ActiveWindowFocusReason);
}

void UiAPI::OnSceneRectChanged(const QRectF &rect)
{
    foreach(QGraphicsProxyWidget *widget, fullScreenWidgets)
        widget->setGeometry(rect);
}

void UiAPI::DeleteCallingWidgetOnClose()
{
    QGraphicsProxyWidget *proxy = dynamic_cast<QGraphicsProxyWidget *>(sender());
    if (proxy && !proxy->isVisible())
        proxy->deleteLater();
}
<commit_msg>UiAPI crash bug: Check headless mode when AddWidget*() functions are called, stupid code might call this even in headless mode and we crashed to graphics scene ptr being null. Make a informative print and ask the user to check his code ;)<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

#include "DebugOperatorNew.h"

#include "UiAPI.h"
#include "UiMainWindow.h"
#include "UiGraphicsView.h"
#include "QtUiAsset.h"
#include "UiProxyWidget.h"
#include "Application.h"

#include "Framework.h"
#include "AssetAPI.h"
#include "GenericAssetFactory.h"
#include "NullAssetFactory.h"
#include "LoggingFunctions.h"

#include <QEvent>
#include <QLayout>
#include <QVBoxLayout>
#include <QScrollBar>
#include <QUiLoader>
#include <QFile>
#include <QDir>

#include "MemoryLeakCheck.h"

/// The SuppressedPaintWidget is used as a viewport for the main QGraphicsView.
/** Its purpose is to disable all automatic drawing of the QGraphicsView to screen so that
    we can composite an Ogre 3D render with the Qt widgets added to a QGraphicsScene. */
class SuppressedPaintWidget : public QWidget {
public:
    SuppressedPaintWidget(QWidget *parent = 0, Qt::WindowFlags f = 0);
    virtual ~SuppressedPaintWidget() {}

protected:
    virtual bool event(QEvent *event);
    virtual void paintEvent(QPaintEvent *event);
};

SuppressedPaintWidget::SuppressedPaintWidget(QWidget *parent, Qt::WindowFlags f)
:QWidget(parent, f)
{
    setAttribute(Qt::WA_PaintOnScreen);
    setAttribute(Qt::WA_NoSystemBackground);
    setAttribute(Qt::WA_OpaquePaintEvent, true);
}

bool SuppressedPaintWidget::event(QEvent *event)
{
    switch(event->type())
    {
    case QEvent::UpdateRequest:
    case QEvent::Paint:
    case QEvent::Wheel:
    case QEvent::Resize:
        return true;
    default:
        return QWidget::event(event);
    }
}

void SuppressedPaintWidget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
}

UiAPI::UiAPI(Framework *owner_) :
    owner(owner_),
    mainWindow(0),
    graphicsView(0),
    graphicsScene(0)
{
    if (owner_->IsHeadless())
    {
        owner_->Asset()->RegisterAssetTypeFactory(AssetTypeFactoryPtr(new NullAssetFactory("QtUiFile")));
        return;
    }

    owner_->Asset()->RegisterAssetTypeFactory(AssetTypeFactoryPtr(new GenericAssetFactory<QtUiAsset>("QtUiFile")));

    mainWindow = new UiMainWindow(owner);
    mainWindow->setAutoFillBackground(false);
    mainWindow->setWindowIcon(QIcon(Application::InstallationDirectory() + "data/ui/images/icon/naali_logo_32px_RC1.ico"));
    connect(mainWindow, SIGNAL(WindowCloseEvent()), owner, SLOT(Exit()));

    // Prepare graphics view and scene
    graphicsView = new UiGraphicsView(mainWindow);

    ///\todo Memory leak below, see very end of ~Renderer() for comments.

    // QMainWindow has a layout by default. It will not let you set another.
    // Leave this check here if the window type changes to for example QWidget so we dont crash then.
    if (!mainWindow->layout())
        mainWindow->setLayout(new QVBoxLayout());
    mainWindow->layout()->setMargin(0);
    mainWindow->layout()->setContentsMargins(0,0,0,0);
    mainWindow->layout()->addWidget(graphicsView);

    viewportWidget = new SuppressedPaintWidget();
    graphicsView->setViewport(viewportWidget);
    //viewportWidget->setAttribute(Qt::WA_DontShowOnScreen, true);
    viewportWidget->setGeometry(0, 0, graphicsView->width(), graphicsView->height());
    viewportWidget->setContentsMargins(0,0,0,0);

    mainWindow->setContentsMargins(0,0,0,0);
    graphicsView->setContentsMargins(0,0,0,0);

    graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    graphicsView->horizontalScrollBar()->setValue(0);
    graphicsView->horizontalScrollBar()->setRange(0, 0);

    graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    graphicsView->verticalScrollBar()->setValue(0);
    graphicsView->verticalScrollBar()->setRange(0, 0);

    graphicsScene = new QGraphicsScene(this);

    graphicsView->setScene(graphicsScene);
    graphicsView->scene()->setSceneRect(graphicsView->rect());

    connect(graphicsScene, SIGNAL(changed(const QList<QRectF> &)), graphicsView, SLOT(HandleSceneChanged(const QList<QRectF> &)));
    connect(graphicsScene, SIGNAL(sceneRectChanged(const QRectF &)), SLOT(OnSceneRectChanged(const QRectF &)));
    connect(mainWindow, SIGNAL(WindowResizeEvent(int,int)), graphicsView, SLOT(Resize(int,int)));

    mainWindow->LoadWindowSettingsFromFile();
    graphicsView->Resize(mainWindow->width(), mainWindow->height());

    graphicsView->show();
    mainWindow->show();
    viewportWidget->show();

    /// Do a full repaint of the view now that we've shown it.
    graphicsView->MarkViewUndirty();
}

UiAPI::~UiAPI()
{
    // If we have a mainwindow delete it, note this will be null on headless mode
    // so this if check needs to be here.
    if (mainWindow)
    {
        mainWindow->close();
        delete mainWindow.data();
    }
    // viewportWidget will be null after main window is deleted above
    // as it is inside the main window (is a child so gets deleted)
    if (!viewportWidget.isNull())
    {
        viewportWidget->close();
        delete viewportWidget.data();
    }
}

UiMainWindow *UiAPI::MainWindow() const
{
    return mainWindow;
}

UiGraphicsView *UiAPI::GraphicsView() const
{
    return graphicsView;
}

QGraphicsScene *UiAPI::GraphicsScene() const
{
    return graphicsScene;
}

UiProxyWidget *UiAPI::AddWidgetToScene(QWidget *widget, Qt::WindowFlags flags)
{
    if (owner->IsHeadless())
    {
        LogWarning("UiAPI: You are trying to add widgets to scene on a headless run, check your code!");
        return 0;
    }
    if (!widget)
    {
        LogError("AddWidgetToScene called with a null proxy widget!");
        return 0;
    }

    // QGraphicsProxyWidget maintains symmetry for the following states:
    // state, enabled, visible, geometry, layoutDirection, style, palette,
    // font, cursor, sizeHint, getContentsMargins and windowTitle

    UiProxyWidget *proxy = new UiProxyWidget(widget, flags);
    assert(proxy->widget() == widget);

    // Synchronize windowState flags
    proxy->widget()->setWindowState(widget->windowState());

    AddProxyWidgetToScene(proxy);

    // If the widget has WA_DeleteOnClose on, connect its proxy's visibleChanged()
    // signal to a slot which handles the deletion. This must be done because closing
    // proxy window in our system doesn't yield closeEvent, but hideEvent instead.
    if (widget->testAttribute(Qt::WA_DeleteOnClose))
        connect(proxy, SIGNAL(visibleChanged()), SLOT(DeleteCallingWidgetOnClose()));

    return proxy;
}

bool UiAPI::AddProxyWidgetToScene(UiProxyWidget *widget)
{
    if (owner->IsHeadless())
    {
        LogWarning("UiAPI: You are trying to add widgets to scene on a headless run, check your code!");
        return false;
    }

    if (!widget)
    {
        LogError("AddWidgetToScene called with a null proxy widget!");
        return false;
    }

    if (!widget->widget())
    {
        LogError("AddWidgetToScene called for proxy widget that does not embed a widget!");
        return false;
    }

    if (widgets.contains(widget))
    {
        LogWarning("AddWidgetToScene: Scene already contains the given widget!");
        return false;
    }

    connect(widget, SIGNAL(destroyed(QObject *)), this, SLOT(OnProxyDestroyed(QObject *)));

    widgets.append(widget);

    if (widget->isVisible())
        widget->hide();

    // If no position has been set for Qt::Dialog widget, use default one so that the window's title
    // bar - or any other critical part, doesn't go outside the view.
    if ((widget->windowFlags() & Qt::Dialog) && widget->pos() == QPointF() && !(widget->widget()->windowState() & Qt::WindowFullScreen))
        widget->setPos(10.0, 200.0);

    // Resize full screen widgets to fit the scene rect.
    if (widget->widget()->windowState() & Qt::WindowFullScreen)
    {
        fullScreenWidgets << widget;
        widget->setGeometry(graphicsScene->sceneRect().toRect());
    }

    graphicsScene->addItem(widget);
    return true;
}

void UiAPI::RemoveWidgetFromScene(QWidget *widget)
{
    if (owner->IsHeadless())
    {
        LogWarning("UiAPI: You are trying to remove widgets from scene on a headless run, check your code!");
        return;
    }

    if (!widget)
        return;

    if (graphicsScene)
        graphicsScene->removeItem(widget->graphicsProxyWidget());
    widgets.removeOne(widget->graphicsProxyWidget());
    fullScreenWidgets.removeOne(widget->graphicsProxyWidget());
}

void UiAPI::RemoveWidgetFromScene(QGraphicsProxyWidget *widget)
{
    if (owner->IsHeadless())
    {
        LogWarning("UiAPI: You are trying to remove widgets from scene on a headless run, check your code!");
        return;
    }
    if (!widget)
        return;

    if (graphicsScene)
        graphicsScene->removeItem(widget);
    widgets.removeOne(widget);
    fullScreenWidgets.removeOne(widget);
}

void UiAPI::OnProxyDestroyed(QObject* obj)
{
    // Make sure we don't get dangling pointers
    // Note: at this point it's a QObject, not a QGraphicsProxyWidget anymore
    QGraphicsProxyWidget* proxy = static_cast<QGraphicsProxyWidget*>(obj);
    widgets.removeOne(proxy);
    fullScreenWidgets.removeOne(proxy);
}

QWidget *UiAPI::LoadFromFile(const QString &filePath, bool addToScene, QWidget *parent)
{
    QWidget *widget = 0;

    AssetAPI::AssetRefType refType = AssetAPI::ParseAssetRef(filePath);
    if (refType != AssetAPI::AssetRefLocalPath && refType != AssetAPI::AssetRefRelativePath)
    {
        AssetPtr asset = owner->Asset()->GetAsset(filePath);
        if (!asset)
        {
            LogError(("LoadFromFile: Asset \"" + filePath + "\" is not loaded to the asset system. Call RequestAsset prior to use!").toStdString());
            return 0;
        }

        QtUiAsset *uiAsset = dynamic_cast<QtUiAsset*>(asset.get());
        if (!uiAsset)
        {
            LogError(("LoadFromFile: Asset \"" + filePath + "\" is not of type QtUiFile!").toStdString());
            return 0;
        }
        if (!uiAsset->IsLoaded())
        {
            LogError(("LoadFromFile: Asset \"" + filePath + "\" data is not valid!").toStdString());
            return 0;
        }

        // Get the asset data with the assetrefs replaced to point to the disk sources on the current local system.
        QByteArray data = uiAsset->GetRefReplacedAssetData();

        QUiLoader loader;
        QDataStream dataStream(&data, QIODevice::ReadOnly);
        widget = loader.load(dataStream.device(), parent);
    }
    else // The file is from absolute source location.
    {
        QString path = filePath;
        // If the user submitted a relative path, try to lookup whether a path relative to cwd or the application installation directory was meant.
        if (QDir::isRelativePath(path))
        {
            QString cwdPath = Application::CurrentWorkingDirectory() + filePath;
            if (QFile::exists(cwdPath))
                path = cwdPath;
            else
                path = Application::InstallationDirectory() + filePath;
        }
        QFile file(path);
        QUiLoader loader;
        file.open(QFile::ReadOnly);
        widget = loader.load(&file, parent);
    }

    if (!widget)
    {
        LogError(("LoadFromFile: Failed to load widget from file \"" + filePath + "\"!").toStdString());
        return 0;
    }

    if (addToScene && widget)
    {
        if (!owner->IsHeadless())
            AddWidgetToScene(widget);
        else
            LogWarning("UiAPI::LoadFromFile: You have addToScene = true, but this is a headless run (hence no ui scene).");
    }

    return widget;
}

void UiAPI::EmitContextMenuAboutToOpen(QMenu *menu, QList<QObject *> targets)
{
    emit ContextMenuAboutToOpen(menu,targets);
}

void UiAPI::ShowWidget(QWidget *widget) const
{
    if (!widget)
    {
        LogError("ShowWidget called on a null widget!");
        return;
    }

    if (widget->graphicsProxyWidget())
        widget->graphicsProxyWidget()->show();
    else
        widget->show();
}

void UiAPI::HideWidget(QWidget *widget) const
{
    if (!widget)
    {
        LogError("HideWidget called on a null widget!");
        return;
    }

    if (widget->graphicsProxyWidget())
        widget->graphicsProxyWidget()->hide();
    else
        widget->hide();
}

void UiAPI::BringWidgetToFront(QWidget *widget) const
{
    if (!widget)
    {
        LogError("BringWidgetToFront called on a null widget!");
        return;
    }

    ShowWidget(widget);
    graphicsScene->setActiveWindow(widget->graphicsProxyWidget());
    graphicsScene->setFocusItem(widget->graphicsProxyWidget(), Qt::ActiveWindowFocusReason);
}

void UiAPI::BringProxyWidgetToFront(QGraphicsProxyWidget *widget) const
{
    if (!widget)
    {
        LogError("BringWidgetToFront called on a null QGraphicsProxyWidget!");
        return;
    }

    graphicsScene->setActiveWindow(widget);
    graphicsScene->setFocusItem(widget, Qt::ActiveWindowFocusReason);
}

void UiAPI::OnSceneRectChanged(const QRectF &rect)
{
    foreach(QGraphicsProxyWidget *widget, fullScreenWidgets)
        widget->setGeometry(rect);
}

void UiAPI::DeleteCallingWidgetOnClose()
{
    QGraphicsProxyWidget *proxy = dynamic_cast<QGraphicsProxyWidget *>(sender());
    if (proxy && !proxy->isVisible())
        proxy->deleteLater();
}
<|endoftext|>


<commit_before>#include <boost/filesystem.hpp>
#include <boost/range/algorithm/mismatch.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/predicate.hpp>

#include <unordered_set>
#include <fstream>
#include <iostream>

namespace meka {
  namespace folder {
    auto const build   = "build";
    auto const src     = "src";
    auto const include = "include";
    auto const test    = "test";
  }

  namespace extension {
    auto const cpp = { ".cpp", ".cc", ".C", ".c++", ".cxx" };
    auto const hpp = { ".hpp", ".hh", ".H", ".h++", ".hxx" };
    auto const c   = { ".c" };
    auto const h   = { ".h" };
    auto const obj = ".o";
    auto const arc = ".a";
  }

  namespace suffix {
    auto const test = "_test";
  }

  auto const mekaninja = R"(
ninja_required_version = 1.3
builddir = build

cblk =
cred =
cgrn =
cylw =
cblu =
cprp =
ccyn =
cwht =
crgb =
cdef =
crst =

cbblk = ${cblk}
cbred = ${cred}
cbgrn = ${cgrn}
cbylw = ${cylw}
cbblu = ${cblu}
cbprp = ${cprp}
cbcyn = ${ccyn}
cbwht = ${cwht}
cbrgb = ${crgb}
cbdef = ${cdef}
cbrst = ${crst}

cxx   = clang++-3.6
cc    = clang-3.6
ar    = ar

cflags   = -std=c11 -fpic -g -O0
cxxflags = -std=c++1y -fpic -g -O0
ldflags  = -L$builddir/lib -Wl,-rpath,$builddir/lib -L/usr/local/lib

rule cxx
  command = $cxx -MMD -MT $out -MF $out.d $cxxflags $incdirs -xc++ -c $in -o $out
  description = ${cylw}CXX${crst} ${cgrn}$out${crst}
  depfile = $out.d
  deps = gcc

rule cc
  command = $cc -MMD -MT $out -MF $out.d $cflags $incdirs -xc -c $in -o $out
  description = ${cylw}CXX${crst} ${cgrn}$out${crst}
  depfile = $out.d
  deps = gcc

rule arc
  command = rm -f $out && $ar crs $out $in
  description = ${cylw}AR${crst}  ${cblu}$out${crst}

rule exe
  command = $cxx -o $out $in $ldflags -Wl,--start-group $libs -Wl,--end-group
  description = ${cylw}EXE${crst} ${cblu}$out${crst}

)";

  namespace fs {
    using namespace ::boost::filesystem;

    auto const filename = [](fs::path path) { return std::move(path).filename().string(); };

    auto const relative = [](fs::path from, fs::path to) {
      auto const pair = boost::mismatch(from, to);

      if (pair.first == std::begin(from))
        return std::move(to);

      auto rel = fs::path {};
      std::for_each(pair.first, from.end(), [&](fs::path const& i) { rel /= ".."; });
      std::for_each(pair.second, to.end(), [&](fs::path const& i) { rel /= i; });

      return std::move(rel);
    };

    auto const is_file = [](auto it) {
      switch (it.status().type()) {
        default:
        case fs::status_error:
        case fs::file_not_found:
        case fs::directory_file:
        case fs::type_unknown:
          return false;

        case fs::regular_file:
        case fs::symlink_file:
        case fs::block_file:
        case fs::character_file:
        case fs::fifo_file:
        case fs::socket_file:
          return true;
      }
    };

    auto const is_directory = [](auto it) {
      switch (it.status().type()) {
        default:
        case fs::status_error:
        case fs::file_not_found:
        case fs::type_unknown:
        case fs::regular_file:
        case fs::symlink_file:
        case fs::block_file:
        case fs::character_file:
        case fs::fifo_file:
        case fs::socket_file:
          return false;

        case fs::directory_file:
          return true;
      }
    };
  }

  struct project {
    std::string           name;
    fs::path              path;
    std::vector<fs::path> sources;
    std::vector<fs::path> tests;

    std::vector<fs::path> objects  = {};
    std::vector<fs::path> binaries = {};
  };

  auto const find_sources = [](fs::path root) {
    auto sources = std::vector<fs::path> {};

    for (auto it = fs::recursive_directory_iterator{root / folder::src}, end = fs::recursive_directory_iterator {}; it != end; ++it) {
      if (!fs::is_file(it))
        continue;

      auto const path = *it;
      auto const ext  = fs::extension(path);
      if (std::find(std::begin(extension::cpp), std::end(extension::cpp), ext) == std::end(extension::cpp) &&
          std::find(std::begin(extension::c), std::end(extension::c), ext) == std::end(extension::c))
        continue;

      if (boost::algorithm::ends_with(fs::filename(path), suffix::test + ext))
        continue;

      sources.emplace_back(fs::relative(root, *it));
    }

    return std::move(sources);
  };

  auto const find_tests = [](fs::path root) {
    auto tests = std::vector<fs::path> {};

    for (auto it = fs::recursive_directory_iterator{root / folder::src}, end = fs::recursive_directory_iterator {}; it != end; ++it) {
      if (!fs::is_file(it))
        continue;

      auto const path = *it;
      auto const ext  = fs::extension(path);
      if (std::find(std::begin(extension::cpp), std::end(extension::cpp), ext) == std::end(extension::cpp))
        continue;

      if (!boost::algorithm::ends_with(fs::filename(path), suffix::test + ext))
        continue;

      tests.emplace_back(fs::relative(root, *it));
    }

    if (!fs::exists(root / folder::test))
      return std::move(tests);

    for (auto it = fs::recursive_directory_iterator{root / folder::test}, end = fs::recursive_directory_iterator {}; it != end; ++it) {
      if (!fs::is_file(it))
        continue;

      auto const path = *it;
      auto const ext  = fs::extension(path);
      if (std::find(std::begin(extension::cpp), std::end(extension::cpp), ext) == std::end(extension::cpp))
        continue;

      tests.emplace_back(fs::relative(root, *it));
    }

    return std::move(tests);
  };

  auto const find_projects = [](fs::path root) {
    auto names    = std::unordered_set<std::string> {};
    auto projects = std::vector<project> {};

    for (auto it = fs::recursive_directory_iterator{root}, end = fs::recursive_directory_iterator {}; it != end; ++it) {
      if (!fs::is_directory(it))
        continue;

      auto const base = fs::filename(*it);
      if (base == folder::build) {
        it.no_push();
        continue;
      }

      if (base != folder::src)
        continue;

      it.no_push();

      auto const path = fs::path(*it).parent_path();
      auto const relp = fs::relative(root, path);
      auto const name = fs::filename(path);
      if (names.find(name) != names.end()) {
        std::cerr << "W: project " << name << " in " << path << " already found, ignoring\n";
        continue;
      }
      names.insert(name);

      projects.push_back({ name, relp, find_sources(path), find_tests(path) });
    }

    return std::move(projects);
  };

  extern "C" int main(int, char*[]) {
    auto const root      = fs::current_path();
    auto const ninja     = std::string { std::getenv("NINJA") ? std::getenv("NINJA") : "ninja" };

    auto const builddir  = fs::path(folder::build);
    auto const objdir    = builddir / "obj";
    auto const libdir    = builddir / "lib";
    auto const bindir    = builddir / "bin";

    auto projects = find_projects(root);

    {
      auto const ninjafile = (objdir / "build.ninja").string();
      fs::create_directories(objdir);

      {
        auto && out = std::ofstream { ninjafile };
        out << mekaninja;

        auto incdirs = std::vector<std::string> {};
        std::transform(std::begin(projects), std::end(projects), std::back_inserter(incdirs), [&root](auto project) { return "-I" + (project.path / folder::include).string(); });

        for (auto const& p : projects) {
          for (auto const& s : p.sources) {
            if (std::find(std::begin(extension::c), std::end(extension::c), fs::extension(s)) == std::end(extension::c))
              out << "build " << fs::change_extension(objdir / p.name / s, extension::obj).string() << ": cxx " << (p.path / s).string() << "\n";
            else
              out << "build " << fs::change_extension(objdir / p.name / s, extension::obj).string() << ": cc " << (p.path / s).string() << "\n";
            out << "  incdirs = -I" << (p.path / folder::src).string() << " " << boost::algorithm::join(incdirs, " ") << "\n";
            out << "\n";
          }
        }
      }

      auto const command = ninja + " -f " + ninjafile + " -k0";
      auto const result  = std::system(command.c_str());

      if (result)
        return result;
    }

    {
      auto const ninjafile = (libdir / "build.ninja").string();
      fs::create_directories(libdir);

      {
        auto && out = std::ofstream { ninjafile };
        out << mekaninja;

        for (auto& p : projects) {
          for (auto const& s : p.sources) {
            auto const object  = fs::change_extension(objdir / p.name / s, extension::obj);
            auto const command = "nm " + object.string() + " --defined-only | grep --quiet ' T main'";
            auto const result  = std::system(command.c_str());

            if (result)
              p.objects.emplace_back(std::move(object));
            else
              p.binaries.emplace_back(std::move(object));
          }

          auto objects = std::vector<std::string> {};
          std::transform(std::begin(p.objects), std::end(p.objects), std::back_inserter(objects), [](auto path) { return path.string(); });

          out << "build " << (libdir / p.name).string() << extension::arc << ": arc $\n";
          for (auto const& o : objects)
            out << "  " << o << " $\n";
          out << "\n";
        }
      }

      auto const command = ninja + " -f " + ninjafile + " -k0";
      auto const result  = std::system(command.c_str());

      if (result)
        return result;
    }

    {
      auto const ninjafile = (bindir / "build.ninja").string();
      fs::create_directories(bindir);

      {
        auto && out = std::ofstream { ninjafile };
        out << mekaninja;

        auto archives = std::vector<std::string> {};
        std::transform(std::begin(projects), std::end(projects), std::back_inserter(archives), [libdir](auto project) { return (libdir / project.name).string() + extension::arc; });

        for (auto const& p : projects) {
          for (auto const& o : p.binaries) {
            out << "build " << (bindir / p.name / fs::basename(o)).string() << ": exe " << o.string() << " | " << boost::algorithm::join(archives, " $\n    ") << "\n";
            out << "  libs = " << boost::algorithm::join(archives, " ") << "\n";
            out << "\n";
          }
        }
      }

      auto const command = ninja + " -f " + ninjafile + " -k0";
      auto const result  = std::system(command.c_str());

      if (result)
        return result;
    }

    return 0;
  }

}
<commit_msg>Support header-only libraries and add their include folder to the include path.<commit_after>#include <boost/filesystem.hpp>
#include <boost/range/algorithm/mismatch.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/predicate.hpp>

#include <unordered_set>
#include <fstream>
#include <iostream>

namespace meka {
  namespace folder {
    auto const build   = "build";
    auto const src     = "src";
    auto const include = "include";
    auto const test    = "test";
  }

  namespace extension {
    auto const cpp = { ".cpp", ".cc", ".C", ".c++", ".cxx" };
    auto const hpp = { ".hpp", ".hh", ".H", ".h++", ".hxx" };
    auto const c   = { ".c" };
    auto const h   = { ".h" };
    auto const obj = ".o";
    auto const arc = ".a";
  }

  namespace suffix {
    auto const test = "_test";
  }

  auto const mekaninja = R"(
ninja_required_version = 1.3
builddir = build

cblk =
cred =
cgrn =
cylw =
cblu =
cprp =
ccyn =
cwht =
crgb =
cdef =
crst =

cbblk = ${cblk}
cbred = ${cred}
cbgrn = ${cgrn}
cbylw = ${cylw}
cbblu = ${cblu}
cbprp = ${cprp}
cbcyn = ${ccyn}
cbwht = ${cwht}
cbrgb = ${crgb}
cbdef = ${cdef}
cbrst = ${crst}

cxx   = clang++-3.6
cc    = clang-3.6
ar    = ar

cflags   = -std=c11 -fpic -g -O0
cxxflags = -std=c++1y -fpic -g -O0
ldflags  = -L$builddir/lib -Wl,-rpath,$builddir/lib -L/usr/local/lib

rule cxx
  command = $cxx -MMD -MT $out -MF $out.d $cxxflags $incdirs -xc++ -c $in -o $out
  description = ${cylw}CXX${crst} ${cgrn}$out${crst}
  depfile = $out.d
  deps = gcc

rule cc
  command = $cc -MMD -MT $out -MF $out.d $cflags $incdirs -xc -c $in -o $out
  description = ${cylw}CXX${crst} ${cgrn}$out${crst}
  depfile = $out.d
  deps = gcc

rule arc
  command = rm -f $out && $ar crs $out $in
  description = ${cylw}AR${crst}  ${cblu}$out${crst}

rule exe
  command = $cxx -o $out $in $ldflags -Wl,--start-group $libs -Wl,--end-group
  description = ${cylw}EXE${crst} ${cblu}$out${crst}

)";

  namespace fs {
    using namespace ::boost::filesystem;

    auto const filename = [](fs::path path) { return std::move(path).filename().string(); };

    auto const relative = [](fs::path from, fs::path to) {
      auto const pair = boost::mismatch(from, to);

      if (pair.first == std::begin(from))
        return std::move(to);

      auto rel = fs::path {};
      std::for_each(pair.first, from.end(), [&](fs::path const& i) { rel /= ".."; });
      std::for_each(pair.second, to.end(), [&](fs::path const& i) { rel /= i; });

      return std::move(rel);
    };

    auto const is_file = [](auto it) {
      switch (it.status().type()) {
        default:
        case fs::status_error:
        case fs::file_not_found:
        case fs::directory_file:
        case fs::type_unknown:
          return false;

        case fs::regular_file:
        case fs::symlink_file:
        case fs::block_file:
        case fs::character_file:
        case fs::fifo_file:
        case fs::socket_file:
          return true;
      }
    };

    auto const is_directory = [](auto it) {
      switch (it.status().type()) {
        default:
        case fs::status_error:
        case fs::file_not_found:
        case fs::type_unknown:
        case fs::regular_file:
        case fs::symlink_file:
        case fs::block_file:
        case fs::character_file:
        case fs::fifo_file:
        case fs::socket_file:
          return false;

        case fs::directory_file:
          return true;
      }
    };
  }

  struct project {
    project() = default;
    project(std::string name, fs::path path, std::vector<fs::path> sources, std::vector<fs::path> tests)
      : name(std::move(name)), path(std::move(path)), sources(std::move(sources)), tests(std::move(tests)) {}

    std::string           name;
    fs::path              path;
    std::vector<fs::path> sources;
    std::vector<fs::path> tests;

    std::vector<fs::path> objects  = {};
    std::vector<fs::path> binaries = {};
  };

  auto const find_sources = [](fs::path root) {
    auto sources = std::vector<fs::path> {};

    if (!fs::exists(root / folder::src))
      return std::move(sources);

    for (auto it = fs::recursive_directory_iterator{root / folder::src}, end = fs::recursive_directory_iterator {}; it != end; ++it) {
      if (!fs::is_file(it))
        continue;

      auto const path = *it;
      auto const ext  = fs::extension(path);
      if (std::find(std::begin(extension::cpp), std::end(extension::cpp), ext) == std::end(extension::cpp) &&
          std::find(std::begin(extension::c), std::end(extension::c), ext) == std::end(extension::c))
        continue;

      if (boost::algorithm::ends_with(fs::filename(path), suffix::test + ext))
        continue;

      sources.emplace_back(fs::relative(root, *it));
    }

    return std::move(sources);
  };

  auto const find_tests = [](fs::path root) {
    auto tests = std::vector<fs::path> {};

    if (fs::exists(root / folder::src)) {
      for (auto it = fs::recursive_directory_iterator{root / folder::src}, end = fs::recursive_directory_iterator {}; it != end; ++it) {
        if (!fs::is_file(it))
          continue;

        auto const path = *it;
        auto const ext  = fs::extension(path);
        if (std::find(std::begin(extension::cpp), std::end(extension::cpp), ext) == std::end(extension::cpp))
          continue;

        if (!boost::algorithm::ends_with(fs::filename(path), suffix::test + ext))
          continue;

        tests.emplace_back(fs::relative(root, *it));
      }
    }

    if (!fs::exists(root / folder::test))
      return std::move(tests);

    for (auto it = fs::recursive_directory_iterator{root / folder::test}, end = fs::recursive_directory_iterator {}; it != end; ++it) {
      if (!fs::is_file(it))
        continue;

      auto const path = *it;
      auto const ext  = fs::extension(path);
      if (std::find(std::begin(extension::cpp), std::end(extension::cpp), ext) == std::end(extension::cpp))
        continue;

      tests.emplace_back(fs::relative(root, *it));
    }

    return std::move(tests);
  };

  auto const find_projects = [](fs::path root) {
    auto names    = std::unordered_set<std::string> {};
    auto projects = std::vector<project> {};

    for (auto it = fs::recursive_directory_iterator{root}, end = fs::recursive_directory_iterator {}; it != end; ++it) {
      if (!fs::is_directory(it))
        continue;

      auto const base = fs::filename(*it);
      if (base == folder::build) {
        it.no_push();
        continue;
      }

      if (base == folder::include && fs::exists(*it / ".." / folder::src))
        continue;

      if (base != folder::src && base != folder::include)
        continue;

      it.no_push();

      auto const path = fs::path(*it).parent_path();
      auto const relp = fs::relative(root, path);
      auto const name = fs::filename(path);
      if (names.find(name) != names.end()) {
        std::cerr << "W: project " << name << " in " << path << " already found, ignoring\n";
        continue;
      }
      names.insert(name);

      projects.emplace_back(name, relp, find_sources(path), find_tests(path));
    }

    return std::move(projects);
  };

  extern "C" int main(int, char*[]) {
    auto const root      = fs::current_path();
    auto const ninja     = std::string { std::getenv("NINJA") ? std::getenv("NINJA") : "ninja" };

    auto const builddir  = fs::path(folder::build);
    auto const objdir    = builddir / "obj";
    auto const libdir    = builddir / "lib";
    auto const bindir    = builddir / "bin";

    auto projects = find_projects(root);

    {
      auto const ninjafile = (objdir / "build.ninja").string();
      fs::create_directories(objdir);

      {
        auto && out = std::ofstream { ninjafile };
        out << mekaninja;

        auto incdirs = std::vector<std::string> {};
        std::transform(std::begin(projects), std::end(projects), std::back_inserter(incdirs), [&root](auto project) { return "-I" + (project.path / folder::include).string(); });

        for (auto const& p : projects) {
          for (auto const& s : p.sources) {
            if (std::find(std::begin(extension::c), std::end(extension::c), fs::extension(s)) == std::end(extension::c))
              out << "build " << fs::change_extension(objdir / p.name / s, extension::obj).string() << ": cxx " << (p.path / s).string() << "\n";
            else
              out << "build " << fs::change_extension(objdir / p.name / s, extension::obj).string() << ": cc " << (p.path / s).string() << "\n";
            out << "  incdirs = -I" << (p.path / folder::src).string() << " " << boost::algorithm::join(incdirs, " ") << "\n";
            out << "\n";
          }
        }
      }

      auto const command = ninja + " -f " + ninjafile + " -k0";
      auto const result  = std::system(command.c_str());

      if (result)
        return result;
    }

    {
      auto const ninjafile = (libdir / "build.ninja").string();
      fs::create_directories(libdir);

      {
        auto && out = std::ofstream { ninjafile };
        out << mekaninja;

        for (auto& p : projects) {
          for (auto const& s : p.sources) {
            auto const object  = fs::change_extension(objdir / p.name / s, extension::obj);
            auto const command = "nm " + object.string() + " --defined-only | grep --quiet ' T main'";
            auto const result  = std::system(command.c_str());

            if (result)
              p.objects.emplace_back(std::move(object));
            else
              p.binaries.emplace_back(std::move(object));
          }

          auto objects = std::vector<std::string> {};
          std::transform(std::begin(p.objects), std::end(p.objects), std::back_inserter(objects), [](auto path) { return path.string(); });

          out << "build " << (libdir / p.name).string() << extension::arc << ": arc $\n";
          for (auto const& o : objects)
            out << "  " << o << " $\n";
          out << "\n";
        }
      }

      auto const command = ninja + " -f " + ninjafile + " -k0";
      auto const result  = std::system(command.c_str());

      if (result)
        return result;
    }

    {
      auto const ninjafile = (bindir / "build.ninja").string();
      fs::create_directories(bindir);

      {
        auto && out = std::ofstream { ninjafile };
        out << mekaninja;

        auto archives = std::vector<std::string> {};
        std::transform(std::begin(projects), std::end(projects), std::back_inserter(archives), [libdir](auto project) { return (libdir / project.name).string() + extension::arc; });

        for (auto const& p : projects) {
          for (auto const& o : p.binaries) {
            out << "build " << (bindir / p.name / fs::basename(o)).string() << ": exe " << o.string() << " | " << boost::algorithm::join(archives, " $\n    ") << "\n";
            out << "  libs = " << boost::algorithm::join(archives, " ") << "\n";
            out << "\n";
          }
        }
      }

      auto const command = ninja + " -f " + ninjafile + " -k0";
      auto const result  = std::system(command.c_str());

      if (result)
        return result;
    }

    return 0;
  }

}
<|endoftext|>