This makes the scene react properly to dataChanged() signals from the MessageModel. Only affected
ChatLines are relayouted, the rest moved as appropriately. We can now also call updateGeometryByWidth()
with unchanged width to force a relayout in case the style has changed.
}
qreal ContentsChatItem::setGeometryByWidth(qreal w) {
- if(w == width()) {
- //qDebug() << Q_FUNC_INFO << "Geometry change requested with identical width!";
- }
- // We use this for reloading layout info as well
- //if(w != width()) {
+ // We use this for reloading layout info as well, so we can't bail out if the width doesn't change
+
+ // compute height
+ int lines = 1;
+ WrapColumnFinder finder(this);
+ while(finder.nextWrapColumn(w) > 0)
+ lines++;
+ qreal h = lines * fontMetrics()->lineSpacing();
+ delete _data;
+ _data = 0;
+
+ if(w != width() || h != height()) {
prepareGeometryChange();
- setWidth(w);
- // compute height
- int lines = 1;
- WrapColumnFinder finder(this);
- while(finder.nextWrapColumn() > 0)
- lines++;
- setHeight(lines * fontMetrics()->lineSpacing());
- delete _data;
- _data = 0;
- //}
- return height();
+ setGeometry(w, h);
+ }
+ return h;
}
void ContentsChatItem::doLayout(QTextLayout *layout) const {
if(!line.isValid())
break;
- int col = finder.nextWrapColumn();
+ int col = finder.nextWrapColumn(width());
line.setNumColumns(col >= 0 ? col - line.textStart() : layout->text().length());
line.setPosition(QPointF(0, h));
h += fontMetrics()->lineSpacing();
ContentsChatItem::WrapColumnFinder::~WrapColumnFinder() {
}
-qint16 ContentsChatItem::WrapColumnFinder::nextWrapColumn() {
+qint16 ContentsChatItem::WrapColumnFinder::nextWrapColumn(qreal width) {
if(wordidx >= wrapList.count())
return -1;
lineCount++;
- qreal targetWidth = lineCount * item->width() + choppedTrailing;
+ qreal targetWidth = lineCount * width + choppedTrailing;
qint16 start = wordidx;
qint16 end = wrapList.count() - 1;
WrapColumnFinder(const ChatItem *parent);
~WrapColumnFinder();
- qint16 nextWrapColumn();
+ qint16 nextWrapColumn(qreal width);
private:
const ChatItem *item;
void ChatLine::setGeometryByWidth(const qreal &width, const qreal &contentsWidth, qreal &linePos) {
qreal height = _contentsItem.setGeometryByWidth(contentsWidth);
linePos -= height;
- bool needGeometryChange = linePos == pos().y();
+ bool needGeometryChange = (height != _height || width != _width);
- if(needGeometryChange) {
+ if(height != _height) {
_timestampItem.prepareGeometryChange();
+ _timestampItem.setHeight(height);
_senderItem.prepareGeometryChange();
+ _senderItem.setHeight(height);
}
- _timestampItem.setHeight(height);
- _senderItem.setHeight(height);
- if(needGeometryChange)
+ if(needGeometryChange) {
prepareGeometryChange();
-
- _height = height;
- _width = width;
+ _height = height;
+ _width = width;
+ }
setPos(0, linePos); // set pos is _very_ cheap if nothing changes.
}
}
void ChatScene::dataChanged(const QModelIndex &tl, const QModelIndex &br) {
- // This should only be sent (currently) if the style is reloaded -> re-layout the whole scene
- // TODO: Check range and only do partial relayouts, if appropriate
-
- layout();
+ layout(tl.row(), br.row(), _sceneRect.width());
}
void ChatScene::updateForViewport(qreal width, qreal height) {
void ChatScene::setWidth(qreal width) {
if(width == _sceneRect.width())
return;
- layout(width);
+ layout(0, _lines.count()-1, width);
}
-void ChatScene::layout(qreal width) {
+void ChatScene::layout(int start, int end, qreal width) {
// clock_t startT = clock();
- if(width < 0)
- width = _sceneRect.width();
-
// disabling the index while doing this complex updates is about
// 2 to 10 times faster!
//setItemIndexMethod(QGraphicsScene::NoIndex);
- QList<ChatLine *>::iterator lineIter = _lines.end();
- QList<ChatLine *>::iterator lineIterBegin = _lines.begin();
- qreal linePos = _sceneRect.y() + _sceneRect.height();
- qreal contentsWidth = width - secondColumnHandle()->sceneRight();
- while(lineIter != lineIterBegin) {
- lineIter--;
- (*lineIter)->setGeometryByWidth(width, contentsWidth, linePos);
+ if(end >= 0) {
+ int row = end;
+ qreal linePos = _lines.at(row)->scenePos().y() + _lines.at(row)->height();
+ qreal contentsWidth = width - secondColumnHandle()->sceneRight();
+ while(row >= start) {
+ _lines.at(row--)->setGeometryByWidth(width, contentsWidth, linePos);
+ }
+
+ if(row >= 0) {
+ // remaining items don't need geometry changes, but maybe repositioning?
+ ChatLine *line = _lines.at(row);
+ qreal offset = linePos - (line->scenePos().y() + line->height());
+ if(offset != 0) {
+ while(row >= 0) {
+ line = _lines.at(row--);
+ line->setPos(0, line->scenePos().y() + offset);
+ }
+ }
+ }
}
+
//setItemIndexMethod(QGraphicsScene::BspTreeIndex);
updateSceneRect(width);
public slots:
void updateForViewport(qreal width, qreal height);
void setWidth(qreal width);
- void layout(qreal width = -1);
+ void layout(int start, int end, qreal width);
// these are used by the chatitems to notify the scene and manage selections
void setSelectingItem(ChatItem *item);