TreeModel: Take responsibility for some of the casting

This adds a templated layer on top of TreeModel that can specify
item types for the top three layers in the model, relieving user
code from some of the previously necessary type casting.

Two common setups get an extra layer with convenience functions
on top: TwoLevelTreeModel for two-level model with a first level
of static headers and a uniform second level, and UniformTreeModel
where all non-root nodes are the same.

"Untyped" plain TreeModels are still possible.

The walkTree() feature and untyped iteration in the base
TreeItem and TreeModel is retained for now to ease transition
in downstream modules, but is planned to be removed soon.

Change-Id: I67d75a1a4e18e8f254dbfb458db03510d8990d8b
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
hjk
2016-05-27 11:12:03 +02:00
parent ded0b1c4f5
commit 7a80f2f01e
13 changed files with 267 additions and 130 deletions

View File

@@ -351,7 +351,6 @@ public:
void reinitialize(bool includeInspectData = false);
WatchItem *findItem(const QByteArray &iname) const;
const WatchItem *watchItem(const QModelIndex &idx) const;
void reexpandItems();
@@ -368,7 +367,6 @@ public:
bool m_contentsValid;
bool m_resetLocationScheduled;
WatchItem *root() const { return static_cast<WatchItem *>(rootItem()); }
WatchItem *m_localsRoot; // Not owned.
WatchItem *m_inspectorRoot; // Not owned.
WatchItem *m_watchRoot; // Not owned.
@@ -394,8 +392,7 @@ WatchModel::WatchModel(WatchHandler *handler, DebuggerEngine *engine)
m_contentsValid = true; // FIXME
m_resetLocationScheduled = false;
setHeader(QStringList() << tr("Name") << tr("Value") << tr("Type"));
auto root = new WatchItem;
setHeader({ tr("Name"), tr("Value"), tr("Type") });
m_localsRoot = new WatchItem;
m_localsRoot->iname = "local";
m_localsRoot->name = tr("Locals");
@@ -411,12 +408,12 @@ WatchModel::WatchModel(WatchHandler *handler, DebuggerEngine *engine)
m_tooltipRoot = new WatchItem;
m_tooltipRoot->iname = "tooltip";
m_tooltipRoot->name = tr("Tooltip");
auto root = rootItem();
root->appendChild(m_localsRoot);
root->appendChild(m_inspectorRoot);
root->appendChild(m_watchRoot);
root->appendChild(m_returnRoot);
root->appendChild(m_tooltipRoot);
setRootItem(root);
m_requestUpdateTimer.setSingleShot(true);
connect(&m_requestUpdateTimer, &QTimer::timeout,
@@ -444,12 +441,7 @@ void WatchModel::reinitialize(bool includeInspectData)
WatchItem *WatchModel::findItem(const QByteArray &iname) const
{
return root()->findItem(iname);
}
const WatchItem *WatchModel::watchItem(const QModelIndex &idx) const
{
return static_cast<WatchItem *>(itemForIndex(idx));
return findNonRooItem([iname](WatchItem *item) { return item->iname == iname; });
}
static QByteArray parentName(const QByteArray &iname)
@@ -912,7 +904,7 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
l.append(indexForItem(item));
return QVariant::fromValue(l);
}
const WatchItem *item = watchItem(idx);
const WatchItem *item = nonRootItemForIndex(idx);
if (!item)
return QVariant();
@@ -1074,7 +1066,7 @@ Qt::ItemFlags WatchModel::flags(const QModelIndex &idx) const
if (!idx.isValid())
return 0;
const WatchItem *item = watchItem(idx);
const WatchItem *item = nonRootItemForIndex(idx);
if (!item)
return Qt::ItemIsEnabled|Qt::ItemIsSelectable;
@@ -1140,7 +1132,7 @@ bool WatchModel::canFetchMore(const QModelIndex &idx) const
return false;
// See "hasChildren" below.
const WatchItem *item = watchItem(idx);
const WatchItem *item = nonRootItemForIndex(idx);
if (!item)
return false;
if (!item->wantsChildren)
@@ -1155,7 +1147,7 @@ void WatchModel::fetchMore(const QModelIndex &idx)
if (!idx.isValid())
return;
WatchItem *item = static_cast<WatchItem *>(itemForIndex(idx));
WatchItem *item = nonRootItemForIndex(idx);
if (item) {
m_expandedINames.insert(item->iname);
if (item->children().isEmpty()) {
@@ -1167,7 +1159,7 @@ void WatchModel::fetchMore(const QModelIndex &idx)
bool WatchModel::hasChildren(const QModelIndex &idx) const
{
const WatchItem *item = watchItem(idx);
const WatchItem *item = nonRootItemForIndex(idx);
if (!item)
return true;
if (item->rowCount() > 0)
@@ -1310,7 +1302,7 @@ bool WatchHandler::insertItem(WatchItem *item)
item->update();
item->walkTree([this](TreeItem *sub) { m_model->showEditValue(static_cast<WatchItem *>(sub)); });
item->forAllChildren<WatchItem *>([this](WatchItem *sub) { m_model->showEditValue(sub); });
return !found;
}
@@ -1344,10 +1336,8 @@ void WatchHandler::removeAllData(bool includeInspectData)
void WatchHandler::resetValueCache()
{
m_model->m_valueCache.clear();
TreeItem *root = m_model->rootItem();
root->walkTree([this, root](TreeItem *item) {
auto watchItem = static_cast<WatchItem *>(item);
m_model->m_valueCache[watchItem->iname] = watchItem->value;
m_model->forAllItems([this](WatchItem *item) {
m_model->m_valueCache[item->iname] = item->value;
});
}
@@ -1361,13 +1351,13 @@ void WatchHandler::notifyUpdateStarted(const QList<QByteArray> &inames)
auto marker = [](TreeItem *it) { static_cast<WatchItem *>(it)->outdated = true; };
if (inames.isEmpty()) {
m_model->forEachItemAtLevel<WatchItem *>(2, [marker](WatchItem *item) {
item->walkTree(marker);
m_model->forSecondLevelItems([marker](WatchItem *item) {
item->forAllChildren<WatchItem *>(marker);
});
} else {
foreach (auto iname, inames) {
for (auto iname : inames) {
if (WatchItem *item = m_model->findItem(iname))
item->walkTree(marker);
item->forAllChildren<WatchItem *>(marker);
}
}
@@ -1378,23 +1368,16 @@ void WatchHandler::notifyUpdateStarted(const QList<QByteArray> &inames)
void WatchHandler::notifyUpdateFinished()
{
struct OutDatedItemsFinder : public TreeItemVisitor
{
bool preVisit(TreeItem *item)
{
auto watchItem = static_cast<WatchItem *>(item);
if (level() <= 1 || !watchItem->outdated)
return true;
toRemove.append(watchItem);
QList<WatchItem *> toRemove;
m_model->forSelectedItems([this, &toRemove](WatchItem *item) {
if (item->outdated) {
toRemove.append(item);
return false;
}
return true;
});
QList<WatchItem *> toRemove;
} finder;
m_model->root()->walkTree(&finder);
foreach (auto item, finder.toRemove)
foreach (auto item, toRemove)
delete m_model->takeItem(item);
m_model->m_contentsValid = true;
@@ -1840,21 +1823,16 @@ void WatchHandler::addTypeFormats(const QByteArray &type, const DisplayFormats &
m_model->m_reportedTypeFormats.insert(QLatin1String(stripForFormat(type)), formats);
}
static void showInEditorHelper(const WatchItem *item, QTextStream &ts, int depth)
{
const QChar tab = QLatin1Char('\t');
const QChar nl = QLatin1Char('\n');
ts << QString(depth, tab) << item->name << tab << displayValue(item) << tab
<< item->type << nl;
foreach (const TreeItem *child, item->children())
showInEditorHelper(static_cast<const WatchItem *>(child), ts, depth + 1);
}
QString WatchHandler::editorContents()
{
QString contents;
QTextStream ts(&contents);
showInEditorHelper(m_model->root(), ts, 0);
m_model->forAllItems([&ts](WatchItem *item) {
const QChar tab = QLatin1Char('\t');
const QChar nl = QLatin1Char('\n');
ts << QString(item->level(), tab) << item->name << tab << displayValue(item) << tab
<< item->type << nl;
});
return contents;
}