From 052b0b4c92570ea114ff67d901d7cb0d7fec7f5d Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 15 Dec 2020 14:22:37 +0100 Subject: [PATCH 1/8] Debugger: Re-organize std::vector and std::deque dumpers There are indications that the std::__1:: namespace cannot be relied upon anymore. Task-number: QTCREATORBUG-25061 Change-Id: I54d8d2fc757b1cfc9b27f00660f2814d745f2bc6 Reviewed-by: David Schulz --- share/qtcreator/debugger/dumper.py | 3 + share/qtcreator/debugger/stdtypes.py | 187 ++++++++++++++------------- 2 files changed, 100 insertions(+), 90 deletions(-) diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index 425e33640a9..4468ed9fa15 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -3060,6 +3060,9 @@ class DumperBase(): def extractPointer(self): return self.split('p')[0] + def hasMember(self, name): + return self.findMemberByName(name) is not None + def findMemberByName(self, name): self.check() if self.type.code == TypeCode.Typedef: diff --git a/share/qtcreator/debugger/stdtypes.py b/share/qtcreator/debugger/stdtypes.py index 4de5baf4f91..41bdc4ec76f 100644 --- a/share/qtcreator/debugger/stdtypes.py +++ b/share/qtcreator/debugger/stdtypes.py @@ -76,12 +76,26 @@ def qdump__std____1__complex(d, value): def qdump__std__deque(d, value): if d.isQnxTarget(): - qdump__std__deque__QNX(d, value) - return - if d.isMsvcTarget(): - qdump__std__deque__MSVC(d, value) - return + qdumpHelper__std__deque__qnx(d, value) + elif d.isMsvcTarget(): + qdumpHelper__std__deque__msvc(d, value) + elif value.hasMember("_M_impl"): + qdumpHelper__std__deque__libstdcxx(d, value) + elif value.hasMember("__start_"): + qdumpHelper__std__deque__libcxx(d, value) + elif value.type.size() == 10 * d.ptrSize(): + qdumpHelper__std__deque__libstdcxx(d, value) + elif value.type.size() == 6 * d.ptrSize(): + qdumpHelper__std__deque__libcxx(d, value) + else: + qdumpHelper__std__deque__libstdcxx(d, value) + +def qdump__std____1__deque(d, value): + qdumpHelper__std__deque__libcxx(d, value) + + +def qdumpHelper__std__deque__libstdcxx(d, value): innerType = value.type[0] innerSize = innerType.size() bufsize = 1 @@ -113,7 +127,7 @@ def qdump__std__deque(d, value): pnode = newnode -def qdump__std____1__deque(d, value): +def qdumpHelper__std__deque__libcxx(d, value): mptr, mfirst, mbegin, mend, start, size = value.split("pppptt") d.check(0 <= size and size <= 1000 * 1000 * 1000) d.putItemCount(size) @@ -129,7 +143,7 @@ def qdump__std____1__deque(d, value): d.putSubItem(i, d.createValue(base + j * innerSize, innerType)) -def qdump__std__deque__QNX(d, value): +def qdumpHelper__std__deque__qnx(d, value): innerType = value.type[0] innerSize = innerType.size() if innerSize <= 1: @@ -166,7 +180,7 @@ def qdump__std__deque__QNX(d, value): myoff += 1 -def qdump__std__deque__MSVC(d, value): +def qdumpHelper__std__deque__msvc(d, value): innerType = value.type[0] innerSize = innerType.size() if innerSize <= 1: @@ -1048,95 +1062,88 @@ def qedit__std__vector(d, value, data): def qdump__std__vector(d, value): if d.isQnxTarget() or d.isMsvcTarget(): - qdumpHelper__std__vector__QNX(d, value) + qdumpHelper__std__vector__msvc(d, value) + elif value.hasMember("_M_impl"): + qdumpHelper__std__vector__libstdcxx(d, value) + elif value.hasMember("__begin_"): + qdumpHelper__std__vector__libcxx(d, value) else: - qdumpHelper__std__vector(d, value, False) + qdumpHelper__std__vector__libstdcxx(d, value) -def qdumpHelper__std__vector(d, value, isLibCpp): - innerType = value.type[0] - isBool = innerType.name == 'bool' - - if isBool: - if isLibCpp: - start = value["__begin_"].pointer() - size = value["__size_"].integer() - alloc = size - else: - start = value["_M_start"]["_M_p"].pointer() - soffset = value["_M_start"]["_M_offset"].integer() - finish = value["_M_finish"]["_M_p"].pointer() - foffset = value["_M_finish"]["_M_offset"].integer() - alloc = value["_M_end_of_storage"].pointer() - size = (finish - start) * 8 + foffset - soffset # 8 is CHAR_BIT. - else: - if isLibCpp: - start = value["__begin_"].pointer() - finish = value["__end_"].pointer() - alloc = value["__end_cap_"].pointer() - else: - start = value["_M_start"].pointer() - finish = value["_M_finish"].pointer() - alloc = value["_M_end_of_storage"].pointer() - size = int((finish - start) / innerType.size()) - d.check(finish <= alloc) - if size > 0: - d.checkPointer(start) - d.checkPointer(finish) - d.checkPointer(alloc) - - d.check(0 <= size and size <= 1000 * 1000 * 1000) - - d.putItemCount(size) - if isBool: - if d.isExpanded(): - with Children(d, size, maxNumChild=10000, childType=innerType): - for i in d.childRange(): - q = start + int(i / 8) - with SubItem(d, i): - d.putValue((int(d.extractPointer(q)) >> (i % 8)) & 1) - d.putType("bool") - else: - d.putPlotData(start, size, innerType) - - -def qdumpHelper__std__vector__QNX(d, value): - innerType = value.type[0] - isBool = innerType.name == 'bool' - if isBool: - (proxy1, proxy2, start, last, end, size) = value.split("pppppi") - else: - (proxy, start, last, end) = value.split("pppp") - size = (last - start) // innerType.size() - - try: - d.check(0 <= size and size <= 1000 * 1000 * 1000) - d.check(last <= end) - except RuntimeError: - if isBool: - (start, last, end, size) = value.split("pppi") - else: - (start, last, end) = value.split("ppp") - size = (last - start) // innerType.size() - d.check(0 <= size and size <= 1000 * 1000 * 1000) - d.check(last <= end) - +def qdumpHelper__std__vector__nonbool(d, start, finish, alloc, inner_type): + size = int((finish - start) / inner_type.size()) + d.check(finish <= alloc) if size > 0: d.checkPointer(start) - d.checkPointer(last) - d.checkPointer(end) + d.checkPointer(finish) + d.checkPointer(alloc) + d.check(0 <= size and size <= 1000 * 1000 * 1000) + d.putItemCount(size) + d.putPlotData(start, size, inner_type) + +def qdumpHelper__std__vector__bool(d, start, size, inner_type): + d.check(0 <= size and size <= 1000 * 1000 * 1000) d.putItemCount(size) if d.isExpanded(): - if isBool: - with Children(d, size, maxNumChild=10000, childType=innerType): - for i in d.childRange(): - q = start + int(i / 8) - with SubItem(d, i): - d.putValue((d.extractPointer(q) >> (i % 8)) & 1) - d.putType("bool") - else: - d.putPlotData(start, size, innerType) + with Children(d, size, maxNumChild=10000, childType=inner_type): + for i in d.childRange(): + q = start + int(i / 8) + with SubItem(d, i): + d.putValue((int(d.extractPointer(q)) >> (i % 8)) & 1) + d.putType("bool") + + +def qdumpHelper__std__vector__libstdcxx(d, value): + inner_type = value.type[0] + if inner_type.name == "bool": + start = value["_M_start"]["_M_p"].pointer() + soffset = value["_M_start"]["_M_offset"].integer() + finish = value["_M_finish"]["_M_p"].pointer() + foffset = value["_M_finish"]["_M_offset"].integer() + alloc = value["_M_end_of_storage"].pointer() + size = (finish - start) * 8 + foffset - soffset # 8 is CHAR_BIT. + qdumpHelper__std__vector__bool(d, start, size, inner_type) + else: + start = value["_M_start"].pointer() + finish = value["_M_finish"].pointer() + alloc = value["_M_end_of_storage"].pointer() + qdumpHelper__std__vector__nonbool(d, start, finish, alloc, inner_type) + + +def qdumpHelper__std__vector__libcxx(d, value): + inner_type = value.type[0] + if inner_type.name == "bool": + start = value["__begin_"].pointer() + size = value["__size_"].integer() + qdumpHelper__std__vector__bool(d, start, size, inner_type) + else: + start = value["__begin_"].pointer() + finish = value["__end_"].pointer() + alloc = value["__end_cap_"].pointer() + qdumpHelper__std__vector__nonbool(d, start, finish, alloc, inner_type) + + +def qdumpHelper__std__vector__msvc(d, value): + inner_type = value.type[0] + if inner_type.name == "bool": + proxy1, proxy2, start, finish, alloc, size = value.split("pppppi") + try: + d.check(0 <= size and size <= 1000 * 1000 * 1000) + d.check(finish <= alloc) + except RuntimeError: + start, finish, alloc, size = value.split("pppi") + qdumpHelper__std__vector__bool(d, start, size, inner_type) + else: + proxy, start, finish, alloc = value.split("pppp") + size = (finish - start) // inner_type.size() + try: + d.check(0 <= size and size <= 1000 * 1000 * 1000) + d.check(finish <= alloc) + except RuntimeError: + start, finish, alloc = value.split("ppp") + qdumpHelper__std__vector__nonbool(d, start, finish, alloc, inner_type) def qform__std____1__vector(): @@ -1144,7 +1151,7 @@ def qform__std____1__vector(): def qdump__std____1__vector(d, value): - qdumpHelper__std__vector(d, value, True) + qdumpHelper__std__vector__libcxx(d, value) def qform__std____debug__vector(): From 739eeec19d1560743f57579281e63585e1b7d11f Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 4 Jan 2021 10:17:30 +0100 Subject: [PATCH 2/8] Explicitly state that only 64 bit Windows is supported by our binary packages. Building on 32bit is still possible. Fixes: QTCREATORBUG-25182 Change-Id: Ic88579bcd9bf3b6aef449e6ac3bcaa6430cd68f2 Reviewed-by: Leena Miettinen --- README.md | 2 +- .../src/overview/creator-only/creator-desktop-platforms.qdoc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 86e9b1eb787..1d9834f2a35 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ https://doc.qt.io/qtcreator/creator-overview.html The standalone binary packages support the following platforms: -* Windows 7 or later +* Windows 7 (64-bit) or later * (K)Ubuntu Linux 18.04 (64-bit) or later * macOS 10.13 or later diff --git a/doc/qtcreator/src/overview/creator-only/creator-desktop-platforms.qdoc b/doc/qtcreator/src/overview/creator-only/creator-desktop-platforms.qdoc index 00ad408e575..b01aec102e3 100644 --- a/doc/qtcreator/src/overview/creator-only/creator-desktop-platforms.qdoc +++ b/doc/qtcreator/src/overview/creator-only/creator-desktop-platforms.qdoc @@ -74,7 +74,7 @@ \section1 Windows - Windows 7 or later is supported. + Windows 7 (64-bit) or later is supported. \note Some \QC plugins rely on Direct3D (part of DirectX). You might have to manually enable support for it if you are running Windows in a From 498f0939e474a1f50fd24c87ca900493be115927 Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Mon, 21 Dec 2020 11:40:28 +0100 Subject: [PATCH 3/8] SyntaxHighlighter: Fix typo Change-Id: I6fca22438d97afde235ecb22da1083c6103021fd Reviewed-by: David Schulz --- src/plugins/texteditor/syntaxhighlighter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/texteditor/syntaxhighlighter.cpp b/src/plugins/texteditor/syntaxhighlighter.cpp index 2c2c9d0648b..5a35ce1b4f4 100644 --- a/src/plugins/texteditor/syntaxhighlighter.cpp +++ b/src/plugins/texteditor/syntaxhighlighter.cpp @@ -768,7 +768,7 @@ FontSettings SyntaxHighlighter::fontSettings() const return d->fontSettings; } /*! - The syntax highlighter is not anymore reacting to the text document if \a noAutmatic is + The syntax highlighter is not anymore reacting to the text document if \a noAutomatic is \c true. */ void SyntaxHighlighter::setNoAutomaticHighlighting(bool noAutomatic) From 34798b3efdcc00231cca0000b4e65b79322ee8d9 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 17 Dec 2020 13:28:48 +0100 Subject: [PATCH 4/8] ProjectExplorer: Introduce and use a new MultiSelectionAspect Only provide the minimum functionality to make it usable for the target selection in Make steps. Task-number: QTCREATORBUG-25088 Change-Id: I6458a0bd544d2fff596df3240c69e05d7bdea14b Reviewed-by: Christian Kandeler --- src/libs/utils/aspects.cpp | 141 ++++++++++++++++++ src/libs/utils/aspects.h | 30 +++- .../autotoolsprojectmanager/makestep.cpp | 4 +- .../genericprojectmanager/genericmakestep.cpp | 6 +- src/plugins/projectexplorer/makestep.cpp | 54 +------ src/plugins/projectexplorer/makestep.h | 8 +- 6 files changed, 186 insertions(+), 57 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 79509a6b9d2..1dd6bf2cea4 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -250,6 +251,23 @@ public: QString m_tooltip; }; +class MultiSelectionAspectPrivate +{ +public: + QStringList m_value; + QStringList m_allValues; + MultiSelectionAspect::DisplayStyle m_displayStyle + = MultiSelectionAspect::DisplayStyle::ListView; + QString m_labelText; + + // These are all owned by the configuration widget. + QPointer m_listView; + QPointer m_label; + + void updateListView(); + bool setValueSelectedHelper(const QString &value, bool on); +}; + class StringAspectPrivate { public: @@ -1033,6 +1051,129 @@ void SelectionAspect::addOption(const QString &displayName, const QString &toolT d->m_options.append({displayName, toolTip}); } +/*! + \class Utils::MultiSelectionAspect + \inmodule QtCreator + + \brief A multi-selection aspect represents one or more choices out of + several. + + The multi-selection aspect is displayed using a QListWidget with + checkable items. +*/ + +MultiSelectionAspect::MultiSelectionAspect() + : d(new Internal::MultiSelectionAspectPrivate) +{} + +/*! + \reimp +*/ +MultiSelectionAspect::~MultiSelectionAspect() = default; + +/*! + \reimp +*/ +void MultiSelectionAspect::addToLayout(LayoutBuilder &builder) +{ + QTC_CHECK(d->m_listView == nullptr); + if (d->m_allValues.isEmpty()) + return; + + switch (d->m_displayStyle) { + case DisplayStyle::ListView: + d->m_label = new QLabel(d->m_labelText); + d->m_listView = new QListWidget; + for (const QString &value : qAsConst(d->m_allValues)) { + auto item = new QListWidgetItem(value, d->m_listView); + item->setFlags(item->flags() | Qt::ItemIsUserCheckable); + item->setCheckState(d->m_value.contains(item->text()) ? Qt::Checked : Qt::Unchecked); + } + connect(d->m_listView, &QListWidget::itemChanged, this, + [this](QListWidgetItem *item) { + if (d->setValueSelectedHelper(item->text(), item->checkState() & Qt::Checked)) + emit changed(); + }); + builder.addItems({d->m_label.data(), d->m_listView.data()}); + } +} + +bool Internal::MultiSelectionAspectPrivate::setValueSelectedHelper(const QString &value, bool on) +{ + if (on && !m_value.contains(value)) { + m_value.append(value); + return true; + } + if (!on && m_value.contains(value)) { + m_value.removeOne(value); + return true; + } + return false; +} + +QStringList MultiSelectionAspect::allValues() const +{ + return d->m_allValues; +} + +void MultiSelectionAspect::setAllValues(const QStringList &val) +{ + d->m_allValues = val; +} + +void MultiSelectionAspect::setLabelText(const QString &labelText) +{ + d->m_labelText = labelText; +} + +void Internal::MultiSelectionAspectPrivate::updateListView() +{ + if (!m_listView) + return; + const int n = m_listView->count(); + QTC_CHECK(n == m_allValues.size()); + for (int i = 0; i != n; ++i) { + auto item = m_listView->item(i); + item->setCheckState(m_value.contains(item->text()) ? Qt::Checked : Qt::Unchecked); + } +} + +/*! + \reimp +*/ +void MultiSelectionAspect::fromMap(const QVariantMap &map) +{ + d->m_value = map.value(settingsKey(), QStringList()).toStringList(); +} + +/*! + \reimp +*/ +void MultiSelectionAspect::toMap(QVariantMap &data) const +{ + saveToMap(data, d->m_value, QStringList()); +} + +void MultiSelectionAspect::setDisplayStyle(MultiSelectionAspect::DisplayStyle style) +{ + d->m_displayStyle = style; +} + +QStringList MultiSelectionAspect::value() const +{ + return d->m_value; +} + +void MultiSelectionAspect::setValue(const QStringList &value) +{ + if (d->m_value == value) + return; + d->m_value = value; + d->updateListView(); + emit changed(); +} + + /*! \class Utils::IntegerAspect \inmodule QtCreator diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 28a49c855f5..3bbd0b449ba 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -44,6 +44,7 @@ namespace Internal { class AspectContainerPrivate; class BoolAspectPrivate; class IntegerAspectPrivate; +class MultiSelectionAspectPrivate; class SelectionAspectPrivate; class StringAspectPrivate; class StringListAspectPrivate; @@ -97,7 +98,6 @@ protected: class QTCREATOR_UTILS_EXPORT BaseAspects { - BaseAspects(const BaseAspects &) = delete; BaseAspects &operator=(const BaseAspects &) = delete; @@ -202,6 +202,34 @@ private: std::unique_ptr d; }; +class QTCREATOR_UTILS_EXPORT MultiSelectionAspect : public BaseAspect +{ + Q_OBJECT + +public: + MultiSelectionAspect(); + ~MultiSelectionAspect() override; + + void addToLayout(LayoutBuilder &builder) override; + + enum class DisplayStyle { ListView }; + void setDisplayStyle(DisplayStyle style); + + QStringList value() const; + void setValue(const QStringList &val); + + QStringList allValues() const; + void setAllValues(const QStringList &val); + + void setLabelText(const QString &labelText); + + void fromMap(const QVariantMap &map) override; + void toMap(QVariantMap &map) const override; + +private: + std::unique_ptr d; +}; + class QTCREATOR_UTILS_EXPORT StringAspect : public BaseAspect { Q_OBJECT diff --git a/src/plugins/autotoolsprojectmanager/makestep.cpp b/src/plugins/autotoolsprojectmanager/makestep.cpp index be644731f02..41e21081bf4 100644 --- a/src/plugins/autotoolsprojectmanager/makestep.cpp +++ b/src/plugins/autotoolsprojectmanager/makestep.cpp @@ -49,10 +49,10 @@ MakeStep::MakeStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id) { setAvailableBuildTargets({"all", "clean"}); if (bsl->id() == ProjectExplorer::Constants::BUILDSTEPS_CLEAN) { - setBuildTarget("clean", true); + setSelectedBuildTarget("clean"); setIgnoreReturnValue(true); } else { - setBuildTarget("all", true); + setSelectedBuildTarget("all"); } } diff --git a/src/plugins/genericprojectmanager/genericmakestep.cpp b/src/plugins/genericprojectmanager/genericmakestep.cpp index aabca395687..c22725c6cf6 100644 --- a/src/plugins/genericprojectmanager/genericmakestep.cpp +++ b/src/plugins/genericprojectmanager/genericmakestep.cpp @@ -43,13 +43,13 @@ public: GenericMakeStep::GenericMakeStep(BuildStepList *parent, Utils::Id id) : MakeStep(parent, id) { + setAvailableBuildTargets({"all", "clean"}); if (parent->id() == ProjectExplorer::Constants::BUILDSTEPS_BUILD) { - setBuildTarget("all"); + setSelectedBuildTarget("all"); } else if (parent->id() == ProjectExplorer::Constants::BUILDSTEPS_CLEAN) { - setBuildTarget("clean"); + setSelectedBuildTarget("clean"); setIgnoreReturnValue(true); } - setAvailableBuildTargets({"all", "clean"}); } GenericMakeStepFactory::GenericMakeStepFactory() diff --git a/src/plugins/projectexplorer/makestep.cpp b/src/plugins/projectexplorer/makestep.cpp index 560cc177828..a6144c5b9a4 100644 --- a/src/plugins/projectexplorer/makestep.cpp +++ b/src/plugins/projectexplorer/makestep.cpp @@ -49,8 +49,6 @@ #include #include #include -#include -#include #include using namespace Core; @@ -105,8 +103,9 @@ MakeStep::MakeStep(BuildStepList *parent, Id id) .arg(text) + "

