diff --git a/src/plugins/boostbuildprojectmanager/BoostBuildProjectManager.json.in b/src/plugins/boostbuildprojectmanager/BoostBuildProjectManager.json.in
new file mode 100644
index 00000000000..8700c634398
--- /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 00000000000..e3391759bc0
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/BoostBuildProjectManager.mimetypes.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+ Boost.Build Project file
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Boost.Build Project Files
+
+
+
+
+
+ Boost.Build Project Includes
+
+
+
+
diff --git a/src/plugins/boostbuildprojectmanager/b2buildconfiguration.cpp b/src/plugins/boostbuildprojectmanager/b2buildconfiguration.cpp
new file mode 100644
index 00000000000..796d868de00
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2buildconfiguration.cpp
@@ -0,0 +1,391 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+// 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+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(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(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
+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 result;
+ result << createBuildInfo(parent->kit(), projectPath, BuildConfiguration::Debug);
+ result << createBuildInfo(parent->kit(), projectPath, BuildConfiguration::Release);
+ return result;
+}
+
+QList
+BuildConfigurationFactory::availableSetups(ProjectExplorer::Kit const* k
+ , QString const& projectPath) const
+{
+ BBPM_QDEBUG(projectPath);
+
+ QList 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(parent->project());
+ QTC_ASSERT(project, return 0);
+
+ BuildInfo const* bi = static_cast(info);
+ QScopedPointer 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(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 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 00000000000..a9edb7743e8
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2buildconfiguration.h
@@ -0,0 +1,138 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+//
+// 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
+#include
+#include
+// Qt
+#include
+#include
+#include
+
+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
+ availableBuilds(ProjectExplorer::Target const* parent) const;
+
+ QList
+ 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 00000000000..927a7ab9094
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2buildinfo.cpp
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+//
+// 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 00000000000..30374592eef
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2buildinfo.h
@@ -0,0 +1,44 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+//
+// 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
+#include
+#include
+// 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 00000000000..d6bc0772a73
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2buildstep.cpp
@@ -0,0 +1,420 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+// 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+// Qt
+#include
+#include
+#include
+#include
+// std
+#include
+
+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& 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(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(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();
+}
+
+QList
+BuildStepFactory::availableCreationIds(ProjectExplorer::BuildStepList* parent) const
+{
+ return canHandle(parent)
+ ? QList() << Core::Id(Constants::BUILDSTEP_ID)
+ : QList();
+}
+
+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(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(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 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("%1: %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("%1: %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 00000000000..3b587777d21
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2buildstep.h
@@ -0,0 +1,162 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+//
+// 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
+#include
+#include
+#include
+// Qt
+#include
+#include
+#include
+#include
+
+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& 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 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
+ 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 00000000000..d69ddc13854
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2openprojectwizard.cpp
@@ -0,0 +1,272 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+// 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
+#include
+#include
+#include
+#include
+#include
+#include
+// Qt
+#include
+#include
+#include
+#include
+#include
+#include
+
+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(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(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 00000000000..d7d6a93f63c
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2openprojectwizard.h
@@ -0,0 +1,127 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+// 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
+#include
+#include
+#include
+// Qt
+#include
+#include
+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 00000000000..af552e3e03f
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2outputparser.cpp
@@ -0,0 +1,197 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+//
+// 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
+#include
+#include
+#include
+// Qt
+#include
+#include
+#include
+
+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 00000000000..a2f54cf59ce
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2outputparser.h
@@ -0,0 +1,64 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+//
+// 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
+#include
+// Qt
+#include
+#include
+
+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 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 00000000000..2074c60ff64
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2project.cpp
@@ -0,0 +1,306 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+// 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+// Qt
+#include
+#include
+#include
+
+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 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 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 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 00000000000..6b8a813443a
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2project.h
@@ -0,0 +1,106 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+//
+// 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
+#include
+#include
+#include
+// Qt
+#include
+#include
+#include
+
+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 entriesRaw_;
+
+ // Auxiliary file Jamfile.${JAMFILE_INCLUDES_EXT} with list of source files.
+ QString includesFilePath_;
+
+ ProjectFile* projectFile_;
+ ProjectNode* projectNode_;
+
+ QFuture 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 00000000000..bcfeef9eafa
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2projectfile.cpp
@@ -0,0 +1,80 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+//
+// 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 00000000000..5e440df646f
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2projectfile.h
@@ -0,0 +1,47 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+//
+// 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
+
+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 00000000000..dcc4f439d88
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2projectmanager.cpp
@@ -0,0 +1,64 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+//
+// 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
+// Qt
+#include
+#include
+
+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 00000000000..d4222beb617
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2projectmanager.h
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+//
+// 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
+// Qt
+#include
+#include
+
+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 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 00000000000..3287ab357de
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2projectmanager_global.h
@@ -0,0 +1,23 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+//
+// 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
+
+#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 00000000000..a6db0a1b5b2
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2projectmanagerconstants.h
@@ -0,0 +1,68 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+//
+// 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
+
+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 00000000000..b5c3ae11865
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2projectmanagerplugin.cpp
@@ -0,0 +1,83 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+//
+// 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
+#include
+#include
+#include
+#include
+#include
+#include
+// Qt
+#include
+#include
+#include
+#include
+
+#include
+
+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 00000000000..e54dcaabeb6
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2projectmanagerplugin.h
@@ -0,0 +1,48 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+//
+// 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
+
+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 00000000000..2c97b565cf7
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2projectnode.cpp
@@ -0,0 +1,260 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+// 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
+#include
+#include
+// Qt
+#include
+#include
+#include
+#include
+#include
+#include
+
+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
+ProjectNode::supportedActions(Node* node) const
+{
+ Q_UNUSED(node);
+
+ // TODO: Jamfiles (auto)editing not supported, does it make sense to manage files?
+ return QList();
+}
+
+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 ProjectNode::runConfigurationsFor(Node* node)
+{
+ Q_UNUSED(node);
+ return QList();
+}
+
+void ProjectNode::refresh(QSet 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()
+ << projectFileNode << filesFileNode << includesFileNode);
+ }
+
+ oldFileList.remove(project_->filesFilePath());
+ oldFileList.remove(project_->includesFilePath());
+
+ QSet newFileList = project_->files().toSet();
+ newFileList.remove(project_->filesFilePath());
+ newFileList.remove(project_->includesFilePath());
+
+ // Calculate set of added and removed files
+ QSet removed = oldFileList;
+ removed.subtract(newFileList);
+ QSet added = newFileList;
+ added.subtract(oldFileList);
+
+ typedef QHash 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 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 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() << 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() << folder);
+
+ return folder;
+}
+
+ProjectExplorer::FolderNode*
+ProjectNode::findFolderByName(QStringList const& components, int const end) const
+{
+ if (end == 0)
+ return const_cast(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 00000000000..9a1e5422daf
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2projectnode.h
@@ -0,0 +1,77 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+// 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
+// Qt
+#include
+#include
+#include
+#include
+#include
+
+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 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 runConfigurationsFor(Node* node);
+
+ void refresh(QSet 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 00000000000..376d26071d0
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2utility.cpp
@@ -0,0 +1,151 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+// 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
+#include
+// Qt
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+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 sortFilesIntoPaths(QString const& basePath
+ , QSet const& files)
+{
+ QHash 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 00000000000..2f810cf35c0
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/b2utility.h
@@ -0,0 +1,60 @@
+//
+// Copyright (C) 2013 Mateusz Łoskot
+// 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
+#include
+#include
+#include
+#include
+
+//////////////////////////////////////////////////////////////////////////////////////////
+#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 sortFilesIntoPaths(QString const& basePath
+ , QSet 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 00000000000..44d7c94bbc7
--- /dev/null
+++ b/src/plugins/boostbuildprojectmanager/boostbuildproject.qrc
@@ -0,0 +1,5 @@
+
+
+ BoostBuildProjectManager.mimetypes.xml
+
+
diff --git a/src/plugins/boostbuildprojectmanager/boostbuildprojectmanager.pro b/src/plugins/boostbuildprojectmanager/boostbuildprojectmanager.pro
new file mode 100644
index 00000000000..c743db04d04
--- /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 00000000000..3e8bb8694ae
--- /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 00000000000..df648bc5fd9
--- /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
+
+using namespace ProjectExplorer;
+
+// opt. drive letter + filename: (2 brackets)
+static const char * const FILE_PATTERN = "(|([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
+
+# include "projectexplorer.h"
+# include "metatypedeclarations.h"
+# include "outputparser_test.h"
+
+void ProjectExplorerPlugin::testClangOutputParser_data()
+{
+ QTest::addColumn("input");
+ QTest::addColumn("inputChannel");
+ QTest::addColumn("childStdOutLines");
+ QTest::addColumn("childStdErrLines");
+ QTest::addColumn