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