From 603763515d61fc1cd3febbfd7c3268d5216df768 Mon Sep 17 00:00:00 2001 From: Manuel Nickschas Date: Tue, 19 Aug 2008 00:09:47 +0200 Subject: [PATCH] Use inheritance for handling the different ChatItem types --- src/qtui/chatitem.cpp | 107 ++++++++++++++-------------- src/qtui/chatitem.h | 160 +++++++++++++++++++++++++----------------- src/qtui/chatline.cpp | 6 +- src/qtui/chatline.h | 34 ++++----- 4 files changed, 172 insertions(+), 135 deletions(-) diff --git a/src/qtui/chatitem.cpp b/src/qtui/chatitem.cpp index c2f2425c..6a9b1436 100644 --- a/src/qtui/chatitem.cpp +++ b/src/qtui/chatitem.cpp @@ -31,11 +31,9 @@ #include "chatlinemodel.h" #include "qtui.h" -ChatItem::ChatItem(int col, QAbstractItemModel *model, QGraphicsItem *parent) +ChatItem::ChatItem(ChatLineModel::ColumnType col, QAbstractItemModel *model, QGraphicsItem *parent) : QGraphicsItem(parent), _fontMetrics(0), - _col(col), - _lines(0), _layoutData(0), _selectionMode(NoSelection), _selectionStart(-1) @@ -71,13 +69,7 @@ qreal ChatItem::setGeometry(qreal w, qreal h) { } qreal ChatItem::computeHeight() { - if(data(ChatLineModel::ColumnTypeRole).toUInt() != ChatLineModel::ContentsColumn) - return fontMetrics()->lineSpacing(); // only contents can be multi-line - - _lines = 1; - WrapColumnFinder finder(this); - while(finder.nextWrapColumn() > 0) _lines++; - return _lines * fontMetrics()->lineSpacing(); + return fontMetrics()->lineSpacing(); // only contents can be multi-line } QTextLayout *ChatItem::createLayout(QTextOption::WrapMode wrapMode, Qt::Alignment alignment) { @@ -101,46 +93,16 @@ void ChatItem::setLayout(QTextLayout *layout) { } void ChatItem::updateLayout() { - switch(data(ChatLineModel::ColumnTypeRole).toUInt()) { - case ChatLineModel::TimestampColumn: - if(!haveLayout()) setLayout(createLayout(QTextOption::WrapAnywhere, Qt::AlignLeft)); - // fallthrough - case ChatLineModel::SenderColumn: - if(!haveLayout()) setLayout(createLayout(QTextOption::WrapAnywhere, Qt::AlignRight)); - layout()->beginLayout(); - { - QTextLine line = layout()->createLine(); - if(line.isValid()) { - line.setLineWidth(width()); - line.setPosition(QPointF(0,0)); - } - layout()->endLayout(); - } - break; - case ChatLineModel::ContentsColumn: { - if(!haveLayout()) setLayout(createLayout(QTextOption::WrapAnywhere)); - - // Now layout - ChatLineModel::WrapList wrapList = data(ChatLineModel::WrapListRole).value(); - if(!wrapList.count()) return; // empty chatitem - - qreal h = 0; - WrapColumnFinder finder(this); - layout()->beginLayout(); - forever { - QTextLine line = layout()->createLine(); - if(!line.isValid()) - break; - - int col = finder.nextWrapColumn(); - line.setNumColumns(col >= 0 ? col - line.textStart() : layout()->text().length()); - line.setPosition(QPointF(0, h)); - h += line.height() + fontMetrics()->leading(); - } - layout()->endLayout(); - } - break; + if(!haveLayout()) + setLayout(createLayout(QTextOption::WrapAnywhere, Qt::AlignLeft)); + + layout()->beginLayout(); + QTextLine line = layout()->createLine(); + if(line.isValid()) { + line.setLineWidth(width()); + line.setPosition(QPointF(0,0)); } + layout()->endLayout(); } void ChatItem::clearLayoutData() { @@ -321,10 +283,51 @@ void ChatItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { event->ignore(); } +/*************************************************************************************************/ + +/*************************************************************************************************/ + +void SenderChatItem::updateLayout() { + if(!haveLayout()) setLayout(createLayout(QTextOption::WrapAnywhere, Qt::AlignRight)); + ChatItem::updateLayout(); +} + +/*************************************************************************************************/ + +qreal ContentsChatItem::computeHeight() { + int lines = 1; + WrapColumnFinder finder(this); + while(finder.nextWrapColumn() > 0) lines++; + return lines * fontMetrics()->lineSpacing(); +} + +void ContentsChatItem::updateLayout() { + if(!haveLayout()) setLayout(createLayout(QTextOption::WrapAnywhere)); + + // Now layout + ChatLineModel::WrapList wrapList = data(ChatLineModel::WrapListRole).value(); + if(!wrapList.count()) return; // empty chatitem + + qreal h = 0; + WrapColumnFinder finder(this); + layout()->beginLayout(); + forever { + QTextLine line = layout()->createLine(); + if(!line.isValid()) + break; + + int col = finder.nextWrapColumn(); + line.setNumColumns(col >= 0 ? col - line.textStart() : layout()->text().length()); + line.setPosition(QPointF(0, h)); + h += line.height() + fontMetrics()->leading(); + } + layout()->endLayout(); +} + /*************************************************************************************************/ -ChatItem::WrapColumnFinder::WrapColumnFinder(ChatItem *_item) : item(_item) { +ContentsChatItem::WrapColumnFinder::WrapColumnFinder(ChatItem *_item) : item(_item) { wrapList = item->data(ChatLineModel::WrapListRole).value(); wordidx = 0; layout = 0; @@ -333,11 +336,11 @@ ChatItem::WrapColumnFinder::WrapColumnFinder(ChatItem *_item) : item(_item) { w = 0; } -ChatItem::WrapColumnFinder::~WrapColumnFinder() { +ContentsChatItem::WrapColumnFinder::~WrapColumnFinder() { delete layout; } -qint16 ChatItem::WrapColumnFinder::nextWrapColumn() { +qint16 ContentsChatItem::WrapColumnFinder::nextWrapColumn() { while(wordidx < wrapList.count()) { w += wrapList.at(wordidx).width; if(w >= item->width()) { diff --git a/src/qtui/chatitem.h b/src/qtui/chatitem.h index 44cbaaa5..745f2d32 100644 --- a/src/qtui/chatitem.h +++ b/src/qtui/chatitem.h @@ -33,70 +33,69 @@ class QTextLayout; class ChatItem : public QGraphicsItem { - public: - ChatItem(int col, QAbstractItemModel *, QGraphicsItem *parent); - virtual ~ChatItem(); +protected: + ChatItem(ChatLineModel::ColumnType column, QAbstractItemModel *, QGraphicsItem *parent); + virtual ~ChatItem(); - inline const QAbstractItemModel *model() const { return chatScene() ? chatScene()->model() : 0; } - int row() const; - inline int column() const { return _col; } - inline ChatScene *chatScene() const { return qobject_cast(scene()); } +public: + inline const QAbstractItemModel *model() const { return chatScene() ? chatScene()->model() : 0; } + inline int row() const; + virtual ChatLineModel::ColumnType column() const = 0; + inline ChatScene *chatScene() const { return qobject_cast(scene()); } - inline QFontMetricsF *fontMetrics() const { return _fontMetrics; } - inline virtual QRectF boundingRect() const { return _boundingRect; } - inline qreal width() const { return _boundingRect.width(); } - inline qreal height() const { return _boundingRect.height(); } + inline QFontMetricsF *fontMetrics() const { return _fontMetrics; } + inline QRectF boundingRect() const { return _boundingRect; } + inline qreal width() const { return _boundingRect.width(); } + inline qreal height() const { return _boundingRect.height(); } - inline bool haveLayout() const { return _layoutData != 0 && layout() != 0; } - void clearLayoutData(); - void updateLayout(); - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + inline bool haveLayout() const { return _layoutData != 0 && layout() != 0; } + void clearLayoutData(); + virtual QTextLayout *createLayout(QTextOption::WrapMode, Qt::Alignment = Qt::AlignLeft); + virtual void updateLayout(); + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - virtual QVariant data(int role) const; + virtual QVariant data(int role) const; - // returns height - qreal setGeometry(qreal width, qreal height = -1); + // returns height + qreal setGeometry(qreal width, qreal height = -1); - // selection stuff, to be called by the scene - void clearSelection(); - void setFullSelection(); - void continueSelecting(const QPointF &pos); + // selection stuff, to be called by the scene + void clearSelection(); + void setFullSelection(); + void continueSelecting(const QPointF &pos); QList findWords(const QString &searchWord, Qt::CaseSensitivity caseSensitive); - protected: - virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); - virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); +protected: + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); - virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event); - virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); - virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event); + virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event); + virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); + virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event); - private: - struct LayoutData; - class WrapColumnFinder; + struct LayoutData; + inline QTextLayout *layout() const; + void setLayout(QTextLayout *); + qint16 posToCursor(const QPointF &pos); - inline QTextLayout *layout() const; - void setLayout(QTextLayout *); - qint16 posToCursor(const QPointF &pos); - qreal computeHeight(); - QTextLayout *createLayout(QTextOption::WrapMode, Qt::Alignment = Qt::AlignLeft); + virtual qreal computeHeight(); - // internal selection stuff - void setSelection(int start, int length); + QRectF _boundingRect; - QRectF _boundingRect; - QFontMetricsF *_fontMetrics; - int _col; - quint8 _lines; +private: + // internal selection stuff + void setSelection(int start, int length); - enum SelectionMode { NoSelection, PartialSelection, FullSelection }; - SelectionMode _selectionMode; - qint16 _selectionStart, _selectionEnd; + QFontMetricsF *_fontMetrics; - LayoutData *_layoutData; + enum SelectionMode { NoSelection, PartialSelection, FullSelection }; + SelectionMode _selectionMode; + qint16 _selectionStart, _selectionEnd; + + LayoutData *_layoutData; }; struct ChatItem::LayoutData { @@ -106,22 +105,55 @@ struct ChatItem::LayoutData { ~LayoutData() { delete layout; } }; -class ChatItem::WrapColumnFinder { - public: - WrapColumnFinder(ChatItem *parent); - ~WrapColumnFinder(); - - qint16 nextWrapColumn(); - - private: - ChatItem *item; - QTextLayout *layout; - QTextLine line; - ChatLineModel::WrapList wrapList; - qint16 wordidx; - qint16 lastwrapcol; - qreal lastwrappos; - qreal w; +class TimestampChatItem : public ChatItem { + +public: + TimestampChatItem(QAbstractItemModel *model, QGraphicsItem *parent) : ChatItem(column(), model, parent) {} + inline ChatLineModel::ColumnType column() const { return ChatLineModel::TimestampColumn; } + +}; + +class SenderChatItem : public ChatItem { + +public: + SenderChatItem(QAbstractItemModel *model, QGraphicsItem *parent) : ChatItem(column(), model, parent) {} + inline ChatLineModel::ColumnType column() const { return ChatLineModel::SenderColumn; } + + void updateLayout(); +}; + +class ContentsChatItem : public ChatItem { + +public: + ContentsChatItem(QAbstractItemModel *model, QGraphicsItem *parent) : ChatItem(column(), model, parent) {} + inline ChatLineModel::ColumnType column() const { return ChatLineModel::ContentsColumn; } + + void updateLayout(); + +private: + qreal computeHeight(); + + class WrapColumnFinder; +}; + + + +class ContentsChatItem::WrapColumnFinder { +public: + WrapColumnFinder(ChatItem *parent); + ~WrapColumnFinder(); + + qint16 nextWrapColumn(); + +private: + ChatItem *item; + QTextLayout *layout; + QTextLine line; + ChatLineModel::WrapList wrapList; + qint16 wordidx; + qint16 lastwrapcol; + qreal lastwrappos; + qreal w; }; #include "chatline.h" diff --git a/src/qtui/chatline.cpp b/src/qtui/chatline.cpp index 5213be8a..94820d63 100644 --- a/src/qtui/chatline.cpp +++ b/src/qtui/chatline.cpp @@ -35,9 +35,9 @@ ChatLine::ChatLine(int row, QAbstractItemModel *model, QGraphicsItem *parent) : QGraphicsItem(parent), _row(row), // needs to be set before the items - _timestampItem(ChatLineModel::TimestampColumn, model, this), - _senderItem(ChatLineModel::SenderColumn, model, this), - _contentsItem(ChatLineModel::ContentsColumn, model, this), + _timestampItem(model, this), + _senderItem(model, this), + _contentsItem(model, this), _width(0), _height(0), _selection(0) diff --git a/src/qtui/chatline.h b/src/qtui/chatline.h index 15805cc6..c429f02d 100644 --- a/src/qtui/chatline.h +++ b/src/qtui/chatline.h @@ -28,35 +28,37 @@ class ChatLine : public QGraphicsItem { - public: +public: ChatLine(int row, QAbstractItemModel *model, QGraphicsItem *parent = 0); - virtual QRectF boundingRect () const; + virtual QRectF boundingRect () const; inline int row() { return _row; } inline void setRow(int row) { _row = row; } inline const QAbstractItemModel *model() const { return chatScene() ? chatScene()->model() : 0; } inline ChatScene *chatScene() const { return qobject_cast(scene()); } - inline qreal width() const { return _width; } - inline qreal height() const { return _height; } - ChatItem &item(ChatLineModel::ColumnType); + inline qreal width() const { return _width; } + inline qreal height() const { return _height; } + ChatItem &item(ChatLineModel::ColumnType); - virtual void paint (QPainter * painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + virtual void paint (QPainter * painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - // returns height - qreal setGeometry(qreal width, qreal firstColPos, qreal secondColPos); - void setSelected(bool selected, ChatLineModel::ColumnType minColumn = ChatLineModel::ContentsColumn); - void setHighlighted(bool highlighted); + // returns height + qreal setGeometry(qreal width, qreal firstColPos, qreal secondColPos); + void setSelected(bool selected, ChatLineModel::ColumnType minColumn = ChatLineModel::ContentsColumn); + void setHighlighted(bool highlighted); - protected: +protected: - private: +private: int _row; - ChatItem _timestampItem, _senderItem, _contentsItem; - qreal _width, _height; + TimestampChatItem _timestampItem; + SenderChatItem _senderItem; + ContentsChatItem _contentsItem; + qreal _width, _height; - enum { Selected = 0x40, Highlighted = 0x80 }; - quint8 _selection; // save space, so we put both the col and the flags into one byte + enum { Selected = 0x40, Highlighted = 0x80 }; + quint8 _selection; // save space, so we put both the col and the flags into one byte }; #endif -- 2.20.1