- setItemIndexMethod(QGraphicsScene::NoIndex);
-}
-
-ChatScene::~ChatScene() {
-}
-
-void ChatScene::rowsInserted(const QModelIndex &index, int start, int end) {
- Q_UNUSED(index);
-// QModelIndex sidx = model()->index(start, 0);
-// QModelIndex eidx = model()->index(end, 0);
-// qDebug() << "rowsInserted" << start << end << "-" << sidx.data(MessageModel::MsgIdRole).value<MsgId>() << eidx.data(MessageModel::MsgIdRole).value<MsgId>();
-
- qreal h = 0;
- qreal y = 0;
- qreal width = _sceneRect.width();
- bool atBottom = (start == _lines.count());
- bool atTop = !atBottom && (start == 0);
- bool moveTop = false;
-
- if(start < _lines.count()) {
- y = _lines.value(start)->y();
- } else if(atBottom && !_lines.isEmpty()) {
- y = _lines.last()->y() + _lines.last()->height();
- }
-
- qreal contentsWidth = width - secondColumnHandle()->sceneRight();
- qreal senderWidth = secondColumnHandle()->sceneLeft() - firstColumnHandle()->sceneRight();
- qreal timestampWidth = firstColumnHandle()->sceneLeft();
- QPointF contentsPos(secondColumnHandle()->sceneRight(), 0);
- QPointF senderPos(firstColumnHandle()->sceneRight(), 0);
-
- if(atTop) {
- for(int i = end; i >= start; i--) {
- ChatLine *line = new ChatLine(i, model(),
- width,
- timestampWidth, senderWidth, contentsWidth,
- senderPos, contentsPos);
- h += line->height();
- line->setPos(0, y-h);
- _lines.insert(start, line);
- addItem(line);
- }
- } else {
- for(int i = start; i <= end; i++) {
- ChatLine *line = new ChatLine(i, model(),
- width,
- timestampWidth, senderWidth, contentsWidth,
- senderPos, contentsPos);
- line->setPos(0, y+h);
- h += line->height();
- _lines.insert(i, line);
- addItem(line);
- }
- }
-
- // update existing items
- for(int i = end+1; i < _lines.count(); i++) {
- _lines[i]->setRow(i);
- }
-
- // update selection
- if(_selectionStart >= 0) {
- int offset = end - start + 1;
- int oldStart = _selectionStart;
- if(_selectionStart >= start)
- _selectionStart += offset;
- if(_selectionEnd >= start) {
- _selectionEnd += offset;
- if(_selectionStart == oldStart)
- for(int i = start; i < start + offset; i++)
- _lines[i]->setSelected(true);
- }
- if(_firstSelectionRow >= start)
- _firstSelectionRow += offset;
- }
-
- // neither pre- or append means we have to do dirty work: move items...
- int moveStart = 0;
- int moveEnd = _lines.count() - 1;
- qreal offset = h;
- if(!(atTop || atBottom)) {
- // move top means: moving 0 to end (aka: end + 1)
- // move top means: moving end + 1 to _lines.count() - 1 (aka: _lines.count() - (end + 1)
- if(end + 1 < _lines.count() - end - 1) {
- // move top part
- moveTop = true;
- offset = -offset;
- moveEnd = end;
- } else {
- // move bottom part
- moveStart = end + 1;
- }
- ChatLine *line = 0;
- for(int i = moveStart; i <= moveEnd; i++) {
- line = _lines.at(i);
- line->setPos(0, line->pos().y() + offset);
- }
- }
-
- // check if all went right
- Q_ASSERT(start == 0 || _lines.at(start - 1)->pos().y() + _lines.at(start - 1)->height() == _lines.at(start)->pos().y());
+ for (int i = _lines.count() -1; i >= 0; i--) {
+ if (_lines.at(i)->msgType() != Message::DayChange)
+ return _lines.at(i);
+ }
+ return 0;
+ }
+
+ // return the next-lower line
+ if (!ignoreDayChange)
+ return *(--start);
+
+ do {
+ if ((*(--start))->msgType() != Message::DayChange)
+ return *start;
+ }
+ while (start != _lines.begin());
+ return 0;
+}
+
+
+ChatItem *ChatScene::chatItemAt(const QPointF &scenePos) const
+{
+ foreach(QGraphicsItem *item, items(scenePos, Qt::IntersectsItemBoundingRect, Qt::AscendingOrder)) {
+ ChatLine *line = qgraphicsitem_cast<ChatLine *>(item);
+ if (line)
+ return line->itemAt(line->mapFromScene(scenePos));
+ }
+ return 0;
+}
+
+
+bool ChatScene::containsBuffer(const BufferId &id) const
+{
+ MessageFilter *filter = qobject_cast<MessageFilter *>(model());
+ if (filter)
+ return filter->containsBuffer(id);
+ else
+ return false;
+}
+
+
+void ChatScene::setMarkerLineVisible(bool visible)
+{
+ _markerLineVisible = visible;
+ if (visible && _markerLineValid)
+ markerLine()->setVisible(true);
+ else
+ markerLine()->setVisible(false);
+}
+
+
+void ChatScene::setMarkerLine(MsgId msgId)
+{
+ if (!isSingleBufferScene())
+ return;
+
+ if (!msgId.isValid())
+ msgId = Client::markerLine(singleBufferId());
+
+ if (msgId.isValid()) {
+ ChatLine *line = chatLine(msgId, false, true);
+ if (line) {
+ markerLine()->setChatLine(line);
+ // if this was the last line, we won't see it because it's outside the sceneRect
+ // .. which is exactly what we want :)
+ markerLine()->setPos(line->pos() + QPointF(0, line->height()));
+
+ // DayChange messages might have been hidden outside the scene rect, don't make the markerline visible then!
+ if (markerLine()->pos().y() >= sceneRect().y()) {
+ _markerLineValid = true;
+ if (_markerLineVisible)
+ markerLine()->setVisible(true);
+ if (_markerLineJumpPending) {
+ _markerLineJumpPending = false;
+ if (markerLine()->isVisible()) {
+ markerLine()->ensureVisible(QRectF(), 50, 50);
+ }
+ }
+ return;
+ }
+ }
+ }
+ _markerLineValid = false;
+ markerLine()->setVisible(false);
+}
+
+
+void ChatScene::jumpToMarkerLine(bool requestBacklog)
+{
+ if (!isSingleBufferScene())
+ return;
+
+ if (markerLine()->isVisible()) {
+ markerLine()->ensureVisible(QRectF(), 50, 50);
+ return;
+ }
+ if (!_markerLineValid && requestBacklog) {
+ MsgId msgId = Client::markerLine(singleBufferId());
+ if (msgId.isValid()) {
+ _markerLineJumpPending = true;
+ Client::backlogManager()->requestBacklog(singleBufferId(), msgId, -1, -1, 0);
+
+ // If we filtered out the lastSeenMsg (by changing filters after setting it), we'd never jump because the above request
+ // won't fetch any prior lines. Thus, trigger a dynamic backlog request just in case, so repeated
+ // jump tries will eventually cause enough backlog to be fetched.
+ // This is a bit hackish, but not wasteful, as jumping to the top of the ChatView would trigger a dynamic fetch anyway.
+ this->requestBacklog();
+ }
+ }
+}
+
+
+void ChatScene::rowsInserted(const QModelIndex &index, int start, int end)
+{
+ Q_UNUSED(index);
+
+// QModelIndex sidx = model()->index(start, 2);
+// QModelIndex eidx = model()->index(end, 2);
+// qDebug() << "rowsInserted:";
+// if(start > 0) {
+// QModelIndex ssidx = model()->index(start - 1, 2);
+// qDebug() << "Start--:" << start - 1 << ssidx.data(MessageModel::MsgIdRole).value<MsgId>()
+// << ssidx.data(Qt::DisplayRole).toString();
+// }
+// qDebug() << "Start:" << start << sidx.data(MessageModel::MsgIdRole).value<MsgId>()
+// << sidx.data(Qt::DisplayRole).toString();
+// qDebug() << "End:" << end << eidx.data(MessageModel::MsgIdRole).value<MsgId>()
+// << eidx.data(Qt::DisplayRole).toString();
+// if(end + 1 < model()->rowCount()) {
+// QModelIndex eeidx = model()->index(end + 1, 2);
+// qDebug() << "End++:" << end + 1 << eeidx.data(MessageModel::MsgIdRole).value<MsgId>()
+// << eeidx.data(Qt::DisplayRole).toString();
+// }
+
+ qreal h = 0;
+ qreal y = 0;
+ qreal width = _sceneRect.width();
+ bool atBottom = (start == _lines.count());
+ bool atTop = !atBottom && (start == 0);
+
+ if (start < _lines.count()) {
+ y = _lines.value(start)->y();
+ }
+ else if (atBottom && !_lines.isEmpty()) {
+ y = _lines.last()->y() + _lines.last()->height();
+ }
+
+ qreal contentsWidth = width - secondColumnHandle()->sceneRight();
+ qreal senderWidth = secondColumnHandle()->sceneLeft() - firstColumnHandle()->sceneRight();
+ qreal timestampWidth = firstColumnHandle()->sceneLeft();
+ QPointF contentsPos(secondColumnHandle()->sceneRight(), 0);
+ QPointF senderPos(firstColumnHandle()->sceneRight(), 0);
+
+ if (atTop) {
+ for (int i = end; i >= start; i--) {
+ ChatLine *line = new ChatLine(i, model(),
+ width,
+ timestampWidth, senderWidth, contentsWidth,
+ senderPos, contentsPos);
+ h += line->height();
+ line->setPos(0, y-h);
+ _lines.insert(start, line);
+ addItem(line);
+ }
+ }
+ else {
+ for (int i = start; i <= end; i++) {
+ ChatLine *line = new ChatLine(i, model(),
+ width,
+ timestampWidth, senderWidth, contentsWidth,
+ senderPos, contentsPos);
+ line->setPos(0, y+h);
+ h += line->height();
+ _lines.insert(i, line);
+ addItem(line);
+ }
+ }
+
+ // update existing items
+ for (int i = end+1; i < _lines.count(); i++) {
+ _lines[i]->setRow(i);
+ }
+
+ // update selection
+ if (_selectionStart >= 0) {
+ int offset = end - start + 1;
+ int oldStart = _selectionStart;
+ if (_selectionStart >= start)
+ _selectionStart += offset;
+ if (_selectionEnd >= start) {
+ _selectionEnd += offset;
+ if (_selectionStart == oldStart)
+ for (int i = start; i < start + offset; i++)
+ _lines[i]->setSelected(true);
+ }
+ if (_firstSelectionRow >= start)
+ _firstSelectionRow += offset;
+ }
+
+ // neither pre- or append means we have to do dirty work: move items...
+ if (!(atTop || atBottom)) {
+ ChatLine *line = 0;
+ for (int i = 0; i <= end; i++) {
+ line = _lines.at(i);
+ line->setPos(0, line->pos().y() - h);
+ if (line == markerLine()->chatLine())
+ markerLine()->setPos(line->pos() + QPointF(0, line->height()));
+ }
+ }
+
+ // check if all went right
+ Q_ASSERT(start == 0 || _lines.at(start - 1)->pos().y() + _lines.at(start - 1)->height() == _lines.at(start)->pos().y());