X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fqtui%2Fchatitem.cpp;h=2ca66aa17b9d07c30256fc7e829255e6e8bb907c;hp=8ff441c264eb1426b85db33385f320e129ea54ac;hb=edc446b0c31b048efddaf1943cb85eb0db6a0faa;hpb=f662db526c93bd3411509317d665b4f69c6832a0 diff --git a/src/qtui/chatitem.cpp b/src/qtui/chatitem.cpp index 8ff441c2..2ca66aa1 100644 --- a/src/qtui/chatitem.cpp +++ b/src/qtui/chatitem.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-09 by the Quassel Project * + * Copyright (C) 2005-2010 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -31,6 +31,7 @@ #include "buffermodel.h" #include "bufferview.h" #include "chatitem.h" +#include "chatline.h" #include "chatlinemodel.h" #include "contextmenuactionprovider.h" #include "iconloader.h" @@ -38,15 +39,13 @@ #include "qtui.h" #include "qtuistyle.h" -ChatItem::ChatItem(const qreal &width, const qreal &height, const QPointF &pos, QGraphicsItem *parent) - : QGraphicsItem(parent), - _boundingRect(0, 0, width, height), - _selectionMode(NoSelection), - _selectionStart(-1) +ChatItem::ChatItem(const QRectF &boundingRect, ChatLine *parent) +: _parent(parent), + _boundingRect(boundingRect), + _selectionMode(NoSelection), + _selectionStart(-1) { - setAcceptHoverEvents(true); - setZValue(20); - setPos(pos); + } QVariant ChatItem::data(int role) const { @@ -58,7 +57,8 @@ QVariant ChatItem::data(int role) const { return model()->data(index, role); } -qint16 ChatItem::posToCursor(const QPointF &pos) const { +qint16 ChatItem::posToCursor(const QPointF &posInLine) const { + QPointF pos = mapFromLine(posInLine); if(pos.y() > height()) return data(MessageModel::DisplayRole).toString().length(); if(pos.y() < 0) return 0; @@ -103,8 +103,6 @@ void ChatItem::doLayout(QTextLayout *layout) const { } void ChatItem::paintBackground(QPainter *painter) { - painter->setClipRect(boundingRect()); // no idea why QGraphicsItem clipping won't work - QVariant bgBrush; if(_selectionMode == FullSelection) bgBrush = data(ChatLineModel::SelectedBackgroundRole); @@ -122,7 +120,7 @@ void ChatItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QTextLayout layout; initLayout(&layout); - layout.draw(painter, QPointF(0,0), additionalFormats(), boundingRect()); + layout.draw(painter, pos(), additionalFormats(), boundingRect()); // layout()->draw(painter, QPointF(0,0), formats, boundingRect()); @@ -229,27 +227,27 @@ void ChatItem::setSelection(SelectionMode mode, qint16 start, qint16 end) { _selectionMode = mode; _selectionStart = start; _selectionEnd = end; - update(); + chatLine()->update(); } void ChatItem::setFullSelection() { if(_selectionMode != FullSelection) { _selectionMode = FullSelection; - update(); + chatLine()->update(); } } void ChatItem::clearSelection() { if(_selectionMode != NoSelection) { _selectionMode = NoSelection; - update(); + chatLine()->update(); } } void ChatItem::continueSelecting(const QPointF &pos) { _selectionMode = PartialSelection; _selectionEnd = posToCursor(pos); - update(); + chatLine()->update(); } bool ChatItem::isPosOverSelection(const QPointF &pos) const { @@ -296,18 +294,18 @@ void ChatItem::handleClick(const QPointF &pos, ChatScene::ClickMode clickMode) { chatScene()->setSelectingItem(this); _selectionStart = _selectionEnd = posToCursor(pos); _selectionMode = NoSelection; // will be set to PartialSelection by mouseMoveEvent - update(); + chatLine()->update(); } } void ChatItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { if(event->buttons() == Qt::LeftButton) { - if(contains(event->pos())) { + if(boundingRect().contains(event->pos())) { qint16 end = posToCursor(event->pos()); if(end != _selectionEnd) { _selectionEnd = end; _selectionMode = (_selectionStart != _selectionEnd ? PartialSelection : NoSelection); - update(); + chatLine()->update(); } } else { setFullSelection(); @@ -381,12 +379,24 @@ void SenderChatItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *op gradient.setColorAt(0, Qt::white); gradient.setColorAt(1, Qt::black); } - maskPainter.fillRect(boundingRect(), gradient); + maskPainter.fillRect(0, 0, pixmap.width(), pixmap.height(), gradient); pixmap.setAlphaChannel(mask); - painter->drawPixmap(0, 0, pixmap); + painter->drawPixmap(pos(), pixmap); } else { - layout.draw(painter, QPointF(0,0), additionalFormats(), boundingRect()); + layout.draw(painter, pos(), additionalFormats(), boundingRect()); + } +} + +void SenderChatItem::handleClick(const QPointF &pos, ChatScene::ClickMode clickMode) { + if(clickMode == ChatScene::DoubleClick) { + BufferInfo curBufInfo = Client::networkModel()->bufferInfo(data(MessageModel::BufferIdRole).value()); + QString nick = data(MessageModel::EditRole).toString(); + // check if the nick is a valid ircUser + if(!nick.isEmpty() && Client::network(curBufInfo.networkId())->ircUser(nick)) + Client::bufferModel()->switchToOrStartQuery(curBufInfo.networkId(), nick); } + else + ChatItem::handleClick(pos, clickMode); } // ************************************************************ @@ -395,10 +405,11 @@ void SenderChatItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *op ContentsChatItem::ActionProxy ContentsChatItem::_actionProxy; -ContentsChatItem::ContentsChatItem(const qreal &width, const QPointF &pos, QGraphicsItem *parent) - : ChatItem(0, 0, pos, parent), +ContentsChatItem::ContentsChatItem(const QPointF &pos, const qreal &width, ChatLine *parent) + : ChatItem(QRectF(pos, QSizeF(width, 0)), parent), _data(0) { + setPos(pos); setGeometryByWidth(width); } @@ -426,22 +437,24 @@ qreal ContentsChatItem::setGeometryByWidth(qreal w) { WrapColumnFinder finder(this); while(finder.nextWrapColumn(w) > 0) lines++; - qreal h = lines * fontMetrics()->lineSpacing(); + qreal spacing = qMax(fontMetrics()->lineSpacing(), fontMetrics()->height()); // cope with negative leading() + qreal h = lines * spacing; delete _data; _data = 0; - if(w != width() || h != height()) { - prepareGeometryChange(); + if(w != width() || h != height()) setGeometry(w, h); - } + return h; } void ContentsChatItem::doLayout(QTextLayout *layout) const { + // QString t = data(Qt::DisplayRole).toString(); bool d = t.contains("protien"); ChatLineModel::WrapList wrapList = data(ChatLineModel::WrapListRole).value(); if(!wrapList.count()) return; // empty chatitem qreal h = 0; + qreal spacing = qMax(fontMetrics()->lineSpacing(), fontMetrics()->height()); // cope with negative leading() WrapColumnFinder finder(this); layout->beginLayout(); forever { @@ -450,9 +463,25 @@ void ContentsChatItem::doLayout(QTextLayout *layout) const { break; int col = finder.nextWrapColumn(width()); - line.setNumColumns(col >= 0 ? col - line.textStart() : layout->text().length()); + if(col < 0) + col = layout->text().length(); + int num = col - line.textStart(); + + line.setNumColumns(num); + + // Sometimes, setNumColumns will create a line that's too long (cf. Qt bug 238249) + // We verify this and try setting the width again, making it shorter each time until the lengths match. + // Dead fugly, but seems to work… + for(int i = line.textLength()-1; i >= 0 && line.textLength() > num; i--) { + line.setNumColumns(i); + } + if(num != line.textLength()) { + qWarning() << "WARNING: Layout engine couldn't workaround Qt bug 238249, please report!"; + // qDebug() << num << line.textLength() << t.mid(line.textStart(), line.textLength()) << t.mid(line.textStart() + line.textLength()); + } + line.setPosition(QPointF(0, h)); - h += fontMetrics()->lineSpacing(); + h += spacing; } layout->endLayout(); } @@ -489,11 +518,11 @@ QVector ContentsChatItem::additionalFormats() const { void ContentsChatItem::endHoverMode() { if(privateData()) { if(privateData()->currentClickable.isValid()) { - setCursor(Qt::ArrowCursor); + chatLine()->setCursor(Qt::ArrowCursor); privateData()->currentClickable = Clickable(); } clearWebPreview(); - update(); + chatLine()->update(); } } @@ -523,7 +552,7 @@ void ContentsChatItem::handleClick(const QPointF &pos, ChatScene::ClickMode clic setSelectionStart(start); setSelectionEnd(end); } - update(); + chatLine()->update(); } else if(clickMode == ChatScene::TripleClick) { setSelection(PartialSelection, 0, data(ChatLineModel::DisplayRole).toString().length()); } @@ -556,9 +585,9 @@ void ContentsChatItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { onClickable = true; } if(onClickable) { - setCursor(Qt::PointingHandCursor); + chatLine()->setCursor(Qt::PointingHandCursor); privateData()->currentClickable = click; - update(); + chatLine()->update(); return; } } @@ -616,12 +645,13 @@ void ContentsChatItem::showWebPreview(const Clickable &click) { qreal height = line.height(); qreal y = height * line.lineNumber(); - QPointF topLeft = scenePos() + QPointF(x, y); + QPointF topLeft = mapToScene(pos()) + QPointF(x, y); QRectF urlRect = QRectF(topLeft.x(), topLeft.y(), width, height); - QString url = data(ChatLineModel::DisplayRole).toString().mid(click.start(), click.length()); - if(!url.contains("://")) - url = "http://" + url; + QString urlstr = data(ChatLineModel::DisplayRole).toString().mid(click.start(), click.length()); + if(!urlstr.contains("://")) + urlstr= "http://" + urlstr; + QUrl url = QUrl::fromEncoded(urlstr.toUtf8(), QUrl::TolerantMode); chatScene()->loadWebPreview(this, url, urlRect); #endif }