summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMateusz Loskot <mateusz@loskot.net>2015-05-06 00:16:58 +0200
committerOrgad Shaneh <orgads@gmail.com>2015-07-01 10:43:09 +0000
commit7389250fcd1ada74514f90e8670d7af087e6a7c7 (patch)
tree11cacc00d934db20de04737058ebda99b17828fb
parent188d4bfdb24c938a0c60042418852f2a8bcb2a73 (diff)
downloadqt-creator-7389250fcd1ada74514f90e8670d7af087e6a7c7.tar.gz
Add Boost.Build Project Manager plug-in
Preparing to contribute the plug-in, see the announcement at http://lists.qt-project.org/pipermail/qt-creator/2015-February/004436.html Change-Id: Ic3920c9b888af5bea1b7742b8ff49984c29a2909 Reviewed-by: Orgad Shaneh <orgads@gmail.com> Reviewed-by: Eike Ziller <eike.ziller@theqtcompany.com> Reviewed-by: Leena Miettinen <riitta-leena.miettinen@theqtcompany.com> Reviewed-by: hjk <hjk@theqtcompany.com>
-rw-r--r--src/plugins/boostbuildprojectmanager/BoostBuildProjectManager.json.in19
-rw-r--r--src/plugins/boostbuildprojectmanager/BoostBuildProjectManager.mimetypes.xml36
-rw-r--r--src/plugins/boostbuildprojectmanager/b2buildconfiguration.cpp391
-rw-r--r--src/plugins/boostbuildprojectmanager/b2buildconfiguration.h138
-rw-r--r--src/plugins/boostbuildprojectmanager/b2buildinfo.cpp26
-rw-r--r--src/plugins/boostbuildprojectmanager/b2buildinfo.h44
-rw-r--r--src/plugins/boostbuildprojectmanager/b2buildstep.cpp420
-rw-r--r--src/plugins/boostbuildprojectmanager/b2buildstep.h162
-rw-r--r--src/plugins/boostbuildprojectmanager/b2openprojectwizard.cpp272
-rw-r--r--src/plugins/boostbuildprojectmanager/b2openprojectwizard.h127
-rw-r--r--src/plugins/boostbuildprojectmanager/b2outputparser.cpp197
-rw-r--r--src/plugins/boostbuildprojectmanager/b2outputparser.h64
-rw-r--r--src/plugins/boostbuildprojectmanager/b2project.cpp306
-rw-r--r--src/plugins/boostbuildprojectmanager/b2project.h106
-rw-r--r--src/plugins/boostbuildprojectmanager/b2projectfile.cpp80
-rw-r--r--src/plugins/boostbuildprojectmanager/b2projectfile.h47
-rw-r--r--src/plugins/boostbuildprojectmanager/b2projectmanager.cpp64
-rw-r--r--src/plugins/boostbuildprojectmanager/b2projectmanager.h54
-rw-r--r--src/plugins/boostbuildprojectmanager/b2projectmanager_global.h23
-rw-r--r--src/plugins/boostbuildprojectmanager/b2projectmanagerconstants.h68
-rw-r--r--src/plugins/boostbuildprojectmanager/b2projectmanagerplugin.cpp83
-rw-r--r--src/plugins/boostbuildprojectmanager/b2projectmanagerplugin.h48
-rw-r--r--src/plugins/boostbuildprojectmanager/b2projectnode.cpp260
-rw-r--r--src/plugins/boostbuildprojectmanager/b2projectnode.h77
-rw-r--r--src/plugins/boostbuildprojectmanager/b2utility.cpp151
-rw-r--r--src/plugins/boostbuildprojectmanager/b2utility.h60
-rw-r--r--src/plugins/boostbuildprojectmanager/boostbuildproject.qrc5
-rw-r--r--src/plugins/boostbuildprojectmanager/boostbuildprojectmanager.pro46
-rw-r--r--src/plugins/boostbuildprojectmanager/boostbuildprojectmanager_dependencies.pri12
-rw-r--r--src/plugins/boostbuildprojectmanager/external/projectexplorer/clangparser.cpp270
-rw-r--r--src/plugins/boostbuildprojectmanager/external/projectexplorer/clangparser.h59
-rw-r--r--src/plugins/boostbuildprojectmanager/external/projectexplorer/gccparser.cpp880
-rw-r--r--src/plugins/boostbuildprojectmanager/external/projectexplorer/gccparser.h67
-rw-r--r--src/plugins/boostbuildprojectmanager/external/projectexplorer/ldparser.cpp126
-rw-r--r--src/plugins/boostbuildprojectmanager/external/projectexplorer/ldparser.h54
-rw-r--r--src/plugins/boostbuildprojectmanager/filesselectionwizardpage.cpp232
-rw-r--r--src/plugins/boostbuildprojectmanager/filesselectionwizardpage.h106
-rw-r--r--src/plugins/boostbuildprojectmanager/selectablefilesmodel.cpp681
-rw-r--r--src/plugins/boostbuildprojectmanager/selectablefilesmodel.h189
-rw-r--r--src/plugins/plugins.pro1
40 files changed, 6051 insertions, 0 deletions
diff --git a/src/plugins/boostbuildprojectmanager/BoostBuildProjectManager.json.in b/src/plugins/boostbuildprojectmanager/BoostBuildProjectManager.json.in
new file mode 100644
index 0000000000..8700c63439
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/BoostBuildProjectManager.json.in
@@ -0,0 +1,19 @@
+{
+ \"Name\" : \"BoostBuildProjectManager\",
+ \"Version\" : \"$$QTCREATOR_VERSION\",
+ \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\",
+ \"Vendor\" : \"Mateusz Łoskot\",
+ \"Copyright\" : \"2013 (C) Mateusz Łoskot\",
+ \"License\" : [ \"GNU Lesser General Public License, Version 2.1\",
+ \"\",
+ \"This is free software; you can redistribute and/or modify it under the terms\",
+ \"of the GNU Lesser General Public License, Version 2.1 as published\",
+ \"by the Free Software Foundation.\",
+ \"See accompanying fike LICENSE.txt file or\",
+ \"copy at http://www.gnu.org/licenses/lgpl-2.1-standalone.html for more information.\",
+ \"\" ],
+ \"Category\" : \"Build Systems\",
+ \"Description\" : \"Qt Creator plugin for Boost.Build\",
+ \"Url\" : \"https://github.com/mloskot/qt-creator-plugin-boostbuild/\",
+ $$dependencyList
+}
diff --git a/src/plugins/boostbuildprojectmanager/BoostBuildProjectManager.mimetypes.xml b/src/plugins/boostbuildprojectmanager/BoostBuildProjectManager.mimetypes.xml
new file mode 100644
index 0000000000..e3391759bc
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/BoostBuildProjectManager.mimetypes.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
+<!--
+ Note the use of character groups, i.e. [Jj]amfile, seems to be impossible.
+ Also, Qt Creator at the moment disobeys this rule specified by freedesktop.org:
+ "Applications MUST match globs case-insensitively,
+ except when the case-sensitive attribute is set to true."
+ as per https://codereview.qt-project.org/#change,72567
+-->
+ <mime-type type="text/x-boostbuild-project">
+ <sub-class-of type="text/plain"/>
+ <comment>Boost.Build Project file</comment>
+ <glob pattern="Jamroot"/>
+ <glob pattern="jamroot"/>
+ <glob pattern="Jamroot.jam"/>
+ <glob pattern="jamroot.jam"/>
+ <glob pattern="Jamfile"/>
+ <glob pattern="jamfile"/>
+ <glob pattern="Jamfile.v2"/>
+ <glob pattern="jamfile.v2"/>
+ <glob pattern="Jamfile.jam"/>
+ <glob pattern="jamfile.jam"/>
+ </mime-type>
+ <mime-type type="application/vnd.qtcreator.boostbuild.files">
+ <sub-class-of type="text/plain"/>
+ <comment>Boost.Build Project Files</comment>
+ <glob pattern="Jam*.qtcreator.files"/>
+ <glob pattern="jam*.qtcreator.files"/>
+ </mime-type>
+ <mime-type type="application/vnd.qtcreator.boostbuild.includes">
+ <sub-class-of type="text/plain"/>
+ <comment>Boost.Build Project Includes</comment>
+ <glob pattern="Jam*.qtcreator.includes"/>
+ <glob pattern="jam*.qtcreator.includes"/>
+ </mime-type>
+</mime-info>
diff --git a/src/plugins/boostbuildprojectmanager/b2buildconfiguration.cpp b/src/plugins/boostbuildprojectmanager/b2buildconfiguration.cpp
new file mode 100644
index 0000000000..796d868de0
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2buildconfiguration.cpp
@@ -0,0 +1,391 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#include "b2buildconfiguration.h"
+#include "b2buildinfo.h"
+#include "b2buildstep.h"
+#include "b2project.h"
+#include "b2projectmanagerconstants.h"
+#include "b2utility.h"
+
+#include <coreplugin/icore.h>
+#include <projectexplorer/buildinfo.h>
+#include <projectexplorer/buildsteplist.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/kitinformation.h>
+#include <projectexplorer/project.h>
+#include <projectexplorer/namedwidget.h>
+#include <projectexplorer/target.h>
+
+#include <utils/pathchooser.h>
+#include <utils/fileutils.h>
+#include <utils/qtcassert.h>
+#include <utils/mimetypes/mimedatabase.h>
+
+#include <QFileInfo>
+#include <QFormLayout>
+#include <QInputDialog>
+#include <QScopedPointer>
+#include <QString>
+
+#include <memory>
+
+using namespace ProjectExplorer;
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+BuildConfiguration::BuildConfiguration(Target* parent)
+ : ProjectExplorer::BuildConfiguration(parent, Core::Id(Constants::BUILDCONFIGURATION_ID))
+{
+ ProjectExplorer::Project const* p = parent->project();
+ Q_ASSERT(p);
+ setWorkingDirectory(p->projectDirectory());
+}
+
+BuildConfiguration::BuildConfiguration(Target* parent, BuildConfiguration* source)
+ : ProjectExplorer::BuildConfiguration(parent, source)
+{
+ if (BuildConfiguration* bc = qobject_cast<BuildConfiguration*>(source))
+ setWorkingDirectory(bc->workingDirectory());
+}
+
+BuildConfiguration::BuildConfiguration(Target* parent, Core::Id const id)
+ : ProjectExplorer::BuildConfiguration(parent, id)
+{
+ ProjectExplorer::Project const* p = parent->project();
+ Q_ASSERT(p);
+ setWorkingDirectory(p->projectDirectory());
+}
+
+QVariantMap BuildConfiguration::toMap() const
+{
+ QVariantMap map(ProjectExplorer::BuildConfiguration::toMap());
+ map.insert(QLatin1String(Constants::BC_KEY_WORKDIR), workingDirectory_.toString());
+ return map;
+}
+
+bool BuildConfiguration::fromMap(QVariantMap const& map)
+{
+ if (!ProjectExplorer::BuildConfiguration::fromMap(map))
+ return false;
+
+ QString dir = map.value(QLatin1String(Constants::BC_KEY_WORKDIR)).toString();
+ setWorkingDirectory(Utils::FileName::fromString(dir));
+
+ return true;
+}
+
+ProjectExplorer::NamedWidget*
+BuildConfiguration::createConfigWidget()
+{
+ return new BuildSettingsWidget(this);
+}
+
+BuildConfiguration::BuildType
+BuildConfiguration::buildType() const
+{
+ BuildType type = Unknown;
+
+ ProjectExplorer::BuildStepList* buildStepList
+ = stepList(Core::Id(ProjectExplorer::Constants::BUILDSTEPS_BUILD));
+ Q_ASSERT(buildStepList);
+ foreach (ProjectExplorer::BuildStep* bs, buildStepList->steps()) {
+ if (BuildStep* bbStep = qobject_cast<BuildStep*>(bs)) {
+ type = bbStep->buildType();
+ break;
+ }
+ }
+
+ return type;
+}
+
+Utils::FileName BuildConfiguration::workingDirectory() const
+{
+ Q_ASSERT(!workingDirectory_.isEmpty());
+ return workingDirectory_;
+}
+
+void BuildConfiguration::setWorkingDirectory(Utils::FileName const& dir)
+{
+ if (dir.isEmpty()) {
+ if (Target* t = target()) {
+ QString const dwd
+ = Project::defaultWorkingDirectory(t->project()->projectDirectory().toString());
+ workingDirectory_ = Utils::FileName::fromString(dwd);
+ }
+ } else {
+ workingDirectory_ = dir;
+ }
+
+ Q_ASSERT(!workingDirectory_.isEmpty());
+ emitWorkingDirectoryChanged();
+}
+
+void BuildConfiguration::emitWorkingDirectoryChanged()
+{
+ if (workingDirectory() != lastEmmitedWorkingDirectory_) {
+ lastEmmitedWorkingDirectory_= workingDirectory();
+ emit workingDirectoryChanged();
+ }
+}
+
+BuildConfigurationFactory::BuildConfigurationFactory(QObject* parent)
+ : IBuildConfigurationFactory(parent)
+{
+}
+
+int
+BuildConfigurationFactory::priority(ProjectExplorer::Target const* parent) const
+{
+ return canHandle(parent) ? 0 : -1;
+}
+
+int
+BuildConfigurationFactory::priority(ProjectExplorer::Kit const* k
+ , QString const& projectPath) const
+{
+ BBPM_QDEBUG(k->displayName() << ", " << projectPath);
+
+ Utils::MimeDatabase mdb;
+ Utils::MimeType mimeType = mdb.mimeTypeForFile(QFileInfo(projectPath));
+
+ return (k && mimeType.matchesName(QLatin1String(Constants::MIMETYPE_JAMFILE)))
+ ? 0
+ : -1;
+}
+
+QList<ProjectExplorer::BuildInfo*>
+BuildConfigurationFactory::availableBuilds(ProjectExplorer::Target const* parent) const
+{
+ BBPM_QDEBUG("target: " << parent->displayName());
+
+ ProjectExplorer::Project* project = parent->project();
+ QString const projectPath(project->projectDirectory().toString());
+ BBPM_QDEBUG(projectPath);
+
+ QList<ProjectExplorer::BuildInfo*> result;
+ result << createBuildInfo(parent->kit(), projectPath, BuildConfiguration::Debug);
+ result << createBuildInfo(parent->kit(), projectPath, BuildConfiguration::Release);
+ return result;
+}
+
+QList<ProjectExplorer::BuildInfo*>
+BuildConfigurationFactory::availableSetups(ProjectExplorer::Kit const* k
+ , QString const& projectPath) const
+{
+ BBPM_QDEBUG(projectPath);
+
+ QList<ProjectExplorer::BuildInfo*> result;
+ result << createBuildInfo(k, projectPath, BuildConfiguration::Debug);
+ result << createBuildInfo(k, projectPath, BuildConfiguration::Release);
+ return result;
+}
+
+ProjectExplorer::BuildConfiguration*
+BuildConfigurationFactory::create(ProjectExplorer::Target* parent
+ , ProjectExplorer::BuildInfo const* info) const
+{
+ QTC_ASSERT(parent, return 0);
+ QTC_ASSERT(info->factory() == this, return 0);
+ QTC_ASSERT(info->kitId == parent->kit()->id(), return 0);
+ QTC_ASSERT(!info->displayName.isEmpty(), return 0);
+ BBPM_QDEBUG(info->displayName);
+
+ Project* project = qobject_cast<Project*>(parent->project());
+ QTC_ASSERT(project, return 0);
+
+ BuildInfo const* bi = static_cast<BuildInfo const*>(info);
+ QScopedPointer<BuildConfiguration> bc(new BuildConfiguration(parent));
+ bc->setDisplayName(bi->displayName);
+ bc->setDefaultDisplayName(bi->displayName);
+ bc->setBuildDirectory(bi->buildDirectory);
+ bc->setWorkingDirectory(bi->workingDirectory);
+
+ BuildStepFactory* stepFactory = BuildStepFactory::getObject();
+ QTC_ASSERT(stepFactory, return 0);
+
+ // Build steps
+ if (ProjectExplorer::BuildStepList* buildSteps
+ = bc->stepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD)) {
+ BuildStep* step = stepFactory->create(buildSteps);
+ QTC_ASSERT(step, return 0);
+ step->setBuildType(bi->buildType);
+ buildSteps->insertStep(0, step);
+ }
+
+ // Clean steps
+ if (ProjectExplorer::BuildStepList* cleanSteps
+ = bc->stepList(ProjectExplorer::Constants::BUILDSTEPS_CLEAN)) {
+ BuildStep* step = stepFactory->create(cleanSteps);
+ QTC_ASSERT(step, return 0);
+ step->setBuildType(bi->buildType);
+ cleanSteps->insertStep(0, step);
+ }
+
+ return bc.take();
+}
+
+bool
+BuildConfigurationFactory::canClone(ProjectExplorer::Target const* parent
+ , ProjectExplorer::BuildConfiguration* source) const
+{
+ Q_ASSERT(parent);
+ Q_ASSERT(source);
+
+ return canHandle(parent)
+ ? source->id() == Constants::BUILDCONFIGURATION_ID
+ : false;
+}
+
+BuildConfiguration*
+BuildConfigurationFactory::clone(ProjectExplorer::Target* parent
+ , ProjectExplorer::BuildConfiguration* source)
+{
+ Q_ASSERT(parent);
+ Q_ASSERT(source);
+
+ BuildConfiguration* copy = 0;
+ if (canClone(parent, source)) {
+ BuildConfiguration* old = static_cast<BuildConfiguration*>(source);
+ copy = new BuildConfiguration(parent, old);
+ }
+ return copy;
+}
+
+bool
+BuildConfigurationFactory::canRestore(ProjectExplorer::Target const* parent
+ , QVariantMap const& map) const
+{
+ Q_ASSERT(parent);
+
+ return canHandle(parent)
+ ? ProjectExplorer::idFromMap(map) == Constants::BUILDCONFIGURATION_ID
+ : false;
+}
+
+BuildConfiguration*
+BuildConfigurationFactory::restore(ProjectExplorer::Target *parent
+ , QVariantMap const& map)
+{
+ Q_ASSERT(parent);
+
+ if (canRestore(parent, map)) {
+ QScopedPointer<BuildConfiguration> bc(new BuildConfiguration(parent));
+ if (bc->fromMap(map))
+ return bc.take();
+ }
+ return 0;
+}
+
+bool
+BuildConfigurationFactory::canHandle(ProjectExplorer::Target const* t) const
+{
+ QTC_ASSERT(t, return false);
+
+ return t->project()->supportsKit(t->kit())
+ ? t->project()->id() == Constants::PROJECT_ID
+ : false;
+}
+
+BuildInfo*
+BuildConfigurationFactory::createBuildInfo(ProjectExplorer::Kit const* k
+ , QString const& projectPath
+ , BuildConfiguration::BuildType type) const
+{
+ Q_ASSERT(k);
+
+ BuildInfo* info = new BuildInfo(this);
+ if (type == BuildConfiguration::Release)
+ info->displayName = tr("Release");
+ else
+ info->displayName = tr("Debug");
+ info->typeName = tr("Default (%1)").arg(info->displayName);
+ info->buildType = type;
+ info->buildDirectory = defaultBuildDirectory(projectPath);
+ info->workingDirectory = defaultWorkingDirectory(projectPath);
+ info->kitId = k->id();
+
+ BBPM_QDEBUG(info->typeName << " in " << projectPath);
+ return info;
+}
+
+/*static*/ Utils::FileName
+BuildConfigurationFactory::defaultBuildDirectory(QString const& top)
+{
+ return Utils::FileName::fromString(Project::defaultBuildDirectory(top));
+}
+
+/*static*/ Utils::FileName
+BuildConfigurationFactory::defaultWorkingDirectory(QString const& top)
+{
+ return Utils::FileName::fromString(Project::defaultWorkingDirectory(top));
+}
+
+BuildSettingsWidget::BuildSettingsWidget(BuildConfiguration* bc)
+ : bc_(bc)
+ , buildPathChooser_(0)
+{
+ setDisplayName(tr("Boost.Build Manager"));
+
+ QFormLayout* fl = new QFormLayout(this);
+ fl->setContentsMargins(0, -1, 0, -1);
+ fl->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
+
+ QString const projectPath(bc_->target()->project()->projectDirectory().toString());
+
+ // Working directory
+ workPathChooser_ = new Utils::PathChooser(this);
+ workPathChooser_->setEnabled(true);
+ workPathChooser_->setEnvironment(bc_->environment());
+ workPathChooser_->setBaseDirectory(projectPath);
+ workPathChooser_->setPath(bc_->workingDirectory().toString());
+ fl->addRow(tr("Run Boost.Build in:"), workPathChooser_);
+
+ // Build directory
+ buildPathChooser_ = new Utils::PathChooser(this);
+ buildPathChooser_->setEnabled(true);
+ buildPathChooser_->setEnvironment(bc_->environment());
+ buildPathChooser_->setBaseDirectory(projectPath);
+ buildPathChooser_->setPath(bc_->rawBuildDirectory().toString());
+ fl->addRow(tr("Set build directory to:"), buildPathChooser_);
+
+ connect(workPathChooser_, SIGNAL(changed(QString))
+ , this, SLOT(workingDirectoryChanged()));
+
+ connect(buildPathChooser_, SIGNAL(changed(QString))
+ , this, SLOT(buildDirectoryChanged()));
+
+ connect(bc, SIGNAL(environmentChanged())
+ , this, SLOT(environmentHasChanged()));
+}
+
+void BuildSettingsWidget::buildDirectoryChanged()
+{
+ QTC_ASSERT(bc_, return);
+ bc_->setBuildDirectory(Utils::FileName::fromString(buildPathChooser_->rawPath()));
+}
+
+void BuildSettingsWidget::workingDirectoryChanged()
+{
+ QTC_ASSERT(bc_, return);
+ bc_->setWorkingDirectory(Utils::FileName::fromString(workPathChooser_->rawPath()));
+}
+
+void BuildSettingsWidget::environmentHasChanged()
+{
+ Q_ASSERT(buildPathChooser_);
+ buildPathChooser_->setEnvironment(bc_->environment());
+}
+
+} // namespace Internal
+} // namespace BoostBuildProjectManager
diff --git a/src/plugins/boostbuildprojectmanager/b2buildconfiguration.h b/src/plugins/boostbuildprojectmanager/b2buildconfiguration.h
new file mode 100644
index 0000000000..a9edb7743e
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2buildconfiguration.h
@@ -0,0 +1,138 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#ifndef BBBUILDCONFIGURATION_HPP
+#define BBBUILDCONFIGURATION_HPP
+
+// Qt Creator
+#include <projectexplorer/buildconfiguration.h>
+#include <projectexplorer/namedwidget.h>
+#include <utils/fileutils.h>
+// Qt
+#include <QList>
+#include <QString>
+#include <QVariantMap>
+
+namespace Utils {
+class FileName;
+class PathChooser;
+}
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+class BuildInfo;
+class BuildSettingsWidget;
+
+class BuildConfiguration : public ProjectExplorer::BuildConfiguration
+{
+ Q_OBJECT
+
+ friend class BuildConfigurationFactory;
+
+public:
+ explicit BuildConfiguration(ProjectExplorer::Target* parent);
+
+ QVariantMap toMap() const;
+
+ ProjectExplorer::NamedWidget* createConfigWidget();
+
+ BuildType buildType() const;
+
+ Utils::FileName workingDirectory() const;
+ void setWorkingDirectory(Utils::FileName const& dir);
+
+signals:
+ void workingDirectoryChanged();
+
+protected:
+ BuildConfiguration(ProjectExplorer::Target* parent, BuildConfiguration* source);
+ BuildConfiguration(ProjectExplorer::Target* parent, Core::Id const id);
+
+ bool fromMap(QVariantMap const& map);
+
+ friend class BuildSettingsWidget;
+
+private slots:
+ void emitWorkingDirectoryChanged();
+
+private:
+ Utils::FileName workingDirectory_;
+ Utils::FileName lastEmmitedWorkingDirectory_;
+};
+
+class BuildConfigurationFactory : public ProjectExplorer::IBuildConfigurationFactory
+{
+ Q_OBJECT
+
+public:
+ explicit BuildConfigurationFactory(QObject* parent = 0);
+
+ int priority(ProjectExplorer::Target const* parent) const;
+ int priority(ProjectExplorer::Kit const* k, QString const& projectPath) const;
+
+ QList<ProjectExplorer::BuildInfo*>
+ availableBuilds(ProjectExplorer::Target const* parent) const;
+
+ QList<ProjectExplorer::BuildInfo*>
+ availableSetups(ProjectExplorer::Kit const* k, QString const& projectPath) const;
+
+ ProjectExplorer::BuildConfiguration*
+ create(ProjectExplorer::Target* parent
+ , ProjectExplorer::BuildInfo const* info) const;
+
+ bool
+ canClone(ProjectExplorer::Target const* parent
+ , ProjectExplorer::BuildConfiguration* source) const;
+
+ BuildConfiguration*
+ clone(ProjectExplorer::Target* parent, ProjectExplorer::BuildConfiguration* source);
+
+ bool
+ canRestore(ProjectExplorer::Target const* parent, QVariantMap const& map) const;
+
+ BuildConfiguration*
+ restore(ProjectExplorer::Target *parent, QVariantMap const& map);
+
+ static Utils::FileName defaultBuildDirectory(QString const& top);
+ static Utils::FileName defaultWorkingDirectory(QString const& top);
+
+private:
+ bool canHandle(ProjectExplorer::Target const* target) const;
+
+ BuildInfo*
+ createBuildInfo(ProjectExplorer::Kit const* k
+ , QString const& projectPath
+ , BuildConfiguration::BuildType type) const;
+};
+
+class BuildSettingsWidget : public ProjectExplorer::NamedWidget
+{
+ Q_OBJECT
+
+public:
+ BuildSettingsWidget(BuildConfiguration* bc);
+
+private slots:
+ void environmentHasChanged();
+ void buildDirectoryChanged();
+ void workingDirectoryChanged();
+
+private:
+ BuildConfiguration* bc_;
+ Utils::PathChooser* workPathChooser_;
+ Utils::PathChooser* buildPathChooser_;
+};
+
+} // namespace Internal
+} // namespace BoostBuildProjectManager
+
+#endif // BBBUILDCONFIGURATION_HPP
diff --git a/src/plugins/boostbuildprojectmanager/b2buildinfo.cpp b/src/plugins/boostbuildprojectmanager/b2buildinfo.cpp
new file mode 100644
index 0000000000..927a7ab909
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2buildinfo.cpp
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#include "b2buildinfo.h"
+#include "b2buildconfiguration.h"
+#include "b2projectmanagerconstants.h"
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+BuildInfo::BuildInfo(BuildConfigurationFactory const* f)
+ : ProjectExplorer::BuildInfo(f)
+ , buildType(BuildConfiguration::Debug)
+{
+}
+
+} // namespace Internal
+} // namespace BoostBuildProjectManager
diff --git a/src/plugins/boostbuildprojectmanager/b2buildinfo.h b/src/plugins/boostbuildprojectmanager/b2buildinfo.h
new file mode 100644
index 0000000000..30374592ee
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2buildinfo.h
@@ -0,0 +1,44 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#ifndef BBBUILDINFO_HPP
+#define BBBUILDINFO_HPP
+
+#include "b2buildconfiguration.h"
+// Qt Creator
+#include <projectexplorer/buildconfiguration.h>
+#include <projectexplorer/buildinfo.h>
+#include <utils/fileutils.h>
+// Qt
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+class BuildConfigurationFactory;
+
+class BuildInfo : public ProjectExplorer::BuildInfo
+{
+public:
+ explicit BuildInfo(BuildConfigurationFactory const* f);
+
+ // Boost.Build option variant={debug|release}
+ // By default, the debug variant is set.
+ BuildConfiguration::BuildType buildType;
+
+ // Boost.Build command working directory.
+ // By default, empty what indicates project path from where Jamfile was opened.
+ Utils::FileName workingDirectory;
+};
+
+} // namespace Internal
+} // namespace BoostBuildProjectManager
+
+#endif // BBBUILDINFO_HPP
diff --git a/src/plugins/boostbuildprojectmanager/b2buildstep.cpp b/src/plugins/boostbuildprojectmanager/b2buildstep.cpp
new file mode 100644
index 0000000000..d6bc0772a7
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2buildstep.cpp
@@ -0,0 +1,420 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+// Copyright (C) 2013 Openismus GmbH.
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#include "b2buildconfiguration.h"
+#include "b2buildstep.h"
+#include "b2outputparser.h"
+#include "b2projectmanagerconstants.h"
+#include "b2utility.h"
+// Qt Creator
+#include <extensionsystem/pluginmanager.h>
+#include <projectexplorer/buildconfiguration.h>
+#include <projectexplorer/buildstep.h>
+#include <projectexplorer/buildsteplist.h>
+#include <projectexplorer/kitinformation.h>
+#include <projectexplorer/processparameters.h>
+#include <projectexplorer/project.h>
+#include <projectexplorer/projectconfiguration.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/target.h>
+#include <projectexplorer/toolchain.h>
+#include <utils/environment.h>
+#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
+// Qt
+#include <QFormLayout>
+#include <QLineEdit>
+#include <QScopedPointer>
+#include <QString>
+// std
+#include <memory>
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+BuildStep::BuildStep(ProjectExplorer::BuildStepList* bsl)
+ : ProjectExplorer::AbstractProcessStep(bsl, Core::Id(Constants::BUILDSTEP_ID))
+{
+}
+
+BuildStep::BuildStep(ProjectExplorer::BuildStepList* bsl, BuildStep* bs)
+ : AbstractProcessStep(bsl, bs)
+ , tasks_(bs->tasks_)
+ , arguments_(bs->arguments_)
+{
+}
+
+BuildStep::BuildStep(ProjectExplorer::BuildStepList* bsl, Core::Id const id)
+ : AbstractProcessStep(bsl, id)
+{
+}
+
+bool BuildStep::init()
+{
+ setDefaultDisplayName(QLatin1String(Constants::BOOSTBUILD));
+
+ tasks_.clear();
+ ProjectExplorer::ToolChain* tc
+ = ProjectExplorer::ToolChainKitInformation::toolChain(target()->kit());
+ if (!tc) {
+ BBPM_QDEBUG("Qt Creator needs compiler");
+ typedef ProjectExplorer::Task Task;
+ Task task(Task::Error
+ , tr("Qt Creator needs a compiler set up to build. Configure a compiler in the kit options.")
+ , Utils::FileName(), -1
+ , ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
+
+ tasks_.append(task);
+ return !tasks_.empty(); // otherwise the tasks will not get reported
+ }
+
+ BuildConfiguration* bc = thisBuildConfiguration();
+ QTC_ASSERT(bc, return false);
+
+ setIgnoreReturnValue(Constants::ReturnValueNotIgnored);
+
+ ProjectExplorer::ProcessParameters* pp = processParameters();
+ pp->setMacroExpander(bc->macroExpander());
+ {
+ // from GenericProjectManager code:
+ // Force output to english for the parsers.
+ // Do this here and not in the toolchain's addToEnvironment() to not
+ // screw up the users run environment.
+ Utils::Environment env = bc->environment();
+ env.set(QLatin1String("LC_ALL"), QLatin1String("C"));
+ pp->setEnvironment(env);
+ }
+ pp->setWorkingDirectory(bc->workingDirectory().toString());
+ pp->setCommand(makeCommand(bc->environment()));
+ pp->setArguments(allArguments());
+ pp->resolveAll();
+
+ // Create Boost.Build parser and chain with existing parsers
+ setOutputParser(new BoostBuildParser());
+ if (ProjectExplorer::IOutputParser* parser = target()->kit()->createOutputParser())
+ appendOutputParser(parser);
+ outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory());
+
+ BBPM_QDEBUG(displayName() << ", " << bc->buildDirectory().toString()
+ << ", " << pp->effectiveWorkingDirectory());
+
+ return ProjectExplorer::AbstractProcessStep::init();
+}
+
+void BuildStep::run(QFutureInterface<bool>& fi)
+{
+ BBPM_QDEBUG("running: " << displayName());
+
+ bool canContinue = true;
+ foreach (ProjectExplorer::Task const& t, tasks_) {
+ addTask(t);
+ canContinue = false;
+ }
+
+ if (!canContinue) {
+ emit addOutput(tr("Configuration is faulty. Check the Issues view for details.")
+ , BuildStep::MessageOutput);
+ fi.reportResult(false);
+ emit finished();
+ } else {
+ AbstractProcessStep::run(fi);
+ }
+}
+
+BuildConfiguration* BuildStep::thisBuildConfiguration() const
+{
+ BuildConfiguration* bc = 0;
+ if (ProjectExplorer::BuildConfiguration* bcBase = buildConfiguration()) {
+ bc = qobject_cast<BuildConfiguration*>(bcBase);
+ } else {
+ // TODO: Do we need to do anything with this case?
+ // From QmakeProjectManager:
+ // That means the step is in the deploylist, so we listen to the active build
+ // config changed signal and react...
+
+ bcBase = target()->activeBuildConfiguration();
+ bc = qobject_cast<BuildConfiguration*>(bcBase);
+ }
+ return bc;
+}
+
+ProjectExplorer::BuildStepConfigWidget* BuildStep::createConfigWidget()
+{
+ return new BuildStepConfigWidget(this);
+}
+
+bool BuildStep::immutable() const
+{
+ return false;
+}
+
+QVariantMap BuildStep::toMap() const
+{
+ QVariantMap map(ProjectExplorer::AbstractProcessStep::toMap());
+ map.insert(QLatin1String(Constants::BS_KEY_ARGUMENTS), additionalArguments());
+ return map;
+}
+
+bool BuildStep::fromMap(QVariantMap const& map)
+{
+ QString const args(map.value(QLatin1String(Constants::BS_KEY_ARGUMENTS)).toString());
+ setAdditionalArguments(args);
+
+ return ProjectExplorer::AbstractProcessStep::fromMap(map);
+}
+
+QString BuildStep::makeCommand(Utils::Environment const& env) const
+{
+ Q_UNUSED(env);
+ return QLatin1String(Constants::COMMAND_BB2);
+}
+
+QString BuildStep::additionalArguments() const
+{
+ return Utils::QtcProcess::joinArgs(arguments_);
+}
+
+QString BuildStep::allArguments() const
+{
+ QStringList args(arguments_);
+
+ // Collect implicit arguments not specified by user directly as option=value pair
+ if (ProjectExplorer::BuildConfiguration* bc = buildConfiguration()) {
+ QString const builddir(bc->buildDirectory().toString());
+ if (!builddir.isEmpty())
+ args.append(QLatin1String("--build-dir=") + builddir);
+ }
+
+ return Utils::QtcProcess::joinArgs(args);
+}
+
+void BuildStep::appendAdditionalArgument(QString const& arg)
+{
+ // TODO: use map or find duplicates?
+ arguments_.append(arg);
+}
+
+void BuildStep::setAdditionalArguments(QString const& args)
+{
+ Utils::QtcProcess::SplitError err;
+ QStringList argsList = Utils::QtcProcess::splitArgs(args, Utils::HostOsInfo::hostOs(), false, &err);
+ if (err == Utils::QtcProcess::SplitOk) {
+ arguments_ = argsList;
+ emit argumentsChanged(args);
+ }
+}
+
+ProjectExplorer::BuildConfiguration::BuildType
+BuildStep::buildType() const
+{
+ // TODO: what is user inputs "variant = release" or mixed-case value?
+ return arguments_.contains(QLatin1String("variant=release"))
+ ? BuildConfiguration::Release
+ : BuildConfiguration::Debug;
+}
+
+void
+BuildStep::setBuildType(ProjectExplorer::BuildConfiguration::BuildType type)
+{
+ // TODO: Move literals to constants
+ QString arg(QLatin1String("variant="));
+ if (type == BuildConfiguration::Release)
+ arg += QLatin1String("release");
+ else
+ arg += QLatin1String("debug");
+
+ appendAdditionalArgument(arg);
+}
+
+BuildStepFactory::BuildStepFactory(QObject* parent)
+ : IBuildStepFactory(parent)
+{
+}
+
+/*static*/ BuildStepFactory* BuildStepFactory::getObject()
+{
+ return ExtensionSystem::PluginManager::getObject<BuildStepFactory>();
+}
+
+QList<Core::Id>
+BuildStepFactory::availableCreationIds(ProjectExplorer::BuildStepList* parent) const
+{
+ return canHandle(parent)
+ ? QList<Core::Id>() << Core::Id(Constants::BUILDSTEP_ID)
+ : QList<Core::Id>();
+}
+
+QString BuildStepFactory::displayNameForId(Core::Id const id) const
+{
+ BBPM_QDEBUG("id: " << id.toString());
+
+ QString name;
+ if (id == Constants::BUILDSTEP_ID) {
+ name = tr("Boost.Build"
+ , "Display name for BoostBuildProjectManager::BuildStep id.");
+ }
+ return name;
+}
+
+bool BuildStepFactory::canCreate(ProjectExplorer::BuildStepList* parent
+ , Core::Id const id) const
+{
+ return canHandle(parent) && Core::Id(Constants::BUILDSTEP_ID) == id;
+}
+
+BuildStep*
+BuildStepFactory::create(ProjectExplorer::BuildStepList* parent)
+{
+ ProjectExplorer::BuildStep* step = create(parent, Constants::BUILDSTEP_ID);
+ return qobject_cast<BuildStep*>(step);
+}
+
+ProjectExplorer::BuildStep*
+BuildStepFactory::create(ProjectExplorer::BuildStepList* parent, Core::Id const id)
+{
+ BBPM_QDEBUG("id: " << id.toString());
+ if (!canCreate(parent, id))
+ return 0;
+
+ BuildStep* step = new BuildStep(parent);
+
+ if (parent->id() == ProjectExplorer::Constants::BUILDSTEPS_CLEAN)
+ step->appendAdditionalArgument(QLatin1String("--clean"));
+
+ return step;
+}
+
+bool BuildStepFactory::canClone(ProjectExplorer::BuildStepList *parent
+ , ProjectExplorer::BuildStep *source) const
+{
+ return canCreate(parent, source->id());
+}
+
+ProjectExplorer::BuildStep*
+BuildStepFactory::clone(ProjectExplorer::BuildStepList* parent
+ , ProjectExplorer::BuildStep* source)
+{
+ return canClone(parent, source)
+ ? new BuildStep(parent, static_cast<BuildStep*>(source))
+ : 0;
+}
+
+bool BuildStepFactory::canRestore(ProjectExplorer::BuildStepList* parent
+ , QVariantMap const& map) const
+{
+ return canCreate(parent, ProjectExplorer::idFromMap(map));
+}
+
+ProjectExplorer::BuildStep*
+BuildStepFactory::restore(ProjectExplorer::BuildStepList* parent
+ , QVariantMap const& map)
+{
+ Q_ASSERT(parent);
+
+ if (canRestore(parent, map)) {
+ QScopedPointer<BuildStep> bs(new BuildStep(parent));
+ if (bs->fromMap(map))
+ return bs.take();
+ }
+ return 0;
+}
+
+bool BuildStepFactory::canHandle(ProjectExplorer::BuildStepList* parent) const
+{
+ QTC_ASSERT(parent, return false);
+ return parent->target()->project()->id() == Constants::PROJECT_ID;
+}
+
+BuildStepConfigWidget::BuildStepConfigWidget(BuildStep* step)
+ : step_(step)
+{
+ QFormLayout *fl = new QFormLayout(this);
+ fl->setMargin(0);
+ fl->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
+ setLayout(fl);
+
+ arguments_ = new QLineEdit(this);
+ arguments_->setText(step_->additionalArguments());
+ fl->addRow(tr("Arguments:"), arguments_);
+
+ updateDetails();
+
+ connect(arguments_, SIGNAL(textChanged(QString))
+ , step, SLOT(setAdditionalArguments(QString)));
+ connect(step, SIGNAL(argumentsChanged(QString))
+ , this, SLOT(updateDetails()));
+ connect(step_->project(), SIGNAL(environmentChanged())
+ , this, SLOT(updateDetails()));
+
+ if (BuildConfiguration* bc = step_->thisBuildConfiguration()) {
+ connect(bc, SIGNAL(buildDirectoryChanged())
+ , this, SLOT(updateDetails()));
+ }
+}
+
+BuildStepConfigWidget::~BuildStepConfigWidget()
+{
+}
+
+QString BuildStepConfigWidget::displayName() const
+{
+ return tr(Constants::BOOSTBUILD
+ , "BoostBuildProjectManager::BuildStep display name.");
+}
+
+QString BuildStepConfigWidget::summaryText() const
+{
+ return summaryText_;
+}
+
+void BuildStepConfigWidget::setSummaryText(QString const& text)
+{
+ if (text != summaryText_) {
+ summaryText_ = text;
+ emit updateSummary();
+ }
+}
+
+void BuildStepConfigWidget::updateDetails()
+{
+ ProjectExplorer::ToolChain* tc
+ = ProjectExplorer::ToolChainKitInformation::toolChain(step_->target()->kit());
+ if (!tc) {
+ setSummaryText(tr("<b>%1:</b> %2")
+ .arg(QLatin1String(Constants::BOOSTBUILD))
+ .arg(ProjectExplorer::ToolChainKitInformation::msgNoToolChainInTarget()));
+ return;
+ }
+
+ BuildConfiguration* bc = step_->thisBuildConfiguration();
+ QTC_ASSERT(bc, return;);
+
+ ProjectExplorer::ProcessParameters params;
+ params.setMacroExpander(bc->macroExpander());
+ params.setEnvironment(bc->environment());
+ params.setWorkingDirectory(bc->workingDirectory().toString());
+ params.setCommand(step_->makeCommand(bc->environment()));
+ params.setArguments(step_->allArguments());
+
+ if (params.commandMissing()) {
+ setSummaryText(tr("<b>%1:</b> %2 not found in the environment.")
+ .arg(QLatin1String(Constants::BOOSTBUILD))
+ .arg(params.command())); // Override display text
+ } else {
+ setSummaryText(params.summary(displayName()));
+ }
+
+}
+
+} // namespace Internal
+} // namespace BoostBuildProjectManager
diff --git a/src/plugins/boostbuildprojectmanager/b2buildstep.h b/src/plugins/boostbuildprojectmanager/b2buildstep.h
new file mode 100644
index 0000000000..3b587777d2
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2buildstep.h
@@ -0,0 +1,162 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#ifndef BBBUILDSTEP_HPP
+#define BBBUILDSTEP_HPP
+
+// Qt Creator
+#include <projectexplorer/abstractprocessstep.h>
+#include <projectexplorer/buildconfiguration.h>
+#include <projectexplorer/buildstep.h>
+#include <projectexplorer/task.h>
+// Qt
+#include <QLineEdit>
+#include <QList>
+#include <QString>
+#include <QVariantMap>
+
+namespace ProjectExplorer {
+class Project;
+}
+
+namespace Utils {
+class Environment;
+}
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+class BuildConfiguration;
+
+class BuildStep : public ProjectExplorer::AbstractProcessStep
+{
+ Q_OBJECT
+ friend class BuildStepFactory;
+ friend class BuildStepConfigWidget;
+
+public:
+
+ explicit BuildStep(ProjectExplorer::BuildStepList* bsl);
+
+ bool init();
+
+ void run(QFutureInterface<bool>& interface);
+
+ ProjectExplorer::BuildStepConfigWidget* createConfigWidget();
+
+ bool immutable() const;
+
+ QVariantMap toMap() const;
+
+ bool fromMap(QVariantMap const& map);
+
+ QString makeCommand(Utils::Environment const& env) const;
+
+ QString additionalArguments() const;
+
+ QString allArguments() const;
+
+ void appendAdditionalArgument(QString const& arg);
+
+ ProjectExplorer::BuildConfiguration::BuildType
+ buildType() const;
+
+ void setBuildType(ProjectExplorer::BuildConfiguration::BuildType type);
+
+public slots:
+ void setAdditionalArguments(QString const& list);
+
+signals:
+ void argumentsChanged(QString const& list);
+
+protected:
+ BuildStep(ProjectExplorer::BuildStepList* bsl, BuildStep* bs);
+ BuildStep(ProjectExplorer::BuildStepList* bsl, Core::Id const id);
+
+private:
+ BuildConfiguration* thisBuildConfiguration() const;
+
+ QList<ProjectExplorer::Task> tasks_;
+ QStringList arguments_;
+};
+
+// Factory used to create instances of BuildStep.
+class BuildStepFactory : public ProjectExplorer::IBuildStepFactory
+{
+ Q_OBJECT
+
+public:
+ BuildStepFactory(QObject* parent = 0);
+
+ static BuildStepFactory* getObject();
+
+ QList<Core::Id>
+ availableCreationIds(ProjectExplorer::BuildStepList* bc) const;
+
+ QString
+ displayNameForId(const Core::Id id) const;
+
+ bool
+ canCreate(ProjectExplorer::BuildStepList* parent, Core::Id const id) const;
+
+ BuildStep*
+ create(ProjectExplorer::BuildStepList* parent);
+
+ ProjectExplorer::BuildStep*
+ create(ProjectExplorer::BuildStepList* parent, Core::Id const id);
+
+ bool
+ canClone(ProjectExplorer::BuildStepList *parent
+ , ProjectExplorer::BuildStep *source) const;
+
+ ProjectExplorer::BuildStep*
+ clone(ProjectExplorer::BuildStepList* parent, ProjectExplorer::BuildStep* source);
+
+ bool
+ canRestore(ProjectExplorer::BuildStepList* parent, QVariantMap const& map) const;
+
+ ProjectExplorer::BuildStep*
+ restore(ProjectExplorer::BuildStepList* parent, QVariantMap const& map);
+
+private:
+
+ bool
+ canHandle(ProjectExplorer::BuildStepList* parent) const;
+};
+
+class BuildStepConfigWidget : public ProjectExplorer::BuildStepConfigWidget
+{
+ Q_OBJECT
+
+public:
+ explicit BuildStepConfigWidget(BuildStep* buildStep);
+ ~BuildStepConfigWidget();
+ QString displayName() const;
+ QString summaryText() const;
+
+private slots:
+
+ void updateDetails();
+
+private:
+ void setSummaryText(const QString &text);
+
+ ProjectExplorer::BuildConfiguration* bc_;
+ BuildStep* step_;
+ QString summaryText_;
+ QLineEdit* arguments_;
+};
+
+} // namespace Internal
+} // namespace BoostBuildProjectManager
+
+#endif // BBBUILDSTEP_HPP
+
diff --git a/src/plugins/boostbuildprojectmanager/b2openprojectwizard.cpp b/src/plugins/boostbuildprojectmanager/b2openprojectwizard.cpp
new file mode 100644
index 0000000000..d69ddc1385
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2openprojectwizard.cpp
@@ -0,0 +1,272 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#include "b2openprojectwizard.h"
+#include "b2project.h"
+#include "b2projectmanagerconstants.h"
+#include "b2utility.h"
+#include "filesselectionwizardpage.h"
+// Qt Creator
+#include <coreplugin/iwizardfactory.h>
+#include <coreplugin/icore.h>
+#include <projectexplorer/customwizard/customwizard.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <utils/pathchooser.h>
+#include <utils/qtcassert.h>
+#include <utils/mimetypes/mimedatabase.h>
+// Qt
+#include <QFileInfo>
+#include <QFormLayout>
+#include <QLabel>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QVBoxLayout>
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+OpenProjectWizard::OpenProjectWizard(Project const* const project)
+ : project_(project)
+ , projectOpened_(false)
+{
+ // Project instance has been created, but it's only partially initialised and
+ // rest of the initialization takes place after this wizard completes.
+ Q_ASSERT(project_);
+
+ setDisplayName(tr("Open %1 Project").arg(BBPM_C(BOOSTBUILD)));
+ setId(BBPM_C(PROJECT_WIZARD_ID));
+ setWizardKind(ProjectWizard); // affects dir vs file path and sub-projects handling
+
+ // TODO: do we need categories or flags?
+}
+
+bool OpenProjectWizard::run(QString const& platform, QVariantMap const& extraValues)
+{
+ QVariantMap extraValuesCopy(extraValues);
+
+ // Project name should be passed by caller, but,
+ // since we have Project instance handy, double-check.
+ if (!extraValuesCopy.contains(BBPM_C(P_KEY_PROJECTNAME)))
+ extraValuesCopy.insert(BBPM_C(P_KEY_PROJECTNAME), project_->displayName());
+
+ projectOpened_ = false;
+ outputValues_.clear();
+
+ runWizard(project_->projectFilePath().toString(), 0, platform, extraValuesCopy);
+
+ return projectOpened_;
+}
+
+Core::BaseFileWizard *OpenProjectWizard::create(QWidget* parent, Core::WizardDialogParameters const& parameters) const
+{
+ OpenProjectWizardDialog* wizard(new OpenProjectWizardDialog(parent
+ , parameters.defaultPath(), parameters.extraValues()
+ , const_cast<OpenProjectWizard*>(this)->outputValues_));
+
+ foreach (QWizardPage* p, parameters.extensionPages())
+ wizard->addPage(p);
+
+ return wizard;
+}
+
+Core::GeneratedFiles
+OpenProjectWizard::generateFiles(QWizard const* wizard, QString* errorMessage) const
+{
+ Q_UNUSED(errorMessage)
+ Q_ASSERT(project_);
+
+ OpenProjectWizardDialog const* openWizard
+ = qobject_cast<OpenProjectWizardDialog const*>(wizard);
+
+ QDir const projectDir(openWizard->path());
+
+ // Set up MIME filters for C/C++ headers
+ QStringList headerFilters;
+ QStringList const headerMimeTypes = QStringList()
+ << QLatin1String("text/x-chdr") << QLatin1String("text/x-c++hdr");
+
+ Utils::MimeDatabase mdb;
+ foreach (QString const& headerMime, headerMimeTypes) {
+ Utils::MimeType mime = mdb.mimeTypeForName(headerMime);
+ foreach (QString const& gp, mime.globPatterns())
+ headerFilters.append(gp);
+ }
+
+ // Generate list of include paths.
+ // If any C/C++ headers in any directory from paths, add it to include paths,
+ // used for C/C++ parsing only.
+ QStringList includePaths;
+ QStringList const paths = openWizard->selectedPaths();
+ foreach (QString const& path, paths) {
+ QFileInfo const fileInfo(path);
+ QDir const thisDir(fileInfo.absoluteFilePath());
+ if (!thisDir.entryList(headerFilters, QDir::Files).isEmpty()) {
+ QString const relative = projectDir.relativeFilePath(thisDir.path());
+ includePaths.append(relative.isEmpty() ? QLatin1String(".") : relative);
+ }
+ }
+
+ // Generate list of sources
+ QStringList sources = openWizard->selectedFiles();
+ Utility::makeRelativePaths(projectDir.absolutePath(), sources);
+
+ Core::GeneratedFile generatedFilesFile(project_->filesFilePath());
+ generatedFilesFile.setContents(sources.join(QLatin1String("\n")));
+
+ Core::GeneratedFile generatedIncludesFile(project_->includesFilePath());
+ generatedIncludesFile.setContents(includePaths.join(QLatin1String("\n")));
+
+ Core::GeneratedFiles files;
+ files.append(generatedFilesFile);
+ files.append(generatedIncludesFile);
+ return files;
+}
+
+bool
+OpenProjectWizard::postGenerateFiles(QWizard const* wizard
+ , Core::GeneratedFiles const& files, QString* errorMessage)
+{
+ Q_UNUSED(wizard);
+
+ projectOpened_
+ = ProjectExplorer::CustomProjectWizard::postGenerateOpen(files, errorMessage);
+
+ return projectOpened_;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+OpenProjectWizardDialog::OpenProjectWizardDialog(QWidget* parent
+ , QString const& projectFile
+ , QVariantMap const& extraValues, QVariantMap& outputValues)
+ : Core::BaseFileWizard(parent)
+ , outputValues_(outputValues)
+ , extraValues_(extraValues)
+ , projectFile_(projectFile)
+{
+ setWindowTitle(tr("Open %1 Project").arg(BBPM_C(BOOSTBUILD)));
+
+ pathsPage_ = new PathsSelectionWizardPage(this);
+ pathsPage_->setTitle(tr("Project Name and Paths"));
+ int const pathsPageId = addPage(pathsPage_);
+ wizardProgress()->item(pathsPageId)->setTitle(tr("Location"));
+
+ filesPage_ = new FilesSelectionWizardPage(this);
+ filesPage_->setTitle(tr("File Selection"));
+ int const filesPageId = addPage(filesPage_);
+ wizardProgress()->item(filesPageId)->setTitle(tr("Files"));
+}
+
+
+QString OpenProjectWizardDialog::path() const
+{
+ QFileInfo const projectFileInfo(projectFile());
+ QTC_ASSERT(projectFileInfo.isFile(), return QString());
+
+ return projectFileInfo.absoluteDir().absolutePath();
+}
+
+QString OpenProjectWizardDialog::projectFile() const
+{
+ return projectFile_;
+}
+
+QString OpenProjectWizardDialog::projectName() const
+{
+ return pathsPage_->projectName();
+}
+
+QString OpenProjectWizardDialog::defaultProjectName() const
+{
+ return extraValues_.value(BBPM_C(P_KEY_PROJECTNAME)).toString();
+}
+
+QStringList OpenProjectWizardDialog::selectedFiles() const
+{
+ return filesPage_->selectedFiles();
+}
+
+QStringList OpenProjectWizardDialog::selectedPaths() const
+{
+ return filesPage_->selectedPaths();
+}
+
+void OpenProjectWizardDialog::setProjectName(QString const& name)
+{
+ outputValues_.insert(QLatin1String(Constants::P_KEY_PROJECTNAME), name);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+PathsSelectionWizardPage::PathsSelectionWizardPage(OpenProjectWizardDialog* wizard)
+ : QWizardPage(wizard)
+ , wizard_(wizard)
+{
+ QFormLayout *fl = new QFormLayout();
+ setLayout(fl);
+
+ QLabel* pathLabel = new QLabel(this);
+ pathLabel->setText(tr("Opening the following Jamfile as a project:"));
+ fl->addRow(pathLabel);
+
+ QLineEdit* pathLine = new QLineEdit(this);
+ pathLine->setReadOnly(true);
+ pathLine->setDisabled(true);
+ pathLine->setText(wizard_->projectFile());
+ fl->addRow(pathLine);
+
+ QString projectName(Utility::parseJamfileProjectName(wizard_->projectFile()));
+ if (projectName.isEmpty())
+ projectName = wizard_->defaultProjectName();
+
+ nameLineEdit_ = new QLineEdit(this);
+ connect(nameLineEdit_, &QLineEdit::textChanged
+ , wizard_, &OpenProjectWizardDialog::setProjectName);
+ nameLineEdit_->setText(projectName);
+ fl->addRow(tr("Project name:"), nameLineEdit_);
+
+ QLabel* defaultsLabel = new QLabel(this);
+ defaultsLabel->setText(tr("Default Boost.Build runtime locations:"));
+ fl->addRow(defaultsLabel);
+
+ QLineEdit* workingLine = new QLineEdit(this);
+ workingLine->setReadOnly(true);
+ workingLine->setDisabled(true);
+ workingLine->setText(Project::defaultWorkingDirectory(wizard_->projectFile()));
+ fl->addRow(tr("Working directory:"), workingLine);
+
+ QLineEdit* buildLine = new QLineEdit(this);
+ buildLine->setReadOnly(true);
+ buildLine->setDisabled(true);
+ buildLine->setText(Project::defaultBuildDirectory(wizard_->projectFile()));
+ fl->addRow(tr("Build directory:"), buildLine);
+
+ // TODO: indicate if we can find Boost.Build executable?
+
+ QString const info(tr(
+ "This allows you to use Qt Creator as an IDE to edit and navigate C++ code, "
+ "run %1 command, work through compilation issues, "
+ "configure executable targets to run and debug.")
+ .arg(QLatin1String(Constants::BOOSTBUILD)));
+ QLabel* infoLabel = new QLabel(this);
+ infoLabel->setWordWrap(true);
+ infoLabel->setText(info);
+ fl->addRow(infoLabel);
+}
+
+QString PathsSelectionWizardPage::projectName() const
+{
+ return nameLineEdit_->text();
+}
+
+} // namespace Internal
+} // namespace BoostBuildProjectManager
diff --git a/src/plugins/boostbuildprojectmanager/b2openprojectwizard.h b/src/plugins/boostbuildprojectmanager/b2openprojectwizard.h
new file mode 100644
index 0000000000..d7d6a93f63
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2openprojectwizard.h
@@ -0,0 +1,127 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#ifndef BBOPENPROJECTWIZARD_HPP
+#define BBOPENPROJECTWIZARD_HPP
+
+// Qt Creator
+#include <coreplugin/basefilewizard.h>
+#include <coreplugin/basefilewizardfactory.h>
+#include <coreplugin/generatedfile.h>
+#include <utils/wizard.h>
+// Qt
+#include <QString>
+#include <QStringList>
+QT_BEGIN_NAMESPACE
+class QVBoxLayout;
+class QLabel;
+class QTreeView;
+class QLineEdit;
+QT_END_NAMESPACE
+
+namespace Utils {
+class PathChooser;
+}
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+class Project;
+class PathsSelectionWizardPage;
+class FilesSelectionWizardPage;
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// NOTE: The Boost.Build wizard is based on Core::BaseFileWizard which seems to be
+// dedicated to build "New Project" wizards. So, the plugin uses the base class in
+// unconventional, matching its features to Boost.Build wizard needs, like:
+// - no parent QWidget is used
+// - platform name is set from default Kit display name, usually it's "Desktop"
+// - extra values QVariantMap may carry custom data
+// CAUTION: This wizard may stop building or start failing in run-time,
+// if Qt Creator changes the base class significantly.
+class OpenProjectWizard : public Core::BaseFileWizardFactory
+{
+ Q_OBJECT
+
+public:
+ OpenProjectWizard(Project const* const project);
+
+ bool run(QString const& platform, QVariantMap const& extraValues);
+
+ QVariantMap outputValues() const { return outputValues_; }
+
+protected:
+
+ Core::BaseFileWizard*
+ create(QWidget* parent, Core::WizardDialogParameters const& parameters) const;
+
+ Core::GeneratedFiles
+ generateFiles(QWizard const* baseWizard, QString* errorMessage) const;
+
+ bool
+ postGenerateFiles(QWizard const* wizard
+ , Core::GeneratedFiles const& files, QString* errorMessage);
+
+private:
+ Project const* const project_;
+ QVariantMap outputValues_;
+ bool projectOpened_;
+};
+
+//////////////////////////////////////////////////////////////////////////////////////////
+class OpenProjectWizardDialog : public Core::BaseFileWizard
+{
+ Q_OBJECT
+
+public:
+ OpenProjectWizardDialog(QWidget* parent, QString const& projectFile
+ , QVariantMap const& extraValues, QVariantMap& outputValues);
+
+ QString path() const;
+ QString projectFile() const;
+ QString projectName() const;
+ QString defaultProjectName() const;
+
+ QStringList selectedFiles() const;
+ QStringList selectedPaths() const;
+
+public slots:
+ void setProjectName(QString const& name);
+
+private:
+ QVariantMap& outputValues_;
+ QVariantMap extraValues_;
+ QString projectFile_;
+ PathsSelectionWizardPage* pathsPage_;
+ FilesSelectionWizardPage* filesPage_;
+};
+
+//////////////////////////////////////////////////////////////////////////////////////////
+class PathsSelectionWizardPage : public QWizardPage
+{
+ Q_OBJECT
+
+public:
+ explicit PathsSelectionWizardPage(OpenProjectWizardDialog* wizard);
+
+ QString projectName() const;
+ void setProjectName(QString const& name);
+
+private:
+ OpenProjectWizardDialog* wizard_;
+ QLineEdit* nameLineEdit_;
+};
+
+} // namespace Internal
+} // namespace BoostBuildProjectManager
+
+#endif // BBOPENPROJECTWIZARD_HPP
diff --git a/src/plugins/boostbuildprojectmanager/b2outputparser.cpp b/src/plugins/boostbuildprojectmanager/b2outputparser.cpp
new file mode 100644
index 0000000000..af552e3e03
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2outputparser.cpp
@@ -0,0 +1,197 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#include "b2outputparser.h"
+#include "b2utility.h"
+#include "external/projectexplorer/gccparser.h"
+#include "external/projectexplorer/ldparser.h"
+#include "external/projectexplorer/clangparser.h"
+// Qt Creator
+#include <projectexplorer/ioutputparser.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/task.h>
+#include <utils/qtcassert.h>
+// Qt
+#include <QRegExp>
+#include <QString>
+#include <QStringRef>
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+namespace {
+char const* const RxToolsetFromCommand = "^([\\w-]+)(?:\\.)([\\w-]+).+$";
+char const* const RxToolsetFromWarning = "^warning\\:.+toolset.+\\\"([\\w-]+)\\\".*$";
+// TODO: replace filename with full path? ^\*\*passed\*\*\s(.+\.test)
+char const* const RxTestPassed = "^\\*\\*passed\\*\\*\\s+(.+\\.test)\\s*$";
+char const* const RxTestFailed = "^\\.\\.\\.failed\\s+testing\\.capture-output\\s+(.+\\.run)\\.\\.\\.$";
+char const* const RxTestFailedAsExpected = "^\\(failed-as-expected\\)\\s+(.+\\.o)\\s*$";
+char const* const RxTestFileLineN = "(\\.[ch][px]*)\\(([0-9]+)\\)"; // replace \\1:\\2
+char const* const RxTestFileObj = "\\W(\\w+)(\\.o)";
+}
+
+BoostBuildParser::BoostBuildParser()
+ : rxToolsetNameCommand_(QLatin1String(RxToolsetFromCommand))
+ , rxToolsetNameWarning_(QLatin1String(RxToolsetFromWarning))
+ , rxTestPassed_(QLatin1String(RxTestPassed))
+ , rxTestFailed_(QLatin1String(RxTestFailed))
+ , rxTestFailedAsExpected_(QLatin1String(RxTestFailedAsExpected))
+ , rxTestFileLineN_(QLatin1String(RxTestFileLineN))
+ , rxTestFileObj_(QLatin1String(RxTestFileObj))
+ , lineMode_(Common)
+{
+ rxToolsetNameCommand_.setMinimal(true);
+ QTC_CHECK(rxToolsetNameCommand_.isValid());
+
+ rxToolsetNameWarning_.setMinimal(true);
+ QTC_CHECK(rxToolsetNameWarning_.isValid());
+
+ rxTestPassed_.setMinimal(true);
+ QTC_CHECK(rxTestPassed_.isValid());
+
+ rxTestFailed_.setMinimal(true);
+ QTC_CHECK(rxTestFailed_.isValid());
+
+ rxTestFailedAsExpected_.setMinimal(true);
+ QTC_CHECK(rxTestFailedAsExpected_.isValid());
+
+ rxTestFileLineN_.setMinimal(true);
+ QTC_CHECK(rxTestFileLineN_.isValid());
+}
+
+QString BoostBuildParser::findToolset(QString const& line) const
+{
+ QString name;
+ if (rxToolsetNameWarning_.indexIn(line) > -1)
+ name = rxToolsetNameWarning_.cap(1);
+ else if (rxToolsetNameCommand_.indexIn(line) > -1)
+ name = rxToolsetNameCommand_.cap(1);
+ return name;
+}
+
+void BoostBuildParser::setToolsetParser(QString const& toolsetName)
+{
+ if (!toolsetName.isEmpty() && toolsetName_.isEmpty()) {
+ if (QStringRef(&toolsetName, 0, 3) == QLatin1String("gcc")) {
+ appendOutputParser(new ProjectExplorer::GccParser());
+ toolsetName_ = toolsetName;
+ } else if (QStringRef(&toolsetName, 0, 5) == QLatin1String("clang")) {
+ // clang-xxx found (e.g. clang-linux)
+ appendOutputParser(new ProjectExplorer::ClangParser());
+ toolsetName_ = toolsetName;
+ } else {
+ // TODO: Add more toolsets (Intel, VC++, etc.)
+ }
+ }
+}
+
+void BoostBuildParser::stdOutput(QString const& rawLine)
+{
+ setToolsetParser(findToolset(rawLine));
+
+ QString const line
+ = rightTrimmed(rawLine).replace(rxTestFileLineN_, QLatin1String("\\1:\\2"));
+ if (!toolsetName_.isEmpty() && line.startsWith(toolsetName_))
+ lineMode_ = Toolset;
+ else if (line.startsWith(QLatin1String("testing"))
+ || line.startsWith(QLatin1String("(failed-as-expected)")))
+ lineMode_ = Testing;
+ else if (line.startsWith(QLatin1String("common")))
+ lineMode_ = Common;
+
+ // TODO: Why forwarding stdOutput to ProjectExplorer::IOutputParser::stdError?
+ // Because of a bug (or feature?) in Boost.Build:
+ // stdout and stderr not forwarded to respective channels
+ // https://svn.boost.org/trac/boost/ticket/9485
+
+ if (lineMode_ == Toolset) {
+ ProjectExplorer::IOutputParser::stdError(line);
+ } else if (lineMode_ == Testing) {
+ if (rxTestPassed_.indexIn(line) > -1) {
+ BBPM_QDEBUG(rxTestPassed_.capturedTexts());
+ // TODO: issue #3
+ ProjectExplorer::Task task(ProjectExplorer::Task::Unknown
+ , rxTestPassed_.cap(0)
+ , Utils::FileName::fromString(rxTestPassed_.cap(1))
+ , -1 // line
+ , ProjectExplorer::Constants::TASK_CATEGORY_COMPILE);
+ setTask(task);
+ lineMode_ = Common;
+ } else if (rxTestFailed_.indexIn(line) > -1) {
+ BBPM_QDEBUG(rxTestFailed_.capturedTexts());
+
+ // Report summary task for "...failed testing.capture-output /myfile.run"
+ ProjectExplorer::Task task(ProjectExplorer::Task::Error
+ , rxTestFailed_.cap(0)
+ , Utils::FileName::fromString(rxTestFailed_.cap(1))
+ , -1 // line
+ , ProjectExplorer::Constants::TASK_CATEGORY_COMPILE);
+ setTask(task);
+
+ lineMode_ = Common;
+ } else if (rxTestFailedAsExpected_.indexIn(line) > -1) {
+ BBPM_QDEBUG(rxTestFailedAsExpected_.capturedTexts());
+
+ // TODO: Handling of "(failed-as-expected)" is not great, might be confusing.
+ // Boost.Build spits out compile command first, so compilation errors arrive
+ // and are parsed immediately (issue tasks are created)
+ // due to lineMode_==Toolset.
+ // Then, "(failed-as-expected)" status arrives and there seem to be no way to
+ // look back and clear all the issue tasks created for compilation errors.
+ // TODO: Ask Volodya if b2 could announce "testing." before compile command
+ // for a compile-time test.
+
+ QString fileName(rxTestFailedAsExpected_.cap(1));
+ if (rxTestFileObj_.indexIn(fileName))
+ fileName = rxTestFileObj_.cap(1) + QLatin1String(".cpp");// FIXME:hardcoded ext
+
+ // ATM, we can only indicate in UI that test failed-as-expected
+ ProjectExplorer::Task task(ProjectExplorer::Task::Error
+ , rxTestFailedAsExpected_.cap(0)
+ , Utils::FileName::fromString(fileName)
+ , -1 // line
+ , ProjectExplorer::Constants::TASK_CATEGORY_COMPILE);
+ setTask(task);
+
+ lineMode_ = Common;
+ } else {
+ // Parses compilation errors of run-time tests, creates issue tasks
+ ProjectExplorer::IOutputParser::stdError(line);
+ }
+ } else {
+ doFlush();
+ ProjectExplorer::IOutputParser::stdOutput(line);
+ }
+}
+
+void BoostBuildParser::stdError(QString const& line)
+{
+ setToolsetParser(findToolset(line));
+ ProjectExplorer::IOutputParser::stdError(line);
+}
+
+void BoostBuildParser::doFlush()
+{
+ if (!lastTask_.isNull()) {
+ ProjectExplorer::Task t = lastTask_;
+ lastTask_.clear();
+ emit addTask(t);
+ }
+}
+
+void BoostBuildParser::setTask(ProjectExplorer::Task const& task)
+{
+ doFlush();
+ lastTask_ = task;
+}
+
+} // namespace Internal
+} // namespace BoostBuildProjectManager
diff --git a/src/plugins/boostbuildprojectmanager/b2outputparser.h b/src/plugins/boostbuildprojectmanager/b2outputparser.h
new file mode 100644
index 0000000000..a2f54cf59c
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2outputparser.h
@@ -0,0 +1,64 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#ifndef BBOUTPUTPARSER_HPP
+#define BBOUTPUTPARSER_HPP
+
+// Qt Creator
+#include <projectexplorer/ioutputparser.h>
+#include <projectexplorer/task.h>
+// Qt
+#include <QPointer>
+#include <QString>
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+class BoostBuildParser : public ProjectExplorer::IOutputParser
+{
+ Q_OBJECT
+
+public:
+ BoostBuildParser();
+
+ void stdOutput(QString const& line);
+ void stdError(QString const& line);
+
+protected:
+ void doFlush();
+
+private:
+
+ QString findToolset(QString const& line) const;
+ void setToolsetParser(QString const& toolsetName);
+ void setTask(ProjectExplorer::Task const& task);
+
+ QRegExp rxToolsetNameCommand_; // ".compile." command line
+ QRegExp rxToolsetNameWarning_; // "warning: " status line
+ QRegExp rxTestPassed_; // "**passed**" status line
+ QRegExp rxTestFailed_; // "...failed testing" status line
+ QRegExp rxTestFailedAsExpected_; // "(failed-as-expected)" status line
+ QRegExp rxTestFileLineN_; // file.cpp(XX) => file.cpp:XX
+ QRegExp rxTestFileObj_; // file.o => file.cpp
+ QString toolsetName_;
+
+ // Boost.Build command mode relates to first command token in line.
+ enum LineMode { Common, Toolset, Testing };
+ LineMode lineMode_;
+
+ ProjectExplorer::Task lastTask_;
+ QPointer<ProjectExplorer::IOutputParser> parser_;
+};
+
+} // namespace Internal
+} // namespace BoostBuildProjectManager
+
+#endif // BBOUTPUTPARSER_HPP
diff --git a/src/plugins/boostbuildprojectmanager/b2project.cpp b/src/plugins/boostbuildprojectmanager/b2project.cpp
new file mode 100644
index 0000000000..2074c60ff6
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2project.cpp
@@ -0,0 +1,306 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#include "b2buildconfiguration.h"
+#include "b2buildstep.h"
+#include "b2openprojectwizard.h"
+#include "b2project.h"
+#include "b2projectfile.h"
+#include "b2projectmanager.h"
+#include "b2projectmanagerconstants.h"
+#include "b2projectnode.h"
+#include "b2utility.h"
+// Qt Creator
+#include <app/app_version.h>
+#include <coreplugin/icontext.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/generatedfile.h>
+#include <coreplugin/progressmanager/progressmanager.h>
+#include <cpptools/cppmodelmanager.h>
+#include <cpptools/cppprojects.h>
+#include <cpptools/cpptoolsconstants.h>
+#include <projectexplorer/kit.h>
+#include <projectexplorer/kitinformation.h>
+#include <projectexplorer/kitmanager.h>
+#include <projectexplorer/project.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/projectnodes.h>
+#include <projectexplorer/target.h>
+#include <qtsupport/customexecutablerunconfiguration.h>
+#include <utils/fileutils.h>
+#include <utils/QtConcurrentTools>
+// Qt
+#include <QDir>
+#include <QFileInfo>
+#include <QMessageBox>
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+Project::Project(ProjectManager* manager, QString const& fileName)
+ : manager_(manager)
+ , filePath_(fileName)
+ , projectFile_(new ProjectFile(this, filePath_)) // enables projectDirectory()
+ , projectNode_(new ProjectNode(this, projectFile_))
+{
+ Q_ASSERT(manager_);
+ Q_ASSERT(!filePath_.isEmpty());
+
+ setProjectContext(Core::Context(Constants::PROJECT_CONTEXT));
+ setProjectLanguages(Core::Context(ProjectExplorer::Constants::LANG_CXX));
+#if defined(IDE_VERSION_MAJOR) && (IDE_VERSION_MAJOR == 3 && IDE_VERSION_MINOR > 0)
+ setId(Constants::PROJECT_ID);
+#endif
+
+ QFileInfo const projectFileInfo(filePath_);
+ QDir const projectDir(projectFileInfo.dir());
+ projectName_ = defaultProjectName(filePath_);
+ filesFilePath_ = QFileInfo(projectDir
+ , filePath_ + QLatin1String(Constants::EXT_JAMFILE_FILES)).absoluteFilePath();
+ includesFilePath_ = QFileInfo(projectDir
+ , filePath_ + QLatin1String(Constants::EXT_JAMFILE_INCLUDES)).absoluteFilePath();
+
+ projectNode_->setDisplayName(displayName());
+
+ manager_->registerProject(this);
+
+ // TODO: Add file watchers
+ //projectFileWatcher_->addPath(projectFilePath);
+ //connect(projectFileWatcher_, SIGNAL(fileChanged(QString)), this, SLOT(refresh()));
+
+ BBPM_QDEBUG("created project: " << displayName() << " in " << projectDirectory());
+}
+
+Project::~Project()
+{
+ manager_->unregisterProject(this);
+ delete projectNode_;
+}
+
+QString Project::displayName() const
+{
+ return projectName_;
+}
+
+#if defined(IDE_VERSION_MAJOR) && (IDE_VERSION_MAJOR == 3 && IDE_VERSION_MINOR == 0)
+Core::Id Project::id() const
+{
+ return Core::Id(Constants::PROJECT_ID);
+}
+#endif
+
+Core::IDocument* Project::document() const
+{
+ return projectFile_;
+}
+
+ProjectExplorer::IProjectManager* Project::projectManager() const
+{
+ return manager_;
+}
+
+ProjectExplorer::ProjectNode* Project::rootProjectNode() const
+{
+ return projectNode_;
+}
+
+QStringList Project::files(FilesMode fileMode) const
+{
+ // TODO: handle ExcludeGeneratedFiles, but what files exactly?
+ // *.qtcreator.files, *.qtcreator.includes and *.user?
+ Q_UNUSED(fileMode);
+ return files_;
+}
+
+QStringList Project::files() const
+{
+ return files(FilesMode::AllFiles);
+}
+
+QString Project::filesFilePath() const
+{
+ Q_ASSERT(!filesFilePath_.isEmpty());
+ return filesFilePath_;
+}
+
+QString Project::includesFilePath() const
+{
+ Q_ASSERT(!includesFilePath_.isEmpty());
+ return includesFilePath_;
+}
+
+bool Project::needsConfiguration() const
+{
+ // TODO: Does Boost.Build project require any configuration on loading?
+ // - Kit selection
+ // - build/stage directory
+ // - targets listing
+ // CMakeProjectManager seems to request configuration in fromMap()
+
+ return false;
+}
+
+/*static*/
+QString Project::defaultProjectName(QString const& fileName)
+{
+ QFileInfo const fileInfo(fileName);
+ return fileInfo.absoluteDir().dirName();
+}
+
+/*static*/
+QString Project::defaultBuildDirectory(QString const& top)
+{
+ Utils::FileName fn(Utils::FileName::fromString(defaultWorkingDirectory(top)));
+ fn.appendPath(BBPM_C(BUILD_DIR_NAME));
+ return fn.toString();
+}
+
+/*static*/
+QString Project::defaultWorkingDirectory(QString const& top)
+{
+ // Accepts both, project file or project directory, as top.
+ return ProjectExplorer::Project::projectDirectory(Utils::FileName::fromString(top)).toString();
+}
+
+void Project::setProjectName(QString const& name)
+{
+ if (projectName_ != name) {
+ projectName_ = name;
+ projectNode_->setDisplayName(projectName_);
+ // TODO: signal?
+ }
+}
+
+QVariantMap Project::toMap() const
+{
+ QVariantMap map(ProjectExplorer::Project::toMap());
+ map.insert(QLatin1String(Constants::P_KEY_PROJECTNAME), projectName_);
+ return map;
+}
+
+// This function is called at the very beginning to restore the settings
+// from .user file, if there is any with previous settings stored.
+bool Project::fromMap(QVariantMap const& map)
+{
+ BBPM_QDEBUG(displayName());
+ QTC_ASSERT(projectNode_, return false);
+
+ if (!ProjectExplorer::Project::fromMap(map))
+ return false;
+
+ QVariantMap extraValues(map);
+ if (!extraValues.contains(BBPM_C(P_KEY_PROJECTNAME)))
+ extraValues.insert(BBPM_C(P_KEY_PROJECTNAME), projectName_);
+ setProjectName(map.value(BBPM_C(P_KEY_PROJECTNAME)).toString());
+
+ // Check required auxiliary files, run wizard of necessary
+ if (!QFileInfo(filesFilePath()).exists() || !QFileInfo(includesFilePath()).exists()) {
+ ProjectExplorer::Kit* defaultKit = ProjectExplorer::KitManager::defaultKit();
+ Q_ASSERT(defaultKit);
+
+ OpenProjectWizard wizard(this);
+ if (!wizard.run(defaultKit->displayName(), extraValues))
+ return false;
+
+ QVariantMap outputValues = wizard.outputValues();
+ setProjectName(outputValues.value(BBPM_C(P_KEY_PROJECTNAME)).toString());
+ }
+
+ // Set up active ProjectConfiguration (aka Target).
+ // NOTE: Call setActiveBuildConfiguration when creating new build configurations.
+ if (!activeTarget()) {
+ // Create project configuration from scratch
+
+ // TODO: Map the Kit to Boost.Build toolset option value
+ ProjectExplorer::Kit* defaultKit = ProjectExplorer::KitManager::defaultKit();
+ Q_ASSERT(defaultKit);
+
+ // Creates as many {Build|Run|Deploy}Configurations for as corresponding
+ // factories report as available.
+ // For example, BuildConfigurationFactory::availableBuilds => Debug and Release
+ ProjectExplorer::Target* target = createTarget(defaultKit);
+ QTC_ASSERT(target, return false);
+
+ addTarget(target);
+ } else {
+ // Configure project from settings sorced from .user file
+ // TODO: Do we need to handle anything from .user here? Do we need this case?
+ BBPM_QDEBUG(displayName() << "has user file");
+ }
+
+ // Sanity check (taken from GenericProjectManager):
+ // We need both a BuildConfiguration and a RunConfiguration!
+ QList<ProjectExplorer::Target*> targetList = targets();
+ foreach (ProjectExplorer::Target* t, targetList) {
+ if (!t->activeBuildConfiguration()) {
+ removeTarget(t);
+ continue;
+ }
+ if (!t->activeRunConfiguration())
+ t->addRunConfiguration(new QtSupport::CustomExecutableRunConfiguration(t));
+ }
+
+ QTC_ASSERT(hasActiveBuildSettings(), return false);
+ QTC_ASSERT(activeTarget() != 0, return false);
+
+ // Trigger loading project tree and parsing sources
+ refresh();
+
+ return true;
+}
+
+void Project::refresh()
+{
+ QTC_ASSERT(QFileInfo(filesFilePath()).exists(), return);
+ QTC_ASSERT(QFileInfo(includesFilePath()).exists(), return);
+
+ QSet<QString> oldFileList;
+ oldFileList = files_.toSet();
+
+ // Parse project:
+ // The manager does not parse Jamfile files.
+ // Only generates and parses list of source files in Jamfile.${JAMFILE_FILES_EXT}
+ QString const projectPath(projectDirectory().toString());
+ filesRaw_ = Utility::readLines(filesFilePath());
+ files_ = Utility::makeAbsolutePaths(projectPath, filesRaw_);
+
+ QStringList includePaths =
+ Utility::makeAbsolutePaths(projectPath,
+ Utility::readLines(includesFilePath()));
+
+ emit fileListChanged();
+
+ projectNode_->refresh(oldFileList);
+
+ // TODO: Does it make sense to move this to separate asynchronous task?
+ // TODO: extract updateCppCodeModel
+ CppTools::CppModelManager *modelmanager =
+ CppTools::CppModelManager::instance();
+ if (modelmanager) {
+ CppTools::ProjectInfo pinfo(this);
+
+ CppTools::ProjectPartBuilder builder(pinfo);
+ //builder.setDefines(); // TODO: waiting for Jamfile parser
+ builder.setIncludePaths(QStringList() << projectDirectory().toString() << includePaths);
+
+ const QList<Core::Id> languages = builder.createProjectPartsForFiles(files_);
+ foreach (Core::Id language, languages)
+ setProjectLanguage(language, true);
+
+ cppModelFuture_.cancel();
+ pinfo.finish();
+ cppModelFuture_ = modelmanager->updateProjectInfo(pinfo);
+ }
+}
+
+} // namespace Internal
+} // namespace BoostBuildProjectManager
diff --git a/src/plugins/boostbuildprojectmanager/b2project.h b/src/plugins/boostbuildprojectmanager/b2project.h
new file mode 100644
index 0000000000..6b8a813443
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2project.h
@@ -0,0 +1,106 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#ifndef BBPROJECT_HPP
+#define BBPROJECT_HPP
+
+// Qt Creator
+#include <app/app_version.h>
+#include <coreplugin/idocument.h>
+#include <projectexplorer/project.h>
+#include <utils/fileutils.h>
+// Qt
+#include <QString>
+#include <QFuture>
+#include <QFutureInterface>
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+class ProjectFile;
+class ProjectManager;
+class ProjectNode;
+
+// Represents a project node in the project explorer.
+class Project : public ProjectExplorer::Project
+{
+ Q_OBJECT
+
+public:
+ Project(ProjectManager* manager, QString const& fileName);
+ ~Project();
+
+#if defined(IDE_VERSION_MAJOR) && (IDE_VERSION_MAJOR == 3 && IDE_VERSION_MINOR == 0)
+ Core::Id id() const;
+#endif
+ QString displayName() const;
+ Core::IDocument* document() const;
+ ProjectExplorer::IProjectManager* projectManager() const;
+ ProjectExplorer::ProjectNode* rootProjectNode() const;
+ QStringList files(FilesMode fileMode) const;
+
+ bool needsConfiguration() const;
+
+ void refresh();
+
+ QString filesFilePath() const;
+ QStringList files() const;
+
+ QString includesFilePath() const;
+
+ static QString defaultProjectName(QString const& fileName);
+ static QString defaultBuildDirectory(QString const& top);
+ static QString defaultWorkingDirectory(QString const& top);
+
+protected:
+
+ QVariantMap toMap() const;
+
+ // Deserializes all project data from the map object
+ // Calls the base ProjectExplorer::Project::fromMap function first.
+ bool fromMap(QVariantMap const& map);
+
+private:
+
+ void setProjectName(QString const& name);
+
+ // Corresponding project manager passed to the constructor
+ ProjectManager* manager_;
+
+ // By default, name of directory with Jamfile.
+ // Boost.Build treats each Jamfile is a separate project,
+ // where hierarchy of Jamfiles makes hierarchy of projects.
+ QString projectName_;
+
+ // Jamfile passed to the constructor (Jamroot, Jamfile, Jamfile.v2).
+ QString filePath_;
+
+ // Auxiliary file Jamfile.${JAMFILE_FILES_EXT} with list of source files.
+ // Role of this file is similar to the .files file in the GenericProjectManager,
+ // hence managing of this file is implemented in very similar manner.
+ QString filesFilePath_;
+ QStringList files_;
+ QStringList filesRaw_;
+ QHash<QString, QString> entriesRaw_;
+
+ // Auxiliary file Jamfile.${JAMFILE_INCLUDES_EXT} with list of source files.
+ QString includesFilePath_;
+
+ ProjectFile* projectFile_;
+ ProjectNode* projectNode_;
+
+ QFuture<void> cppModelFuture_;
+};
+
+} // namespace Internal
+} // namespace BoostBuildProjectManager
+
+#endif // BBPROJECT_HPP
diff --git a/src/plugins/boostbuildprojectmanager/b2projectfile.cpp b/src/plugins/boostbuildprojectmanager/b2projectfile.cpp
new file mode 100644
index 0000000000..bcfeef9eaf
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2projectfile.cpp
@@ -0,0 +1,80 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#include "b2project.h"
+#include "b2projectfile.h"
+#include "b2projectmanagerconstants.h"
+#include "b2utility.h"
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+ProjectFile::ProjectFile(Project* project, QString const& fileName)
+ : Core::IDocument(project)
+ , project_(project)
+{
+ Q_ASSERT(!fileName.isEmpty());
+
+ setFilePath(Utils::FileName::fromString(fileName));
+
+ BBPM_QDEBUG(fileName);
+}
+
+bool ProjectFile::save(QString* errorString, QString const& fileName, bool autoSave)
+{
+ Q_UNUSED(errorString);
+ Q_UNUSED(fileName);
+ Q_UNUSED(autoSave);
+
+ BBPM_QDEBUG("TODO");
+ return false;
+}
+
+QString ProjectFile::defaultPath() const
+{
+ BBPM_QDEBUG("TODO");
+ return QString();
+}
+
+QString ProjectFile::suggestedFileName() const
+{
+ return QString();
+}
+
+QString ProjectFile::mimeType() const
+{
+ BBPM_QDEBUG("TODO");
+ return QLatin1String(Constants::MIMETYPE_JAMFILE);
+}
+
+bool ProjectFile::isModified() const
+{
+ return false;
+}
+
+bool ProjectFile::isSaveAsAllowed() const
+{
+ BBPM_QDEBUG("TODO");
+ return false;
+}
+
+bool ProjectFile::reload(QString* errorString, ReloadFlag flag, ChangeType type)
+{
+ Q_UNUSED(errorString);
+ Q_UNUSED(flag);
+ Q_UNUSED(type);
+
+ BBPM_QDEBUG("TODO");
+ return false;
+}
+
+} // namespace Internal
+} // namespace AutotoolsProjectManager
diff --git a/src/plugins/boostbuildprojectmanager/b2projectfile.h b/src/plugins/boostbuildprojectmanager/b2projectfile.h
new file mode 100644
index 0000000000..5e440df646
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2projectfile.h
@@ -0,0 +1,47 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#ifndef BBPROJECTFILE_HPP
+#define BBPROJECTFILE_HPP
+
+#include <coreplugin/idocument.h>
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+class Project;
+
+// Describes the root of a project for use in Project class.
+// In the context of Boost.Build the implementation is mostly empty,
+// as the modification of a project is done by editing Jamfile.v2 files.
+class ProjectFile : public Core::IDocument
+{
+ Q_OBJECT
+
+public:
+ ProjectFile(Project* project, QString const& fileName);
+
+ bool save(QString* errorString, QString const& fileName, bool autoSave);
+ QString defaultPath() const;
+ QString suggestedFileName() const;
+ QString mimeType() const;
+ bool isModified() const;
+ bool isSaveAsAllowed() const;
+ bool reload(QString* errorString, ReloadFlag flag, ChangeType type);
+
+private:
+ Project* project_;
+};
+
+} // namespace Internal
+} // namespace AutotoolsProjectManager
+
+#endif // BBPROJECTFILE_HPP
diff --git a/src/plugins/boostbuildprojectmanager/b2projectmanager.cpp b/src/plugins/boostbuildprojectmanager/b2projectmanager.cpp
new file mode 100644
index 0000000000..dcc4f439d8
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2projectmanager.cpp
@@ -0,0 +1,64 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#include "b2projectmanager.h"
+#include "b2projectmanagerconstants.h"
+#include "b2project.h"
+#include "b2utility.h"
+// Qt Creator
+#include <projectexplorer/iprojectmanager.h>
+// Qt
+#include <QFileInfo>
+#include <QString>
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+ProjectManager::ProjectManager()
+{
+}
+
+QString ProjectManager::mimeType() const
+{
+ BBPM_QDEBUG(Constants::MIMETYPE_PROJECT);
+
+ return QLatin1String(Constants::MIMETYPE_PROJECT);
+}
+
+ProjectExplorer::Project*
+ProjectManager::openProject(QString const& fileName, QString* errorString)
+{
+ BBPM_QDEBUG("opening project:" << fileName);
+
+ if (!QFileInfo(fileName).isFile()) {
+ if (errorString)
+ *errorString = tr("Failed opening project \"%1\": Project is not a file.")
+ .arg(fileName);
+ return 0;
+ }
+
+ return new Project(this, fileName);
+}
+
+void ProjectManager::registerProject(Project* project)
+{
+ Q_ASSERT(project);
+ projects_.append(project);
+}
+
+void ProjectManager::unregisterProject(Project* project)
+{
+ Q_ASSERT(project);
+ projects_.removeAll(project);
+}
+
+} // namespace Internal
+} // namespace BoostBuildProjectManager
diff --git a/src/plugins/boostbuildprojectmanager/b2projectmanager.h b/src/plugins/boostbuildprojectmanager/b2projectmanager.h
new file mode 100644
index 0000000000..d4222beb61
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2projectmanager.h
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#ifndef BBPROJECTMANAGER_HPP
+#define BBPROJECTMANAGER_HPP
+
+// Qt Creator
+#include <projectexplorer/iprojectmanager.h>
+// Qt
+#include <QList>
+#include <QString>
+
+namespace ProjectExplorer {
+class Project;
+}
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+class Project;
+
+// Sole implementation of the IProjectManager class for the extension.
+class ProjectManager : public ProjectExplorer::IProjectManager
+{
+ Q_OBJECT
+
+public:
+ ProjectManager();
+
+ QString mimeType() const;
+
+ // Creates new instance of Project class.
+ ProjectExplorer::Project*
+ openProject(QString const& fileName, QString* errorString);
+
+ void registerProject(Project* project);
+ void unregisterProject(Project* project);
+
+private:
+ QList<Project*> projects_;
+};
+
+} // namespace Internal
+} // namespace BoostBuildProjectManager
+
+#endif // BBPROJECTMANAGER_HPP
diff --git a/src/plugins/boostbuildprojectmanager/b2projectmanager_global.h b/src/plugins/boostbuildprojectmanager/b2projectmanager_global.h
new file mode 100644
index 0000000000..3287ab357d
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2projectmanager_global.h
@@ -0,0 +1,23 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#ifndef BBPROJECTMANAGER_GLOBAL_HPP
+#define BBPROJECTMANAGER_GLOBAL_HPP
+
+#include <QtGlobal>
+
+#if defined(BOOSTBUILDPROJECTMANAGER_LIBRARY)
+# define BOOSTBUILDPROJECTMANAGER_EXPORT Q_DECL_EXPORT
+#else
+# define BOOSTBUILDPROJECTMANAGER_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // BBPROJECTMANAGER_GLOBAL_HPP
diff --git a/src/plugins/boostbuildprojectmanager/b2projectmanagerconstants.h b/src/plugins/boostbuildprojectmanager/b2projectmanagerconstants.h
new file mode 100644
index 0000000000..a6db0a1b5b
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2projectmanagerconstants.h
@@ -0,0 +1,68 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#ifndef BBPROJECTMANAGERCONSTANTS_HPP
+#define BBPROJECTMANAGERCONSTANTS_HPP
+
+#include <qglobal.h>
+
+namespace BoostBuildProjectManager {
+namespace Constants {
+
+char const BOOSTBUILD[] = "Boost.Build";
+
+char const PROJECT_CONTEXT[] = "BoostBuildProjectManager.ProjectContext";
+char const PROJECT_ID[] = "BoostBuildProjectManager.Project";
+char const PROJECT_WIZARD_ID[] = "BoostBuildProjectManager.Project.Wizard";
+char const PROJECT_READER_TASK_ID[] = "BoostBuildProjectManager.ProjectReader.Task";
+
+char const BUILDCONFIGURATION_ID[] = "BoostBuildProjectManager.BuildConfiguration";
+char const BUILDSTEP_ID[] = "BoostBuildProjectManager.BuildStep";
+
+// Keys for class map registry
+char const P_KEY_PROJECTNAME[] = "BoostBuildProjectManager.Project.ProjectName";
+char const BC_KEY_WORKDIR[] = "BoostBuildProjectManager.BuildConfiguration.WorkingDirectory";
+char const BS_KEY_CLEAN[] = "BoostBuildProjectManager.BuildStep.Clean";
+char const BS_KEY_ARGUMENTS[] = "BoostBuildProjectManager.BuildStep.AdditionalArguments";
+
+// MIME types and file patterns
+char const MIMETYPE_PROJECT[] = "text/x-boostbuild-project";
+char const MIMETYPE_JAMFILE[] = "application/vnd.boostbuild.v2";
+char const MIMETYPE_JAMFILE_FILES[] = "application/vnd.qtcreator.boostbuild.files";
+const char MIMETYPE_JAMFILE_INCLUDES[] = "application/vnd.qtcreator.boostbuild.includes";
+char const EXT_JAMFILE_FILES[] = ".qtcreator.files";
+char const EXT_JAMFILE_INCLUDES[] = ".qtcreator.includes";
+
+// Command and options
+char const COMMAND_BB2[] = "b2";
+char const COMMAND_BJAM[] = "bjam";
+
+char const VARIANT_DEBUG[] = QT_TR_NOOP("Debug");
+char const VARIANT_RELEASE[] = QT_TR_NOOP("Release");
+
+// ${BOOST}/tools/build/v2/doc/src/architecture.xml
+// Since Boost.Build almost always generates targets under the "bin"
+char const BUILD_DIR_NAME[] = "bin";
+
+// FileSelectionWizardPage
+char const HIDE_FILE_FILTER_SETTING[] = "BoostBuildProjectManager/FileFilter";
+char const HIDE_FILE_FILTER_DEFAULT[] = "Makefile*; *.o; *.obj; *~; *.files; *.config; *.creator; *.user; *.includes; *.autosave";
+char const SHOW_FILE_FILTER_SETTING[] = "BoostBuildProjectManager/ShowFileFilter";
+char const SHOW_FILE_FILTER_DEFAULT[] = "*.c; *.cc; *.cpp; *.cp; *.cxx; *.c++; *.h; *.hh; *.h; *.hxx;";
+
+// Meaningful names for common boolean values
+bool const FileNotGenerated = false;
+bool const ReturnValueNotIgnored = false;
+
+} // namespace Constants
+} // namespace BoostBuildProjectManager
+
+#endif // BBPROJECTMANAGERCONSTANTS_HPP
diff --git a/src/plugins/boostbuildprojectmanager/b2projectmanagerplugin.cpp b/src/plugins/boostbuildprojectmanager/b2projectmanagerplugin.cpp
new file mode 100644
index 0000000000..b5c3ae1186
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2projectmanagerplugin.cpp
@@ -0,0 +1,83 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#include "b2buildconfiguration.h"
+#include "b2buildstep.h"
+#include "b2projectmanager.h"
+#include "b2projectmanagerplugin.h"
+#include "b2projectmanagerconstants.h"
+#include <coreplugin/icore.h>
+#include <coreplugin/icontext.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/actionmanager/command.h>
+#include <coreplugin/actionmanager/actioncontainer.h>
+#include <coreplugin/coreconstants.h>
+#include <utils/mimetypes/mimedatabase.h>
+// Qt
+#include <QAction>
+#include <QMessageBox>
+#include <QMainWindow>
+#include <QMenu>
+
+#include <QtPlugin>
+
+namespace BoostBuildProjectManager { namespace Internal {
+
+BoostBuildPlugin::BoostBuildPlugin()
+{
+ // Create your members
+}
+
+BoostBuildPlugin::~BoostBuildPlugin()
+{
+ // Unregister objects from the plugin manager's object pool
+ // Delete members
+}
+
+bool BoostBuildPlugin::initialize(QStringList const& arguments, QString* errorString)
+{
+ Q_UNUSED(arguments)
+ Q_UNUSED(errorString)
+
+ // Register objects in the plugin manager's object pool
+ // Load settings
+ // Add actions to menus
+ // Connect to other plugins' signals
+ // In the initialize function, a plugin can be sure that the plugins it
+ // depends on have initialized their members.
+
+ QLatin1String const mimeTypes(":boostbuildproject/BoostBuildProjectManager.mimetypes.xml");
+ Utils::MimeDatabase::addMimeTypes(mimeTypes);
+
+ addAutoReleasedObject(new BuildStepFactory);
+ addAutoReleasedObject(new BuildConfigurationFactory);
+ //TODO addAutoReleasedObject(new RunConfigurationFactory);
+ addAutoReleasedObject(new ProjectManager);
+
+ return true;
+}
+
+void BoostBuildPlugin::extensionsInitialized()
+{
+ // Retrieve objects from the plugin manager's object pool
+ // In the extensionsInitialized function, a plugin can be sure that all
+ // plugins that depend on it are completely initialized.
+}
+
+ExtensionSystem::IPlugin::ShutdownFlag BoostBuildPlugin::aboutToShutdown()
+{
+ // Save settings
+ // Disconnect from signals that are not needed during shutdown
+ // Hide UI (if you add UI that is not in the main window directly)
+ return SynchronousShutdown;
+}
+
+}}
diff --git a/src/plugins/boostbuildprojectmanager/b2projectmanagerplugin.h b/src/plugins/boostbuildprojectmanager/b2projectmanagerplugin.h
new file mode 100644
index 0000000000..e54dcaabeb
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2projectmanagerplugin.h
@@ -0,0 +1,48 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#ifndef BBPROJECTMANAGERPLUGIN_HPP
+#define BBPROJECTMANAGERPLUGIN_HPP
+
+#include "b2projectmanager_global.h"
+
+#include <extensionsystem/iplugin.h>
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+
+// Sole implementation of the IPlugin class for the extension.
+class BoostBuildPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "BoostBuildProjectManager.json")
+
+public:
+ BoostBuildPlugin();
+ ~BoostBuildPlugin();
+
+ // Called as second step of the plugins loading.
+ // The initialize functions are called in root-to-leaf order of the dependency tree.
+ bool initialize(QStringList const& arguments, QString* errorString);
+
+ // Called as final step of the plugins loading.
+ // At this point, all dependencies along the plugin dependency tree
+ // have been initialized completely.
+ void extensionsInitialized();
+
+ ShutdownFlag aboutToShutdown();
+};
+
+} // namespace Internal
+} // namespace BoostBuildProjectManager
+
+#endif // BBPROJECTMANAGERPLUGIN_HPP
diff --git a/src/plugins/boostbuildprojectmanager/b2projectnode.cpp b/src/plugins/boostbuildprojectmanager/b2projectnode.cpp
new file mode 100644
index 0000000000..2c97b565cf
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2projectnode.cpp
@@ -0,0 +1,260 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#include "b2projectnode.h"
+#include "b2project.h"
+#include "b2utility.h"
+// Qt Creator
+#include <coreplugin/idocument.h>
+#include <projectexplorer/projectnodes.h>
+#include <utils/qtcassert.h>
+// Qt
+#include <QFutureInterface>
+#include <QHash>
+#include <QList>
+#include <QSet>
+#include <QString>
+#include <QStringList>
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+ProjectNode::ProjectNode(Project* project, Core::IDocument* projectFile)
+ : ProjectExplorer::ProjectNode(projectFile->filePath())
+ , project_(project)
+ , projectFile_(projectFile)
+{
+ // TODO: setDisplayName(QFileInfo(projectFile->filePath()).completeBaseName());
+}
+
+bool ProjectNode::hasBuildTargets() const
+{
+ return false;
+}
+
+QList<ProjectExplorer::ProjectAction>
+ProjectNode::supportedActions(Node* node) const
+{
+ Q_UNUSED(node);
+
+ // TODO: Jamfiles (auto)editing not supported, does it make sense to manage files?
+ return QList<ProjectExplorer::ProjectAction>();
+}
+
+bool ProjectNode::canAddSubProject(QString const& filePath) const
+{
+ Q_UNUSED(filePath)
+ return false;
+}
+
+bool ProjectNode::addSubProjects(QStringList const& filePaths)
+{
+ Q_UNUSED(filePaths)
+ return false;
+}
+
+bool ProjectNode::removeSubProjects(QStringList const& filePath)
+{
+ Q_UNUSED(filePath)
+ return false;
+}
+
+bool ProjectNode::addFiles(QStringList const& filePaths, QStringList* notAdded = 0)
+{
+ Q_UNUSED(filePaths);
+ Q_UNUSED(notAdded);
+ return false;
+}
+
+bool ProjectNode::removeFiles(QStringList const& filePaths, QStringList* notRemoved = 0)
+{
+ Q_UNUSED(filePaths);
+ Q_UNUSED(notRemoved);
+ return false;
+}
+
+bool ProjectNode::deleteFiles(QStringList const& filePaths)
+{
+ Q_UNUSED(filePaths);
+ return false;
+}
+
+bool ProjectNode::renameFile(QString const& filePath, QString const& newFilePath)
+{
+ Q_UNUSED(filePath);
+ Q_UNUSED(newFilePath);
+ return false;
+}
+
+QList<ProjectExplorer::RunConfiguration*> ProjectNode::runConfigurationsFor(Node* node)
+{
+ Q_UNUSED(node);
+ return QList<ProjectExplorer::RunConfiguration*>();
+}
+
+void ProjectNode::refresh(QSet<QString> oldFileList)
+{
+ // The idea of refreshing files in project explorer taken from GenericProjectManager
+
+ // Only do this once, at first run.
+ if (oldFileList.isEmpty()) {
+ using ProjectExplorer::FileNode;
+ FileNode* projectFileNode = new FileNode(project_->projectFilePath()
+ , ProjectExplorer::ProjectFileType
+ , Constants::FileNotGenerated);
+
+ FileNode* filesFileNode = new FileNode(Utils::FileName::fromString(project_->filesFilePath())
+ , ProjectExplorer::ProjectFileType
+ , Constants::FileNotGenerated);
+
+ FileNode* includesFileNode = new FileNode(Utils::FileName::fromString(project_->includesFilePath())
+ , ProjectExplorer::ProjectFileType
+ , Constants::FileNotGenerated);
+
+ addFileNodes(QList<FileNode*>()
+ << projectFileNode << filesFileNode << includesFileNode);
+ }
+
+ oldFileList.remove(project_->filesFilePath());
+ oldFileList.remove(project_->includesFilePath());
+
+ QSet<QString> newFileList = project_->files().toSet();
+ newFileList.remove(project_->filesFilePath());
+ newFileList.remove(project_->includesFilePath());
+
+ // Calculate set of added and removed files
+ QSet<QString> removed = oldFileList;
+ removed.subtract(newFileList);
+ QSet<QString> added = newFileList;
+ added.subtract(oldFileList);
+
+ typedef QHash<QString, QStringList> FilesInPaths;
+ typedef FilesInPaths::ConstIterator FilesInPathsIterator;
+ using ProjectExplorer::FileNode;
+ using ProjectExplorer::FileType;
+ QString const baseDir = QFileInfo(path().toString()).absolutePath();
+
+ // Process all added files
+ FilesInPaths filesInPaths = Utility::sortFilesIntoPaths(baseDir, added);
+ for (FilesInPathsIterator it = filesInPaths.constBegin(),
+ cend = filesInPaths.constEnd(); it != cend; ++it) {
+ // Create node
+ QString const& filePath = it.key();
+ QStringList parts;
+ if (!filePath.isEmpty())
+ parts = filePath.split(QLatin1Char('/'));
+
+ FolderNode* folder = findFolderByName(parts, parts.size());
+ if (!folder)
+ folder = createFolderByName(parts, parts.size());
+
+ // Attach content to node
+ QList<FileNode*> fileNodes;
+ foreach (QString const& file, it.value()) {
+ // TODO: handle various types, mime to FileType
+ FileType fileType = ProjectExplorer::SourceType;
+ FileNode* fileNode = new FileNode(Utils::FileName::fromString(file), fileType, Constants::FileNotGenerated);
+ fileNodes.append(fileNode);
+ }
+
+ addFileNodes(fileNodes);
+ }
+
+ // Process all removed files
+ filesInPaths = Utility::sortFilesIntoPaths(baseDir, removed);
+ for (FilesInPathsIterator it = filesInPaths.constBegin(),
+ cend = filesInPaths.constEnd(); it != cend; ++it) {
+ // Create node
+ QString const& filePath = it.key();
+ QStringList parts;
+ if (!filePath.isEmpty())
+ parts = filePath.split(QLatin1Char('/'));
+ FolderNode* folder = findFolderByName(parts, parts.size());
+
+ QList<FileNode*> fileNodes;
+ foreach (QString const& file, it.value()) {
+ foreach (FileNode* fn, folder->fileNodes())
+ if (fn->path() == Utils::FileName::fromString(file))
+ fileNodes.append(fn);
+ }
+
+ removeFileNodes(fileNodes);
+ }
+
+ // Clean up
+ foreach (FolderNode* fn, subFolderNodes())
+ removeEmptySubFolders(this, fn);
+
+}
+
+void ProjectNode::removeEmptySubFolders(FolderNode* parent, FolderNode* subParent)
+{
+ foreach (FolderNode* fn, subParent->subFolderNodes())
+ removeEmptySubFolders(subParent, fn);
+
+ if (subParent->subFolderNodes().isEmpty() && subParent->fileNodes().isEmpty())
+ removeFolderNodes(QList<FolderNode*>() << subParent);
+}
+
+QString appendPathComponents(QStringList const& components, int const end)
+{
+ QString folderName;
+ for (int i = 0; i < end; ++i) {
+ folderName.append(components.at(i));
+ folderName += QLatin1Char('/');
+ }
+ return folderName;
+}
+
+ProjectExplorer::FolderNode*
+ProjectNode::createFolderByName(QStringList const& components, int const end)
+{
+ if (end == 0)
+ return this;
+
+ using ProjectExplorer::FolderNode;
+ QString const baseDir = QFileInfo(path().toString()).path();
+ QString const folderName = appendPathComponents(components, end);
+ FolderNode* folder = new FolderNode(Utils::FileName::fromString(baseDir + QLatin1Char('/') + folderName));
+ folder->setDisplayName(components.at(end - 1));
+
+ FolderNode* parent = findFolderByName(components, end - 1);
+ if (!parent)
+ parent = createFolderByName(components, end - 1);
+ addFolderNodes(QList<FolderNode*>() << folder);
+
+ return folder;
+}
+
+ProjectExplorer::FolderNode*
+ProjectNode::findFolderByName(QStringList const& components, int const end) const
+{
+ if (end == 0)
+ return const_cast<ProjectNode*>(this);
+
+ using ProjectExplorer::FolderNode;
+ FolderNode *parent = findFolderByName(components, end - 1);
+ if (!parent)
+ return 0;
+
+ QString const folderName = appendPathComponents(components, end);
+ QString const baseDir = QFileInfo(path().toString()).path();
+ foreach (FolderNode* fn, parent->subFolderNodes()) {
+ if (fn->path() == Utils::FileName::fromString(baseDir + QLatin1Char('/') + folderName))
+ return fn;
+ }
+
+ return 0;
+}
+
+} // namespace Internal
+} // namespace BoostBuildProjectManager
diff --git a/src/plugins/boostbuildprojectmanager/b2projectnode.h b/src/plugins/boostbuildprojectmanager/b2projectnode.h
new file mode 100644
index 0000000000..9a1e5422da
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2projectnode.h
@@ -0,0 +1,77 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#ifndef BBPROJECTNODE_HPP
+#define BBPROJECTNODE_HPP
+
+// Qt Creator
+#include <projectexplorer/projectnodes.h>
+// Qt
+#include <QFutureInterface>
+#include <QList>
+#include <QSet>
+#include <QString>
+#include <QStringList>
+
+namespace Core {
+class IDocument;
+}
+
+namespace ProjectExplorer {
+class RunConfiguration;
+}
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+class Project;
+
+// An in-memory presentation of a Project.
+// Represents a file or a folder of the project tree.
+// No special operations (addFiles(), removeFiles(), renameFile(), etc.) are offered.
+class ProjectNode : public ProjectExplorer::ProjectNode
+{
+
+public:
+ ProjectNode(Project* project, Core::IDocument* projectFile);
+
+ bool hasBuildTargets() const;
+ QList<ProjectExplorer::ProjectAction> supportedActions(Node* node) const;
+ bool canAddSubProject(QString const& filePath) const;
+ bool addSubProjects(QStringList const& filePaths);
+ bool removeSubProjects(QStringList const& filePaths);
+ bool addFiles(QStringList const& filePaths, QStringList* notAdded /*= 0*/);
+ bool removeFiles(QStringList const& filePaths, QStringList* notRemoved /*= 0*/);
+ bool deleteFiles(QStringList const& filePaths);
+ bool renameFile(QString const& filePath, QString const& newFilePath);
+ QList<ProjectExplorer::RunConfiguration*> runConfigurationsFor(Node* node);
+
+ void refresh(QSet<QString> oldFileList);
+
+private:
+
+ ProjectExplorer::FolderNode*
+ createFolderByName(QStringList const& components, int end);
+
+ ProjectExplorer::FolderNode*
+ findFolderByName(QStringList const& components, int end) const;
+
+ void removeEmptySubFolders(FolderNode* parent, FolderNode* subParent);
+
+ Project* project_;
+ Core::IDocument* projectFile_;
+};
+
+} // namespace Internal
+} // namespace BoostBuildProjectManager
+
+#endif // BBPROJECTNODE_HPP
diff --git a/src/plugins/boostbuildprojectmanager/b2utility.cpp b/src/plugins/boostbuildprojectmanager/b2utility.cpp
new file mode 100644
index 0000000000..376d26071d
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2utility.cpp
@@ -0,0 +1,151 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#include "b2utility.h"
+// Qt Creator
+#include <utils/fileutils.h>
+#include <utils/qtcassert.h>
+// Qt
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QHash>
+#include <QList>
+#include <QRegExp>
+#include <QSet>
+#include <QString>
+#include <QStringList>
+
+namespace BoostBuildProjectManager {
+namespace Utility {
+
+QStringList readLines(QString const& filePath)
+{
+ QFileInfo const fileInfo(filePath);
+ QStringList lines;
+
+ QFile file(fileInfo.absoluteFilePath());
+ if (file.open(QFile::ReadOnly)) {
+ QTextStream stream(&file);
+
+ forever {
+ QString line = stream.readLine();
+ if (line.isNull())
+ break;
+
+ lines.append(line);
+ }
+ }
+
+ return lines;
+}
+
+QStringList makeAbsolutePaths(QString const& basePath, QStringList const& paths)
+{
+ QDir const baseDir(basePath);
+
+ QFileInfo fileInfo;
+ QStringList absolutePaths;
+ foreach (QString const& path, paths) {
+ QString trimmedPath = path.trimmed();
+ if (!trimmedPath.isEmpty()) {
+ trimmedPath = Utils::FileName::fromUserInput(trimmedPath).toString();
+
+ fileInfo.setFile(baseDir, trimmedPath);
+ if (fileInfo.exists()) {
+ QString const absPath = fileInfo.absoluteFilePath();
+ Q_ASSERT(!absPath.isEmpty());
+ absolutePaths.append(absPath);
+ }
+ }
+ }
+ absolutePaths.removeDuplicates();
+ return absolutePaths;
+}
+
+QStringList& makeRelativePaths(QString const& basePath, QStringList& paths)
+{
+ QDir const baseDir(basePath);
+ for (QStringList::iterator it = paths.begin(), end = paths.end(); it != end; ++it)
+ *it = baseDir.relativeFilePath(*it);
+ return paths;
+}
+
+QHash<QString, QStringList> sortFilesIntoPaths(QString const& basePath
+ , QSet<QString> const& files)
+{
+ QHash<QString, QStringList> filesInPath;
+ QDir const baseDir(basePath);
+
+ foreach (QString const& absoluteFileName, files) {
+ QFileInfo const fileInfo(absoluteFileName);
+ Utils::FileName absoluteFilePath = Utils::FileName::fromString(fileInfo.path());
+ QString relativeFilePath;
+
+ if (absoluteFilePath.isChildOf(baseDir)) {
+ relativeFilePath = absoluteFilePath.relativeChildPath(
+ Utils::FileName::fromString(basePath)).toString();
+ } else {
+ // `file' is not part of the project.
+ relativeFilePath = baseDir.relativeFilePath(absoluteFilePath.toString());
+ if (relativeFilePath.endsWith(QLatin1Char('/')))
+ relativeFilePath.chop(1);
+ }
+
+ filesInPath[relativeFilePath].append(absoluteFileName);
+ }
+ return filesInPath;
+}
+
+// Parses Jamfile and looks for project rule to extract project name.
+// Boost.Build project rule has the following syntax:
+// project id : attributes ;
+// The project definition can span across multiple lines, including empty lines.
+// but each syntax token must be separated with a whitespace..
+QString parseJamfileProjectName(QString const& fileName)
+{
+ QString projectName;
+ QFile file(fileName);
+ if (file.exists()) {
+ // Jamfile project rule tokens to search for
+ QString const ruleBeg(QLatin1String("project"));
+ QChar const ruleEnd(QLatin1Char(';'));
+ QChar const attrSep(QLatin1Char(':'));
+ QChar const tokenSep(QLatin1Char(' ')); // used to ensure tokens separation
+ QString projectDef; // buffer for complete project definition
+
+ file.open(QIODevice::ReadOnly | QIODevice::Text);
+ QTextStream stream(&file);
+ while (!stream.atEnd()) {
+ QString const line(stream.readLine());
+ if (projectDef.isEmpty() && line.trimmed().startsWith(ruleBeg))
+ projectDef.append(line + tokenSep);
+ else if (!projectDef.isEmpty())
+ projectDef.append(line + tokenSep);
+
+ if (projectDef.contains(attrSep) || projectDef.contains(ruleEnd))
+ break;
+ }
+
+ if (!projectDef.isEmpty()) {
+ QRegExp rx(QLatin1String("\\s*project\\s+([a-zA-Z\\-\\/]+)\\s+[\\:\\;]?"));
+ rx.setMinimal(true);
+ QTC_CHECK(rx.isValid());
+ if (rx.indexIn(projectDef) > -1)
+ projectName = rx.cap(1);
+ }
+ }
+ return projectName;
+}
+
+} // namespace Utility
+} // namespace BoostBuildProjectManager
diff --git a/src/plugins/boostbuildprojectmanager/b2utility.h b/src/plugins/boostbuildprojectmanager/b2utility.h
new file mode 100644
index 0000000000..2f810cf35c
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2utility.h
@@ -0,0 +1,60 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+//
+// This file is part of Qt Creator Boost.Build plugin project.
+//
+// This is free software; you can redistribute and/or modify it under
+// the terms of the GNU Lesser General Public License, Version 2.1
+// as published by the Free Software Foundation.
+// See accompanying file LICENSE.txt or copy at
+// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
+//
+#ifndef BBUTILITY_HPP
+#define BBUTILITY_HPP
+
+#include "b2projectmanagerconstants.h"
+// Qt
+#include <QDebug>
+#include <QHash>
+#include <QSet>
+#include <QString>
+#include <QStringList>
+
+//////////////////////////////////////////////////////////////////////////////////////////
+#ifdef _DEBUG
+
+#define BBPM_QDEBUG(msg) \
+ qDebug() \
+ << "[" << BoostBuildProjectManager::Constants::BOOSTBUILD << "] " \
+ << "(" << __PRETTY_FUNCTION__ << ")"; \
+ qDebug().nospace() << "\t" << msg
+
+#else
+#define BBPM_QDEBUG(msg)
+
+#endif // _DEBUG
+
+#define BBPM_C(CONSTANT) QLatin1String(BoostBuildProjectManager::Constants::CONSTANT)
+
+//////////////////////////////////////////////////////////////////////////////////////////
+namespace BoostBuildProjectManager {
+namespace Utility {
+
+// Read all lines from a file.
+QStringList readLines(QString const& absoluteFileName);
+
+// Converts the path from relative to the project to an absolute path.
+QStringList makeAbsolutePaths(QString const& basePath, QStringList const& paths);
+
+QStringList& makeRelativePaths(QString const& basePath, QStringList& paths);
+
+QHash<QString, QStringList> sortFilesIntoPaths(QString const& basePath
+ , QSet<QString> const& files);
+
+QString parseJamfileProjectName(QString const& fileName);
+
+} // namespace Utility
+} // namespace BoostBuildProjectManager
+
+#endif // BBUTILITY_HPP
diff --git a/src/plugins/boostbuildprojectmanager/boostbuildproject.qrc b/src/plugins/boostbuildprojectmanager/boostbuildproject.qrc
new file mode 100644
index 0000000000..44d7c94bbc
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/boostbuildproject.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/boostbuildproject">
+ <file>BoostBuildProjectManager.mimetypes.xml</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/boostbuildprojectmanager/boostbuildprojectmanager.pro b/src/plugins/boostbuildprojectmanager/boostbuildprojectmanager.pro
new file mode 100644
index 0000000000..c743db04d0
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/boostbuildprojectmanager.pro
@@ -0,0 +1,46 @@
+include(../../qtcreatorplugin.pri)
+
+HEADERS += \
+ b2buildconfiguration.h \
+ b2buildinfo.h \
+ b2buildstep.h \
+ b2openprojectwizard.h \
+ b2outputparser.h \
+ b2project.h \
+ b2projectfile.h \
+ b2projectmanager.h \
+ b2projectmanager_global.h \
+ b2projectmanagerconstants.h \
+ b2projectmanagerplugin.h \
+ b2projectnode.h \
+ b2utility.h \
+ filesselectionwizardpage.h \
+ selectablefilesmodel.h \
+ external/projectexplorer/clangparser.h \
+ external/projectexplorer/gccparser.h \
+ external/projectexplorer/ldparser.h
+
+SOURCES += \
+ b2buildconfiguration.cpp \
+ b2buildinfo.cpp \
+ b2buildstep.cpp \
+ b2openprojectwizard.cpp \
+ b2outputparser.cpp \
+ b2project.cpp \
+ b2projectfile.cpp \
+ b2projectmanager.cpp \
+ b2projectmanagerplugin.cpp \
+ b2projectnode.cpp \
+ b2utility.cpp \
+ filesselectionwizardpage.cpp \
+ selectablefilesmodel.cpp \
+ external/projectexplorer/clangparser.cpp \
+ external/projectexplorer/gccparser.cpp \
+ external/projectexplorer/ldparser.cpp
+
+RESOURCES += \
+ boostbuildproject.qrc
+
+OTHER_FILES += \
+ $${QTC_PLUGIN_NAME}.mimetypes.xml \
+ $${QTC_PLUGIN_NAME}.pluginspec.in
diff --git a/src/plugins/boostbuildprojectmanager/boostbuildprojectmanager_dependencies.pri b/src/plugins/boostbuildprojectmanager/boostbuildprojectmanager_dependencies.pri
new file mode 100644
index 0000000000..3e8bb8694a
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/boostbuildprojectmanager_dependencies.pri
@@ -0,0 +1,12 @@
+QTC_PLUGIN_NAME = BoostBuildProjectManager
+QTC_LIB_DEPENDS += \
+ extensionsystem \
+ utils
+QTC_PLUGIN_DEPENDS += \
+ coreplugin \
+ projectexplorer \
+ cpptools \
+ texteditor \
+ qtsupport
+QTC_TEST_DEPENDS += \
+ cppeditor
diff --git a/src/plugins/boostbuildprojectmanager/external/projectexplorer/clangparser.cpp b/src/plugins/boostbuildprojectmanager/external/projectexplorer/clangparser.cpp
new file mode 100644
index 0000000000..df648bc5fd
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/external/projectexplorer/clangparser.cpp
@@ -0,0 +1,270 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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 by the Free Software
+** Foundation and appearing in the file LICENSE.txt 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.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "clangparser.h"
+#include "ldparser.h"
+#include <projectexplorer/projectexplorerconstants.h>
+
+using namespace ProjectExplorer;
+
+// opt. drive letter + filename: (2 brackets)
+static const char * const FILE_PATTERN = "(<command line>|([A-Za-z]:)?[^:]+\\.[^:]+)";
+
+ClangParser::ClangParser() :
+ m_commandRegExp(QLatin1String("^clang(\\+\\+)?: +(fatal +)?(warning|error|note): (.*)$")),
+ m_inLineRegExp(QLatin1String("^In (.*) included from (.*):(\\d+):$")),
+ m_messageRegExp(QLatin1String("^") + QLatin1String(FILE_PATTERN) + QLatin1String("(:(\\d+):\\d+|\\((\\d+)\\) *): +(fatal +)?(error|warning|note): (.*)$")),
+ m_summaryRegExp(QLatin1String("^\\d+ (warnings?|errors?)( and \\d (warnings?|errors?))? generated.$")),
+ m_codesignRegExp(QLatin1String("^Code ?Sign error: (.*)$")),
+ m_expectSnippet(false)
+{
+ setObjectName(QLatin1String("ClangParser"));
+
+ appendOutputParser(new LdParser);
+}
+
+void ClangParser::stdError(const QString &line)
+{
+ const QString lne = rightTrimmed(line);
+ if (m_summaryRegExp.indexIn(lne) > -1) {
+ doFlush();
+ m_expectSnippet = false;
+ return;
+ }
+
+ if (m_commandRegExp.indexIn(lne) > -1) {
+ m_expectSnippet = true;
+ Task task(Task::Error,
+ m_commandRegExp.cap(4),
+ Utils::FileName(), /* filename */
+ -1, /* line */
+ Constants::TASK_CATEGORY_COMPILE);
+ if (m_commandRegExp.cap(3) == QLatin1String("warning"))
+ task.type = Task::Warning;
+ else if (m_commandRegExp.cap(3) == QLatin1String("note"))
+ task.type = Task::Unknown;
+ newTask(task);
+ return;
+ }
+
+ if (m_inLineRegExp.indexIn(lne) > -1) {
+ m_expectSnippet = true;
+ newTask(Task(Task::Unknown,
+ lne.trimmed(),
+ Utils::FileName::fromUserInput(m_inLineRegExp.cap(2)), /* filename */
+ m_inLineRegExp.cap(3).toInt(), /* line */
+ Constants::TASK_CATEGORY_COMPILE));
+ return;
+ }
+
+ if (m_messageRegExp.indexIn(lne) > -1) {
+ m_expectSnippet = true;
+ bool ok = false;
+ int lineNo = m_messageRegExp.cap(4).toInt(&ok);
+ if (!ok)
+ lineNo = m_messageRegExp.cap(5).toInt(&ok);
+ Task task(Task::Error,
+ m_messageRegExp.cap(8),
+ Utils::FileName::fromUserInput(m_messageRegExp.cap(1)), /* filename */
+ lineNo,
+ Core::Id(Constants::TASK_CATEGORY_COMPILE));
+ if (m_messageRegExp.cap(7) == QLatin1String("warning"))
+ task.type = Task::Warning;
+ else if (m_messageRegExp.cap(7) == QLatin1String("note"))
+ task.type = Task::Unknown;
+ newTask(task);
+ return;
+ }
+
+ if (m_codesignRegExp.indexIn(lne) > -1) {
+ m_expectSnippet = true;
+ Task task(Task::Error,
+ m_codesignRegExp.cap(1),
+ Utils::FileName(),
+ -1,
+ Core::Id(Constants::TASK_CATEGORY_COMPILE));
+ newTask(task);
+ return;
+ }
+
+ if (m_expectSnippet) {
+ amendDescription(lne, true);
+ return;
+ }
+
+ IOutputParser::stdError(line);
+}
+
+// Unit tests:
+
+#ifdef WITH_TESTS_NOTDISABLED
+# include <QTest>
+
+# include "projectexplorer.h"
+# include "metatypedeclarations.h"
+# include "outputparser_test.h"
+
+void ProjectExplorerPlugin::testClangOutputParser_data()
+{
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<OutputParserTester::Channel>("inputChannel");
+ QTest::addColumn<QString>("childStdOutLines");
+ QTest::addColumn<QString>("childStdErrLines");
+ QTest::addColumn<QList<ProjectExplorer::Task> >("tasks");
+ QTest::addColumn<QString>("outputLines");
+
+ const Core::Id categoryCompile = Constants::TASK_CATEGORY_COMPILE;
+
+ QTest::newRow("pass-through stdout")
+ << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT
+ << QString::fromLatin1("Sometext\n") << QString()
+ << QList<ProjectExplorer::Task>()
+ << QString();
+ QTest::newRow("pass-through stderr")
+ << QString::fromLatin1("Sometext") << OutputParserTester::STDERR
+ << QString() << QString::fromLatin1("Sometext\n")
+ << QList<ProjectExplorer::Task>()
+ << QString();
+
+ QTest::newRow("clang++ warning")
+ << QString::fromLatin1("clang++: warning: argument unused during compilation: '-mthreads'")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << (QList<ProjectExplorer::Task>()
+ << Task(Task::Warning,
+ QLatin1String("argument unused during compilation: '-mthreads'"),
+ Utils::FileName(), -1,
+ categoryCompile))
+ << QString();
+ QTest::newRow("clang++ error")
+ << QString::fromLatin1("clang++: error: no input files [err_drv_no_input_files]")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << (QList<ProjectExplorer::Task>()
+ << Task(Task::Error,
+ QLatin1String("no input files [err_drv_no_input_files]"),
+ Utils::FileName(), -1,
+ categoryCompile))
+ << QString();
+ QTest::newRow("complex warning")
+ << QString::fromLatin1("In file included from ..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qnamespace.h:45:\n"
+ "..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qglobal.h(1425) : warning: unknown attribute 'dllimport' ignored [-Wunknown-attributes]\n"
+ "class Q_CORE_EXPORT QSysInfo {\n"
+ " ^")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << (QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("In file included from ..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qnamespace.h:45:"),
+ Utils::FileName::fromUserInput(QLatin1String("..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qnamespace.h")), 45,
+ categoryCompile)
+ << Task(Task::Warning,
+ QLatin1String("unknown attribute 'dllimport' ignored [-Wunknown-attributes]\n"
+ "class Q_CORE_EXPORT QSysInfo {\n"
+ " ^"),
+ Utils::FileName::fromUserInput(QLatin1String("..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qglobal.h")), 1425,
+ categoryCompile))
+ << QString();
+ QTest::newRow("note")
+ << QString::fromLatin1("..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qglobal.h:1289:27: note: instantiated from:\n"
+ "# define Q_CORE_EXPORT Q_DECL_IMPORT\n"
+ " ^")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << (QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("instantiated from:\n"
+ "# define Q_CORE_EXPORT Q_DECL_IMPORT\n"
+ " ^"),
+ Utils::FileName::fromUserInput(QLatin1String("..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qglobal.h")), 1289,
+ categoryCompile))
+ << QString();
+ QTest::newRow("fatal error")
+ << QString::fromLatin1("/usr/include/c++/4.6/utility:68:10: fatal error: 'bits/c++config.h' file not found\n"
+ "#include <bits/c++config.h>\n"
+ " ^")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << (QList<ProjectExplorer::Task>()
+ << Task(Task::Error,
+ QLatin1String("'bits/c++config.h' file not found\n"
+ "#include <bits/c++config.h>\n"
+ " ^"),
+ Utils::FileName::fromUserInput(QLatin1String("/usr/include/c++/4.6/utility")), 68,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("line confusion")
+ << QString::fromLatin1("/home/code/src/creator/src/plugins/coreplugin/manhattanstyle.cpp:567:51: warning: ?: has lower precedence than +; + will be evaluated first [-Wparentheses]\n"
+ " int x = option->rect.x() + horizontal ? 2 : 6;\n"
+ " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << (QList<ProjectExplorer::Task>()
+ << Task(Task::Warning,
+ QLatin1String("?: has lower precedence than +; + will be evaluated first [-Wparentheses]\n"
+ " int x = option->rect.x() + horizontal ? 2 : 6;\n"
+ " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^"),
+ Utils::FileName::fromUserInput(QLatin1String("/home/code/src/creator/src/plugins/coreplugin/manhattanstyle.cpp")), 567,
+ categoryCompile))
+ << QString();
+ QTest::newRow("code sign error")
+ << QString::fromLatin1("Check dependencies\n"
+ "Code Sign error: No matching provisioning profiles found: No provisioning profiles with a valid signing identity (i.e. certificate and private key pair) were found.\n"
+ "CodeSign error: code signing is required for product type 'Application' in SDK 'iOS 7.0'")
+ << OutputParserTester::STDERR
+ << QString() << QString::fromLatin1("Check dependencies\n")
+ << (QList<ProjectExplorer::Task>()
+ << Task(Task::Error,
+ QLatin1String("No matching provisioning profiles found: No provisioning profiles with a valid signing identity (i.e. certificate and private key pair) were found."),
+ Utils::FileName(), -1,
+ categoryCompile)
+ << Task(Task::Error,
+ QLatin1String("code signing is required for product type 'Application' in SDK 'iOS 7.0'"),
+ Utils::FileName(), -1,
+ categoryCompile))
+ << QString();
+}
+
+void ProjectExplorerPlugin::testClangOutputParser()
+{
+ OutputParserTester testbench;
+ testbench.appendOutputParser(new ClangParser);
+ QFETCH(QString, input);
+ QFETCH(OutputParserTester::Channel, inputChannel);
+ QFETCH(QList<Task>, tasks);
+ QFETCH(QString, childStdOutLines);
+ QFETCH(QString, childStdErrLines);
+ QFETCH(QString, outputLines);
+
+ testbench.testParsing(input, inputChannel,
+ tasks, childStdOutLines, childStdErrLines,
+ outputLines);
+}
+#endif
diff --git a/src/plugins/boostbuildprojectmanager/external/projectexplorer/clangparser.h b/src/plugins/boostbuildprojectmanager/external/projectexplorer/clangparser.h
new file mode 100644
index 0000000000..4a914b7326
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/external/projectexplorer/clangparser.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef CLANGPARSER_H
+#define CLANGPARSER_H
+
+#include "gccparser.h"
+#include <projectexplorer/task.h>
+
+#include <QRegExp>
+
+namespace ProjectExplorer {
+
+class ClangParser : public ProjectExplorer::GccParser
+{
+ Q_OBJECT
+
+public:
+ ClangParser();
+ void stdError(const QString &line);
+
+private:
+ QRegExp m_commandRegExp;
+ QRegExp m_inLineRegExp;
+ QRegExp m_messageRegExp;
+ QRegExp m_summaryRegExp;
+ QRegExp m_codesignRegExp;
+ bool m_expectSnippet;
+};
+
+} // namespace ProjectExplorer
+
+#endif // CLANGPARSER_H
diff --git a/src/plugins/boostbuildprojectmanager/external/projectexplorer/gccparser.cpp b/src/plugins/boostbuildprojectmanager/external/projectexplorer/gccparser.cpp
new file mode 100644
index 0000000000..c6b7e02ba7
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/external/projectexplorer/gccparser.cpp
@@ -0,0 +1,880 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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 by the Free Software
+** Foundation and appearing in the file LICENSE.txt 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.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "gccparser.h"
+#include "ldparser.h"
+#include <projectexplorer/task.h>
+#include <projectexplorer/projectexplorerconstants.h>
+
+#include <utils/qtcassert.h>
+
+using namespace ProjectExplorer;
+
+// opt. drive letter + filename: (2 brackets)
+static const char FILE_PATTERN[] = "(<command[ -]line>|([A-Za-z]:)?[^:]+):";
+static const char COMMAND_PATTERN[] = "^(.*[\\\\/])?([a-z0-9]+-[a-z0-9]+-[a-z0-9]+-)?(gcc|g\\+\\+)(-[0-9\\.]+)?(\\.exe)?: ";
+
+GccParser::GccParser()
+{
+ setObjectName(QLatin1String("GCCParser"));
+ m_regExp.setPattern(QLatin1Char('^') + QLatin1String(FILE_PATTERN)
+ + QLatin1String("(\\d+):(\\d+:)?\\s+((fatal |#)?(warning|error|note):?\\s)?([^\\s].+)$"));
+ m_regExp.setMinimal(true);
+ QTC_CHECK(m_regExp.isValid());
+
+ m_regExpIncluded.setPattern(QString::fromLatin1("\\bfrom\\s") + QLatin1String(FILE_PATTERN)
+ + QLatin1String("(\\d+)(:\\d+)?[,:]?$"));
+ m_regExpIncluded.setMinimal(true);
+ QTC_CHECK(m_regExpIncluded.isValid());
+
+ // optional path with trailing slash
+ // optional arm-linux-none-thingy
+ // name of executable
+ // optional trailing version number
+ // optional .exe postfix
+ m_regExpGccNames.setPattern(QLatin1String(COMMAND_PATTERN));
+ m_regExpGccNames.setMinimal(true);
+ QTC_CHECK(m_regExpGccNames.isValid());
+
+ appendOutputParser(new LdParser);
+}
+
+void GccParser::stdError(const QString &line)
+{
+ QString lne = rightTrimmed(line);
+
+ // Blacklist some lines to not handle them:
+ if (lne.startsWith(QLatin1String("TeamBuilder ")) ||
+ lne.startsWith(QLatin1String("distcc["))) {
+ IOutputParser::stdError(line);
+ return;
+ }
+
+ // Handle misc issues:
+ if (lne.startsWith(QLatin1String("ERROR:")) ||
+ lne == QLatin1String("* cpp failed")) {
+ newTask(Task(Task::Error,
+ lne /* description */,
+ Utils::FileName() /* filename */,
+ -1 /* linenumber */,
+ Constants::TASK_CATEGORY_COMPILE));
+ return;
+ } else if (m_regExpGccNames.indexIn(lne) > -1) {
+ QString description = lne.mid(m_regExpGccNames.matchedLength());
+ Task task(Task::Error,
+ description,
+ Utils::FileName(), /* filename */
+ -1, /* line */
+ Constants::TASK_CATEGORY_COMPILE);
+ if (description.startsWith(QLatin1String("warning: "))) {
+ task.type = Task::Warning;
+ task.description = description.mid(9);
+ } else if (description.startsWith(QLatin1String("fatal: "))) {
+ task.description = description.mid(7);
+ }
+ newTask(task);
+ return;
+ } else if (m_regExp.indexIn(lne) > -1) {
+ Utils::FileName filename = Utils::FileName::fromUserInput(m_regExp.cap(1));
+ int lineno = m_regExp.cap(3).toInt();
+ Task task(Task::Unknown,
+ m_regExp.cap(8) /* description */,
+ filename, lineno,
+ Constants::TASK_CATEGORY_COMPILE);
+ if (m_regExp.cap(7) == QLatin1String("warning"))
+ task.type = Task::Warning;
+ else if (m_regExp.cap(7) == QLatin1String("error") ||
+ task.description.startsWith(QLatin1String("undefined reference to")) ||
+ task.description.startsWith(QLatin1String("multiple definition of")))
+ task.type = Task::Error;
+
+ // Prepend "#warning" or "#error" if that triggered the match on (warning|error)
+ // We want those to show how the warning was triggered
+ if (m_regExp.cap(5).startsWith(QLatin1Char('#')))
+ task.description = m_regExp.cap(5) + task.description;
+
+ newTask(task);
+ return;
+ } else if (m_regExpIncluded.indexIn(lne) > -1) {
+ newTask(Task(Task::Unknown,
+ lne.trimmed() /* description */,
+ Utils::FileName::fromUserInput(m_regExpIncluded.cap(1)) /* filename */,
+ m_regExpIncluded.cap(3).toInt() /* linenumber */,
+ Constants::TASK_CATEGORY_COMPILE));
+ return;
+ } else if (lne.startsWith(QLatin1Char(' '))) {
+ amendDescription(lne, true);
+ return;
+ }
+
+ doFlush();
+ IOutputParser::stdError(line);
+}
+
+void GccParser::stdOutput(const QString &line)
+{
+ doFlush();
+ IOutputParser::stdOutput(line);
+}
+
+void GccParser::newTask(const Task &task)
+{
+ doFlush();
+ m_currentTask = task;
+}
+
+void GccParser::doFlush()
+{
+ if (m_currentTask.isNull())
+ return;
+ Task t = m_currentTask;
+ m_currentTask.clear();
+ emit addTask(t);
+}
+
+void GccParser::amendDescription(const QString &desc, bool monospaced)
+{
+ if (m_currentTask.isNull())
+ return;
+ int start = m_currentTask.description.count() + 1;
+ m_currentTask.description.append(QLatin1Char('\n'));
+ m_currentTask.description.append(desc);
+ if (monospaced) {
+ QTextLayout::FormatRange fr;
+ fr.start = start;
+ fr.length = desc.count() + 1;
+ fr.format.setFontFamily(QLatin1String("Monospaced"));
+ fr.format.setFontStyleHint(QFont::TypeWriter);
+ m_currentTask.formats.append(fr);
+ }
+ return;
+}
+
+// Unit tests:
+
+#ifdef WITH_TESTS_NOTDISABLED
+# include <QTest>
+
+# include "projectexplorer.h"
+# include "metatypedeclarations.h"
+# include "outputparser_test.h"
+
+void ProjectExplorerPlugin::testGccOutputParsers_data()
+{
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<OutputParserTester::Channel>("inputChannel");
+ QTest::addColumn<QString>("childStdOutLines");
+ QTest::addColumn<QString>("childStdErrLines");
+ QTest::addColumn<QList<ProjectExplorer::Task> >("tasks");
+ QTest::addColumn<QString>("outputLines");
+
+ const Core::Id categoryCompile = Constants::TASK_CATEGORY_COMPILE;
+
+ QTest::newRow("pass-through stdout")
+ << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT
+ << QString::fromLatin1("Sometext\n") << QString()
+ << QList<ProjectExplorer::Task>()
+ << QString();
+ QTest::newRow("pass-through stderr")
+ << QString::fromLatin1("Sometext") << OutputParserTester::STDERR
+ << QString() << QString::fromLatin1("Sometext\n")
+ << QList<ProjectExplorer::Task>()
+ << QString();
+
+ QTest::newRow("ar output")
+ << QString::fromLatin1("../../../../x86/i686-unknown-linux-gnu/bin/i686-unknown-linux-gnu-ar: creating lib/libSkyView.a") << OutputParserTester::STDERR
+ << QString() << QString::fromLatin1("../../../../x86/i686-unknown-linux-gnu/bin/i686-unknown-linux-gnu-ar: creating lib/libSkyView.a\n")
+ << QList<ProjectExplorer::Task>()
+ << QString();
+
+ QTest::newRow("GCCE error")
+ << QString::fromLatin1("/temp/test/untitled8/main.cpp: In function `int main(int, char**)':\n"
+ "/temp/test/untitled8/main.cpp:9: error: `sfasdf' undeclared (first use this function)\n"
+ "/temp/test/untitled8/main.cpp:9: error: (Each undeclared identifier is reported only once for each function it appears in.)")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << (QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("In function `int main(int, char**)':"),
+ Utils::FileName::fromUserInput(QLatin1String("/temp/test/untitled8/main.cpp")), -1,
+ categoryCompile)
+ << Task(Task::Error,
+ QLatin1String("`sfasdf' undeclared (first use this function)"),
+ Utils::FileName::fromUserInput(QLatin1String("/temp/test/untitled8/main.cpp")), 9,
+ categoryCompile)
+ << Task(Task::Error,
+ QLatin1String("(Each undeclared identifier is reported only once for each function it appears in.)"),
+ Utils::FileName::fromUserInput(QLatin1String("/temp/test/untitled8/main.cpp")), 9,
+ categoryCompile)
+ )
+ << QString();
+ QTest::newRow("GCCE warning")
+ << QString::fromLatin1("/src/corelib/global/qglobal.h:1635: warning: inline function `QDebug qDebug()' used but never defined")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << (QList<ProjectExplorer::Task>()
+ << Task(Task::Warning,
+ QLatin1String("inline function `QDebug qDebug()' used but never defined"),
+ Utils::FileName::fromUserInput(QLatin1String("/src/corelib/global/qglobal.h")), 1635,
+ categoryCompile))
+ << QString();
+ QTest::newRow("warning")
+ << QString::fromLatin1("main.cpp:7:2: warning: Some warning")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << (QList<ProjectExplorer::Task>() << Task(Task::Warning,
+ QLatin1String("Some warning"),
+ Utils::FileName::fromUserInput(QLatin1String("main.cpp")), 7,
+ categoryCompile))
+ << QString();
+ QTest::newRow("GCCE #error")
+ << QString::fromLatin1("C:\\temp\\test\\untitled8\\main.cpp:7: #error Symbian error")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << (QList<ProjectExplorer::Task>()
+ << Task(Task::Error,
+ QLatin1String("#error Symbian error"),
+ Utils::FileName::fromUserInput(QLatin1String("C:\\temp\\test\\untitled8\\main.cpp")), 7,
+ categoryCompile))
+ << QString();
+ // Symbian reports #warning(s) twice (using different syntax).
+ QTest::newRow("GCCE #warning1")
+ << QString::fromLatin1("C:\\temp\\test\\untitled8\\main.cpp:8: warning: #warning Symbian warning")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << (QList<ProjectExplorer::Task>()
+ << Task(Task::Warning,
+ QLatin1String("#warning Symbian warning"),
+ Utils::FileName::fromUserInput(QLatin1String("C:\\temp\\test\\untitled8\\main.cpp")), 8,
+ categoryCompile))
+ << QString();
+ QTest::newRow("GCCE #warning2")
+ << QString::fromLatin1("/temp/test/untitled8/main.cpp:8:2: warning: #warning Symbian warning")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << (QList<ProjectExplorer::Task>()
+ << Task(Task::Warning,
+ QLatin1String("#warning Symbian warning"),
+ Utils::FileName::fromUserInput(QLatin1String("/temp/test/untitled8/main.cpp")), 8,
+ categoryCompile))
+ << QString();
+ QTest::newRow("Undefined reference (debug)")
+ << QString::fromLatin1("main.o: In function `main':\n"
+ "C:\\temp\\test\\untitled8/main.cpp:8: undefined reference to `MainWindow::doSomething()'\n"
+ "collect2: ld returned 1 exit status")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << (QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("In function `main':"),
+ Utils::FileName::fromUserInput(QLatin1String("main.o")), -1,
+ categoryCompile)
+ << Task(Task::Error,
+ QLatin1String("undefined reference to `MainWindow::doSomething()'"),
+ Utils::FileName::fromUserInput(QLatin1String("C:\\temp\\test\\untitled8/main.cpp")), 8,
+ categoryCompile)
+ << Task(Task::Error,
+ QLatin1String("collect2: ld returned 1 exit status"),
+ Utils::FileName(), -1,
+ categoryCompile)
+ )
+ << QString();
+ QTest::newRow("Undefined reference (release)")
+ << QString::fromLatin1("main.o: In function `main':\n"
+ "C:\\temp\\test\\untitled8/main.cpp:(.text+0x40): undefined reference to `MainWindow::doSomething()'\n"
+ "collect2: ld returned 1 exit status")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << (QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("In function `main':"),
+ Utils::FileName::fromUserInput(QLatin1String("main.o")), -1,
+ categoryCompile)
+ << Task(Task::Error,
+ QLatin1String("undefined reference to `MainWindow::doSomething()'"),
+ Utils::FileName::fromUserInput(QLatin1String("C:\\temp\\test\\untitled8/main.cpp")), -1,
+ categoryCompile)
+ << Task(Task::Error,
+ QLatin1String("collect2: ld returned 1 exit status"),
+ Utils::FileName(), -1,
+ categoryCompile)
+ )
+ << QString();
+ QTest::newRow("linker: dll format not recognized")
+ << QString::fromLatin1("c:\\Qt\\4.6\\lib/QtGuid4.dll: file not recognized: File format not recognized")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << (QList<ProjectExplorer::Task>()
+ << Task(Task::Error,
+ QLatin1String("file not recognized: File format not recognized"),
+ Utils::FileName::fromUserInput(QLatin1String("c:\\Qt\\4.6\\lib/QtGuid4.dll")), -1,
+ categoryCompile))
+ << QString();
+ QTest::newRow("Invalid rpath")
+ << QString::fromLatin1("g++: /usr/local/lib: No such file or directory")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << (QList<ProjectExplorer::Task>()
+ << Task(Task::Error,
+ QLatin1String("/usr/local/lib: No such file or directory"),
+ Utils::FileName(), -1,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("Invalid rpath")
+ << QString::fromLatin1("../../../../master/src/plugins/debugger/gdb/gdbengine.cpp: In member function 'void Debugger::Internal::GdbEngine::handleBreakInsert2(const Debugger::Internal::GdbResponse&)':\n"
+ "../../../../master/src/plugins/debugger/gdb/gdbengine.cpp:2114: warning: unused variable 'index'\n"
+ "../../../../master/src/plugins/debugger/gdb/gdbengine.cpp:2115: warning: unused variable 'handler'")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << (QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("In member function 'void Debugger::Internal::GdbEngine::handleBreakInsert2(const Debugger::Internal::GdbResponse&)':"),
+ Utils::FileName::fromUserInput(QLatin1String("../../../../master/src/plugins/debugger/gdb/gdbengine.cpp")), -1,
+ categoryCompile)
+ << Task(Task::Warning,
+ QLatin1String("unused variable 'index'"),
+ Utils::FileName::fromUserInput(QLatin1String("../../../../master/src/plugins/debugger/gdb/gdbengine.cpp")), 2114,
+ categoryCompile)
+ << Task(Task::Warning,
+ QLatin1String("unused variable 'handler'"),
+ Utils::FileName::fromUserInput(QLatin1String("../../../../master/src/plugins/debugger/gdb/gdbengine.cpp")), 2115,
+ categoryCompile))
+ << QString();
+ QTest::newRow("gnumakeparser.cpp errors")
+ << QString::fromLatin1("/home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp: In member function 'void ProjectExplorer::ProjectExplorerPlugin::testGnuMakeParserTaskMangling_data()':\n"
+ "/home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp:264: error: expected primary-expression before ':' token\n"
+ "/home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp:264: error: expected ';' before ':' token")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << (QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("In member function 'void ProjectExplorer::ProjectExplorerPlugin::testGnuMakeParserTaskMangling_data()':"),
+ Utils::FileName::fromUserInput(QLatin1String("/home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp")), -1,
+ categoryCompile)
+ << Task(Task::Error,
+ QLatin1String("expected primary-expression before ':' token"),
+ Utils::FileName::fromUserInput(QLatin1String("/home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp")), 264,
+ categoryCompile)
+ << Task(Task::Error,
+ QLatin1String("expected ';' before ':' token"),
+ Utils::FileName::fromUserInput(QLatin1String("/home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp")), 264,
+ categoryCompile))
+ << QString();
+ QTest::newRow("distcc error(QTCREATORBUG-904)")
+ << QString::fromLatin1("distcc[73168] (dcc_get_hostlist) Warning: no hostlist is set; can't distribute work\n"
+ "distcc[73168] (dcc_build_somewhere) Warning: failed to distribute, running locally instead")
+ << OutputParserTester::STDERR
+ << QString() << QString::fromLatin1("distcc[73168] (dcc_get_hostlist) Warning: no hostlist is set; can't distribute work\n"
+ "distcc[73168] (dcc_build_somewhere) Warning: failed to distribute, running locally instead\n")
+ << QList<ProjectExplorer::Task>()
+ << QString();
+ QTest::newRow("ld warning (QTCREATORBUG-905)")
+ << QString::fromLatin1("ld: warning: Core::IEditor* QVariant::value<Core::IEditor*>() const has different visibility (hidden) in .obj/debug-shared/openeditorsview.o and (default) in .obj/debug-shared/editormanager.o")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Warning,
+ QLatin1String("Core::IEditor* QVariant::value<Core::IEditor*>() const has different visibility (hidden) in .obj/debug-shared/openeditorsview.o and (default) in .obj/debug-shared/editormanager.o"),
+ Utils::FileName(), -1,
+ categoryCompile))
+ << QString();
+ QTest::newRow("ld fatal")
+ << QString::fromLatin1("ld: fatal: Symbol referencing errors. No output written to testproject")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Error,
+ QLatin1String("Symbol referencing errors. No output written to testproject"),
+ Utils::FileName(), -1,
+ categoryCompile))
+ << QString();
+ QTest::newRow("Teambuilder issues")
+ << QString::fromLatin1("TeamBuilder Client:: error: could not find Scheduler, running Job locally...")
+ << OutputParserTester::STDERR
+ << QString() << QString::fromLatin1("TeamBuilder Client:: error: could not find Scheduler, running Job locally...\n")
+ << QList<ProjectExplorer::Task>()
+ << QString();
+ QTest::newRow("note")
+ << QString::fromLatin1("/home/dev/creator/share/qtcreator/debugger/dumper.cpp:1079: note: initialized from here")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("initialized from here"),
+ Utils::FileName::fromUserInput(QLatin1String("/home/dev/creator/share/qtcreator/debugger/dumper.cpp")), 1079,
+ categoryCompile))
+ << QString();
+ QTest::newRow("static member function")
+ << QString::fromLatin1("/Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c: In static member function 'static std::_Rb_tree_node_base* std::_Rb_global<_Dummy>::_Rebalance_for_erase(std::_Rb_tree_node_base*, std::_Rb_tree_node_base*&, std::_Rb_tree_node_base*&, std::_Rb_tree_node_base*&)':\n"
+ "/Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c:194: warning: suggest explicit braces to avoid ambiguous 'else'")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("In static member function 'static std::_Rb_tree_node_base* std::_Rb_global<_Dummy>::_Rebalance_for_erase(std::_Rb_tree_node_base*, std::_Rb_tree_node_base*&, std::_Rb_tree_node_base*&, std::_Rb_tree_node_base*&)':"),
+ Utils::FileName::fromUserInput(QLatin1String("/Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c")), -1,
+ categoryCompile)
+ << Task(Task::Warning,
+ QLatin1String("suggest explicit braces to avoid ambiguous 'else'"),
+ Utils::FileName::fromUserInput(QLatin1String("/Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c")), 194,
+ categoryCompile))
+ << QString();
+ QTest::newRow("rm false positive")
+ << QString::fromLatin1("rm: cannot remove `release/moc_mainwindow.cpp': No such file or directory")
+ << OutputParserTester::STDERR
+ << QString() << QString(QLatin1String("rm: cannot remove `release/moc_mainwindow.cpp': No such file or directory\n"))
+ << QList<ProjectExplorer::Task>()
+ << QString();
+ QTest::newRow("ranlib false positive")
+ << QString::fromLatin1("ranlib: file: libSupport.a(HashTable.o) has no symbols")
+ << OutputParserTester::STDERR
+ << QString() << QString(QLatin1String("ranlib: file: libSupport.a(HashTable.o) has no symbols\n"))
+ << QList<ProjectExplorer::Task>()
+ << QString();
+ QTest::newRow("ld: missing library")
+ << QString::fromLatin1("/usr/bin/ld: cannot find -ldoesnotexist")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Error,
+ QLatin1String("cannot find -ldoesnotexist"),
+ Utils::FileName(), -1,
+ categoryCompile))
+ << QString();
+ QTest::newRow("In function")
+ << QString::fromLatin1("../../scriptbug/main.cpp: In function void foo(i) [with i = double]:\n"
+ "../../scriptbug/main.cpp:22: instantiated from here\n"
+ "../../scriptbug/main.cpp:8: warning: unused variable c")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("In function void foo(i) [with i = double]:"),
+ Utils::FileName::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), -1,
+ categoryCompile)
+ << Task(Task::Unknown,
+ QLatin1String("instantiated from here"),
+ Utils::FileName::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), 22,
+ categoryCompile)
+ << Task(Task::Warning,
+ QLatin1String("unused variable c"),
+ Utils::FileName::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), 8,
+ categoryCompile))
+ << QString();
+ QTest::newRow("instanciated from here")
+ << QString::fromLatin1("main.cpp:10: instantiated from here ")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("instantiated from here"),
+ Utils::FileName::fromUserInput(QLatin1String("main.cpp")), 10,
+ categoryCompile))
+ << QString();
+ QTest::newRow("In constructor")
+ << QString::fromLatin1("/dev/creator/src/plugins/find/basetextfind.h: In constructor 'Find::BaseTextFind::BaseTextFind(QTextEdit*)':")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("In constructor 'Find::BaseTextFind::BaseTextFind(QTextEdit*)':"),
+ Utils::FileName::fromUserInput(QLatin1String("/dev/creator/src/plugins/find/basetextfind.h")), -1,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("At global scope")
+ << QString::fromLatin1("../../scriptbug/main.cpp: At global scope:\n"
+ "../../scriptbug/main.cpp: In instantiation of void bar(i) [with i = double]:\n"
+ "../../scriptbug/main.cpp:8: instantiated from void foo(i) [with i = double]\n"
+ "../../scriptbug/main.cpp:22: instantiated from here\n"
+ "../../scriptbug/main.cpp:5: warning: unused parameter v")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("At global scope:"),
+ Utils::FileName::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), -1,
+ categoryCompile)
+ << Task(Task::Unknown,
+ QLatin1String("In instantiation of void bar(i) [with i = double]:"),
+ Utils::FileName::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), -1,
+ categoryCompile)
+ << Task(Task::Unknown,
+ QLatin1String("instantiated from void foo(i) [with i = double]"),
+ Utils::FileName::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), 8,
+ categoryCompile)
+ << Task(Task::Unknown,
+ QLatin1String("instantiated from here"),
+ Utils::FileName::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), 22,
+ categoryCompile)
+ << Task(Task::Warning,
+ QLatin1String("unused parameter v"),
+ Utils::FileName::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), 5,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("gcc 4.5 fatal error")
+ << QString::fromLatin1("/home/code/test.cpp:54:38: fatal error: test.moc: No such file or directory")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Error,
+ QLatin1String("test.moc: No such file or directory"),
+ Utils::FileName::fromUserInput(QLatin1String("/home/code/test.cpp")), 54,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("QTCREATORBUG-597")
+ << QString::fromLatin1("debug/qplotaxis.o: In function `QPlotAxis':\n"
+ "M:\\Development\\x64\\QtPlot/qplotaxis.cpp:26: undefined reference to `vtable for QPlotAxis'\n"
+ "M:\\Development\\x64\\QtPlot/qplotaxis.cpp:26: undefined reference to `vtable for QPlotAxis'\n"
+ "collect2: ld returned 1 exit status")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("In function `QPlotAxis':"),
+ Utils::FileName::fromUserInput(QLatin1String("debug/qplotaxis.o")), -1,
+ categoryCompile)
+ << Task(Task::Error,
+ QLatin1String("undefined reference to `vtable for QPlotAxis'"),
+ Utils::FileName::fromUserInput(QLatin1String("M:\\Development\\x64\\QtPlot/qplotaxis.cpp")), 26,
+ categoryCompile)
+ << Task(Task::Error,
+ QLatin1String("undefined reference to `vtable for QPlotAxis'"),
+ Utils::FileName::fromUserInput(QLatin1String("M:\\Development\\x64\\QtPlot/qplotaxis.cpp")), 26,
+ categoryCompile)
+ << Task(Task::Error,
+ QLatin1String("collect2: ld returned 1 exit status"),
+ Utils::FileName(), -1,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("instantiated from here should not be an error")
+ << QString::fromLatin1("../stl/main.cpp: In member function typename _Vector_base<_Tp, _Alloc>::_Tp_alloc_type::const_reference Vector<_Tp, _Alloc>::at(int) [with _Tp = Point, _Alloc = Allocator<Point>]:\n"
+ "../stl/main.cpp:38: instantiated from here\n"
+ "../stl/main.cpp:31: warning: returning reference to temporary\n"
+ "../stl/main.cpp: At global scope:\n"
+ "../stl/main.cpp:31: warning: unused parameter index")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("In member function typename _Vector_base<_Tp, _Alloc>::_Tp_alloc_type::const_reference Vector<_Tp, _Alloc>::at(int) [with _Tp = Point, _Alloc = Allocator<Point>]:"),
+ Utils::FileName::fromUserInput(QLatin1String("../stl/main.cpp")), -1,
+ categoryCompile)
+ << Task(Task::Unknown,
+ QLatin1String("instantiated from here"),
+ Utils::FileName::fromUserInput(QLatin1String("../stl/main.cpp")), 38,
+ categoryCompile)
+ << Task(Task::Warning,
+ QLatin1String("returning reference to temporary"),
+ Utils::FileName::fromUserInput(QLatin1String("../stl/main.cpp")), 31,
+ categoryCompile)
+ << Task(Task::Unknown,
+ QLatin1String("At global scope:"),
+ Utils::FileName::fromUserInput(QLatin1String("../stl/main.cpp")), -1,
+ categoryCompile)
+ << Task(Task::Warning,
+ QLatin1String("unused parameter index"),
+ Utils::FileName::fromUserInput(QLatin1String("../stl/main.cpp")), 31,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("GCCE from lines")
+ << QString::fromLatin1("In file included from C:/Symbian_SDK/epoc32/include/e32cmn.h:6792,\n"
+ " from C:/Symbian_SDK/epoc32/include/e32std.h:25,\n"
+ "C:/Symbian_SDK/epoc32/include/e32cmn.inl: In member function 'SSecureId::operator const TSecureId&() const':\n"
+ "C:/Symbian_SDK/epoc32/include/e32cmn.inl:7094: warning: returning reference to temporary")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("In file included from C:/Symbian_SDK/epoc32/include/e32cmn.h:6792,"),
+ Utils::FileName::fromUserInput(QLatin1String("C:/Symbian_SDK/epoc32/include/e32cmn.h")), 6792,
+ categoryCompile)
+ << Task(Task::Unknown,
+ QLatin1String("from C:/Symbian_SDK/epoc32/include/e32std.h:25,"),
+ Utils::FileName::fromUserInput(QLatin1String("C:/Symbian_SDK/epoc32/include/e32std.h")), 25,
+ categoryCompile)
+ << Task(Task::Unknown,
+ QLatin1String("In member function 'SSecureId::operator const TSecureId&() const':"),
+ Utils::FileName::fromUserInput(QLatin1String("C:/Symbian_SDK/epoc32/include/e32cmn.inl")), -1,
+ categoryCompile)
+ << Task(Task::Warning,
+ QLatin1String("returning reference to temporary"),
+ Utils::FileName::fromUserInput(QLatin1String("C:/Symbian_SDK/epoc32/include/e32cmn.inl")), 7094,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("QTCREATORBUG-2206")
+ << QString::fromLatin1("../../../src/XmlUg/targetdelete.c: At top level:")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("At top level:"),
+ Utils::FileName::fromUserInput(QLatin1String("../../../src/XmlUg/targetdelete.c")), -1,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("GCCE 4: commandline, includes")
+ << QString::fromLatin1("In file included from /Symbian/SDK/EPOC32/INCLUDE/GCCE/GCCE.h:15,\n"
+ " from <command line>:26:\n"
+ "/Symbian/SDK/epoc32/include/variant/Symbian_OS.hrh:1134:26: warning: no newline at end of file")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("In file included from /Symbian/SDK/EPOC32/INCLUDE/GCCE/GCCE.h:15,"),
+ Utils::FileName::fromUserInput(QLatin1String("/Symbian/SDK/EPOC32/INCLUDE/GCCE/GCCE.h")), 15,
+ categoryCompile)
+ << Task(Task::Unknown,
+ QLatin1String("from <command line>:26:"),
+ Utils::FileName::fromUserInput(QLatin1String("<command line>")), 26,
+ categoryCompile)
+ << Task(Task::Warning,
+ QLatin1String("no newline at end of file"),
+ Utils::FileName::fromUserInput(QLatin1String("/Symbian/SDK/epoc32/include/variant/Symbian_OS.hrh")), 1134,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("Linker fail (release build)")
+ << QString::fromLatin1("release/main.o:main.cpp:(.text+0x42): undefined reference to `MainWindow::doSomething()'")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Error,
+ QLatin1String("undefined reference to `MainWindow::doSomething()'"),
+ Utils::FileName::fromUserInput(QLatin1String("main.cpp")), -1,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("enumeration warning")
+ << QString::fromLatin1("../../../src/shared/proparser/profileevaluator.cpp: In member function 'ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::evaluateConditionalFunction(const ProString&, const ProStringList&)':\n"
+ "../../../src/shared/proparser/profileevaluator.cpp:2817:9: warning: case value '0' not in enumerated type 'ProFileEvaluator::Private::TestFunc'")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("In member function 'ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::evaluateConditionalFunction(const ProString&, const ProStringList&)':"),
+ Utils::FileName::fromUserInput(QLatin1String("../../../src/shared/proparser/profileevaluator.cpp")), -1,
+ categoryCompile)
+ << Task(Task::Warning,
+ QLatin1String("case value '0' not in enumerated type 'ProFileEvaluator::Private::TestFunc'"),
+ Utils::FileName::fromUserInput(QLatin1String("../../../src/shared/proparser/profileevaluator.cpp")), 2817,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("include with line:column info")
+ << QString::fromLatin1("In file included from <command-line>:0:0:\n"
+ "./mw.h:4:0: warning: \"STUPID_DEFINE\" redefined")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("In file included from <command-line>:0:0:"),
+ Utils::FileName::fromUserInput(QLatin1String("<command-line>")), 0,
+ categoryCompile)
+ << Task(Task::Warning,
+ QLatin1String("\"STUPID_DEFINE\" redefined"),
+ Utils::FileName::fromUserInput(QLatin1String("./mw.h")), 4,
+ categoryCompile))
+ << QString();
+ QTest::newRow("instanciation with line:column info")
+ << QString::fromLatin1("file.h: In function 'void UnitTest::CheckEqual(UnitTest::TestResults&, const Expected&, const Actual&, const UnitTest::TestDetails&) [with Expected = unsigned int, Actual = int]':\n"
+ "file.cpp:87:10: instantiated from here\n"
+ "file.h:21:5: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("In function 'void UnitTest::CheckEqual(UnitTest::TestResults&, const Expected&, const Actual&, const UnitTest::TestDetails&) [with Expected = unsigned int, Actual = int]':"),
+ Utils::FileName::fromUserInput(QLatin1String("file.h")), -1,
+ categoryCompile)
+ << Task(Task::Unknown,
+ QLatin1String("instantiated from here"),
+ Utils::FileName::fromUserInput(QLatin1String("file.cpp")), 87,
+ categoryCompile)
+ << Task(Task::Warning,
+ QLatin1String("comparison between signed and unsigned integer expressions [-Wsign-compare]"),
+ Utils::FileName::fromUserInput(QLatin1String("file.h")), 21,
+ categoryCompile))
+ << QString();
+ QTest::newRow("linker error") // QTCREATORBUG-3107
+ << QString::fromLatin1("cns5k_ins_parser_tests.cpp:(.text._ZN20CNS5kINSParserEngine21DropBytesUntilStartedEP14CircularBufferIhE[CNS5kINSParserEngine::DropBytesUntilStarted(CircularBuffer<unsigned char>*)]+0x6d): undefined reference to `CNS5kINSPacket::SOH_BYTE'")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Error,
+ QLatin1String("undefined reference to `CNS5kINSPacket::SOH_BYTE'"),
+ Utils::FileName::fromUserInput(QLatin1String("cns5k_ins_parser_tests.cpp")), -1,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("uic warning")
+ << QString::fromLatin1("mainwindow.ui: Warning: The name 'pushButton' (QPushButton) is already in use, defaulting to 'pushButton1'.")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Warning,
+ QLatin1String("The name 'pushButton' (QPushButton) is already in use, defaulting to 'pushButton1'."),
+ Utils::FileName::fromUserInput(QLatin1String("mainwindow.ui")), -1,
+ Constants::TASK_CATEGORY_COMPILE))
+ << QString();
+
+ QTest::newRow("libimf warning")
+ << QString::fromLatin1("libimf.so: warning: warning: feupdateenv is not implemented and will always fail")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Warning,
+ QLatin1String("warning: feupdateenv is not implemented and will always fail"),
+ Utils::FileName::fromUserInput(QLatin1String("libimf.so")), -1,
+ Constants::TASK_CATEGORY_COMPILE))
+ << QString();
+
+ QTest::newRow("gcc 4.8")
+ << QString::fromLatin1("In file included from /home/code/src/creator/src/libs/extensionsystem/pluginerrorview.cpp:31:0:\n"
+ ".uic/ui_pluginerrorview.h:14:25: fatal error: QtGui/QAction: No such file or directory\n"
+ " #include <QtGui/QAction>\n"
+ " ^")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("In file included from /home/code/src/creator/src/libs/extensionsystem/pluginerrorview.cpp:31:0:"),
+ Utils::FileName::fromUserInput(QLatin1String("/home/code/src/creator/src/libs/extensionsystem/pluginerrorview.cpp")), 31,
+ categoryCompile)
+ << Task(Task::Error,
+ QLatin1String("QtGui/QAction: No such file or directory\n"
+ " #include <QtGui/QAction>\n"
+ " ^"),
+ Utils::FileName::fromUserInput(QLatin1String(".uic/ui_pluginerrorview.h")), 14,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("qtcreatorbug-9195")
+ << QString::fromLatin1("In file included from /usr/include/qt4/QtCore/QString:1:0,\n"
+ " from main.cpp:3:\n"
+ "/usr/include/qt4/QtCore/qstring.h: In function 'void foo()':\n"
+ "/usr/include/qt4/QtCore/qstring.h:597:5: error: 'QString::QString(const char*)' is private\n"
+ "main.cpp:7:22: error: within this context")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << ( QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("In file included from /usr/include/qt4/QtCore/QString:1:0,"),
+ Utils::FileName::fromUserInput(QLatin1String("/usr/include/qt4/QtCore/QString")), 1,
+ categoryCompile)
+ << Task(Task::Unknown,
+ QLatin1String("from main.cpp:3:"),
+ Utils::FileName::fromUserInput(QLatin1String("main.cpp")), 3,
+ categoryCompile)
+ << Task(Task::Unknown,
+ QLatin1String("In function 'void foo()':"),
+ Utils::FileName::fromUserInput(QLatin1String("/usr/include/qt4/QtCore/qstring.h")), -1,
+ categoryCompile)
+ << Task(Task::Error,
+ QLatin1String("'QString::QString(const char*)' is private"),
+ Utils::FileName::fromUserInput(QLatin1String("/usr/include/qt4/QtCore/qstring.h")), 597,
+ categoryCompile)
+ << Task(Task::Error,
+ QLatin1String("within this context"),
+ Utils::FileName::fromUserInput(QLatin1String("main.cpp")), 7,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("ld: Multiple definition error")
+ << QString::fromLatin1("foo.o: In function `foo()':\n"
+ "/home/user/test/foo.cpp:2: multiple definition of `foo()'\n"
+ "bar.o:/home/user/test/bar.cpp:4: first defined here\n"
+ "collect2: error: ld returned 1 exit status")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << (QList<ProjectExplorer::Task>()
+ << Task(Task::Unknown,
+ QLatin1String("In function `foo()':"),
+ Utils::FileName::fromUserInput(QLatin1String("foo.o")), -1,
+ categoryCompile)
+ << Task(Task::Error,
+ QLatin1String("multiple definition of `foo()'"),
+ Utils::FileName::fromUserInput(QLatin1String("/home/user/test/foo.cpp")), 2,
+ categoryCompile)
+ << Task(Task::Unknown,
+ QLatin1String("first defined here"),
+ Utils::FileName::fromUserInput(QLatin1String("/home/user/test/bar.cpp")), 4,
+ categoryCompile)
+ << Task(Task::Error,
+ QLatin1String("collect2: error: ld returned 1 exit status"),
+ Utils::FileName(), -1,
+ categoryCompile)
+ )
+ << QString();
+
+ QTest::newRow("ld: .data section")
+ << QString::fromLatin1("foo.o:(.data+0x0): multiple definition of `foo'\n"
+ "bar.o:(.data+0x0): first defined here\n"
+ "collect2: error: ld returned 1 exit status")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << (QList<ProjectExplorer::Task>()
+ << Task(Task::Error,
+ QLatin1String("multiple definition of `foo'"),
+ Utils::FileName::fromUserInput(QLatin1String("foo.o")), -1,
+ categoryCompile)
+ << Task(Task::Unknown,
+ QLatin1String("first defined here"),
+ Utils::FileName::fromUserInput(QLatin1String("bar.o")), -1,
+ categoryCompile)
+ << Task(Task::Error,
+ QLatin1String("collect2: error: ld returned 1 exit status"),
+ Utils::FileName(), -1,
+ categoryCompile)
+ )
+ << QString();
+}
+
+void ProjectExplorerPlugin::testGccOutputParsers()
+{
+ OutputParserTester testbench;
+ testbench.appendOutputParser(new GccParser);
+ QFETCH(QString, input);
+ QFETCH(OutputParserTester::Channel, inputChannel);
+ QFETCH(QList<Task>, tasks);
+ QFETCH(QString, childStdOutLines);
+ QFETCH(QString, childStdErrLines);
+ QFETCH(QString, outputLines);
+
+ testbench.testParsing(input, inputChannel,
+ tasks, childStdOutLines, childStdErrLines,
+ outputLines);
+}
+#endif
diff --git a/src/plugins/boostbuildprojectmanager/external/projectexplorer/gccparser.h b/src/plugins/boostbuildprojectmanager/external/projectexplorer/gccparser.h
new file mode 100644
index 0000000000..db8ce4f2b3
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/external/projectexplorer/gccparser.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef GCCPARSER_H
+#define GCCPARSER_H
+
+#include <projectexplorer/ioutputparser.h>
+
+#include <projectexplorer/task.h>
+
+#include <QRegExp>
+
+namespace ProjectExplorer {
+
+class GccParser : public ProjectExplorer::IOutputParser
+{
+ Q_OBJECT
+
+public:
+ GccParser();
+
+ void stdError(const QString &line);
+ void stdOutput(const QString &line);
+
+protected:
+ void newTask(const Task &task);
+ void doFlush();
+
+ void amendDescription(const QString &desc, bool monospaced);
+
+private:
+ QRegExp m_regExp;
+ QRegExp m_regExpIncluded;
+ QRegExp m_regExpGccNames;
+
+ Task m_currentTask;
+};
+
+} // namespace ProjectExplorer
+
+#endif // GCCPARSER_H
diff --git a/src/plugins/boostbuildprojectmanager/external/projectexplorer/ldparser.cpp b/src/plugins/boostbuildprojectmanager/external/projectexplorer/ldparser.cpp
new file mode 100644
index 0000000000..9c3866c121
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/external/projectexplorer/ldparser.cpp
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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 by the Free Software
+** Foundation and appearing in the file LICENSE.txt 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.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "ldparser.h"
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/task.h>
+
+#include <utils/qtcassert.h>
+
+using namespace ProjectExplorer;
+
+namespace {
+ // opt. drive letter + filename: (2 brackets)
+ const char * const FILE_PATTERN = "(([A-Za-z]:)?[^:]+\\.[^:]+):";
+ // line no. or elf segment + offset (1 bracket)
+ // const char * const POSITION_PATTERN = "(\\d+|\\(\\.[^:]+[+-]0x[a-fA-F0-9]+\\):)";
+ const char * const POSITION_PATTERN = "(\\d+|\\(\\..+[+-]0x[a-fA-F0-9]+\\)):";
+ const char * const COMMAND_PATTERN = "^(.*[\\\\/])?([a-z0-9]+-[a-z0-9]+-[a-z0-9]+-)?(ld|gold)(-[0-9\\.]+)?(\\.exe)?: ";
+}
+
+LdParser::LdParser()
+{
+ setObjectName(QLatin1String("LdParser"));
+ m_regExpLinker.setPattern(QLatin1Char('^') +
+ QString::fromLatin1(FILE_PATTERN) + QLatin1Char('(') +
+ QString::fromLatin1(FILE_PATTERN) + QLatin1String(")?(") +
+ QLatin1String(POSITION_PATTERN) + QLatin1String(")?\\s(.+)$"));
+ m_regExpLinker.setMinimal(true);
+ QTC_CHECK(m_regExpLinker.isValid());
+
+ m_regExpGccNames.setPattern(QLatin1String(COMMAND_PATTERN));
+ m_regExpGccNames.setMinimal(true);
+ QTC_CHECK(m_regExpGccNames.isValid());
+}
+
+void LdParser::stdError(const QString &line)
+{
+ QString lne = rightTrimmed(line);
+ if (lne.startsWith(QLatin1String("TeamBuilder "))
+ || lne.startsWith(QLatin1String("distcc["))
+ || lne.contains(QLatin1String("ar: creating "))) {
+ IOutputParser::stdError(line);
+ return;
+ }
+
+ if (lne.startsWith(QLatin1String("collect2:"))) {
+ emit addTask(Task(Task::Error,
+ lne /* description */,
+ Utils::FileName() /* filename */,
+ -1 /* linenumber */,
+ Constants::TASK_CATEGORY_COMPILE));
+ return;
+ } else if (m_regExpGccNames.indexIn(lne) > -1) {
+ QString description = lne.mid(m_regExpGccNames.matchedLength());
+ Task task(Task::Error,
+ description,
+ Utils::FileName(), /* filename */
+ -1, /* line */
+ Constants::TASK_CATEGORY_COMPILE);
+ if (description.startsWith(QLatin1String("warning: "))) {
+ task.type = Task::Warning;
+ task.description = description.mid(9);
+ } else if (description.startsWith(QLatin1String("fatal: "))) {
+ task.description = description.mid(7);
+ }
+ emit addTask(task);
+ return;
+ } else if (m_regExpLinker.indexIn(lne) > -1) {
+ bool ok;
+ int lineno = m_regExpLinker.cap(7).toInt(&ok);
+ if (!ok)
+ lineno = -1;
+ Utils::FileName filename = Utils::FileName::fromUserInput(m_regExpLinker.cap(1));
+ const QString sourceFileName = m_regExpLinker.cap(4);
+ if (!sourceFileName.isEmpty()
+ && !sourceFileName.startsWith(QLatin1String("(.text"))
+ && !sourceFileName.startsWith(QLatin1String("(.data"))) {
+ filename = Utils::FileName::fromUserInput(sourceFileName);
+ }
+ QString description = m_regExpLinker.cap(8).trimmed();
+ Task task(Task::Error, description, filename, lineno,
+ Constants::TASK_CATEGORY_COMPILE);
+ if (description.startsWith(QLatin1String("At global scope")) ||
+ description.startsWith(QLatin1String("At top level")) ||
+ description.startsWith(QLatin1String("instantiated from ")) ||
+ description.startsWith(QLatin1String("In ")) ||
+ description.startsWith(QLatin1String("first defined here"))) {
+ task.type = Task::Unknown;
+ }
+ if (description.startsWith(QLatin1String("warning: "), Qt::CaseInsensitive)) {
+ task.type = Task::Warning;
+ task.description = description.mid(9);
+ }
+
+ emit addTask(task);
+ return;
+ }
+
+ IOutputParser::stdError(line);
+}
diff --git a/src/plugins/boostbuildprojectmanager/external/projectexplorer/ldparser.h b/src/plugins/boostbuildprojectmanager/external/projectexplorer/ldparser.h
new file mode 100644
index 0000000000..5038763b14
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/external/projectexplorer/ldparser.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef LDPARSER_H
+#define LDPARSER_H
+
+#include <projectexplorer/ioutputparser.h>
+
+#include <QRegExp>
+
+namespace ProjectExplorer {
+
+class LdParser : public ProjectExplorer::IOutputParser
+{
+ Q_OBJECT
+
+public:
+ LdParser();
+ void stdError(const QString &line);
+
+private:
+ QRegExp m_regExpLinker;
+ QRegExp m_regExpGccNames;
+};
+
+} // namespace ProjectExplorer
+
+#endif // GCCPARSER_H
diff --git a/src/plugins/boostbuildprojectmanager/filesselectionwizardpage.cpp b/src/plugins/boostbuildprojectmanager/filesselectionwizardpage.cpp
new file mode 100644
index 0000000000..4a3b8b924c
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/filesselectionwizardpage.cpp
@@ -0,0 +1,232 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+**
+** This file, as part of Qt Creator Plugin for Boost.Build,
+** was modified to accommodate OpenProjectWizard requirements.
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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 by the Free Software
+** Foundation and appearing in the file LICENSE.txt 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.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "filesselectionwizardpage.h"
+
+#include "b2openprojectwizard.h"
+#include "b2projectmanagerconstants.h"
+#include "selectablefilesmodel.h"
+
+#include <coreplugin/icore.h>
+#include <utils/pathchooser.h>
+
+#include <QVBoxLayout>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QFileInfo>
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+FilesSelectionWizardPage::FilesSelectionWizardPage(OpenProjectWizardDialog *openProjectWizard, QWidget *parent)
+ : QWizardPage(parent), m_openProjectWizardDialog(openProjectWizard), m_model(0), m_finished(false)
+{
+ QVBoxLayout *layout = new QVBoxLayout(this);
+
+ createShowFileFilterControls(layout);
+ createHideFileFilterControls(layout);
+ createChooseBaseDirControls(layout);
+ createApplyButton(layout);
+
+ m_view = new QTreeView;
+ m_view->setMinimumSize(500, 400);
+ m_view->setHeaderHidden(true);
+ m_view->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
+ m_label = new QLabel;
+ m_label->setMaximumWidth(500);
+
+ layout->addWidget(m_view);
+ layout->addWidget(m_label);
+}
+
+void FilesSelectionWizardPage::createHideFileFilterControls(QVBoxLayout *layout)
+{
+ QHBoxLayout *hbox = new QHBoxLayout;
+ m_hideFilesFilterLabel = new QLabel;
+ m_hideFilesFilterLabel->setText(tr("Hide files matching:"));
+
+ m_hideFilesFilterLabel->hide();
+ hbox->addWidget(m_hideFilesFilterLabel);
+ m_hideFilesfilterLineEdit = new QLineEdit;
+
+ const QString filter = Core::ICore::settings()->value(QLatin1String(Constants::HIDE_FILE_FILTER_SETTING),
+ QLatin1String(Constants::HIDE_FILE_FILTER_DEFAULT)).toString();
+ m_hideFilesfilterLineEdit->setText(filter);
+ m_hideFilesfilterLineEdit->hide();
+ hbox->addWidget(m_hideFilesfilterLineEdit);
+ layout->addLayout(hbox);
+}
+
+void FilesSelectionWizardPage::createShowFileFilterControls(QVBoxLayout *layout)
+{
+ QHBoxLayout *hbox = new QHBoxLayout;
+ m_showFilesFilterLabel = new QLabel;
+ m_showFilesFilterLabel->setText(tr("Show files matching:"));
+ m_showFilesFilterLabel->hide();
+ hbox->addWidget(m_showFilesFilterLabel);
+ m_showFilesfilterLineEdit = new QLineEdit;
+
+ const QString filter = Core::ICore::settings()->value(QLatin1String(Constants::SHOW_FILE_FILTER_SETTING),
+ QLatin1String(Constants::SHOW_FILE_FILTER_DEFAULT)).toString();
+ m_showFilesfilterLineEdit->setText(filter);
+ m_showFilesfilterLineEdit->hide();
+ hbox->addWidget(m_showFilesfilterLineEdit);
+ layout->addLayout(hbox);
+}
+
+void FilesSelectionWizardPage::createChooseBaseDirControls(QVBoxLayout *layout)
+{
+ QHBoxLayout *hbox = new QHBoxLayout;
+ m_baseDirLabel = new QLabel;
+ m_baseDirLabel->setText(tr("Base directory:"));
+ m_baseDirLabel->hide();
+ hbox->addWidget(m_baseDirLabel);
+
+ m_lastBaseDir = m_openProjectWizardDialog->path();
+ m_baseDirChooser = new Utils::PathChooser;
+ m_baseDirChooser->setEnabled(true);
+ m_baseDirChooser->setBaseDirectory(m_lastBaseDir);
+ m_baseDirChooser->setPath(m_lastBaseDir);
+ connect(m_baseDirChooser, SIGNAL(changed(QString)), this, SLOT(baseDirectoryChanged()));
+ hbox->addWidget(m_baseDirChooser);
+
+ layout->addLayout(hbox);
+}
+
+void FilesSelectionWizardPage::createApplyButton(QVBoxLayout *layout)
+{
+ QHBoxLayout *hbox = new QHBoxLayout;
+
+ QSpacerItem *horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
+ hbox->addItem(horizontalSpacer);
+
+ m_applyFilterButton = new QPushButton(tr("Apply Filter"), this);
+ m_applyFilterButton->hide();
+ hbox->addWidget(m_applyFilterButton);
+ layout->addLayout(hbox);
+
+ connect(m_applyFilterButton, SIGNAL(clicked()), this, SLOT(applyFilter()));
+}
+
+void FilesSelectionWizardPage::initializePage()
+{
+ m_view->setModel(0);
+ delete m_model;
+ m_model = new SelectableFilesModel(m_lastBaseDir, this);
+ connect(m_model, SIGNAL(parsingProgress(QString)),
+ this, SLOT(parsingProgress(QString)));
+ connect(m_model, SIGNAL(parsingFinished()),
+ this, SLOT(parsingFinished()));
+ m_model->startParsing();
+
+ m_hideFilesFilterLabel->setVisible(false);
+ m_hideFilesfilterLineEdit->setVisible(false);
+
+ m_showFilesFilterLabel->setVisible(false);
+ m_showFilesfilterLineEdit->setVisible(false);
+
+ m_applyFilterButton->setVisible(false);
+ m_view->setVisible(false);
+ m_label->setVisible(true);
+ m_view->setModel(m_model);
+}
+
+void FilesSelectionWizardPage::cleanupPage()
+{
+ m_model->cancel();
+ m_model->waitForFinished();
+}
+
+void FilesSelectionWizardPage::parsingProgress(const QString &text)
+{
+ m_label->setText(tr("Generating file list...\n\n%1").arg(text));
+}
+
+void FilesSelectionWizardPage::parsingFinished()
+{
+ m_finished = true;
+
+ m_hideFilesFilterLabel->setVisible(true);
+ m_hideFilesfilterLineEdit->setVisible(true);
+
+ m_showFilesFilterLabel->setVisible(true);
+ m_showFilesfilterLineEdit->setVisible(true);
+
+ m_applyFilterButton->setVisible(true);
+ m_view->setVisible(true);
+ m_label->setVisible(false);
+ m_view->expand(m_view->model()->index(0,0, QModelIndex()));
+ emit completeChanged();
+ applyFilter();
+ // work around qt
+ m_openProjectWizardDialog->setTitleFormat(m_openProjectWizardDialog->titleFormat());
+}
+
+bool FilesSelectionWizardPage::isComplete() const
+{
+ return m_finished;
+}
+
+QStringList FilesSelectionWizardPage::selectedPaths() const
+{
+ return m_model ? m_model->selectedPaths() : QStringList();
+}
+
+QStringList FilesSelectionWizardPage::selectedFiles() const
+{
+ return m_model ? m_model->selectedFiles() : QStringList();
+}
+
+void FilesSelectionWizardPage::applyFilter()
+{
+ const QString showFilesFilter = m_showFilesfilterLineEdit->text();
+ Core::ICore::settings()->setValue(QLatin1String(Constants::SHOW_FILE_FILTER_SETTING), showFilesFilter);
+
+ const QString hideFilesFilter = m_hideFilesfilterLineEdit->text();
+ Core::ICore::settings()->setValue(QLatin1String(Constants::HIDE_FILE_FILTER_SETTING), hideFilesFilter);
+
+ m_model->applyFilter(showFilesFilter, hideFilesFilter);
+}
+
+void FilesSelectionWizardPage::baseDirectoryChanged()
+{
+ QString const baseDir(m_baseDirChooser->path());
+ if (baseDir != m_lastBaseDir && QFileInfo(baseDir).isDir())
+ {
+ m_lastBaseDir = baseDir;
+ initializePage();
+ }
+}
+} // namespace Internal
+} // namespace BoostBuildProjectManager
diff --git a/src/plugins/boostbuildprojectmanager/filesselectionwizardpage.h b/src/plugins/boostbuildprojectmanager/filesselectionwizardpage.h
new file mode 100644
index 0000000000..fe2aa81950
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/filesselectionwizardpage.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+**
+** This file, as part of Qt Creator Plugin for Boost.Build,
+** was modified to accommodate OpenProjectWizard requirements.
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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 by the Free Software
+** Foundation and appearing in the file LICENSE.txt 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.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef FILESSELECTIONWIZARDPAGE_HPP
+#define FILESSELECTIONWIZARDPAGE_HPP
+
+#include <QWizardPage>
+
+QT_BEGIN_NAMESPACE
+class QVBoxLayout;
+class QLabel;
+class QTreeView;
+class QLineEdit;
+QT_END_NAMESPACE
+
+namespace Utils {
+class PathChooser;
+}
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+class OpenProjectWizardDialog;
+class SelectableFilesModel;
+
+// TODO: Submit feature request to Qt Creator to make the FileSelectionWizardPage
+// a reusable component.
+class FilesSelectionWizardPage : public QWizardPage
+{
+ Q_OBJECT
+
+public:
+ FilesSelectionWizardPage(OpenProjectWizardDialog *openProjectWizard, QWidget *parent = 0);
+ bool isComplete() const;
+ void initializePage();
+ void cleanupPage();
+ QStringList selectedFiles() const;
+ QStringList selectedPaths() const;
+
+private slots:
+ void applyFilter();
+ void parsingProgress(const QString &text);
+ void parsingFinished();
+ void baseDirectoryChanged();
+
+private:
+ void createHideFileFilterControls(QVBoxLayout *layout);
+ void createShowFileFilterControls(QVBoxLayout *layout);
+ void createChooseBaseDirControls(QVBoxLayout *layout);
+ void createApplyButton(QVBoxLayout *layout);
+
+ OpenProjectWizardDialog *m_openProjectWizardDialog;
+ SelectableFilesModel *m_model;
+
+ QLabel *m_hideFilesFilterLabel;
+ QLineEdit *m_hideFilesfilterLineEdit;
+
+ QLabel *m_showFilesFilterLabel;
+ QLineEdit *m_showFilesfilterLineEdit;
+
+ QPushButton *m_applyFilterButton;
+
+ QLabel* m_baseDirLabel;
+ Utils::PathChooser* m_baseDirChooser;
+ QString m_lastBaseDir;
+
+ QTreeView *m_view;
+ QLabel *m_label;
+ bool m_finished;
+};
+
+} // namespace Internal
+} // namespace BoostBuildProjectManager
+
+#endif // FILESSELECTIONWIZARDPAGE_HPP
diff --git a/src/plugins/boostbuildprojectmanager/selectablefilesmodel.cpp b/src/plugins/boostbuildprojectmanager/selectablefilesmodel.cpp
new file mode 100644
index 0000000000..45a3e29f5e
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/selectablefilesmodel.cpp
@@ -0,0 +1,681 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+**
+** This file, as part of Qt Creator Plugin for Boost.Build,
+** was modified to accommodate OpenProjectWizard requirements.
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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 by the Free Software
+** Foundation and appearing in the file LICENSE.txt 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.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "selectablefilesmodel.h"
+#include "b2projectmanagerconstants.h"
+
+#include <coreplugin/fileiconprovider.h>
+#include <coreplugin/icore.h>
+
+#include <utils/QtConcurrentTools>
+
+#include <QDialogButtonBox>
+#include <QHBoxLayout>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QTreeView>
+#include <QDir>
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+SelectableFilesModel::SelectableFilesModel(const QString &baseDir, QObject *parent)
+ : QAbstractItemModel(parent), m_root(0), m_baseDir(baseDir), m_allFiles(true)
+{
+ Q_ASSERT(QFileInfo(m_baseDir).isDir());
+
+ // Dummy tree
+ m_root = new Tree;
+ m_root->name = QLatin1String("/");
+ m_root->parent = 0;
+ m_root->fullPath = m_baseDir;
+ m_root->isDir = true;
+}
+
+void SelectableFilesModel::setInitialMarkedFiles(const QStringList &files)
+{
+ m_files = files.toSet();
+ m_outOfBaseDirFiles.clear();
+ QString base = m_baseDir + QLatin1Char('/');
+ foreach (const QString &file, m_files)
+ if (!file.startsWith(base))
+ m_outOfBaseDirFiles.append(file);
+
+ m_allFiles = false;
+}
+
+void SelectableFilesModel::init()
+{
+}
+
+void SelectableFilesModel::startParsing()
+{
+ // Build a tree in a future
+ m_rootForFuture = new Tree;
+ m_rootForFuture->name = QLatin1String("/");
+ m_rootForFuture->parent = 0;
+ m_rootForFuture->fullPath = m_baseDir;
+ m_rootForFuture->isDir = true;
+
+ connect(&m_watcher, SIGNAL(finished()), this, SLOT(buildTreeFinished()));
+ m_watcher.setFuture(QtConcurrent::run(&SelectableFilesModel::run, this));
+}
+
+void SelectableFilesModel::run(QFutureInterface<void> &fi)
+{
+ m_futureCount = 0;
+ buildTree(m_baseDir, m_rootForFuture, fi);
+}
+
+void SelectableFilesModel::buildTreeFinished()
+{
+ beginResetModel();
+ deleteTree(m_root);
+ m_root = m_rootForFuture;
+ m_rootForFuture = 0;
+ endResetModel();
+ emit parsingFinished();
+}
+
+void SelectableFilesModel::waitForFinished()
+{
+ m_watcher.waitForFinished();
+}
+
+void SelectableFilesModel::cancel()
+{
+ m_watcher.cancel();
+}
+
+bool SelectableFilesModel::filter(Tree *t)
+{
+ if (t->isDir)
+ return false;
+ if (m_files.contains(t->fullPath))
+ return false;
+
+ bool showFilterMatch = false;
+
+ //First loop through show file filters and
+ //if any of them match, cotinue checking.
+ foreach (const Glob &g, m_showFilesFilter) {
+ if (g.isMatch(t->name)) {
+ showFilterMatch = true;
+ break;
+ }
+ }
+
+ //If none of the "show file" filters match just return
+ if (!showFilterMatch)
+ return true;
+
+ foreach (const Glob &g, m_hideFilesFilter) {
+ if (g.isMatch(t->name))
+ return true;
+ }
+
+ return false;
+}
+
+void SelectableFilesModel::buildTree(const QString &baseDir, Tree *tree, QFutureInterface<void> &fi)
+{
+ const QFileInfoList fileInfoList = QDir(baseDir).entryInfoList(QDir::Files |
+ QDir::Dirs |
+ QDir::NoDotAndDotDot);
+ bool allChecked = true;
+ bool allUnchecked = true;
+ foreach (const QFileInfo &fileInfo, fileInfoList) {
+ if (m_futureCount % 100) {
+ emit parsingProgress(fileInfo.absoluteFilePath());
+ if (fi.isCanceled())
+ return;
+ }
+ ++m_futureCount;
+ if (fileInfo.isDir()) {
+ if (fileInfo.isSymLink())
+ continue;
+ Tree *t = new Tree;
+ t->parent = tree;
+ t->name = fileInfo.fileName();
+ t->fullPath = fileInfo.filePath();
+ t->isDir = true;
+ buildTree(fileInfo.filePath(), t, fi);
+ allChecked &= t->checked == Qt::Checked;
+ allUnchecked &= t->checked == Qt::Unchecked;
+ tree->childDirectories.append(t);
+ } else {
+ Tree *t = new Tree;
+ t->parent = tree;
+ t->name = fileInfo.fileName();
+ t->checked = m_allFiles || m_files.contains(fileInfo.absoluteFilePath()) ? Qt::Checked : Qt::Unchecked;
+ t->fullPath = fileInfo.filePath();
+ t->isDir = false;
+ allChecked &= t->checked == Qt::Checked;
+ allUnchecked &= t->checked == Qt::Unchecked;
+ tree->files.append(t);
+ if (!filter(t))
+ tree->visibleFiles.append(t);
+ }
+ }
+ if (tree->childDirectories.isEmpty() && tree->visibleFiles.isEmpty())
+ tree->checked = Qt::Unchecked;
+ else if (allChecked)
+ tree->checked = Qt::Checked;
+ else if (allUnchecked)
+ tree->checked = Qt::Unchecked;
+ else
+ tree->checked = Qt::PartiallyChecked;
+}
+
+SelectableFilesModel::~SelectableFilesModel()
+{
+ deleteTree(m_root);
+}
+
+void SelectableFilesModel::deleteTree(Tree *tree)
+{
+ foreach (Tree *t, tree->childDirectories)
+ deleteTree(t);
+ foreach (Tree *t, tree->files)
+ deleteTree(t);
+ delete tree;
+}
+
+int SelectableFilesModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent)
+ return 1;
+}
+
+int SelectableFilesModel::rowCount(const QModelIndex &parent) const
+{
+ if (!parent.isValid())
+ return 1;
+ Tree *parentT = static_cast<Tree *>(parent.internalPointer());
+ return parentT->childDirectories.size() + parentT->visibleFiles.size();
+}
+
+QModelIndex SelectableFilesModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (!parent.isValid())
+ return createIndex(row, column, m_root);
+ Tree *parentT = static_cast<Tree *>(parent.internalPointer());
+ if (row < parentT->childDirectories.size())
+ return createIndex(row, column, parentT->childDirectories.at(row));
+ else
+ return createIndex(row, column, parentT->visibleFiles.at(row - parentT->childDirectories.size()));
+}
+
+QModelIndex SelectableFilesModel::parent(const QModelIndex &child) const
+{
+ if (!child.isValid())
+ return QModelIndex();
+ Tree *parent = static_cast<Tree *>(child.internalPointer())->parent;
+ if (!parent)
+ return QModelIndex();
+ if (!parent->parent) //then the parent is the root
+ return createIndex(0, 0, parent);
+ // figure out where the parent is
+ int pos = parent->parent->childDirectories.indexOf(parent);
+ if (pos == -1)
+ pos = parent->parent->childDirectories.size() + parent->parent->visibleFiles.indexOf(parent);
+ return createIndex(pos, 0, parent);
+}
+
+QVariant SelectableFilesModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+ Tree *t = static_cast<Tree *>(index.internalPointer());
+ if (role == Qt::DisplayRole)
+ return t->name;
+ if (role == Qt::CheckStateRole)
+ return t->checked;
+ if (role == Qt::DecorationRole) {
+ if (t->icon.isNull())
+ t->icon = Core::FileIconProvider::icon(t->fullPath);
+ return t->icon;
+ }
+ return QVariant();
+}
+
+bool SelectableFilesModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (role == Qt::CheckStateRole) {
+ // We can do that!
+ Tree *t = static_cast<Tree *>(index.internalPointer());
+ t->checked = Qt::CheckState(value.toInt());
+ propagateDown(index);
+ propagateUp(index);
+ emit dataChanged(index, index);
+ }
+ return false;
+}
+
+void SelectableFilesModel::propagateUp(const QModelIndex &index)
+{
+ QModelIndex parent = index.parent();
+ if (!parent.isValid())
+ return;
+ Tree *parentT = static_cast<Tree *>(parent.internalPointer());
+ if (!parentT)
+ return;
+ bool allChecked = true;
+ bool allUnchecked = true;
+ for (int i = 0; i < parentT->childDirectories.size(); ++i) {
+ allChecked &= parentT->childDirectories.at(i)->checked == Qt::Checked;
+ allUnchecked &= parentT->childDirectories.at(i)->checked == Qt::Unchecked;
+ }
+ for (int i = 0; i < parentT->visibleFiles.size(); ++i) {
+ allChecked &= parentT->visibleFiles.at(i)->checked == Qt::Checked;
+ allUnchecked &= parentT->visibleFiles.at(i)->checked == Qt::Unchecked;
+ }
+ Qt::CheckState newState = Qt::PartiallyChecked;
+ if (parentT->childDirectories.isEmpty() && parentT->visibleFiles.isEmpty())
+ newState = Qt::Unchecked;
+ else if (allChecked)
+ newState = Qt::Checked;
+ else if (allUnchecked)
+ newState = Qt::Unchecked;
+ if (parentT->checked != newState) {
+ parentT->checked = newState;
+ emit dataChanged(parent, parent);
+ propagateUp(parent);
+ }
+}
+
+void SelectableFilesModel::propagateDown(const QModelIndex &index)
+{
+ Tree *t = static_cast<Tree *>(index.internalPointer());
+ for (int i = 0; i<t->childDirectories.size(); ++i) {
+ t->childDirectories[i]->checked = t->checked;
+ propagateDown(index.child(i, 0));
+ }
+ for (int i = 0; i<t->files.size(); ++i)
+ t->files[i]->checked = t->checked;
+
+ int rows = rowCount(index);
+ if (rows)
+ emit dataChanged(index.child(0, 0), index.child(rows-1, 0));
+}
+
+Qt::ItemFlags SelectableFilesModel::flags(const QModelIndex &index) const
+{
+ Q_UNUSED(index);
+ return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
+}
+
+QStringList SelectableFilesModel::selectedPaths() const
+{
+ QStringList result;
+ collectPaths(m_root, &result);
+ return result;
+}
+
+void SelectableFilesModel::collectPaths(Tree *root, QStringList *result) const
+{
+ if (root->checked == Qt::Unchecked)
+ return;
+ result->append(root->fullPath);
+ foreach (Tree *t, root->childDirectories)
+ collectPaths(t, result);
+}
+
+QStringList SelectableFilesModel::selectedFiles() const
+{
+ QStringList result = m_outOfBaseDirFiles;
+ collectFiles(m_root, &result);
+ return result;
+}
+
+QStringList SelectableFilesModel::preservedFiles() const
+{
+ return m_outOfBaseDirFiles;
+}
+
+void SelectableFilesModel::collectFiles(Tree *root, QStringList *result) const
+{
+ if (root->checked == Qt::Unchecked)
+ return;
+ foreach (Tree *t, root->childDirectories)
+ collectFiles(t, result);
+ foreach (Tree *t, root->visibleFiles)
+ if (t->checked == Qt::Checked)
+ result->append(t->fullPath);
+}
+
+QList<Glob> SelectableFilesModel::parseFilter(const QString &filter)
+{
+ QList<Glob> result;
+ QStringList list = filter.split(QLatin1Char(';'), QString::SkipEmptyParts);
+ foreach (const QString &e, list) {
+ QString entry = e.trimmed();
+ Glob g;
+ if (entry.indexOf(QLatin1Char('*')) == -1 && entry.indexOf(QLatin1Char('?')) == -1) {
+ g.mode = Glob::EXACT;
+ g.matchString = entry;
+ } else if (entry.startsWith(QLatin1Char('*')) && entry.indexOf(QLatin1Char('*'), 1) == -1
+ && entry.indexOf(QLatin1Char('?'), 1) == -1) {
+ g.mode = Glob::ENDSWITH;
+ g.matchString = entry.mid(1);
+ } else {
+ g.mode = Glob::REGEXP;
+ g.matchRegexp = QRegExp(entry, Qt::CaseInsensitive, QRegExp::Wildcard);
+ }
+ result.append(g);
+ }
+ return result;
+}
+
+void SelectableFilesModel::applyFilter(const QString &showFilesfilter, const QString &hideFilesfilter)
+{
+ m_showFilesFilter = parseFilter(showFilesfilter);
+ m_hideFilesFilter = parseFilter(hideFilesfilter);
+ applyFilter(createIndex(0, 0, m_root));
+}
+
+Qt::CheckState SelectableFilesModel::applyFilter(const QModelIndex &index)
+{
+ bool allChecked = true;
+ bool allUnchecked = true;
+ Tree *t = static_cast<Tree *>(index.internalPointer());
+
+ for (int i=0; i < t->childDirectories.size(); ++i) {
+ Qt::CheckState childCheckState = applyFilter(index.child(i, 0));
+ if (childCheckState == Qt::Checked)
+ allUnchecked = false;
+ else if (childCheckState == Qt::Unchecked)
+ allChecked = false;
+ else
+ allChecked = allUnchecked = false;
+ }
+
+ int visibleIndex = 0;
+ int visibleEnd = t->visibleFiles.size();
+ int startOfBlock = 0;
+
+ bool removeBlock = false;
+ // first remove filtered out rows..
+ for (;visibleIndex < visibleEnd; ++visibleIndex) {
+ if (startOfBlock == visibleIndex) {
+ removeBlock = filter(t->visibleFiles.at(visibleIndex));
+ } else if (removeBlock != filter(t->visibleFiles.at(visibleIndex))) {
+ if (removeBlock) {
+ beginRemoveRows(index, startOfBlock, visibleIndex - 1);
+ for (int i=startOfBlock; i < visibleIndex; ++i)
+ t->visibleFiles[i]->checked = Qt::Unchecked;
+ t->visibleFiles.erase(t->visibleFiles.begin() + startOfBlock,
+ t->visibleFiles.begin() + visibleIndex);
+ endRemoveRows();
+ visibleIndex = startOfBlock; // start again at startOfBlock
+ visibleEnd = t->visibleFiles.size();
+ }
+ removeBlock = filter(t->visibleFiles.at(visibleIndex));
+ startOfBlock = visibleIndex;
+ }
+ }
+ if (removeBlock) {
+ beginRemoveRows(index, startOfBlock, visibleEnd - 1);
+ for (int i=startOfBlock; i < visibleEnd; ++i)
+ t->visibleFiles[i]->checked = Qt::Unchecked;
+ t->visibleFiles.erase(t->visibleFiles.begin() + startOfBlock,
+ t->visibleFiles.begin() + visibleEnd);
+ endRemoveRows();
+ }
+
+ // Figure out which rows should be visible
+ QList<Tree *> newRows;
+ for (int i=0; i < t->files.size(); ++i)
+ if (!filter(t->files.at(i)))
+ newRows.append(t->files.at(i));
+ // now add them!
+ startOfBlock = 0;
+ visibleIndex = 0;
+ visibleEnd = t->visibleFiles.size();
+ int newIndex = 0;
+ int newEnd = newRows.size();
+ while (true) {
+ while (visibleIndex < visibleEnd && newIndex < newEnd &&
+ t->visibleFiles.at(visibleIndex) == newRows.at(newIndex)) {
+ ++newIndex;
+ ++visibleIndex;
+ }
+ if (visibleIndex >= visibleEnd || newIndex >= newEnd)
+ break;
+ startOfBlock = newIndex;
+ while (newIndex < newEnd &&
+ t->visibleFiles.at(visibleIndex) != newRows.at(newIndex)) {
+ ++newIndex;
+ }
+ // end of block = newIndex
+ beginInsertRows(index, visibleIndex, visibleIndex + newIndex-startOfBlock-1);
+ for (int i= newIndex - 1; i >= startOfBlock; --i)
+ t->visibleFiles.insert(visibleIndex, newRows.at(i));
+ endInsertRows();
+ visibleIndex = visibleIndex + newIndex-startOfBlock;
+ visibleEnd = visibleEnd + newIndex-startOfBlock;
+ if (newIndex >= newEnd)
+ break;
+ }
+ if (newIndex != newEnd) {
+ beginInsertRows(index, visibleIndex, visibleIndex + newEnd-newIndex-1);
+ for (int i=newEnd-1; i >=newIndex; --i)
+ t->visibleFiles.insert(visibleIndex, newRows.at(i));
+ endInsertRows();
+ }
+
+ for (int i=0; i < t->visibleFiles.size(); ++i) {
+ if (t->visibleFiles.at(i)->checked == Qt::Checked)
+ allUnchecked = false;
+ else
+ allChecked = false;
+ }
+
+ Qt::CheckState newState = Qt::PartiallyChecked;
+ if (t->childDirectories.isEmpty() && t->visibleFiles.isEmpty())
+ newState = Qt::Unchecked;
+ else if (allChecked)
+ newState = Qt::Checked;
+ else if (allUnchecked)
+ newState = Qt::Unchecked;
+ if (t->checked != newState) {
+ t->checked = newState;
+ emit dataChanged(index, index);
+ }
+
+ return newState;
+}
+
+//////////
+// SelectableFilesDialog
+//////////
+
+SelectableFilesDialog::SelectableFilesDialog(const QString &path, const QStringList files, QWidget *parent)
+ : QDialog(parent)
+{
+ QVBoxLayout *layout = new QVBoxLayout();
+ setLayout(layout);
+ setWindowTitle(tr("Edit Files"));
+
+ m_view = new QTreeView(this);
+
+ createShowFileFilterControls(layout);
+ createHideFileFilterControls(layout);
+ createApplyButton(layout);
+
+ m_selectableFilesModel = new SelectableFilesModel(path, this);
+ m_selectableFilesModel->setInitialMarkedFiles(files);
+ m_view->setModel(m_selectableFilesModel);
+ m_view->setMinimumSize(500, 400);
+ m_view->setHeaderHidden(true);
+ m_view->hide();
+ layout->addWidget(m_view);
+
+ m_preservedFiles = new QLabel;
+ m_preservedFiles->hide();
+ layout->addWidget(m_preservedFiles);
+
+ m_progressLabel = new QLabel(this);
+ m_progressLabel->setMaximumWidth(500);
+ layout->addWidget(m_progressLabel);
+
+ QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Horizontal, this);
+ buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ connect(buttonBox, SIGNAL(accepted()),
+ this, SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()),
+ this, SLOT(reject()));
+ layout->addWidget(buttonBox);
+
+ connect(m_selectableFilesModel, SIGNAL(parsingProgress(QString)),
+ this, SLOT(parsingProgress(QString)));
+ connect(m_selectableFilesModel, SIGNAL(parsingFinished()),
+ this, SLOT(parsingFinished()));
+
+ m_selectableFilesModel->startParsing();
+}
+
+void SelectableFilesDialog::createHideFileFilterControls(QVBoxLayout *layout)
+{
+ QHBoxLayout *hbox = new QHBoxLayout;
+ m_hideFilesFilterLabel = new QLabel;
+ m_hideFilesFilterLabel->setText(tr("Hide files matching:"));
+ m_hideFilesFilterLabel->hide();
+ hbox->addWidget(m_hideFilesFilterLabel);
+ m_hideFilesfilterLineEdit = new QLineEdit;
+
+ const QString filter = Core::ICore::settings()->value(QLatin1String(Constants::HIDE_FILE_FILTER_SETTING),
+ QLatin1String(Constants::HIDE_FILE_FILTER_DEFAULT)).toString();
+ m_hideFilesfilterLineEdit->setText(filter);
+ m_hideFilesfilterLineEdit->hide();
+ hbox->addWidget(m_hideFilesfilterLineEdit);
+ layout->addLayout(hbox);
+}
+
+void SelectableFilesDialog::createShowFileFilterControls(QVBoxLayout *layout)
+{
+ QHBoxLayout *hbox = new QHBoxLayout;
+ m_showFilesFilterLabel = new QLabel;
+ m_showFilesFilterLabel->setText(tr("Show files matching:"));
+ m_showFilesFilterLabel->hide();
+ hbox->addWidget(m_showFilesFilterLabel);
+ m_showFilesfilterLineEdit = new QLineEdit;
+
+ const QString filter = Core::ICore::settings()->value(QLatin1String(Constants::SHOW_FILE_FILTER_SETTING),
+ QLatin1String(Constants::SHOW_FILE_FILTER_DEFAULT)).toString();
+ m_showFilesfilterLineEdit->setText(filter);
+ m_showFilesfilterLineEdit->hide();
+ hbox->addWidget(m_showFilesfilterLineEdit);
+ layout->addLayout(hbox);
+}
+
+void SelectableFilesDialog::createApplyButton(QVBoxLayout *layout)
+{
+ QHBoxLayout *hbox = new QHBoxLayout;
+
+ QSpacerItem *horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
+ hbox->addItem(horizontalSpacer);
+
+ m_applyFilterButton = new QPushButton(tr("Apply Filter"), this);
+ m_applyFilterButton->hide();
+ hbox->addWidget(m_applyFilterButton);
+ layout->addLayout(hbox);
+
+ connect(m_applyFilterButton, SIGNAL(clicked()), this, SLOT(applyFilter()));
+}
+
+SelectableFilesDialog::~SelectableFilesDialog()
+{
+ m_selectableFilesModel->cancel();
+ m_selectableFilesModel->waitForFinished();
+}
+
+void SelectableFilesDialog::parsingProgress(const QString &fileName)
+{
+ m_progressLabel->setText(tr("Generating file list...\n\n%1").arg(fileName));
+}
+
+void SelectableFilesDialog::parsingFinished()
+{
+ m_hideFilesFilterLabel->show();
+ m_hideFilesfilterLineEdit->show();
+
+ m_showFilesFilterLabel->show();
+ m_showFilesfilterLineEdit->show();
+
+ m_applyFilterButton->show();
+ m_view->show();
+ m_progressLabel->hide();
+ m_view->expand(QModelIndex());
+ smartExpand(m_selectableFilesModel->index(0,0, QModelIndex()));
+ applyFilter();
+ const QStringList &preservedFiles = m_selectableFilesModel->preservedFiles();
+ if (preservedFiles.isEmpty()) {
+ m_preservedFiles->hide();
+ } else {
+ m_preservedFiles->show();
+ m_preservedFiles->setText(tr("Not showing %n files that are outside of the base directory.\nThese files are preserved.", 0, preservedFiles.count()));
+ }
+}
+
+void SelectableFilesDialog::smartExpand(const QModelIndex &index)
+{
+ if (m_view->model()->data(index, Qt::CheckStateRole) == Qt::PartiallyChecked) {
+ m_view->expand(index);
+ int rows = m_view->model()->rowCount(index);
+ for (int i = 0; i < rows; ++i)
+ smartExpand(index.child(i, 0));
+ }
+}
+
+QStringList SelectableFilesDialog::selectedFiles() const
+{
+ return m_selectableFilesModel->selectedFiles();
+}
+
+void SelectableFilesDialog::applyFilter()
+{
+ const QString showFilesFilter = m_showFilesfilterLineEdit->text();
+ Core::ICore::settings()->setValue(QLatin1String(Constants::SHOW_FILE_FILTER_SETTING), showFilesFilter);
+
+ const QString hideFilesFilter = m_hideFilesfilterLineEdit->text();
+ Core::ICore::settings()->setValue(QLatin1String(Constants::HIDE_FILE_FILTER_SETTING), hideFilesFilter);
+
+ m_selectableFilesModel->applyFilter(showFilesFilter, hideFilesFilter);
+}
+
+} // namespace Internal
+} // namespace BoostBuildProjectManager
+
+
diff --git a/src/plugins/boostbuildprojectmanager/selectablefilesmodel.h b/src/plugins/boostbuildprojectmanager/selectablefilesmodel.h
new file mode 100644
index 0000000000..1b4b5ef481
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/selectablefilesmodel.h
@@ -0,0 +1,189 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
+**
+** This file, as part of Qt Creator Plugin for Boost.Build,
+** was modified to accommodate OpenProjectWizard requirements.
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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 by the Free Software
+** Foundation and appearing in the file LICENSE.txt 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.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef SELECTABLEFILESMODEL_HPP
+#define SELECTABLEFILESMODEL_HPP
+
+#include <QAbstractItemModel>
+#include <QSet>
+#include <QFutureInterface>
+#include <QFutureWatcher>
+#include <QDialog>
+#include <QTreeView>
+#include <QLabel>
+
+QT_BEGIN_NAMESPACE
+class QVBoxLayout;
+QT_END_NAMESPACE
+
+namespace BoostBuildProjectManager {
+namespace Internal {
+
+struct Tree
+{
+ QString name;
+ Qt::CheckState checked;
+ bool isDir;
+ QList<Tree *> childDirectories;
+ QList<Tree *> files;
+ QList<Tree *> visibleFiles;
+ QIcon icon;
+ QString fullPath;
+ Tree *parent;
+};
+
+struct Glob
+{
+ enum Mode { EXACT, ENDSWITH, REGEXP };
+ Mode mode;
+ QString matchString;
+ mutable QRegExp matchRegexp;
+
+ bool isMatch(const QString &text) const
+ {
+ if (mode == Glob::EXACT) {
+ if (text == matchString)
+ return true;
+ } else if (mode == Glob::ENDSWITH) {
+ if (text.endsWith(matchString))
+ return true;
+ } else if (mode == Glob::REGEXP) {
+ if (matchRegexp.exactMatch(text))
+ return true;
+ }
+ return false;
+ }
+};
+
+class SelectableFilesModel : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ SelectableFilesModel(const QString &baseDir, QObject *parent);
+ ~SelectableFilesModel();
+
+ void setInitialMarkedFiles(const QStringList &files);
+
+ int columnCount(const QModelIndex &parent) const;
+ int rowCount(const QModelIndex &parent) const;
+ QModelIndex index(int row, int column, const QModelIndex &parent) const;
+ QModelIndex parent(const QModelIndex &child) const;
+
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+
+ QStringList selectedFiles() const;
+ QStringList selectedPaths() const;
+ QStringList preservedFiles() const;
+
+ // only call this once
+ void startParsing();
+ void waitForFinished();
+ void cancel();
+ void applyFilter(const QString &selectFilesfilter, const QString &hideFilesfilter);
+
+signals:
+ void parsingFinished();
+ void parsingProgress(const QString &filename);
+
+private slots:
+ void buildTreeFinished();
+
+private:
+ QList<Glob> parseFilter(const QString &filter);
+ Qt::CheckState applyFilter(const QModelIndex &index);
+ bool filter(Tree *t);
+ void init();
+ void run(QFutureInterface<void> &fi);
+ void collectFiles(Tree *root, QStringList *result) const;
+ void collectPaths(Tree *root, QStringList *result) const;
+ void buildTree(const QString &baseDir, Tree *tree, QFutureInterface<void> &fi);
+ void deleteTree(Tree *tree);
+ void propagateUp(const QModelIndex &index);
+ void propagateDown(const QModelIndex &index);
+ Tree *m_root;
+ // Used in the future thread need to all not used after calling startParsing
+ QString m_baseDir;
+ QSet<QString> m_files;
+ QStringList m_outOfBaseDirFiles;
+ QFutureWatcher<void> m_watcher;
+ Tree *m_rootForFuture;
+ int m_futureCount;
+ bool m_allFiles;
+
+ QList<Glob> m_hideFilesFilter;
+ QList<Glob> m_showFilesFilter;
+};
+
+class SelectableFilesDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ SelectableFilesDialog(const QString &path, const QStringList files, QWidget *parent);
+ ~SelectableFilesDialog();
+ QStringList selectedFiles() const;
+
+private slots:
+ void applyFilter();
+ void parsingProgress(const QString &fileName);
+ void parsingFinished();
+
+private:
+ void smartExpand(const QModelIndex &index);
+ void createShowFileFilterControls(QVBoxLayout *layout);
+ void createHideFileFilterControls(QVBoxLayout *layout);
+ void createApplyButton(QVBoxLayout *layout);
+ SelectableFilesModel *m_selectableFilesModel;
+
+ QLabel *m_hideFilesFilterLabel;
+ QLineEdit *m_hideFilesfilterLineEdit;
+
+ QLabel *m_showFilesFilterLabel;
+ QLineEdit *m_showFilesfilterLineEdit;
+
+ QPushButton *m_applyFilterButton;
+
+ QTreeView *m_view;
+ QLabel *m_preservedFiles;
+ QLabel *m_progressLabel;
+};
+
+} // namespace Internal
+} // namespace BoostBuildProjectManager
+
+#endif // SELECTABLEFILESMODEL_HPP
+
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
index b39c61e6b5..2dcc147ddc 100644
--- a/src/plugins/plugins.pro
+++ b/src/plugins/plugins.pro
@@ -29,6 +29,7 @@ SUBDIRS = \
designer \
resourceeditor \
genericprojectmanager \
+ boostbuildprojectmanager \
qmljseditor \
qmlprojectmanager \
glsleditor \