ProjectExplorer: Introduce BuildDirectoryAspect

Change-Id: Id57d0a7901d2cec7b2d4f1fbeed6a1ecb41642cc
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Christian Kandeler
2019-11-25 17:55:39 +01:00
parent 684d3e40a7
commit dd7f4890a2
6 changed files with 184 additions and 18 deletions

View File

@@ -25,8 +25,108 @@
#include "buildaspects.h"
#include <utils/fileutils.h>
#include <utils/utilsicons.h>
#include <QLabel>
#include <QLayout>
using namespace Utils;
namespace ProjectExplorer {
class BuildDirectoryAspect::Private
{
public:
FilePath sourceDir;
FilePath savedShadowBuildDir;
QString problem;
QPointer<QLabel> warningLabel;
QPointer<QLabel> problemLabel;
};
BuildDirectoryAspect::BuildDirectoryAspect() : d(new Private)
{
setSettingsKey("ProjectExplorer.BuildConfiguration.BuildDirectory");
setLabelText(tr("Build directory:"));
setDisplayStyle(PathChooserDisplay);
setExpectedKind(Utils::PathChooser::Directory);
setUncheckedSemantics(UncheckedSemantics::ReadOnly);
}
BuildDirectoryAspect::~BuildDirectoryAspect()
{
delete d;
}
void BuildDirectoryAspect::allowInSourceBuilds(const FilePath &sourceDir)
{
d->sourceDir = sourceDir;
makeCheckable(tr("Shadow Build"), QString());
}
bool BuildDirectoryAspect::isShadowBuild() const
{
return !d->sourceDir.isEmpty() && d->sourceDir != filePath();
}
void BuildDirectoryAspect::setProblem(const QString &description)
{
d->problem = description;
updateProblemLabel();
}
void BuildDirectoryAspect::toMap(QVariantMap &map) const
{
BaseStringAspect::toMap(map);
if (!d->sourceDir.isEmpty()) {
const FilePath shadowDir = isChecked() ? filePath() : d->savedShadowBuildDir;
map.insert(settingsKey() + ".shadowDir", shadowDir.toString());
}
}
void BuildDirectoryAspect::fromMap(const QVariantMap &map)
{
BaseStringAspect::fromMap(map);
if (!d->sourceDir.isEmpty()) {
d->savedShadowBuildDir = FilePath::fromString(map.value(settingsKey() + ".shadowDir")
.toString());
setChecked(d->sourceDir != filePath());
}
}
void BuildDirectoryAspect::addToLayout(LayoutBuilder &builder)
{
BaseStringAspect::addToLayout(builder);
d->warningLabel = new QLabel;
d->warningLabel->setAlignment(Qt::AlignTop);
d->warningLabel->setPixmap(Icons::WARNING.pixmap());
d->problemLabel = new QLabel;
d->problemLabel->setAlignment(Qt::AlignTop);
builder.startNewRow().addItems(QString(), d->warningLabel.data(), d->problemLabel.data());
updateProblemLabel();
if (!d->sourceDir.isEmpty()) {
connect(this, &BaseStringAspect::checkedChanged, builder.layout(), [this] {
if (isChecked()) {
setFilePath(d->savedShadowBuildDir);
} else {
d->savedShadowBuildDir = filePath();
setFilePath(d->sourceDir);
}
});
}
}
void BuildDirectoryAspect::updateProblemLabel()
{
if (!d->warningLabel)
return;
QTC_ASSERT(d->problemLabel, return);
d->problemLabel->setText(d->problem);
d->problemLabel->setVisible(!d->problem.isEmpty());
d->warningLabel->setVisible(!d->problem.isEmpty());
}
SeparateDebugInfoAspect::SeparateDebugInfoAspect()
{
setDisplayName(tr("Separate Debug Info"));

View File

@@ -28,8 +28,32 @@
#include "projectexplorer_export.h"
#include "projectconfigurationaspects.h"
namespace Utils { class FilePath; }
namespace ProjectExplorer {
class PROJECTEXPLORER_EXPORT BuildDirectoryAspect : public BaseStringAspect
{
Q_OBJECT
public:
BuildDirectoryAspect();
~BuildDirectoryAspect() override;
void allowInSourceBuilds(const Utils::FilePath &sourceDir);
bool isShadowBuild() const;
void setProblem(const QString &description);
private:
void toMap(QVariantMap &map) const override;
void fromMap(const QVariantMap &map) override;
void addToLayout(LayoutBuilder &builder) override;
void updateProblemLabel();
class Private;
Private * const d;
};
class PROJECTEXPLORER_EXPORT SeparateDebugInfoAspect : public BaseTriStateAspect
{
Q_OBJECT

View File

@@ -25,6 +25,7 @@
#include "buildconfiguration.h"
#include "buildaspects.h"
#include "buildenvironmentwidget.h"
#include "buildinfo.h"
#include "buildsteplist.h"
@@ -35,7 +36,6 @@
#include "kitinformation.h"
#include "kitmanager.h"
#include "project.h"
#include "projectconfigurationaspects.h"
#include "projectexplorer.h"
#include "projectexplorerconstants.h"
#include "projectmacroexpander.h"
@@ -44,6 +44,7 @@
#include "session.h"
#include <coreplugin/idocument.h>
#include <coreplugin/variablechooser.h>
#include <utils/algorithm.h>
#include <utils/detailswidget.h>
@@ -61,7 +62,6 @@ static const char BUILD_STEP_LIST_COUNT[] = "ProjectExplorer.BuildConfiguration.
static const char BUILD_STEP_LIST_PREFIX[] = "ProjectExplorer.BuildConfiguration.BuildStepList.";
static const char CLEAR_SYSTEM_ENVIRONMENT_KEY[] = "ProjectExplorer.BuildConfiguration.ClearSystemEnvironment";
static const char USER_ENVIRONMENT_CHANGES_KEY[] = "ProjectExplorer.BuildConfiguration.UserEnvironmentChanges";
static const char BUILDDIRECTORY_KEY[] = "ProjectExplorer.BuildConfiguration.BuildDirectory";
namespace ProjectExplorer {
namespace Internal {
@@ -72,7 +72,7 @@ public:
bool m_clearSystemEnvironment = false;
Utils::EnvironmentItems m_userEnvironmentChanges;
QList<BuildStepList *> m_stepLists;
ProjectExplorer::BaseStringAspect *m_buildDirectoryAspect = nullptr;
BuildDirectoryAspect *m_buildDirectoryAspect = nullptr;
Utils::FilePath m_lastEmittedBuildDirectory;
mutable Utils::Environment m_cachedEnvironment;
QString m_configWidgetDisplayName;
@@ -116,16 +116,12 @@ BuildConfiguration::BuildConfiguration(Target *target, Core::Id id)
connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged,
this, &BuildConfiguration::updateCacheAndEmitEnvironmentChanged);
d->m_buildDirectoryAspect = addAspect<BaseStringAspect>();
d->m_buildDirectoryAspect->setSettingsKey(BUILDDIRECTORY_KEY);
d->m_buildDirectoryAspect->setLabelText(tr("Build directory:"));
d->m_buildDirectoryAspect->setDisplayStyle(BaseStringAspect::PathChooserDisplay);
d->m_buildDirectoryAspect->setExpectedKind(Utils::PathChooser::Directory);
d->m_buildDirectoryAspect = addAspect<BuildDirectoryAspect>();
d->m_buildDirectoryAspect->setBaseFileName(target->project()->projectDirectory());
d->m_buildDirectoryAspect->setEnvironment(environment());
d->m_buildDirectoryAspect->setMacroExpanderProvider([this] { return macroExpander(); });
connect(d->m_buildDirectoryAspect, &BaseStringAspect::changed,
this, &BuildConfiguration::buildDirectoryChanged);
connect(this, &BuildConfiguration::environmentChanged, this, [this] {
d->m_buildDirectoryAspect->setEnvironment(environment());
this->target()->buildEnvironmentChanged(this);
@@ -133,7 +129,6 @@ BuildConfiguration::BuildConfiguration(Target *target, Core::Id id)
connect(target, &Target::parsingStarted, this, &BuildConfiguration::enabledChanged);
connect(target, &Target::parsingFinished, this, &BuildConfiguration::enabledChanged);
connect(this, &BuildConfiguration::enabledChanged, this, [this] {
if (isActive() && project() == SessionManager::startupProject()) {
ProjectExplorerPlugin::updateActions();
@@ -309,7 +304,7 @@ QVariant BuildConfiguration::extraInfo() const
return d->m_extraInfo;
}
ProjectExplorer::BaseStringAspect *BuildConfiguration::buildDirectoryAspect() const
ProjectExplorer::BuildDirectoryAspect *BuildConfiguration::buildDirectoryAspect() const
{
return d->m_buildDirectoryAspect;
}

View File

@@ -36,7 +36,7 @@ namespace ProjectExplorer {
namespace Internal { class BuildConfigurationPrivate; }
class BaseStringAspect;
class BuildDirectoryAspect;
class BuildInfo;
class BuildSystem;
class BuildStepList;
@@ -107,7 +107,7 @@ public:
static void prependCompilerPathToEnvironment(Kit *k, Utils::Environment &env);
void updateCacheAndEmitEnvironmentChanged();
ProjectExplorer::BaseStringAspect *buildDirectoryAspect() const;
ProjectExplorer::BuildDirectoryAspect *buildDirectoryAspect() const;
void setConfigWidgetDisplayName(const QString &display);
void setBuildDirectoryHistoryCompleter(const QString &history);
void setConfigWidgetHasFrame(bool configWidgetHasFrame);

View File

@@ -32,6 +32,7 @@
#include "runconfiguration.h"
#include "target.h"
#include <coreplugin/variablechooser.h>
#include <utils/utilsicons.h>
#include <utils/fancylineedit.h>
#include <utils/pathchooser.h>
@@ -84,6 +85,8 @@ class BaseStringAspectPrivate
{
public:
BaseStringAspect::DisplayStyle m_displayStyle = BaseStringAspect::LabelDisplay;
BaseStringAspect::UncheckedSemantics m_uncheckedSemantics
= BaseStringAspect::UncheckedSemantics::ReadOnly;
QString m_labelText;
std::function<QString(const QString &)> m_displayFilter;
std::unique_ptr<BaseBoolAspect> m_checker;
@@ -98,10 +101,20 @@ public:
QPointer<FancyLineEdit> m_lineEditDisplay;
QPointer<PathChooser> m_pathChooserDisplay;
QPointer<QTextEdit> m_textEditDisplay;
Utils::MacroExpanderProvider m_expanderProvider;
QPixmap m_labelPixmap;
Utils::FilePath m_baseFileName;
bool m_readOnly = false;
bool m_showToolTipOnLabel = false;
template<class Widget> void updateWidgetFromCheckStatus(Widget *w)
{
const bool enabled = !m_checker || m_checker->value();
if (m_uncheckedSemantics == BaseStringAspect::UncheckedSemantics::Disabled)
w->setEnabled(enabled);
else
w->setReadOnly(!enabled);
}
};
class BaseIntegerAspectPrivate
@@ -205,6 +218,12 @@ bool BaseStringAspect::isChecked() const
return !d->m_checker || d->m_checker->value();
}
void BaseStringAspect::setChecked(bool checked)
{
QTC_ASSERT(d->m_checker, return);
d->m_checker->setValue(checked);
}
void BaseStringAspect::setDisplayStyle(DisplayStyle displayStyle)
{
d->m_displayStyle = displayStyle;
@@ -260,6 +279,16 @@ void BaseStringAspect::setReadOnly(bool readOnly)
d->m_textEditDisplay->setReadOnly(readOnly);
}
void BaseStringAspect::setMacroExpanderProvider(const MacroExpanderProvider &expanderProvider)
{
d->m_expanderProvider = expanderProvider;
}
void BaseStringAspect::setUncheckedSemantics(BaseStringAspect::UncheckedSemantics semantics)
{
d->m_uncheckedSemantics = semantics;
}
void BaseStringAspect::addToLayout(LayoutBuilder &builder)
{
QTC_CHECK(!d->m_label);
@@ -270,6 +299,14 @@ void BaseStringAspect::addToLayout(LayoutBuilder &builder)
d->m_label->setPixmap(d->m_labelPixmap);
builder.addItem(d->m_label.data());
const auto useMacroExpander = [this, &builder](QWidget *w) {
if (!d->m_expanderProvider)
return;
const auto chooser = new Core::VariableChooser(builder.layout()->parentWidget());
chooser->addSupportedWidget(w);
chooser->addMacroExpanderProvider(d->m_expanderProvider);
};
switch (d->m_displayStyle) {
case PathChooserDisplay:
d->m_pathChooserDisplay = new PathChooser;
@@ -279,6 +316,7 @@ void BaseStringAspect::addToLayout(LayoutBuilder &builder)
d->m_pathChooserDisplay->setEnvironment(d->m_environment);
d->m_pathChooserDisplay->setBaseFileName(d->m_baseFileName);
d->m_pathChooserDisplay->setReadOnly(d->m_readOnly);
useMacroExpander(d->m_pathChooserDisplay->lineEdit());
connect(d->m_pathChooserDisplay, &PathChooser::pathChanged,
this, &BaseStringAspect::setValue);
builder.addItem(d->m_pathChooserDisplay.data());
@@ -289,6 +327,7 @@ void BaseStringAspect::addToLayout(LayoutBuilder &builder)
if (!d->m_historyCompleterKey.isEmpty())
d->m_lineEditDisplay->setHistoryCompleter(d->m_historyCompleterKey);
d->m_lineEditDisplay->setReadOnly(d->m_readOnly);
useMacroExpander(d->m_lineEditDisplay);
connect(d->m_lineEditDisplay, &FancyLineEdit::textEdited,
this, &BaseStringAspect::setValue);
builder.addItem(d->m_lineEditDisplay.data());
@@ -297,6 +336,7 @@ void BaseStringAspect::addToLayout(LayoutBuilder &builder)
d->m_textEditDisplay = new QTextEdit;
d->m_textEditDisplay->setPlaceholderText(d->m_placeHolderText);
d->m_textEditDisplay->setReadOnly(d->m_readOnly);
useMacroExpander(d->m_textEditDisplay);
connect(d->m_textEditDisplay, &QTextEdit::textChanged, this, [this] {
const QString value = d->m_textEditDisplay->document()->toPlainText();
if (value != d->m_value) {
@@ -324,21 +364,19 @@ void BaseStringAspect::update()
const QString displayedString = d->m_displayFilter ? d->m_displayFilter(d->m_value)
: d->m_value;
const bool enabled = !d->m_checker || d->m_checker->value();
if (d->m_pathChooserDisplay) {
d->m_pathChooserDisplay->setFileName(FilePath::fromString(displayedString));
d->m_pathChooserDisplay->setEnabled(enabled);
d->updateWidgetFromCheckStatus(d->m_pathChooserDisplay.data());
}
if (d->m_lineEditDisplay) {
d->m_lineEditDisplay->setTextKeepingActiveCursor(displayedString);
d->m_lineEditDisplay->setEnabled(enabled);
d->updateWidgetFromCheckStatus(d->m_lineEditDisplay.data());
}
if (d->m_textEditDisplay) {
d->m_textEditDisplay->setText(displayedString);
d->m_textEditDisplay->setEnabled(enabled);
d->updateWidgetFromCheckStatus(d->m_textEditDisplay.data());
}
if (d->m_labelDisplay) {
@@ -362,6 +400,7 @@ void BaseStringAspect::makeCheckable(const QString &checkerLabel, const QString
connect(d->m_checker.get(), &BaseBoolAspect::changed, this, &BaseStringAspect::update);
connect(d->m_checker.get(), &BaseBoolAspect::changed, this, &BaseStringAspect::changed);
connect(d->m_checker.get(), &BaseBoolAspect::changed, this, &BaseStringAspect::checkedChanged);
update();
}

View File

@@ -29,6 +29,7 @@
#include "environmentaspect.h"
#include <utils/fileutils.h>
#include <utils/macroexpander.h>
#include <utils/pathchooser.h>
#include <memory>
@@ -128,8 +129,12 @@ public:
void setEnvironment(const Utils::Environment &env);
void setBaseFileName(const Utils::FilePath &baseFileName);
void setReadOnly(bool readOnly);
void setMacroExpanderProvider(const Utils::MacroExpanderProvider &expanderProvider);
enum class UncheckedSemantics { Disabled, ReadOnly };
void setUncheckedSemantics(UncheckedSemantics semantics);
bool isChecked() const;
void setChecked(bool checked);
void makeCheckable(const QString &optionalLabel, const QString &optionalBaseKey);
enum DisplayStyle {
@@ -146,6 +151,9 @@ public:
Utils::FilePath filePath() const;
void setFilePath(const Utils::FilePath &val);
signals:
void checkedChanged();
private:
void update();