+ QList<Clickable> findClickables() const;
+ Clickable clickableAt(const QPointF &pos) const;
+
+ void endHoverMode();
+ void showWebPreview(const Clickable &click);
+ void clearWebPreview();
+
+ qreal setGeometryByWidth(qreal w);
+ friend class ChatLine;
+ friend struct ContentsChatItemPrivate;
+
+ QFontMetricsF *_fontMetrics;
+
+ // we need a receiver for Action signals
+ static ActionProxy _actionProxy;
+};
+
+struct ContentsChatItem::Clickable {
+ // Don't change these enums without also changing the regexps in analyze()!
+ enum Type {
+ Invalid = -1,
+ Url = 0,
+ Channel = 1,
+ Nick = 2
+ };
+
+ Type type;
+ quint16 start;
+ quint16 length;
+
+ inline Clickable() : type(Invalid) {};
+ inline Clickable(Type type_, quint16 start_, quint16 length_) : type(type_), start(start_), length(length_) {};
+ inline bool isValid() const { return type != Invalid; }
+};
+
+struct ContentsChatItemPrivate {
+ ContentsChatItem *contentsItem;
+ QList<ContentsChatItem::Clickable> clickables;
+ ContentsChatItem::Clickable currentClickable;
+ ContentsChatItem::Clickable activeClickable;
+
+ ContentsChatItemPrivate(const QList<ContentsChatItem::Clickable> &c, ContentsChatItem *parent) : contentsItem(parent), clickables(c) {}
+};
+
+//! Acts as a proxy for Action signals targetted at a ContentsChatItem
+/** Since a ChatItem is not a QObject, hence cannot receive signals, we use a static ActionProxy
+ * as a receiver instead. This avoids having to handle ChatItem actions (e.g. context menu entries)
+ * outside the ChatItem.
+ */
+class ContentsChatItem::ActionProxy : public QObject {
+ Q_OBJECT
+
+public slots:
+ inline void copyLinkToClipboard() { item()->copyLinkToClipboard(); }
+
+private:
+ /// Returns the ContentsChatItem that should receive the action event.
+ /** For efficiency reasons, values are not checked for validity. You gotta make sure that you set the data() member
+ * in the Action correctly.
+ * @return The ChatItem from which the sending Action originated
+ */
+ inline ContentsChatItem *item() const {
+ return static_cast<ContentsChatItem *>(qobject_cast<QAction *>(sender())->data().value<void *>());
+ }
+};
+
+/*************************************************************************************************/
+
+// Avoid circular include deps
+#include "chatline.h"
+const QAbstractItemModel *ChatItem::model() const { return static_cast<ChatLine *>(parentItem())->model(); }
+int ChatItem::row() const { return static_cast<ChatLine *>(parentItem())->row(); }