File indexing completed on 2025-01-05 05:14:40
0001 /* 0002 SPDX-FileCopyrightText: 2021 Hamed Masafi <hamed.masfi@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-3.0-or-later 0005 */ 0006 0007 #include "treemodel.h" 0008 0009 #include "kommit_appdebug.h" 0010 #include <QModelIndex> 0011 0012 #include <KLocalizedString> 0013 0014 const QString &TreeModel::separator() const 0015 { 0016 return mSeparator; 0017 } 0018 0019 void TreeModel::setSeparator(const QString &newSeparator) 0020 { 0021 mSeparator = newSeparator; 0022 } 0023 0024 bool TreeModel::lastPartAsData() const 0025 { 0026 return mLastPartAsData; 0027 } 0028 0029 void TreeModel::setLastPartAsData(bool newLastPartAsData) 0030 { 0031 mLastPartAsData = newLastPartAsData; 0032 } 0033 0034 const QIcon &TreeModel::defaultIcon() const 0035 { 0036 return mDefaultIcon; 0037 } 0038 0039 void TreeModel::setDefaultIcon(const QIcon &newDefaultIcon) 0040 { 0041 mDefaultIcon = newDefaultIcon; 0042 } 0043 0044 void TreeModel::clear() 0045 { 0046 beginRemoveRows(QModelIndex(), 0, mRootNode->childs.count() - 1); 0047 qDeleteAll(mRootNode->childs); 0048 mRootNode->childs.clear(); 0049 endRemoveRows(); 0050 } 0051 0052 TreeModel::TreeModel(QObject *parent) 0053 : QAbstractItemModel(parent) 0054 , mRootNode(new Node) 0055 { 0056 } 0057 0058 QModelIndex TreeModel::index(const Node *node, int col) const 0059 { 0060 if (node->parent) 0061 return index(node->row, col, index(node->parent, col)); 0062 0063 return index(node->row, col, QModelIndex()); 0064 } 0065 0066 int TreeModel::rowCount(const QModelIndex &parent) const 0067 { 0068 Node *parentItem; 0069 if (parent.column() > 0) 0070 return 0; 0071 0072 if (!parent.isValid()) 0073 parentItem = mRootNode; 0074 else 0075 parentItem = static_cast<Node *>(parent.internalPointer()); 0076 0077 return parentItem->childs.count(); 0078 } 0079 0080 int TreeModel::columnCount(const QModelIndex &parent) const 0081 { 0082 Q_UNUSED(parent) 0083 return 1; 0084 } 0085 0086 QVariant TreeModel::data(const QModelIndex &index, int role) const 0087 { 0088 if (!index.isValid()) 0089 return {}; 0090 0091 if (role == Qt::DisplayRole && index.column() == 0) { 0092 Node *item = static_cast<Node *>(index.internalPointer()); 0093 0094 return item->title; 0095 } else if (role == Qt::DecorationRole) { 0096 return mDefaultIcon; 0097 } 0098 0099 return {}; 0100 } 0101 0102 QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const 0103 { 0104 if (!hasIndex(row, column, parent)) 0105 return {}; 0106 0107 Node *parentItem; 0108 0109 if (!parent.isValid()) 0110 parentItem = mRootNode; 0111 else 0112 parentItem = static_cast<Node *>(parent.internalPointer()); 0113 0114 Node *childItem = parentItem->childs.at(row); 0115 if (childItem) 0116 return createIndex(row, column, childItem); 0117 return {}; 0118 } 0119 0120 QModelIndex TreeModel::parent(const QModelIndex &child) const 0121 { 0122 if (!child.isValid()) 0123 return {}; 0124 0125 Node *childItem = static_cast<Node *>(child.internalPointer()); 0126 Node *parentItem = childItem->parent; 0127 0128 if (parentItem == mRootNode) 0129 return {}; 0130 0131 return createIndex(parentItem->row, 0, parentItem); 0132 } 0133 0134 QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int role) const 0135 { 0136 if (role != Qt::DisplayRole) 0137 return {}; 0138 0139 if (orientation == Qt::Horizontal) { 0140 if (section == 0) 0141 return i18n("Name"); 0142 else 0143 return i18n("Status"); 0144 } else { 0145 return section + 1; 0146 } 0147 } 0148 0149 QStringList TreeModel::rootData() const 0150 { 0151 return mRootNode->data; 0152 } 0153 0154 QStringList TreeModel::data(const QModelIndex &index) const 0155 { 0156 return static_cast<Node *>(index.internalPointer())->data; 0157 } 0158 0159 QString TreeModel::fullPath(const QModelIndex &index) const 0160 { 0161 QString path; 0162 0163 if (index.isValid()) 0164 getFullPath(path, static_cast<Node *>(index.internalPointer())); 0165 else 0166 getFullPath(path, mRootNode); 0167 0168 return path; 0169 } 0170 0171 QString TreeModel::key(const QModelIndex &index) const 0172 { 0173 auto node = static_cast<Node *>(index.internalPointer()); 0174 if (node) 0175 return node->key; 0176 return {}; 0177 } 0178 0179 QString TreeModel::section(const QModelIndex &index) const 0180 { 0181 auto node = static_cast<Node *>(index.internalPointer()); 0182 if (node) 0183 return node->prefix; 0184 return {}; 0185 } 0186 0187 void TreeModel::sortItems() 0188 { 0189 beginResetModel(); 0190 sortNode(mRootNode); 0191 endResetModel(); 0192 } 0193 0194 void TreeModel::addData(const QStringList &data, const QString &prefix, bool split) 0195 { 0196 for (const auto &p : data) { 0197 auto path = p; 0198 path = path.remove(QLatin1Char('\r')).remove(QLatin1Char('\n')).trimmed(); 0199 if (path.isEmpty()) 0200 continue; 0201 0202 TreeModel::Node *node; 0203 0204 if (split) { 0205 auto nodePath = path; 0206 if (!prefix.isEmpty()) 0207 nodePath.prepend(prefix + mSeparator); 0208 0209 auto parts = nodePath.split(mSeparator); 0210 if (mLastPartAsData) { 0211 auto data = parts.takeLast(); 0212 if (mShowRoot) 0213 node = createPath(QStringList() << mSeparator << parts); 0214 else 0215 node = createPath(parts); 0216 0217 if (mShowRoot && node != mRootNode) 0218 node->data.append(data); 0219 auto nodePathParts = nodePath.split(mSeparator); 0220 nodePathParts.takeLast(); 0221 node->key = nodePathParts.join(mSeparator); 0222 } else { 0223 node = createPath(parts); 0224 node->key = path; 0225 } 0226 } else { 0227 if (!prefix.isEmpty()) 0228 node = createPath({prefix, path}); 0229 else 0230 node = createPath({path}); 0231 node->key = path; 0232 } 0233 if (node) { 0234 node->prefix = prefix; 0235 } 0236 } 0237 beginInsertRows(QModelIndex(), 0, mRootNode->childs.count() - 1); 0238 endInsertRows(); 0239 } 0240 0241 TreeModel::Node *TreeModel::find(QStringList &path, Node *node) 0242 { 0243 if (path.empty()) 0244 return nullptr; 0245 0246 auto ch = node->find(path.first()); 0247 if (!ch) 0248 return nullptr; 0249 0250 auto p = path; 0251 p.removeFirst(); 0252 return find(p, ch); 0253 } 0254 0255 TreeModel::Node *TreeModel::createPath(const QStringList &path) 0256 { 0257 Node *parent = mRootNode; 0258 for (const auto &p : path) { 0259 auto child = parent->find(p); 0260 if (!child) { 0261 child = parent->createChild(); 0262 child->title = p; 0263 } 0264 parent = child; 0265 } 0266 return parent; 0267 } 0268 0269 void TreeModel::getFullPath(QString &path, Node *node) const 0270 { 0271 if (mShowRoot && node == mRootNode) 0272 return; 0273 if (node) { 0274 path.prepend(node->title); 0275 0276 if ((mShowRoot && node->parent->parent != mRootNode) || (!mShowRoot && node->parent != mRootNode)) { 0277 path.prepend(mSeparator); 0278 getFullPath(path, node->parent); 0279 } 0280 } 0281 } 0282 0283 void TreeModel::sortNode(Node *node) 0284 { 0285 qCDebug(KOMMIT_LOG) << "Sorting" << node->title; 0286 std::sort(node->childs.begin(), node->childs.end(), [](Node *l, Node *r) { 0287 if (l->childs.empty() && !r->childs.empty()) 0288 return false; 0289 if (!l->childs.empty() && r->childs.empty()) 0290 return true; 0291 return l->title < r->title; 0292 }); 0293 for (auto &n : node->childs) 0294 sortNode(n); 0295 } 0296 0297 bool TreeModel::showRoot() const 0298 { 0299 return mShowRoot; 0300 } 0301 0302 void TreeModel::setShowRoot(bool newDefaultRoot) 0303 { 0304 mShowRoot = newDefaultRoot; 0305 } 0306 0307 #include "moc_treemodel.cpp"