URL recognition (WiP)
[quassel.git] / src / qtui / chatitem.h
1 /***************************************************************************
2  *   Copyright (C) 2005-08 by the Quassel Project                          *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) version 3.                                           *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21 #ifndef CHATITEM_H_
22 #define CHATITEM_H_
23
24 #include <QGraphicsItem>
25 #include <QObject>
26
27 #include "chatlinemodel.h"
28 #include "chatscene.h"
29 #include "uistyle.h"
30 #include "qtui.h"
31
32 class QTextLayout;
33
34 class ChatItem : public QGraphicsItem {
35
36 protected:
37   ChatItem(ChatLineModel::ColumnType column, QAbstractItemModel *, QGraphicsItem *parent);
38   virtual ~ChatItem();
39
40 public:
41   inline const QAbstractItemModel *model() const { return chatScene() ? chatScene()->model() : 0; }
42   inline int row() const;
43   virtual ChatLineModel::ColumnType column() const = 0;
44   inline ChatScene *chatScene() const { return qobject_cast<ChatScene *>(scene()); }
45
46   inline QFontMetricsF *fontMetrics() const { return _fontMetrics; }
47   inline QRectF boundingRect() const { return _boundingRect; }
48   inline qreal width() const { return _boundingRect.width(); }
49   inline qreal height() const { return _boundingRect.height(); }
50
51   virtual inline bool haveLayout() const { return layout() != 0; }
52   virtual void clearLayout();
53   virtual QTextLayout *createLayout(QTextOption::WrapMode, Qt::Alignment = Qt::AlignLeft);
54   virtual void updateLayout();
55   virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
56
57   virtual QVariant data(int role) const;
58
59   // returns height
60   qreal setGeometry(qreal width, qreal height = -1);
61
62   // selection stuff, to be called by the scene
63   void clearSelection();
64   void setFullSelection();
65   void continueSelecting(const QPointF &pos);
66
67   QList<QRectF> findWords(const QString &searchWord, Qt::CaseSensitivity caseSensitive);
68
69 protected:
70   virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
71   virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
72   virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
73
74   virtual inline QTextLayout *layout() const { return _layout; }
75   virtual inline void setLayout(QTextLayout *l) { _layout = l; }
76   qint16 posToCursor(const QPointF &pos);
77
78   virtual qreal computeHeight();
79
80   QRectF _boundingRect;
81
82 private:
83   // internal selection stuff
84   void setSelection(int start, int length);
85
86   QFontMetricsF *_fontMetrics;
87
88   enum SelectionMode { NoSelection, PartialSelection, FullSelection };
89   SelectionMode _selectionMode;
90   qint16 _selectionStart, _selectionEnd;
91
92   QTextLayout *_layout;
93 };
94
95 /*************************************************************************************************/
96
97 //! A ChatItem for the timestamp column
98 class TimestampChatItem : public ChatItem {
99
100 public:
101   TimestampChatItem(QAbstractItemModel *model, QGraphicsItem *parent) : ChatItem(column(), model, parent) {}
102   inline ChatLineModel::ColumnType column() const { return ChatLineModel::TimestampColumn; }
103
104 };
105
106 /*************************************************************************************************/
107
108 //! A ChatItem for the sender column
109 class SenderChatItem : public ChatItem {
110
111 public:
112   SenderChatItem(QAbstractItemModel *model, QGraphicsItem *parent) : ChatItem(column(), model, parent) {}
113   inline ChatLineModel::ColumnType column() const { return ChatLineModel::SenderColumn; }
114
115   virtual void updateLayout();
116 };
117
118 /*************************************************************************************************/
119
120 //! A ChatItem for the contents column
121 class ContentsChatItem : public ChatItem {
122
123 public:
124   ContentsChatItem(QAbstractItemModel *model, QGraphicsItem *parent);
125   virtual ~ContentsChatItem();
126
127   inline ChatLineModel::ColumnType column() const { return ChatLineModel::ContentsColumn; }
128
129   virtual void clearLayout();
130   virtual void updateLayout();
131   virtual inline bool haveLayout() const { return _layoutData != 0 && layout() != 0; }
132
133 protected:
134   virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
135   virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
136   virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
137   virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
138
139   virtual inline QTextLayout *layout() const;
140   virtual void setLayout(QTextLayout *l);
141
142 private:
143   struct LayoutData;
144   struct Clickable;
145   class WrapColumnFinder;
146
147   qreal computeHeight();
148   void analyze();
149
150   LayoutData *_layoutData;
151 };
152
153 struct ContentsChatItem::Clickable {
154   enum Type {
155     Url,
156     Channel,
157     Nick
158   };
159
160   quint16 start;
161   quint16 length;
162   Type type;
163 };
164
165 struct ContentsChatItem::LayoutData {
166   QTextLayout *layout;
167   QList<Clickable> clickables;
168
169   LayoutData() { layout = 0; }
170   ~LayoutData() { delete layout; }
171 };
172
173 class ContentsChatItem::WrapColumnFinder {
174 public:
175   WrapColumnFinder(ChatItem *parent);
176   ~WrapColumnFinder();
177
178   qint16 nextWrapColumn();
179
180 private:
181   ChatItem *item;
182   QTextLayout *layout;
183   QTextLine line;
184   ChatLineModel::WrapList wrapList;
185   qint16 wordidx;
186   qint16 lastwrapcol;
187   qreal lastwrappos;
188   qreal w;
189 };
190
191 /*************************************************************************************************/
192
193 // Avoid circular include deps
194 #include "chatline.h"
195 int ChatItem::row() const { return static_cast<ChatLine *>(parentItem())->row(); }
196 QTextLayout *ContentsChatItem::layout() const { return _layoutData->layout; }
197
198 #endif