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"