qt5base-lts/tests/benchmarks/gui/graphicsview/functional/GraphicsViewBenchmark/widgets/abstractitemview.cpp
Jason McDonald c5303517c3 Remove redundant #ifdef's from benchmarks
Preprocessor directives that refer to QT_VERSION's less than Qt 5 are
redundant in the qt5 modules.

Change-Id: Id3a9c5f0ba07b72d1c99e51c12a240570bf0d58e
Reviewed-by: Rohan McGovern
2011-05-19 14:54:16 +10:00

442 lines
13 KiB
C++

/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QGraphicsLayout>
#include "abstractitemview.h"
#include "abstractviewitem.h"
#include "scrollbar.h"
AbstractItemView::AbstractItemView(QGraphicsWidget *parent)
: AbstractScrollArea(parent),
m_model(0),
m_rootIndex(),
m_container(0),
m_selectionModel(0),
m_currentIndex(),
m_scroller()
{
setRootIndex(QModelIndex());
}
/*virtual*/
AbstractItemView::~AbstractItemView()
{
}
/*virtual*/
void AbstractItemView::setModel(QAbstractItemModel *model, AbstractViewItem *prototype)
{
if( m_model == model || !model)
return;
if (m_model) {
disconnect(m_model, SIGNAL(destroyed()),
this, SLOT(_q_modelDestroyed()));
disconnect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
this, SLOT( dataChanged(QModelIndex,QModelIndex)));
disconnect(m_model, SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(rowsInserted(QModelIndex,int,int)));
disconnect(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
this, SLOT(rowsRemoved(QModelIndex,int,int)));
disconnect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)));
disconnect(m_model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
this, SLOT(rowsAboutToBeInserted(QModelIndex,int,int)));
disconnect(m_model, SIGNAL(columnsInserted(QModelIndex,int,int)),
this, SLOT(columnsInserted(QModelIndex,int,int)));
disconnect(m_model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
this, SLOT(columnsAboutToBeInserted(QModelIndex,int,int)));
disconnect(m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
this, SLOT(columnsRemoved(QModelIndex,int,int)));
disconnect(m_model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
this, SLOT(columnsAboutToBeRemoved(QModelIndex,int,int)));
disconnect(m_model, SIGNAL(modelReset()), this, SLOT(reset()));
disconnect(m_model, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged()));
m_model = 0;
}
setSelectionModel(0);
m_currentIndex = QModelIndex();
m_rootIndex = QModelIndex();
m_model = model;
Q_ASSERT_X(m_model->index(0,0) == m_model->index(0,0),
"AbstractItemView::setModel",
"A model should return the exact same index "
"(including its internal id/pointer) when asked for it twice in a row.");
Q_ASSERT_X(m_model->index(0,0).parent() == QModelIndex(),
"AbstractItemView::setModel",
"The parent of a top level index should be invalid");
connect(m_model, SIGNAL(destroyed()), this, SLOT(modelDestroyed()));
connect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
this, SLOT( dataChanged(QModelIndex,QModelIndex)));
connect(m_model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
this, SLOT(rowsAboutToBeInserted(QModelIndex,int,int)));
connect(m_model, SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(rowsInserted(QModelIndex,int,int)));
connect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)));
connect(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
this, SLOT(rowsRemoved(QModelIndex,int,int)));
connect(m_model, SIGNAL(modelReset()), this, SLOT(reset()));
connect(m_model, SIGNAL(layoutChanged()), this, SLOT(layoutChanged()));
setSelectionModel(new QItemSelectionModel(m_model));
if (prototype && m_container) {
m_container->setItemPrototype(prototype);
m_container->reset();
}
}
/*virtual*/
void AbstractItemView::setContainer(AbstractItemContainer *container)
{
m_container = container;
m_container->setItemView(this);
m_container->setParentItem(viewport());
viewport()->setFlag(
QGraphicsItem::ItemClipsChildrenToShape, true);
m_scroller.setScrollable(this);
installEventFilter(&m_scroller);
}
/*virtual*/
void AbstractItemView::setRootIndex(const QModelIndex &index)
{
m_rootIndex = index;
// TODO fix this if we change index, container should be updated? Or do we need root index?
}
/*virtual*/
int AbstractItemView::indexCount() const
{
if (m_model)
return m_model->rowCount(m_rootIndex);
return 0;
}
/*virtual*/
QAbstractItemModel* AbstractItemView::model() const
{
return m_model;
}
/*virtual*/
QModelIndex AbstractItemView::nextIndex(const QModelIndex &index) const
{
if (!m_model)
return QModelIndex();
if (index.isValid())
return m_model->index(index.row() + 1, 0, m_rootIndex);
else
return m_model->index(0, 0, m_rootIndex);
}
/*virtual*/
QModelIndex AbstractItemView::previousIndex(const QModelIndex &index) const
{
if (!m_model)
return QModelIndex();
if (index.isValid())
return m_model->index(index.row() - 1, 0, m_rootIndex);
else
return m_model->index(m_model->rowCount(m_rootIndex) - 1, 0, m_rootIndex);
}
/*virtual*/
void AbstractItemView::setItemPrototype(AbstractViewItem* prototype)
{
if (prototype && m_container) {
m_container->setItemPrototype(prototype);
m_container->reset();
}
}
void AbstractItemView::setSelectionModel(QItemSelectionModel *smodel)
{
if (smodel && smodel->model() != m_model) {
return;
}
if (m_selectionModel) {
disconnect(m_selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
this, SLOT(currentSelectionChanged(QItemSelection, QItemSelection)));
disconnect(m_selectionModel, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
this, SLOT(currentIndexChanged(QModelIndex, QModelIndex)));
delete m_selectionModel;
m_selectionModel = 0;
}
m_selectionModel = smodel;
if (m_selectionModel) {
connect(m_selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
this, SLOT(currentSelectionChanged(QItemSelection, QItemSelection)));
connect(m_selectionModel, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
this, SLOT(currentIndexChanged(QModelIndex, QModelIndex)));
}
}
/*virtual*/
void AbstractItemView::currentIndexChanged(const QModelIndex &current, const QModelIndex &previous)
{
Q_UNUSED(previous)
if (current != m_currentIndex)
m_currentIndex = current;
}
/*virtual*/
void AbstractItemView::currentSelectionChanged(const QItemSelection &selected,
const QItemSelection &deselected)
{
Q_UNUSED(selected)
Q_UNUSED(deselected)
}
/*virtual*/
void AbstractItemView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
Q_UNUSED(topLeft)
Q_UNUSED(bottomRight)
// TODO implement if we like to edit view items.
}
/*virtual*/
void AbstractItemView::rowsAboutToBeInserted(const QModelIndex &index, int start, int end)
{
Q_UNUSED(index)
Q_UNUSED(start)
Q_UNUSED(end)
// TODO implement
}
/*virtual*/
void AbstractItemView::rowsAboutToBeRemoved(const QModelIndex &index,int start, int end)
{
Q_UNUSED(index)
Q_UNUSED(start)
Q_UNUSED(end)
}
/*virtual*/
void AbstractItemView::rowsRemoved(const QModelIndex &parent,int start, int end)
{
Q_UNUSED(parent)
Q_UNUSED(start)
Q_UNUSED(end)
if (start <= m_currentIndex.row() && m_currentIndex.row() <= end) {
QModelIndex newCurrentIndex = m_model->index(start, 0, m_rootIndex);
if (!newCurrentIndex.isValid()) {
newCurrentIndex = m_model->index(qMax(0,start - 1), 0, m_rootIndex);
}
if (m_selectionModel) {
m_selectionModel->setCurrentIndex(newCurrentIndex, QItemSelectionModel::NoUpdate);
}
}
for (int i = end; i >= start; --i) //The items are already removed from the model.
m_container->removeItem(QModelIndex()); // Indexes are already invalid.
}
/*virtual*/
void AbstractItemView::reset()
{
m_rootIndex = QModelIndex();
if (m_container)
m_container->reset();
setCurrentIndex(QModelIndex());
ScrollBar *sb = verticalScrollBar();
if (sb)
sb->setSliderSize(0);
}
/*virtual*/
void AbstractItemView::rowsInserted(const QModelIndex &parent, int start, int end)
{
if (!m_container)
return;
for (int i = start; i <= end; ++i)
m_container->addItem(m_model->index(i, 0, parent));
refreshContainerGeometry();
}
/*virtual*/
void AbstractItemView::modelDestroyed()
{
m_model = 0;
setSelectionModel(0);
reset();
}
/*virtual*/
void AbstractItemView::layoutChanged()
{
m_container->reset();
}
bool AbstractItemView::event(QEvent *e)
{
bool result = AbstractScrollArea::event(e);
if (e && e->type()==QEvent::LayoutRequest) {
refreshContainerGeometry();
result = true;
}
if (e && e->type()==QEvent::GraphicsSceneResize) {
m_scroller.stopScrolling();
refreshContainerGeometry();
m_container->resize(this->size().width()-verticalScrollBar()->size().width(),
m_container->preferredHeight());
if(verticalScrollBar()->sliderPosition() > verticalScrollBar()->sliderSize())
verticalScrollBar()->setSliderPosition(verticalScrollBar()->sliderSize());
result = true;
}
return result;
}
void AbstractItemView::setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags selectionFlag)
{
if (m_selectionModel)
m_selectionModel->setCurrentIndex(index, selectionFlag);
}
void AbstractItemView::refreshContainerGeometry()
{
if (!m_container || !m_model)
return;
if (m_container->layout() && !m_container->layout()->isActivated())
m_container->layout()->activate();
ScrollBar *sb = verticalScrollBar();
if (sb) {
AbstractViewItem *item = m_container->itemAt(0);
if (item) {
qreal oneItemH = item->size().height();
sb->setSliderSize(oneItemH*m_model->rowCount(m_rootIndex)-size().height());
}
if (!sb->isVisible() && verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff &&
contentsRect().height() < m_container->boundingRect().height())
sb->show();
}
}
void AbstractItemView::scrollContentsBy(qreal dx, qreal dy)
{
AbstractScrollArea::scrollContentsBy(dx, dy);
if (!viewport() || !m_container || (m_container && m_container->itemCount() <= 0) ||
!m_model || (m_model && m_model->rowCount() <= 0) ||
(viewport() && viewport()->boundingRect().height() < contentsRect().height()))
return;
qreal itemH = 1;
AbstractViewItem *item = m_container->itemAt(0);
if(item && item->size().height() > 1) {
itemH = item->size().height();
}
else if(item && item->preferredHeight() > 1) {
itemH = item->preferredHeight();
}
qreal vpx = m_container->pos().x();
qreal vpy = m_container->pos().y();
if ((vpy+m_container->size().height()-dy > pos().y()+size().height()) &&
(qAbs(dy) < itemH) && (vpy-dy <= 0)) {
m_container->setPos(vpx, vpy-dy);
}
else {
qreal vPos = verticalScrollBar()->sliderPosition();
int startRow = m_model->index(vPos/itemH, 0).row();
int itemsInContainer = m_container->itemCount();
for (int i = 0; i<itemsInContainer; ++i) {
AbstractViewItem *changedItem = m_container->itemAt(i);
changedItem->setModelIndex(m_model->index(startRow+i,0));
m_container->setListItemCaching(listItemCaching(), i);
}
qreal diff = vPos-startRow*itemH;
if (diff < 0)
m_container->setPos(vpx, diff);
else
m_container->setPos(vpx, -diff);
}
}
void AbstractItemView::changeTheme()
{
if (m_container)
m_container->themeChange();
}
void AbstractItemView::updateViewContent()
{
if (m_container)
m_container->updateContent();
}