From c902a2a58671e7d145f5e879d87100844bd20df4 Mon Sep 17 00:00:00 2001 From: Marcus Eggenberger Date: Thu, 16 Oct 2008 19:28:29 +0200 Subject: [PATCH 1/1] Spliting the functionality of setWidth into 3 separate functions for regular setWidth, firstClumnHandleChanged, secondClumnHandleChanged. Those functions are still similar, but this allows us to fine tune the individual process and allows us to drop unneeded geometryChange propagation. --- src/qtui/chatitem.cpp | 1 + src/qtui/chatitem.h | 7 --- src/qtui/chatline.cpp | 61 +++++++++++++------ src/qtui/chatline.h | 9 +-- src/qtui/chatscene.cpp | 129 +++++++++++++++++++++++------------------ src/qtui/chatscene.h | 8 ++- 6 files changed, 124 insertions(+), 91 deletions(-) diff --git a/src/qtui/chatitem.cpp b/src/qtui/chatitem.cpp index e72cbdc5..5d520e8c 100644 --- a/src/qtui/chatitem.cpp +++ b/src/qtui/chatitem.cpp @@ -272,6 +272,7 @@ ContentsChatItem::ContentsChatItem(const qreal &width, const QPointF &pos, QGrap qreal ContentsChatItem::setGeometryByWidth(qreal w) { if(w != width()) { + prepareGeometryChange(); setWidth(w); // compute height int lines = 1; diff --git a/src/qtui/chatitem.h b/src/qtui/chatitem.h index 5877040c..3ed2cee3 100644 --- a/src/qtui/chatitem.h +++ b/src/qtui/chatitem.h @@ -80,16 +80,13 @@ protected: // a) calling prepareGeometryChange() immediately before setColumns() // b) calling Chatline::setPos() immediately afterwards inline void setGeometry(qreal width, qreal height) { - prepareGeometryChange(); _boundingRect.setWidth(width); _boundingRect.setHeight(height); } inline void setHeight(const qreal &height) { - prepareGeometryChange(); _boundingRect.setHeight(height); } inline void setWidth(const qreal &width) { - prepareGeometryChange(); _boundingRect.setWidth(width); } @@ -179,10 +176,6 @@ private: void showWebPreview(const Clickable &click); void clearWebPreview(); - - // WARNING: setGeometry and setHeight should not be used without either: - // a) calling prepareGeometryChange() immediately before setColumns() - // b) calling Chatline::setPos() immediately afterwards qreal setGeometryByWidth(qreal w); friend class ChatLine; friend struct ContentsChatItemPrivate; diff --git a/src/qtui/chatline.cpp b/src/qtui/chatline.cpp index f0772b31..1ef2f374 100644 --- a/src/qtui/chatline.cpp +++ b/src/qtui/chatline.cpp @@ -68,43 +68,66 @@ ChatItem &ChatLine::item(ChatLineModel::ColumnType column) { } } -// WARNING: setColumns should not be used without either: -// a) calling prepareGeometryChange() immediately before setColumns() -// b) calling Chatline::setPos() immediately afterwards -// -// NOTE: senderPos and contentsPos are in ChatLines coordinate system! -qreal ChatLine::setColumns(const qreal ×tampWidth, const qreal &senderWidth, const qreal &contentsWidth, - const QPointF &senderPos, const QPointF &contentsPos) { - prepareGeometryChange(); +// NOTE: senderPos is in ChatLines coordinate system! +void ChatLine::setFirstColumn(const qreal ×tampWidth, const qreal &senderWidth, const QPointF &senderPos) { + _timestampItem.prepareGeometryChange(); + _timestampItem.setGeometry(timestampWidth, _height); + // senderItem doesn't need a geom change as it's Pos is changed (ensured by void ChatScene::firstHandlePositionChanged(qreal xpos)) + _senderItem.setGeometry(senderWidth, _height); + _senderItem.setPos(senderPos); + + _timestampItem.clearLayout(); + _senderItem.clearLayout(); +} + +// NOTE: contentsPos is in ChatLines coordinate system! +void ChatLine::setSecondColumn(const qreal &senderWidth, const qreal &contentsWidth, + const QPointF &contentsPos, qreal &linePos) { + // contentsItem doesn't need a geom change as it's Pos is changed (ensured by void ChatScene::firstHandlePositionChanged(qreal xpos)) qreal height = _contentsItem.setGeometryByWidth(contentsWidth); + linePos -= height; + bool needGeometryChange = linePos == pos().y() && height != _height; + + if(needGeometryChange) { + _timestampItem.prepareGeometryChange(); + _senderItem.prepareGeometryChange(); + } + _timestampItem.setHeight(height); _senderItem.setGeometry(senderWidth, height); - _timestampItem.setGeometry(timestampWidth, height); - _senderItem.setPos(senderPos); _contentsItem.setPos(contentsPos); - _contentsItem.clearLayout(); - _senderItem.clearLayout(); _timestampItem.clearLayout(); + _senderItem.clearLayout(); + if(needGeometryChange) + prepareGeometryChange(); _height = height; - return _height; + setPos(0, linePos); } -// WARNING: setGeometryByWidth should not be used without either: -// a) calling prepareGeometryChange() immediately before setColumns() -// b) calling Chatline::setPos() immediately afterwards -qreal ChatLine::setGeometryByWidth(const qreal &width, const qreal &contentsWidth) { - prepareGeometryChange(); +void ChatLine::setGeometryByWidth(const qreal &width, const qreal &contentsWidth, qreal &linePos) { qreal height = _contentsItem.setGeometryByWidth(contentsWidth); + linePos -= height; + bool needGeometryChange = linePos == pos().y(); + + if(needGeometryChange) { + _timestampItem.prepareGeometryChange(); + _senderItem.prepareGeometryChange(); + } _timestampItem.setHeight(height); _senderItem.setHeight(height); _contentsItem.clearLayout(); + + if(needGeometryChange) + prepareGeometryChange(); + _height = height; _width = width; - return _height; + + setPos(0, linePos); // set pos is _very_ cheap if nothing changes. } void ChatLine::setSelected(bool selected, ChatLineModel::ColumnType minColumn) { diff --git a/src/qtui/chatline.h b/src/qtui/chatline.h index dcf2e410..afdd380f 100644 --- a/src/qtui/chatline.h +++ b/src/qtui/chatline.h @@ -52,10 +52,11 @@ public: virtual void paint (QPainter * painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - // setColumns and setGeometryByWidth both return height - qreal setColumns(const qreal ×tampWidth, const qreal &senderWidth, const qreal &contentsWidth, - const QPointF &senderPos, const QPointF &contentsPos); - qreal setGeometryByWidth(const qreal &width, const qreal &contentsWidth); + void setFirstColumn(const qreal ×tampWidth, const qreal &senderWidth, const QPointF &senderPos); + // setSecondColumn and setGeometryByWidth both also relocate the chatline. + // the _bottom_ position is passed via linePos. linePos is updated to the top of the chatLine. + void setSecondColumn(const qreal &senderWidth, const qreal &contentsWidth, const QPointF &contentsPos, qreal &linePos); + void setGeometryByWidth(const qreal &width, const qreal &contentsWidth, qreal &linePos); void setSelected(bool selected, ChatLineModel::ColumnType minColumn = ChatLineModel::ContentsColumn); void setHighlighted(bool highlighted); diff --git a/src/qtui/chatscene.cpp b/src/qtui/chatscene.cpp index ff28ea4a..1adea58f 100644 --- a/src/qtui/chatscene.cpp +++ b/src/qtui/chatscene.cpp @@ -68,13 +68,13 @@ ChatScene::ChatScene(QAbstractItemModel *model, const QString &idString, qreal w _firstColHandle = new ColumnHandleItem(QtUi::style()->firstColumnSeparator()); addItem(_firstColHandle); _firstColHandle->setXPos(_firstColHandlePos); - connect(_firstColHandle, SIGNAL(positionChanged(qreal)), this, SLOT(handlePositionChanged(qreal))); + connect(_firstColHandle, SIGNAL(positionChanged(qreal)), this, SLOT(firstHandlePositionChanged(qreal))); connect(this, SIGNAL(sceneRectChanged(const QRectF &)), _firstColHandle, SLOT(sceneRectChanged(const QRectF &))); _secondColHandle = new ColumnHandleItem(QtUi::style()->secondColumnSeparator()); addItem(_secondColHandle); _secondColHandle->setXPos(_secondColHandlePos); - connect(_secondColHandle, SIGNAL(positionChanged(qreal)), this, SLOT(handlePositionChanged(qreal))); + connect(_secondColHandle, SIGNAL(positionChanged(qreal)), this, SLOT(secondHandlePositionChanged(qreal))); connect(this, SIGNAL(sceneRectChanged(const QRectF &)), _secondColHandle, SLOT(sceneRectChanged(const QRectF &))); setHandleXLimits(); @@ -295,48 +295,23 @@ void ChatScene::updateForViewport(qreal width, qreal height) { setWidth(width); } -// setWidth is used for 2 things: -// a) updating the scene to fit the width of the corresponding view -// b) to update the positions of the items if a columhandle has changed it's position -// forceReposition is true in the second case -// this method features some codeduplication for the sake of performance -void ChatScene::setWidth(qreal width, bool forceReposition) { - if(width == _sceneRect.width() && !forceReposition) +void ChatScene::setWidth(qreal width) { + if(width == _sceneRect.width()) return; -// clock_t startT = clock(); + // clock_t startT = clock(); // disabling the index while doing this complex updates is about // 2 to 10 times faster! setItemIndexMethod(QGraphicsScene::NoIndex); - qreal linePos = _sceneRect.y() + _sceneRect.height(); QList::iterator lineIter = _lines.end(); QList::iterator lineIterBegin = _lines.begin(); - ChatLine *line = 0; - qreal lineHeight = 0; + qreal linePos = _sceneRect.y() + _sceneRect.height(); qreal contentsWidth = width - secondColumnHandle()->sceneRight(); - - if(forceReposition) { - qreal timestampWidth = firstColumnHandle()->sceneLeft(); - qreal senderWidth = secondColumnHandle()->sceneLeft() - firstColumnHandle()->sceneRight(); - QPointF senderPos(firstColumnHandle()->sceneRight(), 0); - QPointF contentsPos(secondColumnHandle()->sceneRight(), 0); - while(lineIter != lineIterBegin) { - lineIter--; - line = *lineIter; - lineHeight = line->setColumns(timestampWidth, senderWidth, contentsWidth, senderPos, contentsPos); - linePos -= lineHeight; - line->setPos(0, linePos); - } - } else { - while(lineIter != lineIterBegin) { - lineIter--; - line = *lineIter; - lineHeight = line->setGeometryByWidth(width, contentsWidth); - linePos -= lineHeight; - line->setPos(0, linePos); - } + while(lineIter != lineIterBegin) { + lineIter--; + (*lineIter)->setGeometryByWidth(width, contentsWidth, linePos); } setItemIndexMethod(QGraphicsScene::BspTreeIndex); @@ -347,29 +322,72 @@ void ChatScene::setWidth(qreal width, bool forceReposition) { // qDebug() << "resized" << _lines.count() << "in" << (float)(endT - startT) / CLOCKS_PER_SEC << "sec"; } -void ChatScene::handlePositionChanged(qreal xpos) { - bool first = (sender() == _firstColHandle); - qreal oldx; - if(first) { - oldx = _firstColHandlePos; - _firstColHandlePos = xpos; - } else { - oldx = _secondColHandlePos; - _secondColHandlePos = xpos; - } +void ChatScene::firstHandlePositionChanged(qreal xpos) { + if(_firstColHandlePos == xpos) + return; + _firstColHandlePos = xpos; ChatViewSettings viewSettings(this); viewSettings.setValue("FirstColumnHandlePos", _firstColHandlePos); - viewSettings.setValue("SecondColumnHandlePos", _secondColHandlePos); - ChatViewSettings defaultSettings; defaultSettings.setValue("FirstColumnHandlePos", _firstColHandlePos); + + // clock_t startT = clock(); + + // disabling the index while doing this complex updates is about + // 2 to 10 times faster! + setItemIndexMethod(QGraphicsScene::NoIndex); + + QList::iterator lineIter = _lines.end(); + QList::iterator lineIterBegin = _lines.begin(); + qreal timestampWidth = firstColumnHandle()->sceneLeft(); + qreal senderWidth = secondColumnHandle()->sceneLeft() - firstColumnHandle()->sceneRight(); + QPointF senderPos(firstColumnHandle()->sceneRight(), 0); + + while(lineIter != lineIterBegin) { + lineIter--; + (*lineIter)->setFirstColumn(timestampWidth, senderWidth, senderPos); + } + setItemIndexMethod(QGraphicsScene::BspTreeIndex); + + setHandleXLimits(); + +// clock_t endT = clock(); +// qDebug() << "resized" << _lines.count() << "in" << (float)(endT - startT) / CLOCKS_PER_SEC << "sec"; +} + +void ChatScene::secondHandlePositionChanged(qreal xpos) { + if(_secondColHandlePos == xpos) + return; + + _secondColHandlePos = xpos; + ChatViewSettings viewSettings(this); + viewSettings.setValue("SecondColumnHandlePos", _secondColHandlePos); + ChatViewSettings defaultSettings; defaultSettings.setValue("SecondColumnHandlePos", _secondColHandlePos); - setWidth(width(), true); // readjust all chatlines - // we get ugly redraw errors if we don't update this explicitly... :( - // width() should be the same for both handles, so just use _firstColHandle regardless - //update(qMin(oldx, xpos), 0, qMax(oldx, xpos) + firstColHandle->width(), height()); + // clock_t startT = clock(); + + // disabling the index while doing this complex updates is about + // 2 to 10 times faster! + setItemIndexMethod(QGraphicsScene::NoIndex); + + QList::iterator lineIter = _lines.end(); + QList::iterator lineIterBegin = _lines.begin(); + qreal linePos = _sceneRect.y() + _sceneRect.height(); + qreal senderWidth = secondColumnHandle()->sceneLeft() - firstColumnHandle()->sceneRight(); + qreal contentsWidth = _sceneRect.width() - secondColumnHandle()->sceneRight(); + QPointF contentsPos(secondColumnHandle()->sceneRight(), 0); + while(lineIter != lineIterBegin) { + lineIter--; + (*lineIter)->setSecondColumn(senderWidth, contentsWidth, contentsPos, linePos); + } + setItemIndexMethod(QGraphicsScene::BspTreeIndex); + + setHandleXLimits(); + +// clock_t endT = clock(); +// qDebug() << "resized" << _lines.count() << "in" << (float)(endT - startT) / CLOCKS_PER_SEC << "sec"; } void ChatScene::setHandleXLimits() { @@ -529,9 +547,9 @@ int ChatScene::sectionByScenePos(int x) { return ChatLineModel::ContentsColumn; } -void ChatScene::updateSceneRect() { +void ChatScene::updateSceneRect(qreal width) { if(_lines.isEmpty()) { - updateSceneRect(QRectF(0, 0, _sceneRect.width(), 0)); + updateSceneRect(QRectF(0, 0, width, 0)); return; } @@ -556,12 +574,7 @@ void ChatScene::updateSceneRect() { // the following call should be safe. If it crashes something went wrong during insert/remove ChatLine *firstLine = _lines.at(_firstLineRow); ChatLine *lastLine = _lines.last(); - updateSceneRect(QRectF(0, firstLine->pos().y(), _sceneRect.width(), lastLine->pos().y() + lastLine->height() - firstLine->pos().y())); -} - -void ChatScene::updateSceneRect(qreal width) { - _sceneRect.setWidth(width); - updateSceneRect(); + updateSceneRect(QRectF(0, firstLine->pos().y(), width, lastLine->pos().y() + lastLine->height() - firstLine->pos().y())); } void ChatScene::updateSceneRect(const QRectF &rect) { diff --git a/src/qtui/chatscene.h b/src/qtui/chatscene.h index 9ac653b7..2f568d31 100644 --- a/src/qtui/chatscene.h +++ b/src/qtui/chatscene.h @@ -56,7 +56,8 @@ public: public slots: void updateForViewport(qreal width, qreal height); - void setWidth(qreal, bool forceReposition = false); + //void setWidth(qreal, bool forceReposition = false); + void setWidth(qreal width); // these are used by the chatitems to notify the scene and manage selections void setSelectingItem(ChatItem *item); @@ -83,7 +84,8 @@ protected slots: void rowsAboutToBeRemoved(const QModelIndex &, int, int); private slots: - void handlePositionChanged(qreal xpos); + void firstHandlePositionChanged(qreal xpos); + void secondHandlePositionChanged(qreal xpos); void showWebPreviewEvent(); void deleteWebPreviewEvent(); @@ -101,8 +103,8 @@ private: // we store the size in a member variable. QRectF _sceneRect; int _firstLineRow; // the first row to display (aka: not a daychange msg) - void updateSceneRect(); void updateSceneRect(qreal width); + inline void updateSceneRect() { updateSceneRect(_sceneRect.width()); } void updateSceneRect(const QRectF &rect); qreal _viewportHeight; -- 2.20.1