File indexing completed on 2024-04-28 15:35:52
0001 // SPDX-FileCopyrightText: 2023 Carl Schwan <carl@carlschwan.eu> 0002 // SPDX-License-Identifier: LGPL-2.1-only or LGPL-3.0-only or LicenseRef-KDE-Accepted-LGPL 0003 0004 #include "tableofcontentmodel.h" 0005 #include <QJsonArray> 0006 #include <QJsonDocument> 0007 #include <QJsonObject> 0008 0009 TreeItem::TreeItem(const QString &title, const QString &href, const QString &id, const QJsonArray &childs, TreeItem *parent) 0010 : m_parentItem(parent) 0011 , m_title(title) 0012 , m_href(href) 0013 , m_id(id) 0014 { 0015 for (const auto &jsonEntry : childs) { 0016 const auto value = jsonEntry.toObject(); 0017 auto child = std::make_unique<TreeItem>(value[QStringLiteral("label")].toString(), 0018 value[QStringLiteral("href")].toString(), 0019 value[QStringLiteral("id")].toString(), 0020 value[QStringLiteral("subitems")].toArray(), 0021 this); 0022 appendChild(std::move(child)); 0023 } 0024 } 0025 0026 void TreeItem::clear() 0027 { 0028 m_childItems.clear(); 0029 } 0030 0031 void TreeItem::appendChild(std::unique_ptr<TreeItem> &&item) 0032 { 0033 m_childItems.push_back(std::move(item)); 0034 } 0035 0036 TreeItem *TreeItem::child(int row) 0037 { 0038 if (row < 0 || row >= m_childItems.size()) { 0039 return nullptr; 0040 } 0041 return m_childItems.at(row).get(); 0042 } 0043 0044 int TreeItem::childCount() const 0045 { 0046 return m_childItems.size(); 0047 } 0048 0049 int TreeItem::row() const 0050 { 0051 if (m_parentItem) { 0052 const auto it = std::find_if(m_parentItem->m_childItems.cbegin(), m_parentItem->m_childItems.cend(), [this](const std::unique_ptr<TreeItem> &treeItem) { 0053 return treeItem.get() == const_cast<TreeItem *>(this); 0054 }); 0055 0056 if (it != m_parentItem->m_childItems.cend()) { 0057 return std::distance(m_parentItem->m_childItems.cbegin(), it); 0058 } 0059 Q_ASSERT(false); // should not happen 0060 return -1; 0061 } 0062 0063 return 0; 0064 } 0065 0066 QVariant TreeItem::data(int role) const 0067 { 0068 switch (role) { 0069 case Qt::DisplayRole: 0070 case TableOfContentModel::TitleRole: 0071 return m_title; 0072 case TableOfContentModel::HrefRole: 0073 return m_href; 0074 case TableOfContentModel::IdRole: 0075 return m_id; 0076 default: 0077 return {}; 0078 } 0079 }; 0080 0081 TreeItem *TreeItem::parentItem() 0082 { 0083 return m_parentItem; 0084 } 0085 0086 TableOfContentModel::TableOfContentModel(QObject *parent) 0087 : QAbstractItemModel(parent) 0088 , m_rootItem(std::make_unique<TreeItem>(QString{}, QString{}, QString{}, QJsonArray{})) 0089 { 0090 } 0091 0092 QHash<int, QByteArray> TableOfContentModel::roleNames() const 0093 { 0094 return { 0095 {TitleRole, "title"}, 0096 {HrefRole, "href"}, 0097 {IdRole, "id"}, 0098 }; 0099 } 0100 0101 QModelIndex TableOfContentModel::index(int row, int column, const QModelIndex &parent) const 0102 { 0103 if (!hasIndex(row, column, parent)) { 0104 return {}; 0105 } 0106 0107 TreeItem *parentItem; 0108 0109 if (!parent.isValid()) { 0110 parentItem = m_rootItem.get(); 0111 } else { 0112 parentItem = static_cast<TreeItem *>(parent.internalPointer()); 0113 } 0114 0115 auto childItem = parentItem->child(row); 0116 if (childItem) { 0117 return createIndex(row, column, childItem); 0118 } 0119 return {}; 0120 } 0121 0122 QModelIndex TableOfContentModel::parent(const QModelIndex &index) const 0123 { 0124 if (!index.isValid()) { 0125 return {}; 0126 } 0127 0128 auto childItem = static_cast<TreeItem *>(index.internalPointer()); 0129 auto parentItem = childItem->parentItem(); 0130 0131 if (parentItem == m_rootItem.get()) { 0132 return {}; 0133 } 0134 0135 return createIndex(parentItem->row(), 0, parentItem); 0136 } 0137 0138 int TableOfContentModel::rowCount(const QModelIndex &parent) const 0139 { 0140 TreeItem *parentItem; 0141 if (parent.column() > 0) { 0142 return 0; 0143 } 0144 if (!parent.isValid()) { 0145 parentItem = m_rootItem.get(); 0146 } else { 0147 parentItem = static_cast<TreeItem *>(parent.internalPointer()); 0148 } 0149 0150 return parentItem->childCount(); 0151 } 0152 0153 int TableOfContentModel::columnCount(const QModelIndex &parent) const 0154 { 0155 Q_UNUSED(parent) 0156 return 1; 0157 } 0158 0159 QVariant TableOfContentModel::data(const QModelIndex &index, int role) const 0160 { 0161 Q_ASSERT(checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid)); 0162 0163 auto item = static_cast<TreeItem *>(index.internalPointer()); 0164 0165 return item->data(role); 0166 } 0167 0168 void TableOfContentModel::importFromJson(const QByteArray &json) 0169 { 0170 auto doc = QJsonDocument::fromJson(json); 0171 Q_ASSERT(doc.isArray()); 0172 0173 const auto jsonEntries = doc.array(); 0174 0175 beginResetModel(); 0176 m_rootItem->clear(); 0177 for (const auto &jsonEntry : jsonEntries) { 0178 const auto value = jsonEntry.toObject(); 0179 m_rootItem->appendChild(std::make_unique<TreeItem>(value[QStringLiteral("label")].toString(), 0180 value[QStringLiteral("href")].toString(), 0181 value[QStringLiteral("id")].toString(), 0182 value[QStringLiteral("subitems")].toArray(), 0183 m_rootItem.get())); 0184 } 0185 endResetModel(); 0186 } 0187 0188 #include "moc_tableofcontentmodel.cpp"