2014-10-14 17:45:32 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2016-01-15 14:58:39 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2014-10-14 17:45:32 +02:00
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator.
|
|
|
|
|
**
|
|
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-15 14:58:39 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2014-10-14 17:45:32 +02:00
|
|
|
**
|
2016-01-15 14:58:39 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2014-10-14 17:45:32 +02:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2016-03-18 07:55:01 +01:00
|
|
|
#pragma once
|
2014-10-14 17:45:32 +02:00
|
|
|
|
|
|
|
|
#include "utils_global.h"
|
2015-01-08 13:27:30 +01:00
|
|
|
|
2014-10-14 17:45:32 +02:00
|
|
|
#include <QAbstractItemModel>
|
|
|
|
|
|
2015-01-09 10:32:17 +01:00
|
|
|
#include <functional>
|
|
|
|
|
|
2014-10-14 17:45:32 +02:00
|
|
|
namespace Utils {
|
|
|
|
|
|
2015-01-14 09:09:15 +01:00
|
|
|
class TreeModel;
|
|
|
|
|
|
2014-10-14 17:45:32 +02:00
|
|
|
class QTCREATOR_UTILS_EXPORT TreeItem
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
TreeItem();
|
2015-01-21 15:44:04 +01:00
|
|
|
explicit TreeItem(const QStringList &displays, int flags = Qt::ItemIsEnabled);
|
2014-10-14 17:45:32 +02:00
|
|
|
virtual ~TreeItem();
|
|
|
|
|
|
|
|
|
|
virtual TreeItem *parent() const { return m_parent; }
|
|
|
|
|
virtual TreeItem *child(int pos) const;
|
|
|
|
|
virtual int rowCount() const;
|
|
|
|
|
|
|
|
|
|
virtual QVariant data(int column, int role) const;
|
2015-01-13 13:46:15 +01:00
|
|
|
virtual bool setData(int column, const QVariant &data, int role);
|
2014-10-14 17:45:32 +02:00
|
|
|
virtual Qt::ItemFlags flags(int column) const;
|
|
|
|
|
|
2015-01-29 09:58:23 +01:00
|
|
|
virtual bool hasChildren() const;
|
2015-01-21 15:50:54 +01:00
|
|
|
virtual bool canFetchMore() const;
|
|
|
|
|
virtual void fetchMore() {}
|
|
|
|
|
|
2014-10-14 17:45:32 +02:00
|
|
|
void prependChild(TreeItem *item);
|
|
|
|
|
void appendChild(TreeItem *item);
|
2015-01-21 15:50:54 +01:00
|
|
|
void insertChild(int pos, TreeItem *item);
|
2015-01-14 09:09:15 +01:00
|
|
|
void removeChildren();
|
2015-03-19 12:42:53 +01:00
|
|
|
void sortChildren(const std::function<bool(const TreeItem *, const TreeItem *)> &cmp);
|
2015-01-14 09:09:15 +01:00
|
|
|
void update();
|
2015-03-11 16:24:01 +01:00
|
|
|
void updateColumn(int column);
|
2015-01-14 09:09:15 +01:00
|
|
|
void expand();
|
|
|
|
|
TreeItem *firstChild() const;
|
2014-12-19 08:44:20 +01:00
|
|
|
TreeItem *lastChild() const;
|
|
|
|
|
int level() const;
|
2014-10-14 17:45:32 +02:00
|
|
|
|
|
|
|
|
void setFlags(Qt::ItemFlags flags);
|
2015-04-22 14:49:14 +02:00
|
|
|
int childCount() const { return m_children.size(); }
|
|
|
|
|
TreeItem *childAt(int index) const { return m_children.at(index); }
|
2015-01-06 17:48:39 +01:00
|
|
|
QVector<TreeItem *> children() const { return m_children; }
|
2015-01-14 09:09:15 +01:00
|
|
|
QModelIndex index() const;
|
|
|
|
|
|
|
|
|
|
TreeModel *model() const { return m_model; }
|
2014-10-14 17:45:32 +02:00
|
|
|
|
2016-05-27 11:12:03 +02:00
|
|
|
template <class T, class Predicate>
|
|
|
|
|
void forSelectedChildren(const Predicate &pred) const {
|
|
|
|
|
foreach (TreeItem *item, m_children) {
|
|
|
|
|
if (pred(static_cast<T>(item)))
|
|
|
|
|
item->forSelectedChildren<T, Predicate>(pred);
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-01-29 09:58:23 +01:00
|
|
|
|
2016-05-27 11:12:03 +02:00
|
|
|
template <class T, typename Predicate>
|
|
|
|
|
void forAllChildren(const Predicate &pred) const {
|
|
|
|
|
foreach (TreeItem *item, m_children) {
|
|
|
|
|
pred(static_cast<T>(item));
|
|
|
|
|
item->forAllChildren<T, Predicate>(pred);
|
2016-05-04 16:41:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-27 11:12:03 +02:00
|
|
|
// Levels are 1-based: Child at Level 1 is an immediate child.
|
|
|
|
|
template <class T, typename Predicate>
|
|
|
|
|
void forFirstLevelChildren(Predicate pred) {
|
|
|
|
|
foreach (TreeItem *item, m_children)
|
|
|
|
|
pred(static_cast<T>(item));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class T, typename Predicate>
|
|
|
|
|
void forSecondLevelChildren(Predicate pred) {
|
|
|
|
|
foreach (TreeItem *item1, m_children)
|
|
|
|
|
foreach (TreeItem *item2, item1->m_children)
|
|
|
|
|
pred(static_cast<T>(item2));
|
2016-05-04 16:41:15 +02:00
|
|
|
}
|
|
|
|
|
|
2016-05-27 11:12:03 +02:00
|
|
|
template <class T, typename Predicate>
|
|
|
|
|
T findFirstLevelChild(Predicate pred) const {
|
|
|
|
|
foreach (TreeItem *item, m_children)
|
|
|
|
|
if (pred(static_cast<T>(item)))
|
|
|
|
|
return static_cast<T>(item);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class T, typename Predicate>
|
|
|
|
|
T findSecondLevelChild(Predicate pred) const {
|
|
|
|
|
foreach (TreeItem *item1, m_children)
|
|
|
|
|
foreach (TreeItem *item2, item1->children())
|
|
|
|
|
if (pred(static_cast<T>(item2)))
|
|
|
|
|
return static_cast<T>(item2);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class T, typename Predicate>
|
|
|
|
|
T findAnyChild(Predicate pred) const {
|
|
|
|
|
foreach (TreeItem *item, m_children) {
|
|
|
|
|
if (pred(static_cast<T>(item)))
|
|
|
|
|
return static_cast<T>(item);
|
|
|
|
|
if (T found = item->findAnyChild<T>(pred))
|
|
|
|
|
return found;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-14 17:45:32 +02:00
|
|
|
private:
|
|
|
|
|
TreeItem(const TreeItem &) Q_DECL_EQ_DELETE;
|
|
|
|
|
void operator=(const TreeItem &) Q_DECL_EQ_DELETE;
|
|
|
|
|
|
|
|
|
|
void clear();
|
2015-01-16 15:24:53 +01:00
|
|
|
void propagateModel(TreeModel *m);
|
2014-10-14 17:45:32 +02:00
|
|
|
|
|
|
|
|
TreeItem *m_parent; // Not owned.
|
2015-01-14 09:09:15 +01:00
|
|
|
TreeModel *m_model; // Not owned.
|
2014-12-19 08:44:20 +01:00
|
|
|
QStringList *m_displays;
|
2014-10-14 17:45:32 +02:00
|
|
|
Qt::ItemFlags m_flags;
|
2014-12-19 08:44:20 +01:00
|
|
|
|
2016-06-09 15:26:33 +02:00
|
|
|
protected:
|
|
|
|
|
QVector<TreeItem *> m_children; // Owned.
|
2014-12-19 08:44:20 +01:00
|
|
|
friend class TreeModel;
|
2014-10-14 17:45:32 +02:00
|
|
|
};
|
|
|
|
|
|
2016-06-09 15:26:33 +02:00
|
|
|
// A TreeItem with children all of the same type.
|
|
|
|
|
template <class ChildType>
|
|
|
|
|
class TypedTreeItem : public TreeItem
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
void sortChildren(const std::function<bool(const ChildType *, const ChildType *)> &lessThan)
|
|
|
|
|
{
|
|
|
|
|
return TreeItem::sortChildren([lessThan](const TreeItem *a, const TreeItem *b) {
|
|
|
|
|
return lessThan(static_cast<const ChildType *>(a), static_cast<const ChildType *>(b));
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename Predicate>
|
|
|
|
|
void forAllChildren(const Predicate &pred) const {
|
|
|
|
|
return TreeItem::forAllChildren<ChildType *, Predicate>(pred);
|
|
|
|
|
}
|
2016-06-10 17:03:21 +02:00
|
|
|
|
|
|
|
|
template <typename Predicate>
|
|
|
|
|
ChildType *findFirstLevelChild(Predicate pred) const {
|
|
|
|
|
return TreeItem::findFirstLevelChild<ChildType *, Predicate>(pred);
|
|
|
|
|
}
|
2016-06-09 15:26:33 +02:00
|
|
|
};
|
|
|
|
|
|
2016-05-27 11:12:03 +02:00
|
|
|
// A general purpose multi-level model where each item can have its
|
|
|
|
|
// own (TreeItem-derived) type.
|
2014-10-14 17:45:32 +02:00
|
|
|
class QTCREATOR_UTILS_EXPORT TreeModel : public QAbstractItemModel
|
|
|
|
|
{
|
2015-01-14 09:09:15 +01:00
|
|
|
Q_OBJECT
|
|
|
|
|
|
2014-10-14 17:45:32 +02:00
|
|
|
public:
|
|
|
|
|
explicit TreeModel(QObject *parent = 0);
|
2015-01-16 15:24:53 +01:00
|
|
|
explicit TreeModel(TreeItem *root, QObject *parent = 0);
|
2016-05-02 08:28:42 +02:00
|
|
|
~TreeModel() override;
|
2014-10-14 17:45:32 +02:00
|
|
|
|
2015-04-22 14:49:14 +02:00
|
|
|
void setHeader(const QStringList &displays);
|
2015-06-11 15:40:30 +02:00
|
|
|
void setHeaderToolTip(const QStringList &tips);
|
2015-04-22 14:49:14 +02:00
|
|
|
void clear();
|
|
|
|
|
|
|
|
|
|
TreeItem *rootItem() const;
|
|
|
|
|
void setRootItem(TreeItem *item);
|
|
|
|
|
TreeItem *itemForIndex(const QModelIndex &) const;
|
|
|
|
|
QModelIndex indexForItem(const TreeItem *needle) const;
|
|
|
|
|
|
|
|
|
|
int topLevelItemCount() const;
|
2016-05-02 08:28:42 +02:00
|
|
|
int rowCount(const QModelIndex &idx = QModelIndex()) const override;
|
|
|
|
|
int columnCount(const QModelIndex &idx) const override;
|
|
|
|
|
|
|
|
|
|
bool setData(const QModelIndex &idx, const QVariant &data, int role) override;
|
|
|
|
|
QVariant data(const QModelIndex &idx, int role) const override;
|
|
|
|
|
QModelIndex index(int, int, const QModelIndex &idx = QModelIndex()) const override;
|
|
|
|
|
QModelIndex parent(const QModelIndex &idx) const override;
|
|
|
|
|
Qt::ItemFlags flags(const QModelIndex &idx) const override;
|
|
|
|
|
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
|
|
|
|
bool hasChildren(const QModelIndex &idx) const override;
|
|
|
|
|
|
|
|
|
|
bool canFetchMore(const QModelIndex &idx) const override;
|
|
|
|
|
void fetchMore(const QModelIndex &idx) override;
|
2015-01-21 15:50:54 +01:00
|
|
|
|
2016-05-27 11:12:03 +02:00
|
|
|
TreeItem *takeItem(TreeItem *item); // item is not destroyed.
|
2015-01-09 10:32:17 +01:00
|
|
|
|
2015-01-14 09:09:15 +01:00
|
|
|
signals:
|
|
|
|
|
void requestExpansion(QModelIndex);
|
|
|
|
|
|
2016-05-27 11:12:03 +02:00
|
|
|
protected:
|
2015-01-14 09:09:15 +01:00
|
|
|
friend class TreeItem;
|
|
|
|
|
|
2014-10-14 17:45:32 +02:00
|
|
|
TreeItem *m_root; // Owned.
|
2015-01-16 15:24:53 +01:00
|
|
|
QStringList m_header;
|
2015-06-11 15:40:30 +02:00
|
|
|
QStringList m_headerToolTip;
|
2015-01-16 15:24:53 +01:00
|
|
|
int m_columnCount;
|
2014-10-14 17:45:32 +02:00
|
|
|
};
|
|
|
|
|
|
2016-05-27 11:12:03 +02:00
|
|
|
// A multi-level model with uniform types per level.
|
|
|
|
|
// All items below second level have to have identitical types.
|
|
|
|
|
template <class FirstLevelItem,
|
|
|
|
|
class SecondLevelItem = FirstLevelItem,
|
|
|
|
|
class RootItem = TreeItem>
|
|
|
|
|
class LeveledTreeModel : public TreeModel
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
explicit LeveledTreeModel(QObject *parent = 0) : TreeModel(parent) {}
|
|
|
|
|
explicit LeveledTreeModel(RootItem *root, QObject *parent = 0) : TreeModel(root, parent) {}
|
|
|
|
|
|
|
|
|
|
template <class Predicate>
|
|
|
|
|
void forFirstLevelItems(const Predicate &pred) const {
|
|
|
|
|
m_root->forFirstLevelChildren<FirstLevelItem *>(pred);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class Predicate>
|
|
|
|
|
void forSecondLevelItems(const Predicate &pred) const {
|
|
|
|
|
m_root->forSecondLevelChildren<SecondLevelItem *>(pred);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class Predicate>
|
|
|
|
|
FirstLevelItem *findFirstLevelItem(const Predicate &pred) const {
|
|
|
|
|
return m_root->findFirstLevelChild<FirstLevelItem *>(pred);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class Predicate>
|
|
|
|
|
SecondLevelItem *findSecondLevelItem(const Predicate &pred) const {
|
|
|
|
|
return m_root->findSecondLevelChild<SecondLevelItem *>(pred);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RootItem *rootItem() const {
|
|
|
|
|
return static_cast<RootItem *>(TreeModel::rootItem());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FirstLevelItem *firstLevelItemForIndex(const QModelIndex &idx) const {
|
|
|
|
|
TreeItem *item = TreeModel::itemForIndex(idx);
|
|
|
|
|
return item && item->level() == 1 ? static_cast<FirstLevelItem *>(item) : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SecondLevelItem *secondLevelItemForIndex(const QModelIndex &idx) const {
|
|
|
|
|
TreeItem *item = TreeModel::itemForIndex(idx);
|
|
|
|
|
return item && item->level() == 2 ? static_cast<SecondLevelItem *>(item) : 0;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// A two-level model with a first level of static headers and a uniform second level.
|
|
|
|
|
template <class SecondLevelItemType>
|
|
|
|
|
class TwoLevelTreeModel : public LeveledTreeModel<TreeItem, SecondLevelItemType>
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
using FirstLevelItem = TreeItem;
|
|
|
|
|
using SecondLevelItem = SecondLevelItemType;
|
|
|
|
|
using BaseType = LeveledTreeModel<FirstLevelItem, SecondLevelItem>;
|
|
|
|
|
|
|
|
|
|
explicit TwoLevelTreeModel(QObject *parent = 0) : BaseType(parent) {}
|
|
|
|
|
|
|
|
|
|
FirstLevelItem *appendFirstLevelItem(const QStringList &display) {
|
|
|
|
|
auto item = new FirstLevelItem(display);
|
|
|
|
|
this->rootItem()->appendChild(item);
|
|
|
|
|
return item;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// A model where all non-root nodes are the same.
|
|
|
|
|
template <class ItemType>
|
|
|
|
|
class UniformTreeModel : public LeveledTreeModel<ItemType, ItemType, ItemType>
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
using BaseType = LeveledTreeModel<ItemType, ItemType, ItemType>;
|
|
|
|
|
|
|
|
|
|
explicit UniformTreeModel(QObject *parent = 0) : BaseType(parent) {}
|
|
|
|
|
|
|
|
|
|
ItemType *nonRootItemForIndex(const QModelIndex &idx) const {
|
|
|
|
|
TreeItem *item = TreeModel::itemForIndex(idx);
|
|
|
|
|
return item && item->parent() ? static_cast<ItemType *>(item) : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class Predicate>
|
|
|
|
|
ItemType *findNonRooItem(const Predicate &pred) const {
|
|
|
|
|
TreeItem *root = this->rootItem();
|
|
|
|
|
return root->findAnyChild<ItemType *>(pred);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class Predicate>
|
|
|
|
|
void forSelectedItems(const Predicate &pred) const {
|
|
|
|
|
TreeItem *root = this->rootItem();
|
|
|
|
|
root->forSelectedChildren<ItemType *, Predicate>(pred);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class Predicate>
|
|
|
|
|
void forAllItems(const Predicate &pred) const {
|
|
|
|
|
TreeItem *root = this->rootItem();
|
|
|
|
|
root->forAllChildren<ItemType *, Predicate>(pred);
|
|
|
|
|
}
|
2016-06-09 15:34:48 +02:00
|
|
|
|
|
|
|
|
ItemType *itemForIndex(const QModelIndex &idx) const {
|
|
|
|
|
return static_cast<ItemType *>(BaseType::itemForIndex(idx));
|
|
|
|
|
}
|
2016-05-27 11:12:03 +02:00
|
|
|
};
|
|
|
|
|
|
2014-10-14 17:45:32 +02:00
|
|
|
} // namespace Utils
|