"); m_nonOverrideWarning->setIconType(InfoLabel::Warning); - m_buildTargetsAspect = addAspect(); + m_buildTargetsAspect = addAspect(); m_buildTargetsAspect->setSettingsKey(id.withSuffix(BUILD_TARGETS_SUFFIX).toString()); + m_buildTargetsAspect->setLabelText(tr("Targets:")); const auto updateMakeLabel = [this] { const QString defaultMake = defaultMakeCommand().toString(); @@ -121,15 +120,14 @@ MakeStep::MakeStep(BuildStepList *parent, Id id) connect(m_makeCommandAspect, &StringAspect::changed, this, updateMakeLabel); } -void MakeStep::setBuildTarget(const QString &buildTarget) +void MakeStep::setSelectedBuildTarget(const QString &buildTarget) { - if (!buildTarget.isEmpty()) - setBuildTarget(buildTarget, true); + m_buildTargetsAspect->setValue({buildTarget}); } void MakeStep::setAvailableBuildTargets(const QStringList &buildTargets) { - m_availableTargets = buildTargets; + m_buildTargetsAspect->setAllValues(buildTargets); } bool MakeStep::init() @@ -342,11 +340,6 @@ QWidget *MakeStep::createConfigWidget() { auto widget = new QWidget; - auto targetsLabel = new QLabel(widget); - targetsLabel->setText(tr("Targets:")); - - auto targetsList = new QListWidget(widget); - auto disableInSubDirsLabel = new QLabel(tr("Disable in subdirectories:"), widget); auto disableInSubDirsCheckBox = new QCheckBox(widget); disableInSubDirsCheckBox->setToolTip(tr("Runs this step only for a top-level build.")); @@ -356,7 +349,7 @@ QWidget *MakeStep::createConfigWidget() builder.addRow(m_userArgumentsAspect); builder.addRow(m_jobCountContainer); builder.addRow({disableInSubDirsLabel, disableInSubDirsCheckBox}); - builder.addRow({targetsLabel, targetsList}); + builder.addRow(m_buildTargetsAspect); if (!m_disablingForSubDirsSupported) { disableInSubDirsLabel->hide(); @@ -367,16 +360,6 @@ QWidget *MakeStep::createConfigWidget() }); } - for (const QString &target : qAsConst(m_availableTargets)) { - auto item = new QListWidgetItem(target, targetsList); - item->setFlags(item->flags() | Qt::ItemIsUserCheckable); - item->setCheckState(buildsTarget(item->text()) ? Qt::Checked : Qt::Unchecked); - } - if (m_availableTargets.isEmpty()) { - targetsLabel->hide(); - targetsList->hide(); - } - VariableChooser::addSupportForChildWidgets(widget, macroExpander()); setSummaryUpdater([this] { @@ -420,12 +403,7 @@ QWidget *MakeStep::createConfigWidget() connect(m_userArgumentsAspect, &StringAspect::changed, widget, updateDetails); connect(m_userJobCountAspect, &IntegerAspect::changed, widget, updateDetails); connect(m_overrideMakeflagsAspect, &BoolAspect::changed, widget, updateDetails); - - connect(targetsList, &QListWidget::itemChanged, this, - [this, updateDetails](QListWidgetItem *item) { - setBuildTarget(item->text(), item->checkState() & Qt::Checked); - updateDetails(); - }); + connect(m_buildTargetsAspect, &BaseAspect::changed, widget, updateDetails); connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged, widget, updateDetails); @@ -439,25 +417,9 @@ QWidget *MakeStep::createConfigWidget() return widget; } -bool MakeStep::buildsTarget(const QString &target) const -{ - return m_buildTargetsAspect->value().contains(target); -} - -void MakeStep::setBuildTarget(const QString &target, bool on) -{ - QStringList old = m_buildTargetsAspect->value(); - if (on && !old.contains(target)) - old << target; - else if (!on && old.contains(target)) - old.removeOne(target); - - m_buildTargetsAspect->setValue(old); -} - QStringList MakeStep::availableTargets() const { - return m_availableTargets; + return m_buildTargetsAspect->allValues(); } } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/makestep.h b/src/plugins/projectexplorer/makestep.h index 690b3415f58..c092060f88d 100644 --- a/src/plugins/projectexplorer/makestep.h +++ b/src/plugins/projectexplorer/makestep.h @@ -45,14 +45,13 @@ public: }; explicit MakeStep(ProjectExplorer::BuildStepList *parent, Utils::Id id); - void setBuildTarget(const QString &buildTarget); void setAvailableBuildTargets(const QStringList &buildTargets); + void setSelectedBuildTarget(const QString &buildTarget); bool init() override; void setupOutputFormatter(Utils::OutputFormatter *formatter) override; QWidget *createConfigWidget() override; - bool buildsTarget(const QString &target) const; - void setBuildTarget(const QString &target, bool on); + QStringList availableTargets() const; QString userArguments() const; void setUserArguments(const QString &args); @@ -87,8 +86,7 @@ private: static int defaultJobCount(); QStringList jobArguments() const; - Utils::StringListAspect *m_buildTargetsAspect = nullptr; - QStringList m_availableTargets; + Utils::MultiSelectionAspect *m_buildTargetsAspect = nullptr; Utils::StringAspect *m_makeCommandAspect = nullptr; Utils::StringAspect *m_userArgumentsAspect = nullptr; Utils::AspectContainer *m_jobCountContainer = nullptr; From f5a49e6b0be2fa5d4ae8570a52c42bc59acd4509 Mon Sep 17 00:00:00 2001 From: Lukasz Ornatek Date: Wed, 16 Dec 2020 14:59:17 +0100 Subject: [PATCH 5/8] Implement adding images in the rich text format to the annotations Task-number: QDS-3306 Change-Id: I8372c3d10ad5beb1ec52d8d3d45a3f963711a63c Reviewed-by: Leena Miettinen Reviewed-by: Michael Winkelmann Reviewed-by: Thomas Hartmann --- .../annotationeditor/annotationcommenttab.cpp | 78 ++++++++++++++++++- .../annotationeditor/annotationcommenttab.h | 6 ++ .../richtexteditor/richtexteditor.cpp | 36 +++++++++ .../richtexteditor/richtexteditor.h | 9 +++ 4 files changed, 128 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp index 29e38362418..e1afef38be1 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp @@ -28,8 +28,14 @@ #include "richtexteditor/richtexteditor.h" +#include #include "QStringListModel" +#include "projectexplorer/session.h" +#include "projectexplorer/target.h" +#include "qmldesignerplugin.h" +#include "qmlprojectmanager/qmlproject.h" + namespace QmlDesigner { AnnotationCommentTab::AnnotationCommentTab(QWidget *parent) @@ -38,7 +44,17 @@ AnnotationCommentTab::AnnotationCommentTab(QWidget *parent) { ui->setupUi(this); - m_editor = new RichTextEditor; + m_editor = new RichTextEditor{this}; + + connect(m_editor, &RichTextEditor::insertingImage, this, [this](QString &filePath) { + filePath = backupFile(filePath); + }); + + Utils::FilePath projPath = ProjectExplorer::SessionManager::startupProject()->projectFilePath(); + + m_editor->setDocumentBaseUrl(QUrl::fromLocalFile(projPath.toString())); + m_editor->setImageActionVisible(true); + ui->formLayout->setWidget(3, QFormLayout::FieldRole, m_editor); ui->titleEdit->setModel(new QStringListModel{QStringList{"Description", @@ -113,4 +129,64 @@ void AnnotationCommentTab::commentTitleChanged(const QString &text) emit titleChanged(text, this); } +QString AnnotationCommentTab::backupFile(const QString &filePath) +{ + const QDir projDir( + ProjectExplorer::SessionManager::startupProject()->projectDirectory().toString()); + + const QString imageSubDir(".AnnotationImages"); + const QDir imgDir(projDir.absolutePath() + QDir::separator() + imageSubDir); + + ensureDir(imgDir); + + const QFileInfo oldFile(filePath); + QFileInfo newFile(imgDir, oldFile.fileName()); + + QString newName = newFile.baseName() + "_%1." + newFile.completeSuffix(); + + for (size_t i = 1; true; ++i) { + if (!newFile.exists()) { + QFile(oldFile.absoluteFilePath()).copy(newFile.absoluteFilePath()); + break; + } else if (compareFileChecksum(oldFile.absoluteFilePath(), + newFile.absoluteFilePath()) == 0) { + break; + } + + newFile.setFile(imgDir, newName.arg(i)); + } + + return projDir.relativeFilePath(newFile.absoluteFilePath()); +} + +void AnnotationCommentTab::ensureDir(const QDir &dir) +{ + if (!dir.exists()) { + dir.mkdir("."); + } +} + +int AnnotationCommentTab::compareFileChecksum(const QString &firstFile, const QString &secondFile) +{ + QCryptographicHash sum1(QCryptographicHash::Md5); + + { + QFile f1(firstFile); + if (f1.open(QFile::ReadOnly)) { + sum1.addData(&f1); + } + } + + QCryptographicHash sum2(QCryptographicHash::Md5); + + { + QFile f2(secondFile); + if (f2.open(QFile::ReadOnly)) { + sum2.addData(&f2); + } + } + + return sum1.result().compare(sum2.result()); +} + } //namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h index 55fcf6ff1ed..5f9605f39f7 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h @@ -29,6 +29,8 @@ #include "annotation.h" +class QDir; + namespace QmlDesigner { namespace Ui { @@ -64,6 +66,10 @@ private: RichTextEditor *m_editor; Comment m_comment; + + QString backupFile(const QString &filePath); + void ensureDir(const QDir &dir); + int compareFileChecksum(const QString &firstFile, const QString &secondFile); }; } //namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp index a8e693876e0..d576cf19d1d 100644 --- a/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp +++ b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -120,6 +121,7 @@ RichTextEditor::RichTextEditor(QWidget *parent) setupEditActions(); setupTextActions(); + setupImageActions(); setupHyperlinkActions(); setupAlignActions(); setupListActions(); @@ -184,6 +186,16 @@ void RichTextEditor::setTabChangesFocus(bool change) ui->textEdit->setTabChangesFocus(change); } +void RichTextEditor::setImageActionVisible(bool change) +{ + m_actionImage->setVisible(change); +} + +void RichTextEditor::setDocumentBaseUrl(const QUrl& url) +{ + ui->textEdit->document()->setBaseUrl(url); +} + QIcon RichTextEditor::getIcon(Theme::Icon icon) { const QString fontName = "qtds_propertyIconFont.ttf"; @@ -361,6 +373,30 @@ void RichTextEditor::setupTextActions() ui->toolBar->addSeparator(); } +void RichTextEditor::setupImageActions() +{ + auto insertImage = [this]() { + QFileDialog dialog(this); + dialog.setFileMode(QFileDialog::ExistingFile); + dialog.setWindowTitle(tr("Select Image")); + dialog.setNameFilters({tr("Image files (*.png *.jpg)")}); + + if (dialog.exec()) { + QStringList files = dialog.selectedFiles(); + for (QString& filePath : files) { + emit insertingImage(filePath); + + ui->textEdit->insertHtml(""); + } + } + }; + + m_actionImage = ui->toolBar + ->addAction(getIcon(Theme::Icon::addFile), tr("Insert &Image"), insertImage); + + setImageActionVisible(false); +} + void RichTextEditor::setupHyperlinkActions() { const QIcon bulletIcon(getIcon(Theme::Icon::actionIconBinding)); diff --git a/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.h b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.h index 50053c1ab3c..a2f44dd0443 100644 --- a/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.h +++ b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.h @@ -63,6 +63,13 @@ public: void setTabChangesFocus(bool change); + void setImageActionVisible(bool change); + + void setDocumentBaseUrl(const QUrl &url); + +signals: + void insertingImage(QString &filePath); + private slots: void currentCharFormatChanged(const QTextCharFormat &format); void cursorPositionChanged(); @@ -79,6 +86,7 @@ private: void setupEditActions(); void setupTextActions(); + void setupImageActions(); void setupHyperlinkActions(); void setupAlignActions(); void setupListActions(); @@ -97,6 +105,7 @@ private: QAction *m_actionTextItalic; QAction *m_actionTextUnderline; + QAction *m_actionImage; QAction *m_actionHyperlink; QAction *m_actionAlignLeft; From d20303250427de7eb2c336c4340a123e00d897e0 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 17 Dec 2020 13:38:00 +0100 Subject: [PATCH 6/8] ClangTools: Re-add clang's own include path Amends ef05f29940. Fixes: QTCREATORBUG-25126 Change-Id: I1340916f3f3488b0d1171f04ae1c9f30149c0c5c Reviewed-by: David Schulz --- src/plugins/cpptools/headerpathfilter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/cpptools/headerpathfilter.cpp b/src/plugins/cpptools/headerpathfilter.cpp index c0a1c04cf9d..2e010ead5a2 100644 --- a/src/plugins/cpptools/headerpathfilter.cpp +++ b/src/plugins/cpptools/headerpathfilter.cpp @@ -51,7 +51,7 @@ void HeaderPathFilter::process() for (const HeaderPath &headerPath : headerPaths) filterHeaderPath(headerPath); - if (useTweakedHeaderPaths == UseTweakedHeaderPaths::Yes) + if (useTweakedHeaderPaths != UseTweakedHeaderPaths::No) tweakHeaderPaths(); } From 2a37a5ae16596b34b5146bf5faa3812934943f8a Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Tue, 5 Jan 2021 13:46:41 +0100 Subject: [PATCH 7/8] fix warning Change-Id: I36ef0823a7e0b786b1315df4e3d48fabb99c16f4 Reviewed-by: Marco Bubke --- .../qmldesigner/components/formeditor/formeditoritem.cpp | 2 +- .../components/itemlibrary/itemlibraryassetimporter.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp b/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp index 483c08046c7..1cd42733d9d 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp @@ -1087,7 +1087,7 @@ static int counterClockWise(const std::vector &points) }; const int m = findLR(points); - const int n = points.size(); + const int n = static_cast(points.size()); // Determine previous and next point to m (the lowest, rightmost point). const QPointF a = points[(m + (n - 1)) % n]; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp index 8489c0d63a2..23ab98d1ab0 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp @@ -89,7 +89,7 @@ void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles, if (m_qmlPuppetProcesses.empty()) { finalizeQuick3DImport(); } else { - m_qmlPuppetCount = m_qmlPuppetProcesses.size(); + m_qmlPuppetCount = static_cast(m_qmlPuppetProcesses.size()); const QString progressTitle = tr("Generating icons."); addInfo(progressTitle); notifyProgress(0, progressTitle); From 7d0be4882ce6188f69d11fd7be5d6b61bfef9112 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 18 Dec 2020 14:47:30 +0100 Subject: [PATCH 8/8] QmakeProjectManager: Fix qmake getting re-run unnecessarily ... when separate debug info was disabled. Fixes: QTCREATORBUG-25134 Change-Id: Ia527de39b9409f68d1aa4babd64a30e18bb1f1ae Reviewed-by: hjk --- src/plugins/qmakeprojectmanager/makefileparse.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmakeprojectmanager/makefileparse.cpp b/src/plugins/qmakeprojectmanager/makefileparse.cpp index 0a066633719..2beb5d899f4 100644 --- a/src/plugins/qmakeprojectmanager/makefileparse.cpp +++ b/src/plugins/qmakeprojectmanager/makefileparse.cpp @@ -206,10 +206,13 @@ QList MakeFileParse::parseAssignments(const QList