File indexing completed on 2024-12-22 04:40:11

0001 /*
0002     SPDX-FileCopyrightText: 2007-2009 Sergio Pistone <sergio_pistone@yahoo.com.ar>
0003     SPDX-FileCopyrightText: 2010-2022 Mladen Milinkovic <max@smoothware.net>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "treeview.h"
0009 
0010 #include <QTimer>
0011 #include <QScrollBar>
0012 
0013 TreeView::TreeView(QWidget *parent) :
0014     QTreeView(parent),
0015     m_updateGeometriesTimer(new QTimer(this)),
0016     m_currentModelRows(-1),
0017     m_instantGeometryUpdate(0)
0018 {
0019     // NOTE: The updateGeometries() methods takes forever to execute (around 100ms
0020     // for a view with more that 1 thousand items, and more as more items are added).
0021     // The culprit is the updateGeometries() method in QHeaderView which takes a lot
0022     // of time when there are columns with ResizeToContents mode set.
0023     // To workaround this, we reimplement the updateGeometries method to (re)start a
0024     // timer that invoques the real work only on timeout (reported as BUG 234368 at Qt).
0025     // To further refine our hack, we only delay the geometries update when the model's
0026     // "has rows" (imaginary) property hasn't changed since last geometries update.
0027     // This works very well in our case because the columns with ResizeToContents enabled
0028     // have items of the same size and so their geometries only change with "has rows" state.
0029 
0030     m_updateGeometriesTimer->setInterval(200);
0031     m_updateGeometriesTimer->setSingleShot(true);
0032 
0033     connect(m_updateGeometriesTimer, &QTimer::timeout, this, &TreeView::onUpdateGeometriesTimeout);
0034 }
0035 
0036 TreeView::~TreeView()
0037 {}
0038 
0039 void
0040 TreeView::setModel(QAbstractItemModel *newModel)
0041 {
0042     if(model()) {
0043         disconnect(model(), &QAbstractItemModel::dataChanged, viewport(), QOverload<>::of(&QWidget::update));
0044         disconnect(model(), &QAbstractItemModel::rowsAboutToBeInserted, this, &TreeView::onRowsAboutToBeInserted);
0045         disconnect(model(), &QAbstractItemModel::rowsAboutToBeRemoved, this, &TreeView::onRowsAboutToBeRemoved);
0046     }
0047 
0048     QTreeView::setModel(newModel);
0049 
0050     if(newModel) {
0051         m_currentModelRows = newModel->rowCount();
0052         connect(newModel, &QAbstractItemModel::dataChanged, viewport(), QOverload<>::of(&QWidget::update));
0053         connect(newModel, &QAbstractItemModel::rowsAboutToBeInserted, this, &TreeView::onRowsAboutToBeInserted);
0054         connect(newModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &TreeView::onRowsAboutToBeRemoved);
0055     } else {
0056         m_currentModelRows = -1;
0057     }
0058 }
0059 
0060 void
0061 TreeView::onRowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
0062 {
0063     if(!parent.isValid()) {
0064         m_instantGeometryUpdate = m_currentModelRows == 0 ? 1 : 0;
0065         m_currentModelRows += end - start + 1;
0066     }
0067 }
0068 
0069 void
0070 TreeView::onRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
0071 {
0072     if(!parent.isValid()) {
0073         m_currentModelRows -= end - start + 1;
0074         m_instantGeometryUpdate = m_currentModelRows == 0 ? 1 : 0;
0075     }
0076 }
0077 
0078 void
0079 TreeView::updateGeometries()
0080 {
0081     if(m_instantGeometryUpdate--)
0082         QTreeView::updateGeometries();
0083     else
0084         m_updateGeometriesTimer->start();
0085 }
0086 
0087 void
0088 TreeView::onUpdateGeometriesTimeout()
0089 {
0090     QTreeView::updateGeometries();
0091 }
0092 
0093