From 7540dbeb8ea091c8a39adc158f91384cc47e9bf2 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 26 Sep 2024 12:00:43 +0200 Subject: [PATCH] QtSupport: Use QtVersionItem in QtKitAspect For proper sorting and icons. Task-number: QTCREATORBUG-31574 Change-Id: Ib835091684527ce22b0294c494227979e3b093ec Reviewed-by: hjk --- src/plugins/qtsupport/qtkitaspect.cpp | 119 ++++++++++---- src/plugins/qtsupport/qtoptionspage.cpp | 209 +++++++++++++----------- src/plugins/qtsupport/qtoptionspage.h | 36 +++- 3 files changed, 237 insertions(+), 127 deletions(-) diff --git a/src/plugins/qtsupport/qtkitaspect.cpp b/src/plugins/qtsupport/qtkitaspect.cpp index aa85cf36fde..09bf54015a3 100644 --- a/src/plugins/qtsupport/qtkitaspect.cpp +++ b/src/plugins/qtsupport/qtkitaspect.cpp @@ -3,6 +3,7 @@ #include "qtkitaspect.h" +#include "qtoptionspage.h" #include "qtparser.h" #include "qtsupportconstants.h" #include "qtsupporttr.h" @@ -30,6 +31,80 @@ using namespace Utils; namespace QtSupport { namespace Internal { +class QtVersionListModel : public TreeModel +{ +public: + QtVersionListModel(const Kit &kit, QObject *parent) + : TreeModel(parent) + , m_kit(kit) + {} + + QModelIndex indexForQtId(int id) const + { + if (id == -1) + return index(rowCount() - 1, 0); // The "No Qt" item always comes last + const TreeItem *const item = findItemAtLevel<1>( + [id](TreeItem *item) { return static_cast(item)->uniqueId() == id; }); + return item ? indexForItem(item) : QModelIndex(); + } + + void reset() + { + clear(); + + const FilePath deviceRoot = BuildDeviceKitAspect::device(&m_kit)->rootPath(); + const QtVersions versionsForBuildDevice = QtVersionManager::versions( + [&deviceRoot](const QtVersion *qt) { + return qt->qmakeFilePath().isSameDevice(deviceRoot); + }); + for (QtVersion *v : versionsForBuildDevice) + rootItem()->appendChild(new QtVersionItem(v->uniqueId())); + rootItem()->appendChild(new QtVersionItem(-1)); // The "No Qt" entry. + } + +private: + const Kit &m_kit; +}; + +class QtVersionSortModel : public SortModel +{ +public: + QtVersionSortModel(QObject *parent) : SortModel(parent) {} + + QModelIndex indexForId(int id) const + { + return mapFromSource( + static_cast(sourceModel())->indexForQtId(id)); + } + + void reset() { static_cast(sourceModel())->reset(); } + +private: + bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override + { + const auto source = static_cast(sourceModel()); + const auto item1 = static_cast(source->itemForIndex(source_left)); + const auto item2 = static_cast(source->itemForIndex(source_right)); + QTC_ASSERT(item1 && item2, return false); + + // Criterion 1: "No Qt" comes last + if (item1->uniqueId() == -1) + return false; + if (item2->uniqueId() == -1) + return true; + + // Criterion 2: Invalid Qt versions come after valid ones with warnings, which come + // after valid ones without warnings. + if (const QtVersionItem::Quality qual1 = item1->quality(), qual2 = item2->quality(); + qual1 != qual2) { + return qual1 == QtVersionItem::Quality::Good || qual2 == QtVersionItem::Quality::Bad; + } + + // Criterion 3: Name. + return SortModel::lessThan(source_left, source_right); + } +}; + class QtKitAspectImpl final : public KitAspect { public: @@ -39,8 +114,13 @@ public: m_combo = createSubWidget(); m_combo->setSizePolicy(QSizePolicy::Ignored, m_combo->sizePolicy().verticalPolicy()); + const auto sortModel = new QtVersionSortModel(this); + sortModel->setSourceModel(new QtVersionListModel(*k, this)); + m_combo->setModel(sortModel); refresh(); + + // FIXME: We want the tooltip for the current item (also for toolchains etc). m_combo->setToolTip(ki->description()); connect(m_combo, &QComboBox::currentIndexChanged, this, [this] { @@ -48,10 +128,10 @@ public: currentWasChanged(m_combo->currentIndex()); }); - connect(QtVersionManager::instance(), - &QtVersionManager::qtVersionsChanged, - this, - &QtKitAspectImpl::refresh); + connect(KitManager::instance(), &KitManager::kitUpdated, this, [this](Kit *k) { + if (k == kit()) + refresh(); + }); } ~QtKitAspectImpl() final @@ -71,20 +151,10 @@ private: void refresh() final { const GuardLocker locker(m_ignoreChanges); - m_combo->clear(); - m_combo->addItem(Tr::tr("None"), -1); - - IDeviceConstPtr device = BuildDeviceKitAspect::device(kit()); - const FilePath deviceRoot = device->rootPath(); - - const QtVersions versionsForBuildDevice - = Utils::filtered(QtVersionManager::versions(), [device](QtVersion *qt) { - return qt->qmakeFilePath().isSameDevice(device->rootPath()); - }); - - for (QtVersion *item : versionsForBuildDevice) - m_combo->addItem(item->displayName(), item->uniqueId()); - m_combo->setCurrentIndex(findQtVersion(QtKitAspect::qtVersionId(m_kit))); + const auto sortModel = static_cast(m_combo->model()); + sortModel->reset(); + sortModel->sort(0); + m_combo->setCurrentIndex(sortModel->indexForId(QtKitAspect::qtVersionId(m_kit)).row()); } private: @@ -99,16 +169,9 @@ private: void currentWasChanged(int idx) { - QtKitAspect::setQtVersionId(m_kit, m_combo->itemData(idx).toInt()); - } - - int findQtVersion(const int id) const - { - for (int i = 0; i < m_combo->count(); ++i) { - if (id == m_combo->itemData(i).toInt()) - return i; - } - return -1; + const QAbstractItemModel * const model = m_combo->model(); + const int versionId = model->data(model->index(idx, 0), QtVersionItem::IdRole).toInt(); + QtKitAspect::setQtVersionId(m_kit, versionId); } Guard m_ignoreChanges; diff --git a/src/plugins/qtsupport/qtoptionspage.cpp b/src/plugins/qtsupport/qtoptionspage.cpp index eeb14b0a4a7..5ba6ff5c67a 100644 --- a/src/plugins/qtsupport/qtoptionspage.cpp +++ b/src/plugins/qtsupport/qtoptionspage.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -44,7 +43,6 @@ #include #include -#include #include using namespace Core; @@ -128,117 +126,132 @@ UnsupportedAbisInfo checkForUnsupportedAbis(const QtVersion *version) return info; } -class QtVersionItem : public TreeItem +void QtVersionItem::setIsNameUnique(const std::function &isNameUnique) { -public: - explicit QtVersionItem(QtVersion *version) - : m_version(version) - {} + m_isNameUnique = isNameUnique; +} - ~QtVersionItem() - { - delete m_version; +QtVersionItem::Quality QtVersionItem::quality() const +{ + const QtVersion *version = this->version(); + QTC_ASSERT(version, return Quality::Bad); + + if (!version->isValid()) + return Quality::Bad; + if (!version->warningReason().isEmpty() || hasNonUniqueDisplayName()) + return Quality::Limited; + const UnsupportedAbisInfo abisInfo = checkForUnsupportedAbis(version); + switch (abisInfo.status) { + case UnsupportedAbisInfo::Status::AllMissing: + return Quality::Bad; + case UnsupportedAbisInfo::Status::SomeMissing: + return Quality::Limited; + case UnsupportedAbisInfo::Status::Ok: + break; + } + return Quality::Good; +} + +void QtVersionItem::setChanged(bool changed) +{ + if (changed == m_changed) + return; + m_changed = changed; + update(); +} + +QVariant QtVersionItem::data(int column, int role) const +{ + const QtVersion *version = this->version(); + + if (!version) { + if (role == Qt::DisplayRole && column == 0) + return Tr::tr("No Qt"); + if (role == IdRole) + return -1; + return TreeItem::data(column, role); } - void setVersion(QtVersion *version) - { - m_version = version; - update(); + if (role == Qt::DisplayRole) { + if (column == 0) + return version->displayName(); + if (column == 1) + return version->qmakeFilePath().toUserOutput(); } - int uniqueId() const - { - return m_version ? m_version->uniqueId() : -1; + if (role == Qt::FontRole && m_changed) { + QFont font; + font.setBold(true); + return font; } - QtVersion *version() const - { - return m_version; - } - - QVariant data(int column, int role) const final - { - if (!m_version) - return TreeItem::data(column, role); - - if (role == Qt::DisplayRole) { - if (column == 0) - return m_version->displayName(); - if (column == 1) - return m_version->qmakeFilePath().toUserOutput(); + if (role == Qt::DecorationRole && column == 0) { + switch (quality()) { + case Quality::Good: + return validVersionIcon(); + case Quality::Limited: + return warningVersionIcon(); + case Quality::Bad: + return invalidVersionIcon(); } + } - if (role == Qt::FontRole && m_changed) { - QFont font; - font.setBold(true); - return font; - } - - if (role == Qt::DecorationRole && column == 0) { - if (!m_version->isValid()) - return invalidVersionIcon(); - if (!m_version->warningReason().isEmpty() || hasNonUniqueDisplayName()) - return warningVersionIcon(); - const UnsupportedAbisInfo abisInfo = checkForUnsupportedAbis(m_version); - switch (abisInfo.status) { - case UnsupportedAbisInfo::Status::AllMissing: - return invalidVersionIcon(); - case UnsupportedAbisInfo::Status::SomeMissing: - return warningVersionIcon(); - case UnsupportedAbisInfo::Status::Ok: - break; - } - return validVersionIcon(); + if (role == Qt::ToolTipRole) { + const QString row = "
%1:
" + "
%2
"; + QString desc = "
"; + if (version->isValid()) + desc += row.arg(Tr::tr("Qt Version"), version->qtVersionString()); + desc += row.arg(Tr::tr("Location of qmake"), version->qmakeFilePath().toUserOutput()); + if (version->isValid()) { + const UnsupportedAbisInfo abisInfo = checkForUnsupportedAbis(version); + if (abisInfo.status == UnsupportedAbisInfo::Status::AllMissing) + desc += row.arg(Tr::tr("Error"), abisInfo.message); + if (abisInfo.status == UnsupportedAbisInfo::Status::SomeMissing) + desc += row.arg(Tr::tr("Warning"), abisInfo.message); + const QStringList warnings = version->warningReason(); + for (const QString &w : warnings) + desc += row.arg(Tr::tr("Warning"), w); + } else { + desc += row.arg(Tr::tr("Error"), version->invalidReason()); } - - if (role == Qt::ToolTipRole) { - const QString row = "
%1:
" - "
%2
"; - QString desc = "
"; - if (m_version->isValid()) - desc += row.arg(Tr::tr("Qt Version"), m_version->qtVersionString()); - desc += row.arg(Tr::tr("Location of qmake"), m_version->qmakeFilePath().toUserOutput()); - if (m_version->isValid()) { - const UnsupportedAbisInfo abisInfo = checkForUnsupportedAbis(m_version); - if (abisInfo.status == UnsupportedAbisInfo::Status::AllMissing) - desc += row.arg(Tr::tr("Error"), abisInfo.message); - if (abisInfo.status == UnsupportedAbisInfo::Status::SomeMissing) - desc += row.arg(Tr::tr("Warning"), abisInfo.message); - const QStringList warnings = m_version->warningReason(); - for (const QString &w : warnings) - desc += row.arg(Tr::tr("Warning"), w); - } else { - desc += row.arg(Tr::tr("Error"), m_version->invalidReason()); - } - if (hasNonUniqueDisplayName()) - desc += row.arg(Tr::tr("Warning"), nonUniqueDisplayNameWarning()); - desc += "
"; - return desc; - } - - return QVariant(); + if (hasNonUniqueDisplayName()) + desc += row.arg(Tr::tr("Warning"), nonUniqueDisplayNameWarning()); + desc += "
"; + return desc; } - void setChanged(bool changed) - { - if (changed == m_changed) - return; - m_changed = changed; - update(); - } + if (role == IdRole) + return uniqueId(); - void setIsNameUnique(const std::function &isNameUnique) - { - m_isNameUnique = isNameUnique; - } + return QVariant(); +} -private: - bool hasNonUniqueDisplayName() const { return m_isNameUnique && !m_isNameUnique(m_version); } +int QtVersionItem::uniqueId() const +{ + if (const auto v = std::get_if(&m_version)) + return v ? (*v)->uniqueId() : -1; + return *std::get_if(&m_version); +} - QtVersion *m_version = nullptr; - std::function m_isNameUnique; - bool m_changed = false; -}; +QtVersion *QtVersionItem::version() const +{ + if (const auto v = std::get_if(&m_version)) + return *v; + return QtVersionManager::version(*std::get_if(&m_version)); +} + +void QtVersionItem::setVersion(QtVersion *version) +{ + m_version = version; + update(); +} + +QtVersionItem::~QtVersionItem() +{ + if (const auto v = std::get_if(&m_version)) + delete *v; +} // QtSettingsPageWidget @@ -1130,7 +1143,7 @@ void setupQtSettingsPage() static QtSettingsPage theQtSettingsPage; } -} // Internal +} // namespace Internal bool LinkWithQtSupport::canLinkWithQt() { diff --git a/src/plugins/qtsupport/qtoptionspage.h b/src/plugins/qtsupport/qtoptionspage.h index 892e68ecfc2..963b452e909 100644 --- a/src/plugins/qtsupport/qtoptionspage.h +++ b/src/plugins/qtsupport/qtoptionspage.h @@ -6,8 +6,13 @@ #include "qtsupport_global.h" #include +#include + +#include +#include namespace QtSupport { +class QtVersion; namespace LinkWithQtSupport { QTSUPPORT_EXPORT bool canLinkWithQt(); @@ -16,6 +21,35 @@ QTSUPPORT_EXPORT Utils::FilePath linkedQt(); QTSUPPORT_EXPORT void linkWithQt(); } -namespace Internal { void setupQtSettingsPage(); } +namespace Internal { +class QtVersionItem : public Utils::TreeItem +{ +public: + explicit QtVersionItem(QtVersion *version) : m_version(version) {} + explicit QtVersionItem(int versionId) : m_version(versionId) {} + ~QtVersionItem(); + + void setVersion(QtVersion *version); + int uniqueId() const; + QtVersion *version() const; + void setChanged(bool changed); + void setIsNameUnique(const std::function &isNameUnique); + + enum class Quality { Good, Limited, Bad }; + Quality quality() const; + + static const int IdRole = Qt::UserRole; +private: + QVariant data(int column, int role) const final; + + bool hasNonUniqueDisplayName() const { return m_isNameUnique && !m_isNameUnique(version()); } + + std::variant m_version; + std::function m_isNameUnique; + bool m_changed = false; +}; + +void setupQtSettingsPage(); +} } // QtSupport