1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2019 The Qt Company Ltd. 4 ** Contact: https://www.qt.io/licensing/ 5 ** 6 ** This file is part of Qt Creator. 7 ** 8 ** Commercial License Usage 9 ** Licensees holding valid commercial Qt licenses may use this file in 10 ** accordance with the commercial license agreement provided with the 11 ** Software or, alternatively, in accordance with the terms contained in 12 ** a written agreement between you and The Qt Company. For licensing terms 13 ** and conditions see https://www.qt.io/terms-conditions. For further 14 ** information use the contact form at https://www.qt.io/contact-us. 15 ** 16 ** GNU General Public License Usage 17 ** Alternatively, this file may be used under the terms of the GNU 18 ** General Public License version 3 as published by the Free Software 19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20 ** included in the packaging of this file. Please review the following 21 ** information to ensure the GNU General Public License requirements will 22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 23 ** 24 ****************************************************************************/ 25 26 #pragma once 27 28 #include "utils_global.h" 29 #include "treemodel.h" 30 31 namespace Utils { 32 33 template <class ChildType> 34 class BaseListModel : public TreeModel<TypedTreeItem<ChildType>, ChildType> 35 { 36 public: 37 using BaseModel = TreeModel<TypedTreeItem<ChildType>, ChildType>; 38 using BaseModel::rootItem; 39 BaseModel(parent)40 explicit BaseListModel(QObject *parent = nullptr) : BaseModel(parent) {} 41 itemCount()42 int itemCount() const { return rootItem()->childCount(); } itemAt(int row)43 ChildType *itemAt(int row) const { return rootItem()->childAt(row); } 44 appendItem(ChildType * item)45 void appendItem(ChildType *item) { rootItem()->appendChild(item); } 46 47 template <class Predicate> forItems(const Predicate & pred)48 void forItems(const Predicate &pred) const 49 { 50 rootItem()->forFirstLevelChildren(pred); 51 } 52 53 template <class Predicate> findItem(const Predicate & pred)54 ChildType *findItem(const Predicate &pred) const 55 { 56 return rootItem()->findFirstLevelChild(pred); 57 } 58 sortItems(const std::function<bool (const ChildType *,const ChildType *)> & lessThan)59 void sortItems(const std::function<bool(const ChildType *, const ChildType *)> &lessThan) 60 { 61 return rootItem()->sortChildren([lessThan](const TreeItem *a, const TreeItem *b) { 62 return lessThan(static_cast<const ChildType *>(a), static_cast<const ChildType *>(b)); 63 }); 64 } 65 indexOf(const ChildType * item)66 int indexOf(const ChildType *item) const { return rootItem()->indexOf(item); } 67 clear()68 void clear() { rootItem()->removeChildren(); } 69 begin()70 auto begin() const { return rootItem()->begin(); } end()71 auto end() const { return rootItem()->end(); } 72 }; 73 74 template <class ItemData> 75 class ListItem : public TreeItem 76 { 77 public: 78 ItemData itemData; 79 }; 80 81 template <class ItemData> 82 class ListModel : public BaseListModel<ListItem<ItemData>> 83 { 84 public: 85 using ChildType = ListItem<ItemData>; 86 using BaseModel = BaseListModel<ChildType>; 87 BaseModel(parent)88 explicit ListModel(QObject *parent = nullptr) : BaseModel(parent) {} 89 dataAt(int row)90 const ItemData &dataAt(int row) const 91 { 92 static const ItemData dummyData = {}; 93 auto item = BaseModel::itemAt(row); 94 return item ? item->itemData : dummyData; 95 } 96 findItemByData(const std::function<bool (const ItemData &)> & pred)97 ChildType *findItemByData(const std::function<bool(const ItemData &)> &pred) const 98 { 99 return BaseModel::rootItem()->findFirstLevelChild([pred](ChildType *child) { 100 return pred(child->itemData); 101 }); 102 } 103 destroyItems(const std::function<bool (const ItemData &)> & pred)104 void destroyItems(const std::function<bool(const ItemData &)> &pred) 105 { 106 QList<ChildType *> toDestroy; 107 BaseModel::rootItem()->forFirstLevelChildren([pred, &toDestroy](ChildType *item) { 108 if (pred(item->itemData)) 109 toDestroy.append(item); 110 }); 111 for (ChildType *item : toDestroy) 112 this->destroyItem(item); 113 } 114 findData(const std::function<bool (const ItemData &)> & pred)115 ItemData *findData(const std::function<bool(const ItemData &)> &pred) const 116 { 117 ChildType *item = findItemByData(pred); 118 return item ? &item->itemData : nullptr; 119 } 120 findIndex(const std::function<bool (const ItemData &)> & pred)121 QModelIndex findIndex(const std::function<bool(const ItemData &)> &pred) const 122 { 123 ChildType *item = findItemByData(pred); 124 return item ? BaseTreeModel::indexForItem(item) : QModelIndex(); 125 } 126 allData()127 QList<ItemData> allData() const 128 { 129 QList<ItemData> res; 130 BaseModel::rootItem()->forFirstLevelChildren([&res](ChildType *child) { 131 res.append(child->itemData); 132 }); 133 return res; 134 } 135 setAllData(const QList<ItemData> & items)136 void setAllData(const QList<ItemData> &items) 137 { 138 BaseModel::rootItem()->removeChildren(); 139 for (const ItemData &data : items) 140 appendItem(data); 141 } 142 forAllData(const std::function<void (ItemData &)> & func)143 void forAllData(const std::function<void(ItemData &)> &func) const 144 { 145 BaseModel::rootItem()->forFirstLevelChildren([func](ChildType *child) { 146 func(child->itemData); 147 }); 148 } 149 appendItem(const ItemData & data)150 ChildType *appendItem(const ItemData &data) 151 { 152 auto item = new ChildType; 153 item->itemData = data; 154 BaseModel::rootItem()->appendChild(item); 155 return item; 156 } 157 data(const QModelIndex & idx,int role)158 QVariant data(const QModelIndex &idx, int role) const override 159 { 160 TreeItem *item = BaseModel::itemForIndex(idx); 161 if (item && item->parent() == BaseModel::rootItem()) 162 return itemData(static_cast<ChildType *>(item)->itemData, idx.column(), role); 163 return {}; 164 } 165 flags(const QModelIndex & idx)166 Qt::ItemFlags flags(const QModelIndex &idx) const override 167 { 168 TreeItem *item = BaseModel::itemForIndex(idx); 169 if (item && item->parent() == BaseModel::rootItem()) 170 return itemFlags(static_cast<ChildType *>(item)->itemData, idx.column()); 171 return {}; 172 } 173 174 using QAbstractItemModel::itemData; itemData(const ItemData & idata,int column,int role)175 virtual QVariant itemData(const ItemData &idata, int column, int role) const 176 { 177 if (m_dataAccessor) 178 return m_dataAccessor(idata, column, role); 179 return {}; 180 } 181 itemFlags(const ItemData & idata,int column)182 virtual Qt::ItemFlags itemFlags(const ItemData &idata, int column) const 183 { 184 if (m_flagsAccessor) 185 return m_flagsAccessor(idata, column); 186 return Qt::ItemIsEnabled | Qt::ItemIsSelectable; 187 } 188 setDataAccessor(const std::function<QVariant (const ItemData &,int,int)> & accessor)189 void setDataAccessor(const std::function<QVariant(const ItemData &, int, int)> &accessor) 190 { 191 m_dataAccessor = accessor; 192 } 193 setFlagsAccessor(const std::function<Qt::ItemFlags (const ItemData &,int)> & accessor)194 void setFlagsAccessor(const std::function<Qt::ItemFlags(const ItemData &, int)> &accessor) 195 { 196 m_flagsAccessor = accessor; 197 } 198 199 private: 200 std::function<QVariant(const ItemData &, int, int)> m_dataAccessor; 201 std::function<Qt::ItemFlags(const ItemData &, int)> m_flagsAccessor; 202 }; 203 204 } // namespace Utils 205