+#include "chatview.h"
+#include "client.h"
+#include "clientbacklogmanager.h"
+#include "columnhandleitem.h"
+#include "contextmenuactionprovider.h"
+#include "mainwin.h"
+#include "markerlineitem.h"
+#include "messagefilter.h"
+#include "qtui.h"
+#include "qtuistyle.h"
+#include "chatviewsettings.h"
+#include "webpreviewitem.h"
+
+const qreal minContentsWidth = 200;
+
+ChatScene::ChatScene(QAbstractItemModel *model, const QString &idString, qreal width, ChatView *parent)
+ : QGraphicsScene(0, 0, width, 0, (QObject *)parent),
+ _chatView(parent),
+ _idString(idString),
+ _model(model),
+ _singleBufferId(BufferId()),
+ _sceneRect(0, 0, width, 0),
+ _firstLineRow(-1),
+ _viewportHeight(0),
+ _markerLine(new MarkerLineItem(width)),
+ _markerLineVisible(false),
+ _markerLineValid(false),
+ _markerLineJumpPending(false),
+ _cutoffMode(CutoffRight),
+ _alwaysBracketSender(false),
+ _selectingItem(0),
+ _selectionStart(-1),
+ _isSelecting(false),
+ _clickMode(NoClick),
+ _clickHandled(true),
+ _leftButtonPressed(false)
+{
+ MessageFilter *filter = qobject_cast<MessageFilter *>(model);
+ if (filter && filter->isSingleBufferFilter()) {
+ _singleBufferId = filter->singleBufferId();
+ }
+
+ addItem(_markerLine);
+ connect(this, SIGNAL(sceneRectChanged(const QRectF &)), _markerLine, SLOT(sceneRectChanged(const QRectF &)));
+
+ ChatViewSettings defaultSettings;
+ _defaultFirstColHandlePos = defaultSettings.value("FirstColumnHandlePos", 80).toInt();
+ _defaultSecondColHandlePos = defaultSettings.value("SecondColumnHandlePos", 200).toInt();
+
+ ChatViewSettings viewSettings(this);
+ _firstColHandlePos = viewSettings.value("FirstColumnHandlePos", _defaultFirstColHandlePos).toInt();
+ _secondColHandlePos = viewSettings.value("SecondColumnHandlePos", _defaultSecondColHandlePos).toInt();
+
+ _firstColHandle = new ColumnHandleItem(QtUi::style()->firstColumnSeparator());
+ addItem(_firstColHandle);
+ _firstColHandle->setXPos(_firstColHandlePos);
+ 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(secondHandlePositionChanged(qreal)));
+
+ connect(this, SIGNAL(sceneRectChanged(const QRectF &)), _secondColHandle, SLOT(sceneRectChanged(const QRectF &)));
+
+ setHandleXLimits();
+
+ if (model->rowCount() > 0)
+ rowsInserted(QModelIndex(), 0, model->rowCount() - 1);
+
+ connect(model, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
+ this, SLOT(rowsInserted(const QModelIndex &, int, int)));
+ connect(model, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)),
+ this, SLOT(rowsAboutToBeRemoved(const QModelIndex &, int, int)));
+ connect(model, SIGNAL(rowsRemoved(QModelIndex, int, int)),
+ this, SLOT(rowsRemoved()));
+ connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), SLOT(dataChanged(QModelIndex, QModelIndex)));
+
+#if defined HAVE_WEBKIT || defined HAVE_WEBENGINE
+ webPreview.timer.setSingleShot(true);
+ connect(&webPreview.timer, SIGNAL(timeout()), this, SLOT(webPreviewNextStep()));
+#endif
+ _showWebPreview = defaultSettings.showWebPreview();
+ defaultSettings.notify("ShowWebPreview", this, SLOT(showWebPreviewChanged()));
+
+ _showSenderBrackets = defaultSettings.showSenderBrackets();
+ defaultSettings.notify("ShowSenderBrackets", this, SLOT(showSenderBracketsChanged()));
+
+ _useCustomTimestampFormat = defaultSettings.useCustomTimestampFormat();
+ defaultSettings.notify("UseCustomTimestampFormat", this, SLOT(useCustomTimestampFormatChanged()));
+
+ _timestampFormatString = defaultSettings.timestampFormatString();
+ defaultSettings.notify("TimestampFormat", this, SLOT(timestampFormatStringChanged()));
+ updateTimestampHasBrackets();
+
+ _clickTimer.setInterval(QApplication::doubleClickInterval());
+ _clickTimer.setSingleShot(true);
+ connect(&_clickTimer, SIGNAL(timeout()), SLOT(clickTimeout()));
+
+ setItemIndexMethod(QGraphicsScene::NoIndex);
+}
+
+
+ChatScene::~ChatScene()
+{
+}
+
+
+ChatView *ChatScene::chatView() const
+{
+ return _chatView;
+}
+
+
+ColumnHandleItem *ChatScene::firstColumnHandle() const
+{
+ return _firstColHandle;
+}
+
+
+ColumnHandleItem *ChatScene::secondColumnHandle() const
+{
+ return _secondColHandle;
+}
+
+void ChatScene::resetColumnWidths()
+{
+ //make sure first column is at least 80 px wide, second 120 px
+ int firstColHandlePos = qMax(_defaultFirstColHandlePos,
+ 80);
+ int secondColHandlePos = qMax(_defaultSecondColHandlePos,
+ firstColHandlePos + 120);
+
+ _firstColHandle->setXPos(firstColHandlePos);
+ _secondColHandle->setXPos(secondColHandlePos);
+}
+
+ChatLine *ChatScene::chatLine(MsgId msgId, bool matchExact, bool ignoreDayChange) const
+{
+ if (!_lines.count())
+ return 0;
+
+ QList<ChatLine *>::ConstIterator start = _lines.begin();
+ QList<ChatLine *>::ConstIterator end = _lines.end();
+ QList<ChatLine *>::ConstIterator middle;
+
+ int n = int(end - start);
+ int half;
+
+ while (n > 0) {
+ half = n >> 1;
+ middle = start + half;
+ if ((*middle)->msgId() < msgId) {
+ start = middle + 1;
+ n -= half + 1;
+ }
+ else {
+ n = half;
+ }
+ }
+
+ if (start != end && (*start)->msgId() == msgId && (ignoreDayChange ? (*start)->msgType() != Message::DayChange : true))
+ return *start;
+
+ if (matchExact)
+ return 0;
+
+ if (start == _lines.begin()) // not (yet?) in our scene
+ return 0;
+
+ // if we didn't find the exact msgId, take the next-lower one (this makes sense for lastSeen)
+
+ if (start == end) { // higher than last element
+ if (!ignoreDayChange)
+ return _lines.last();
+
+ 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());
+// if(start != 0) {
+// if(_lines.at(start - 1)->pos().y() + _lines.at(start - 1)->height() != _lines.at(start)->pos().y()) {
+// qDebug() << "lines:" << _lines.count() << "start:" << start << "end:" << end;
+// qDebug() << "line[start - 1]:" << _lines.at(start - 1)->pos().y() << "+" << _lines.at(start - 1)->height() << "=" << _lines.at(start - 1)->pos().y() + _lines.at(start - 1)->height();
+// qDebug() << "line[start]" << _lines.at(start)->pos().y();
+// qDebug() << "needed moving:" << !(atTop || atBottom) << moveTop << moveStart << moveEnd << offset;
+// Q_ASSERT(false)
+// }
+// }
+ Q_ASSERT(end + 1 == _lines.count() || _lines.at(end)->pos().y() + _lines.at(end)->height() == _lines.at(end + 1)->pos().y());
+// if(end + 1 < _lines.count()) {
+// if(_lines.at(end)->pos().y() + _lines.at(end)->height() != _lines.at(end + 1)->pos().y()) {
+// qDebug() << "lines:" << _lines.count() << "start:" << start << "end:" << end;
+// qDebug() << "line[end]:" << _lines.at(end)->pos().y() << "+" << _lines.at(end)->height() << "=" << _lines.at(end)->pos().y() + _lines.at(end)->height();
+// qDebug() << "line[end+1]" << _lines.at(end + 1)->pos().y();
+// qDebug() << "needed moving:" << !(atTop || atBottom) << moveTop << moveStart << moveEnd << offset;
+// Q_ASSERT(false);
+// }
+// }
+
+ if (!atBottom) {
+ if (start < _firstLineRow) {
+ int prevFirstLineRow = _firstLineRow + (end - start + 1);
+ for (int i = end + 1; i < prevFirstLineRow; i++) {
+ _lines.at(i)->show();
+ }
+ }
+ // force new search for first proper line
+ _firstLineRow = -1;
+ }
+ updateSceneRect();
+ if (atBottom) {
+ emit lastLineChanged(_lines.last(), h);
+ }
+
+ // now move the marker line if necessary. we don't need to do anything if we appended lines though...
+ if (!_markerLineValid)
+ setMarkerLine();
+}
+
+
+void ChatScene::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
+{
+ Q_UNUSED(parent);
+
+ qreal h = 0; // total height of removed items;
+
+ bool atTop = (start == 0);
+ bool atBottom = (end == _lines.count() - 1);
+
+ // clear selection
+ if (_selectingItem) {
+ int row = _selectingItem->row();
+ if (row >= start && row <= end)
+ setSelectingItem(0);
+ }
+
+ // remove items from scene
+ QList<ChatLine *>::iterator lineIter = _lines.begin() + start;
+ int lineCount = start;
+ while (lineIter != _lines.end() && lineCount <= end) {
+ if ((*lineIter) == markerLine()->chatLine())
+ markerLine()->setChatLine(0);
+ h += (*lineIter)->height();
+ delete *lineIter;
+ lineIter = _lines.erase(lineIter);
+ lineCount++;
+ }
+
+ // update rows of remaining chatlines
+ for (int i = start; i < _lines.count(); i++) {
+ _lines.at(i)->setRow(i);
+ }
+
+ // update selection
+ if (_selectionStart >= 0) {
+ int offset = end - start + 1;
+ if (_selectionStart >= start)
+ _selectionStart = qMax(_selectionStart - offset, start);
+ if (_selectionEnd >= start)
+ _selectionEnd -= offset;
+ if (_firstSelectionRow >= start)
+ _firstSelectionRow -= offset;
+
+ if (_selectionEnd < _selectionStart) {
+ _isSelecting = false;
+ _selectionStart = -1;
+ }
+ }
+
+ // neither removing at bottom or top means we have to move items...
+ if (!(atTop || atBottom)) {
+ qreal offset = h;
+ int moveStart = 0;
+ int moveEnd = _lines.count() - 1;
+ if (start < _lines.count() - start) {
+ // move top part
+ moveEnd = start - 1;
+ }
+ else {
+ // move bottom part
+ moveStart = start;
+ offset = -offset;
+ }
+ ChatLine *line = 0;
+ for (int i = moveStart; i <= moveEnd; i++) {
+ line = _lines.at(i);
+ line->setPos(0, line->pos().y() + offset);
+ }
+ }
+
+ Q_ASSERT(start == 0 || start >= _lines.count() || _lines.at(start - 1)->pos().y() + _lines.at(start - 1)->height() == _lines.at(start)->pos().y());
+
+ // update sceneRect
+ // when searching for the first non-date-line we have to take into account that our
+ // model still contains the just removed lines so we cannot simply call updateSceneRect()
+ int numRows = model()->rowCount();
+ QModelIndex firstLineIdx;
+ _firstLineRow = -1;
+ bool needOffset = false;
+ do {
+ _firstLineRow++;
+ if (_firstLineRow >= start && _firstLineRow <= end) {
+ _firstLineRow = end + 1;
+ needOffset = true;
+ }
+ firstLineIdx = model()->index(_firstLineRow, 0);
+ }
+ while ((Message::Type)(model()->data(firstLineIdx, MessageModel::TypeRole).toInt()) == Message::DayChange && _firstLineRow < numRows);
+
+ if (needOffset)
+ _firstLineRow -= end - start + 1;
+ updateSceneRect();
+}
+
+
+void ChatScene::rowsRemoved()
+{
+ // move the marker line if necessary
+ setMarkerLine();
+}
+
+
+void ChatScene::dataChanged(const QModelIndex &tl, const QModelIndex &br)
+{
+ layout(tl.row(), br.row(), _sceneRect.width());
+}
+
+
+void ChatScene::updateForViewport(qreal width, qreal height)
+{
+ _viewportHeight = height;
+ setWidth(width);
+}
+
+
+void ChatScene::setWidth(qreal width)
+{
+ if (width == _sceneRect.width())
+ return;
+ layout(0, _lines.count()-1, width);
+}
+
+
+void ChatScene::layout(int start, int end, qreal width)
+{
+ // clock_t startT = clock();
+
+ // disabling the index while doing this complex updates is about
+ // 2 to 10 times faster!
+ //setItemIndexMethod(QGraphicsScene::NoIndex);
+
+ 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);
+ setHandleXLimits();
+ setMarkerLine();
+ emit layoutChanged();
+
+// clock_t endT = clock();
+// qDebug() << "resized" << _lines.count() << "in" << (float)(endT - startT) / CLOCKS_PER_SEC << "sec";
+}
+
+
+void ChatScene::firstHandlePositionChanged(qreal xpos)
+{
+ if (_firstColHandlePos == xpos)
+ return;
+
+ _firstColHandlePos = xpos >= 0 ? xpos : 0;
+ ChatViewSettings viewSettings(this);
+ viewSettings.setValue("FirstColumnHandlePos", _firstColHandlePos);
+ 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<ChatLine *>::iterator lineIter = _lines.end();
+ QList<ChatLine *>::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);
+
+ // clock_t startT = clock();
+
+ // 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 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);