X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fqtui%2Fchatitem.cpp;h=5e2942cc712c7c4f98b8dbf09c148301d4f5ff41;hp=d1ec8116d2e14c383814cecd47a3f8e4adcd04d9;hb=d45d1044c030312878cb648fd1325ce70b079c44;hpb=442f91e70e3b4422948758e696b5e3c4b323bdc1 diff --git a/src/qtui/chatitem.cpp b/src/qtui/chatitem.cpp index d1ec8116..5e2942cc 100644 --- a/src/qtui/chatitem.cpp +++ b/src/qtui/chatitem.cpp @@ -33,6 +33,7 @@ #include "chatitem.h" #include "chatline.h" #include "chatlinemodel.h" +#include "chatview.h" #include "contextmenuactionprovider.h" #include "iconloader.h" #include "mainwin.h" @@ -43,11 +44,53 @@ ChatItem::ChatItem(const QRectF &boundingRect, ChatLine *parent) : _parent(parent), _boundingRect(boundingRect), _selectionMode(NoSelection), - _selectionStart(-1) + _selectionStart(-1), + _cachedLayout(0) { } +ChatItem::~ChatItem() { + delete _cachedLayout; +} + +ChatLine *ChatItem::chatLine() const { + return _parent; +} + +ChatScene *ChatItem::chatScene() const { + return chatLine()->chatScene(); +} + +ChatView *ChatItem::chatView() const { + return chatScene()->chatView(); +} + +const QAbstractItemModel *ChatItem::model() const { + return chatLine()->model(); +} + +int ChatItem::row() const { + return chatLine()->row(); +} + +QPointF ChatItem::mapToLine(const QPointF &p) const { + return p + pos(); +} + +QPointF ChatItem::mapFromLine(const QPointF &p) const { + return p - pos(); +} + +// relative to the ChatLine +QPointF ChatItem::mapToScene(const QPointF &p) const { + return chatLine()->mapToScene(p /* + pos() */); +} + +QPointF ChatItem::mapFromScene(const QPointF &p) const { + return chatLine()->mapFromScene(p) /* - pos() */; +} + QVariant ChatItem::data(int role) const { QModelIndex index = model()->index(row(), column()); if(!index.isValid()) { @@ -57,20 +100,19 @@ QVariant ChatItem::data(int role) const { return model()->data(index, role); } -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; +QTextLayout *ChatItem::layout() const { + if(_cachedLayout) + return _cachedLayout; - QTextLayout layout; - initLayout(&layout); - for(int l = layout.lineCount() - 1; l >= 0; l--) { - QTextLine line = layout.lineAt(l); - if(pos.y() >= line.y()) { - return line.xToCursor(pos.x(), QTextLine::CursorOnCharacter); - } - } - return 0; + _cachedLayout = new QTextLayout; + initLayout(_cachedLayout); + chatView()->setHasCache(chatLine()); + return _cachedLayout; +} + +void ChatItem::clearCache() { + delete _cachedLayout; + _cachedLayout = 0; } void ChatItem::initLayoutHelper(QTextLayout *layout, QTextOption::WrapMode wrapMode, Qt::Alignment alignment) const { @@ -88,8 +130,9 @@ void ChatItem::initLayoutHelper(QTextLayout *layout, QTextOption::WrapMode wrapM layout->setAdditionalFormats(formatRanges); } -UiStyle::FormatList ChatItem::formatList() const { - return data(MessageModel::FormatRole).value(); +void ChatItem::initLayout(QTextLayout *layout) const { + initLayoutHelper(layout, QTextOption::NoWrap); + doLayout(layout); } void ChatItem::doLayout(QTextLayout *layout) const { @@ -102,6 +145,26 @@ void ChatItem::doLayout(QTextLayout *layout) const { layout->endLayout(); } +UiStyle::FormatList ChatItem::formatList() const { + return data(MessageModel::FormatRole).value(); +} + +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; + + for(int l = layout()->lineCount() - 1; l >= 0; l--) { + QTextLine line = layout()->lineAt(l); + if(pos.y() >= line.y()) { + return line.xToCursor(pos.x(), QTextLine::CursorOnCharacter); + } + } + return 0; +} + void ChatItem::paintBackground(QPainter *painter) { QVariant bgBrush; if(_selectionMode == FullSelection) @@ -120,9 +183,7 @@ void ChatItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, painter->setClipRect(boundingRect()); paintBackground(painter); - QTextLayout layout; - initLayout(&layout); - layout.draw(painter, pos(), additionalFormats(), boundingRect()); + layout()->draw(painter, pos(), additionalFormats(), boundingRect()); // layout()->draw(painter, QPointF(0,0), formats, boundingRect()); @@ -278,10 +339,8 @@ QList ChatItem::findWords(const QString &searchWord, Qt::CaseSensitivity searchIdx = plainText.indexOf(searchWord, searchIdx + 1, caseSensitive); } - QTextLayout layout; - initLayout(&layout); foreach(int idx, indexList) { - QTextLine line = layout.lineForTextPosition(idx); + QTextLine line = layout()->lineForTextPosition(idx); qreal x = line.cursorToX(idx); qreal width = line.cursorToX(idx + searchWord.count()) - x; qreal height = line.height(); @@ -346,15 +405,18 @@ void ChatItem::addActionsToMenu(QMenu *menu, const QPointF &pos) { // SenderChatItem // ************************************************************ +void SenderChatItem::initLayout(QTextLayout *layout) const { + initLayoutHelper(layout, QTextOption::ManualWrap, Qt::AlignRight); + doLayout(layout); +} + void SenderChatItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option); Q_UNUSED(widget); painter->save(); painter->setClipRect(boundingRect()); paintBackground(painter); - QTextLayout layout; - initLayout(&layout); - qreal layoutWidth = layout.minimumWidth(); + qreal layoutWidth = layout()->minimumWidth(); qreal offset = 0; if(chatScene()->senderCutoffMode() == ChatScene::CutoffLeft) offset = qMin(width() - layoutWidth, (qreal)0); @@ -364,10 +426,10 @@ void SenderChatItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *op if(layoutWidth > width()) { // Draw a nice gradient for longer items // Qt's text drawing with a gradient brush sucks, so we use an alpha-channeled pixmap instead - QPixmap pixmap(layout.boundingRect().toRect().size()); + QPixmap pixmap(layout()->boundingRect().toRect().size()); pixmap.fill(Qt::transparent); QPainter pixPainter(&pixmap); - layout.draw(&pixPainter, QPointF(qMax(offset, (qreal)0), 0), additionalFormats()); + layout()->draw(&pixPainter, QPointF(qMax(offset, (qreal)0), 0), additionalFormats()); pixPainter.end(); // Create alpha channel mask @@ -389,7 +451,7 @@ void SenderChatItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *op pixmap.setAlphaChannel(mask); painter->drawPixmap(pos(), pixmap); } else { - layout.draw(painter, pos(), additionalFormats(), boundingRect()); + layout()->draw(painter, pos(), additionalFormats(), boundingRect()); } painter->restore(); } @@ -428,6 +490,12 @@ ContentsChatItem::~ContentsChatItem() { delete _data; } +void ContentsChatItem::clearCache() { + delete _data; + _data = 0; + ChatItem::clearCache(); +} + ContentsChatItemPrivate *ContentsChatItem::privateData() const { if(!_data) { ContentsChatItem *that = const_cast(this); @@ -455,8 +523,12 @@ qreal ContentsChatItem::setGeometryByWidth(qreal w) { return h; } +void ContentsChatItem::initLayout(QTextLayout *layout) const { + initLayoutHelper(layout, QTextOption::WrapAtWordBoundaryOrAnywhere); + doLayout(layout); +} + 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 @@ -525,7 +597,7 @@ QVector ContentsChatItem::additionalFormats() const { void ContentsChatItem::endHoverMode() { if(privateData()) { if(privateData()->currentClickable.isValid()) { - chatLine()->setCursor(Qt::ArrowCursor); + chatLine()->unsetCursor(); privateData()->currentClickable = Clickable(); } clearWebPreview(); @@ -644,9 +716,7 @@ void ContentsChatItem::showWebPreview(const Clickable &click) { #ifndef HAVE_WEBKIT Q_UNUSED(click); #else - QTextLayout layout; - initLayout(&layout); - QTextLine line = layout.lineForTextPosition(click.start()); + QTextLine line = layout()->lineForTextPosition(click.start()); qreal x = line.cursorToX(click.start()); qreal width = line.cursorToX(click.start() + click.length()) - x; qreal height = line.height();