File indexing completed on 2024-05-12 04:37:37

0001 /*
0002     SPDX-FileCopyrightText: 2008 Vladimir Prus <ghost@cs.msu.su>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "treeitem.h"
0008 
0009 #include <QModelIndex>
0010 
0011 #include <debug.h>
0012 #include "treemodel.h"
0013 
0014 using namespace KDevelop;
0015 
0016 TreeItem::TreeItem(TreeModel* model, TreeItem *parent)
0017 : model_(model), more_(false), ellipsis_(nullptr), expanded_(false)
0018 {
0019     parentItem = parent;
0020 }
0021 
0022 TreeItem::~TreeItem()
0023 {
0024     const auto copy = childItems;
0025     for (TreeItem* it : copy) {
0026         delete it;
0027     }
0028     delete ellipsis_;
0029 }
0030 
0031 void TreeItem::setData(const QVector<QVariant> &data)
0032 {
0033     itemData=data;
0034 }
0035 
0036 void TreeItem::appendChild(TreeItem *item, bool initial)
0037 {
0038     QModelIndex index = model_->indexForItem(this, 0);
0039 
0040     // Note that we need emit beginRemoveRows, even if we're replacing
0041     // ellipsis item with the real one.  The number of rows does not change
0042     // with the result, but the last item is different.  The address of the
0043     // item is stored inside QModelIndex, so just replacing the item, and
0044     // deleting the old one, will lead to crash.
0045     if (more_)
0046     {
0047         if (!initial)
0048             model_->beginRemoveRows(index, childItems.size(), childItems.size());
0049         more_ = false;
0050         delete ellipsis_;
0051         ellipsis_ = nullptr;
0052         if (!initial)
0053             model_->endRemoveRows();
0054     }
0055 
0056     if (!initial)
0057         model_->beginInsertRows(index, childItems.size(), childItems.size());
0058     childItems.append(item);
0059     if (!initial)
0060         model_->endInsertRows();
0061 }
0062 
0063 void TreeItem::insertChild(int position, TreeItem *child, bool initial)
0064 {
0065     QModelIndex index = model_->indexForItem(this, 0);
0066 
0067     if (!initial)
0068         model_->beginInsertRows(index, position, position);
0069     childItems.insert(position, child);
0070     if (!initial)
0071         model_->endInsertRows();
0072 }
0073 
0074 void TreeItem::reportChange()
0075 {
0076     QModelIndex index = model_->indexForItem(this, 0);
0077     QModelIndex index2 = model_->indexForItem(this, itemData.size()-1);
0078     emit model_->dataChanged(index, index2);
0079 }
0080 
0081 void KDevelop::TreeItem::reportChange(int column)
0082 {
0083     QModelIndex index = model_->indexForItem(this, column);
0084     emit model_->dataChanged(index, index);
0085 }
0086 
0087 
0088 void TreeItem::removeChild(int index)
0089 {
0090     QModelIndex modelIndex = model_->indexForItem(this, 0);
0091 
0092     model_->beginRemoveRows(modelIndex, index, index);
0093     childItems.erase(childItems.begin() + index);
0094     model_->endRemoveRows();
0095 }
0096 
0097 void TreeItem::removeSelf()
0098 {
0099     QModelIndex modelIndex = model_->indexForItem(this, 0);
0100     parentItem->removeChild(modelIndex.row());
0101 }
0102 
0103 void TreeItem::deleteChildren()
0104 {
0105     QVector<TreeItem*> copy = childItems;
0106     clear();
0107     // Only delete the children after removing them
0108     // from model.  Otherwise, the model will touch
0109     // deleted things, with undefined results.
0110     qDeleteAll(copy);
0111 }
0112 
0113 void TreeItem::clear()
0114 {
0115     if (!childItems.isEmpty() || more_)
0116     {
0117         QModelIndex index = model_->indexForItem(this, 0);
0118         model_->beginRemoveRows(index, 0, childItems.size()-1+more_);
0119         childItems.clear();
0120         more_ = false;
0121         delete ellipsis_;
0122         ellipsis_ = nullptr;
0123         model_->endRemoveRows();
0124     }
0125 }
0126 
0127 TreeItem *TreeItem::child(int row)
0128 {
0129     if (row < childItems.size())
0130         return childItems.value(row);
0131     else if (row == childItems.size() && more_)
0132         return ellipsis_;
0133     else
0134         return nullptr;
0135 
0136 }
0137 
0138 int TreeItem::childCount() const
0139 {
0140     return childItems.count() + more_;
0141 }
0142 
0143 int TreeItem::columnCount() const
0144 {
0145     return itemData.count();
0146 }
0147 
0148 QVariant TreeItem::data(int column, int role) const
0149 {
0150     if (role == Qt::DecorationRole)
0151         return icon(column);
0152     else if (role==Qt::DisplayRole || role == Qt::EditRole)
0153         return itemData.value(column);
0154     return QVariant();
0155 }
0156 
0157 TreeItem *TreeItem::parent()
0158 {
0159     return parentItem;
0160 }
0161 
0162 int TreeItem::row() const
0163 {
0164     if (parentItem)
0165         return parentItem->childItems.indexOf(const_cast<TreeItem*>(this));
0166 
0167     return 0;
0168 }
0169 
0170 class EllipsisItem : public TreeItem
0171 {
0172     Q_OBJECT
0173 public:
0174     EllipsisItem(TreeModel *model, TreeItem *parent)
0175     : TreeItem(model, parent)
0176     {
0177         const int dataCount = model->columnCount(QModelIndex());
0178         QVector<QVariant> data;
0179         data.reserve(dataCount);
0180         data.push_back(QVariant(QStringLiteral("...")));
0181         for (int i = 1; i < dataCount; ++i)
0182             data.push_back(QString());
0183         setData(data);
0184     }
0185 
0186     void clicked() override
0187     {
0188         qCDebug(DEBUGGER) << "Ellipsis item clicked";
0189         /* FIXME: restore
0190            Q_ASSERT (parentItem->hasMore()); */
0191         parentItem->fetchMoreChildren();
0192     }
0193 
0194     void fetchMoreChildren() override {}
0195 };
0196 
0197 void TreeItem::setHasMore(bool more)
0198 {
0199     /* FIXME: this will crash if used in ctor of root item,
0200        where the model is not associated with item or something.  */
0201     QModelIndex index = model_->indexForItem(this, 0);
0202 
0203     if (more && !more_)
0204     {
0205         model_->beginInsertRows(index, childItems.size(), childItems.size());
0206         ellipsis_ = new EllipsisItem (model(), this);
0207         more_ = more;
0208         model_->endInsertRows();
0209     }
0210     else if (!more && more_)
0211     {
0212         model_->beginRemoveRows(index, childItems.size(), childItems.size());
0213         delete ellipsis_;
0214         ellipsis_ = nullptr;
0215         more_ = more;
0216         model_->endRemoveRows();
0217     }
0218 }
0219 
0220 void TreeItem::emitAllChildrenFetched()
0221 {
0222     emit allChildrenFetched();
0223 }
0224 
0225 void TreeItem::setHasMoreInitial(bool more)
0226 {
0227     more_ = more;
0228 
0229     if (more)
0230     {
0231         ellipsis_ = new EllipsisItem (model(), this);
0232     }
0233 }
0234 
0235 QVariant KDevelop::TreeItem::icon(int column) const
0236 {
0237     Q_UNUSED(column);
0238     return QVariant();
0239 }
0240 
0241 void KDevelop::TreeItem::setExpanded(bool b)
0242 {
0243     if (expanded_ != b) {
0244         expanded_ = b;
0245         if (expanded_) emit expanded();
0246         else emit collapsed();
0247     }
0248 }
0249 
0250 #include "treeitem.moc"
0251 #include "moc_treeitem.cpp"