+QList<ChatLine *> ChatView::visibleChatLinesSorted(Qt::ItemSelectionMode mode) const
+{
+ QList<ChatLine *> result = visibleChatLines(mode).toList();
+ qSort(result.begin(), result.end(), chatLinePtrLessThan);
+ return result;
+}
+
+
+ChatLine *ChatView::lastVisibleChatLine(bool ignoreDayChange) const
+{
+ if (!scene())
+ return 0;
+
+ QAbstractItemModel *model = scene()->model();
+ if (!model || model->rowCount() == 0)
+ return 0;
+
+ int row = -1;
+
+ QSet<ChatLine *> visibleLines = visibleChatLines(Qt::ContainsItemBoundingRect);
+ foreach(ChatLine *line, visibleLines) {
+ if (line->row() > row && (ignoreDayChange ? line->msgType() != Message::DayChange : true))
+ row = line->row();
+ }
+
+ if (row >= 0)
+ return scene()->chatLine(row);
+
+ return 0;
+}
+
+
+void ChatView::setMarkerLineVisible(bool visible)
+{
+ scene()->setMarkerLineVisible(visible);
+}
+
+
+void ChatView::setMarkerLine(MsgId msgId)
+{
+ if (!scene()->isSingleBufferScene())
+ return;
+
+ BufferId bufId = scene()->singleBufferId();
+ Client::setMarkerLine(bufId, msgId);
+}
+
+
+void ChatView::markerLineSet(BufferId buffer, MsgId msgId)
+{
+ if (!scene()->isSingleBufferScene() || scene()->singleBufferId() != buffer)
+ return;
+
+ scene()->setMarkerLine(msgId);
+ scene()->setMarkerLineVisible(true);
+}
+
+
+void ChatView::jumpToMarkerLine(bool requestBacklog)
+{
+ scene()->jumpToMarkerLine(requestBacklog);
+}
+
+
+void ChatView::addActionsToMenu(QMenu *menu, const QPointF &pos)
+{
+ // zoom actions
+ BufferWidget *bw = qobject_cast<BufferWidget *>(bufferContainer());
+ if (bw) {
+ bw->addActionsToMenu(menu, pos);
+ menu->addSeparator();
+ }
+}
+
+
+void ChatView::zoomIn()
+{
+ _currentScaleFactor *= 1.2;
+ scale(1.2, 1.2);
+ scene()->setWidth(viewport()->width() / _currentScaleFactor - 2);
+}
+
+
+void ChatView::zoomOut()
+{
+ _currentScaleFactor /= 1.2;
+ scale(1 / 1.2, 1 / 1.2);
+ scene()->setWidth(viewport()->width() / _currentScaleFactor - 2);
+}
+
+
+void ChatView::zoomOriginal()
+{
+ scale(1/_currentScaleFactor, 1/_currentScaleFactor);
+ _currentScaleFactor = 1;
+ scene()->setWidth(viewport()->width() - 2);
+}
+
+
+void ChatView::invalidateFilter()
+{
+ // if this is the currently selected chatview
+ // invalidate immediately
+ if (isVisible()) {
+ _scene->filter()->invalidateFilter();
+ _invalidateFilter = false;
+ }
+ // otherwise invalidate whenever the view is shown
+ else {
+ _invalidateFilter = true;
+ }
+}
+
+
+void ChatView::scrollContentsBy(int dx, int dy)
+{
+ QGraphicsView::scrollContentsBy(dx, dy);
+ checkChatLineCaches();
+}
+
+
+void ChatView::setHasCache(ChatLine *line, bool hasCache)
+{
+ if (hasCache)
+ _linesWithCache.insert(line);
+ else
+ _linesWithCache.remove(line);
+}
+
+
+void ChatView::checkChatLineCaches()
+{
+ qreal top = mapToScene(viewport()->rect().topLeft()).y() - 10; // some grace area to avoid premature cleaning
+ qreal bottom = mapToScene(viewport()->rect().bottomRight()).y() + 10;
+ QSet<ChatLine *>::iterator iter = _linesWithCache.begin();
+ while (iter != _linesWithCache.end()) {
+ ChatLine *line = *iter;
+ if (line->pos().y() + line->height() < top || line->pos().y() > bottom) {
+ line->clearCache();
+ iter = _linesWithCache.erase(iter);
+ }
+ else
+ ++iter;
+ }