Debugger: Use DebuggerTreeItem in DebuggerKitAspect

For sorting and icons.

Task-number: QTCREATORBUG-31574
Change-Id: Ieefe3f2dfc0078439ca70db61b512394d9c35fdf
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Christian Kandeler
2024-09-30 17:52:19 +02:00
parent 25c35da043
commit e6a937accf
4 changed files with 163 additions and 75 deletions

View File

@@ -308,7 +308,7 @@ QDateTime DebuggerItem::lastModified() const
DebuggerItem::Problem DebuggerItem::problem() const
{
if (isGeneric())
if (isGeneric() || !m_id.isValid()) // Id can only be invalid for the "none" item.
return Problem::None;
if (m_engineType == NoEngineType)
return Problem::NoEngine;

View File

@@ -3,7 +3,6 @@
#include "debuggeritemmanager.h"
#include "debuggeritem.h"
#include "debuggertr.h"
#include <coreplugin/dialogs/ioptionspage.h>
@@ -26,7 +25,6 @@
#include <utils/persistentsettings.h>
#include <utils/qtcprocess.h>
#include <utils/qtcassert.h>
#include <utils/treemodel.h>
#include <utils/winutils.h>
#include <nanotrace/nanotrace.h>
@@ -102,50 +100,45 @@ private:
// DebuggerTreeItem
// --------------------------------------------------------------------------
class DebuggerTreeItem : public TreeItem
QVariant DebuggerTreeItem::data(int column, int role) const
{
public:
DebuggerTreeItem(const DebuggerItem &item, bool changed)
: m_item(item), m_orig(item), m_added(changed), m_changed(changed)
{}
QVariant data(int column, int role) const override
{
switch (role) {
case Qt::DisplayRole:
switch (column) {
case 0: return m_item.displayName();
case 1: return m_item.command().toUserOutput();
case 2: return m_item.engineTypeName();
}
break;
case Qt::FontRole: {
QFont font;
if (m_changed)
font.setBold(true);
if (m_removed)
font.setStrikeOut(true);
return font;
}
case Qt::DecorationRole:
if (column == 0)
return m_item.decoration();
break;
case Qt::ToolTipRole:
return m_item.validityMessage();
switch (role) {
case Qt::DisplayRole:
switch (column) {
case 0:
return m_item.displayName();
case 1:
return m_item.command().toUserOutput();
case 2:
return m_item.engineTypeName();
}
return QVariant();
break;
case Qt::FontRole: {
QFont font;
if (m_changed)
font.setBold(true);
if (m_removed)
font.setStrikeOut(true);
return font;
}
DebuggerItem m_item; // Displayed, possibly unapplied data.
DebuggerItem m_orig; // Stored original data.
bool m_added;
bool m_changed;
bool m_removed = false;
};
case Qt::DecorationRole:
if (column == 0)
return m_item.decoration();
break;
case Qt::ToolTipRole:
return m_item.validityMessage();
case IdRole:
return m_item.id();
case ProblemRole:
return int(m_item.problem());
}
return QVariant();
}
// --------------------------------------------------------------------------
// DebuggerItemModel

View File

@@ -5,15 +5,15 @@
#include "debugger_global.h"
#include "debuggerconstants.h"
#include "debuggeritem.h"
#include <utils/filepath.h>
#include <utils/treemodel.h>
#include <QList>
namespace Debugger {
class DebuggerItem;
namespace DebuggerItemManager {
DEBUGGER_EXPORT void restoreDebuggers();
@@ -34,4 +34,25 @@ DEBUGGER_EXPORT const DebuggerItem *findById(const QVariant &id);
DEBUGGER_EXPORT const DebuggerItem *findByEngineType(DebuggerEngineType engineType);
} // DebuggerItemManager
namespace Internal {
class DebuggerTreeItem : public Utils::TreeItem
{
public:
DebuggerTreeItem(const DebuggerItem &item, bool changed)
: m_item(item), m_orig(item), m_added(changed), m_changed(changed)
{}
static const inline int IdRole = Qt::UserRole;
static const inline int ProblemRole = Qt::UserRole + 1;
QVariant data(int column, int role) const override;
DebuggerItem m_item; // Displayed, possibly unapplied data.
DebuggerItem m_orig; // Stored original data.
bool m_added;
bool m_changed;
bool m_removed = false;
};
} // Internal
} // Debugger

View File

@@ -22,7 +22,7 @@
#include <QComboBox>
#include <utility>
#include <algorithm>
using namespace ProjectExplorer;
using namespace Utils;
@@ -35,6 +35,98 @@ namespace Debugger {
namespace Internal {
class DebuggerItemListModel : public TreeModel<TreeItem, DebuggerTreeItem>
{
public:
DebuggerItemListModel(const Kit &kit, QObject *parent)
: TreeModel(parent)
, m_kit(kit)
{}
QModelIndex indexForId(const QVariant &id) const
{
// The "None" item always comes last
const auto noneIndex = [this] { return index(rowCount() - 1, 0); };
if (id.isNull())
return noneIndex();
const TreeItem *const item = findItemAtLevel<1>(
[id](TreeItem *item) { return item->data(0, DebuggerTreeItem::IdRole) == id; });
return item ? indexForItem(item) : noneIndex();
}
void reset()
{
clear();
const IDeviceConstPtr device = BuildDeviceKitAspect::device(&m_kit);
const Utils::FilePath rootPath = device->rootPath();
const QList<DebuggerItem> debuggersForBuildDevice
= Utils::filtered(DebuggerItemManager::debuggers(), [&](const DebuggerItem &item) {
if (item.isGeneric())
return device->id() != ProjectExplorer::Constants::DESKTOP_DEVICE_ID;
return item.command().isSameDevice(rootPath);
});
for (const DebuggerItem &item : debuggersForBuildDevice)
rootItem()->appendChild(new DebuggerTreeItem(item, false));
DebuggerItem noneItem;
noneItem.setUnexpandedDisplayName(Tr::tr("None"));
rootItem()->appendChild(new DebuggerTreeItem(noneItem, false));
}
private:
const Kit &m_kit;
};
class DebuggerItemSortModel : public SortModel
{
public:
DebuggerItemSortModel(QObject *parent) : SortModel(parent) {}
QModelIndex indexForId(const QVariant &id) const
{
return mapFromSource(
static_cast<DebuggerItemListModel *>(sourceModel())->indexForId(id));
}
void reset() { static_cast<DebuggerItemListModel *>(sourceModel())->reset(); }
private:
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override
{
const auto source = static_cast<DebuggerItemListModel *>(sourceModel());
const auto item1 = static_cast<DebuggerTreeItem *>(source->itemForIndex(source_left));
const auto item2 = static_cast<DebuggerTreeItem *>(source->itemForIndex(source_right));
QTC_ASSERT(item1 && item2, return false);
// Criterion 1: "None" comes last
if (!item1->data(0, DebuggerTreeItem::IdRole).isValid())
return false;
if (!item2->data(0, DebuggerTreeItem::IdRole).isValid())
return true;
// Criterion 2: Invalid items come after valid ones with warnings, which come
// after valid ones without warnings.
if (const QVariant &p1 = item1->data(0, DebuggerTreeItem::ProblemRole),
&p2 = item2->data(0, DebuggerTreeItem::ProblemRole);
p1 != p2) {
const auto problem1 = static_cast<DebuggerItem::Problem>(p1.toInt());
const auto problem2 = static_cast<DebuggerItem::Problem>(p2.toInt());
if (problem1 == DebuggerItem::Problem::None
|| problem2 == DebuggerItem::Problem::NoEngine) {
return true;
}
if (problem2 == DebuggerItem::Problem::None
|| problem1 == DebuggerItem::Problem::NoEngine) {
return false;
}
}
// Criterion 3: Name.
return SortModel::lessThan(source_left, source_right);
}
};
class DebuggerKitAspectImpl final : public KitAspect
{
public:
@@ -46,16 +138,16 @@ public:
m_comboBox = createSubWidget<QComboBox>();
m_comboBox->setSizePolicy(QSizePolicy::Ignored, m_comboBox->sizePolicy().verticalPolicy());
m_comboBox->setEnabled(true);
const auto sortModel = new DebuggerItemSortModel(this);
sortModel->setSourceModel(new DebuggerItemListModel(*workingCopy, this));
m_comboBox->setModel(sortModel);
refresh();
m_comboBox->setToolTip(factory->description());
connect(m_comboBox, &QComboBox::currentIndexChanged, this, [this] {
if (m_ignoreChanges.isLocked())
return;
int currentIndex = m_comboBox->currentIndex();
QVariant id = m_comboBox->itemData(currentIndex);
m_kit->setValue(DebuggerKitAspect::id(), id);
m_kit->setValue(DebuggerKitAspect::id(), currentId());
});
}
@@ -81,34 +173,16 @@ private:
void refresh() override
{
const GuardLocker locker(m_ignoreChanges);
m_comboBox->clear();
m_comboBox->addItem(Tr::tr("None"), QString());
IDeviceConstPtr device = BuildDeviceKitAspect::device(kit());
const Utils::FilePath path = device->rootPath();
const QList<DebuggerItem> debuggersForBuildDevice
= Utils::filtered(DebuggerItemManager::debuggers(), [path](const DebuggerItem &item) {
return item.command().isSameDevice(path);
});
for (const DebuggerItem &item : debuggersForBuildDevice)
m_comboBox->addItem(item.displayName(), item.id());
const DebuggerItem *item = DebuggerKitAspect::debugger(m_kit);
updateComboBox(item ? item->id() : QVariant());
const auto sortModel = static_cast<DebuggerItemSortModel *>(m_comboBox->model());
sortModel->reset();
sortModel->sort(0);
const DebuggerItem * const item = DebuggerKitAspect::debugger(m_kit);
m_comboBox->setCurrentIndex(sortModel->indexForId(item ? item->id() : QVariant()).row());
}
QVariant currentId() const { return m_comboBox->itemData(m_comboBox->currentIndex()); }
void updateComboBox(const QVariant &id)
QVariant currentId() const
{
for (int i = 0; i < m_comboBox->count(); ++i) {
if (id == m_comboBox->itemData(i)) {
m_comboBox->setCurrentIndex(i);
return;
}
}
m_comboBox->setCurrentIndex(0);
return m_comboBox->itemData(m_comboBox->currentIndex(), DebuggerTreeItem::IdRole);
}
Guard m_ignoreChanges;