Quassel IRC  Pre-Release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
chatline.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2015 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  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19  ***************************************************************************/
20 
21 #include <QDateTime>
22 #include <QGraphicsSceneMouseEvent>
23 #include <QString>
24 #include <QtGui>
25 
26 #include "bufferinfo.h"
27 #include "buffersyncer.h"
28 #include "client.h"
29 #include "chatitem.h"
30 #include "chatline.h"
31 #include "chatview.h"
32 #include "columnhandleitem.h"
33 #include "messagemodel.h"
34 #include "networkmodel.h"
35 #include "qtui.h"
36 #include "qtuisettings.h"
37 #include "qtuistyle.h"
38 
39 ChatLine::ChatLine(int row, QAbstractItemModel *model,
40  const qreal &width,
41  const qreal &timestampWidth, const qreal &senderWidth, const qreal &contentsWidth,
42  const QPointF &senderPos, const QPointF &contentsPos,
43  QGraphicsItem *parent)
44  : QGraphicsItem(parent),
45  _row(row), // needs to be set before the items
46  _model(model),
47  _contentsItem(contentsPos, contentsWidth, this),
48  _senderItem(QRectF(senderPos, QSizeF(senderWidth, _contentsItem.height())), this),
49  _timestampItem(QRectF(0, 0, timestampWidth, _contentsItem.height()), this),
50  _width(width),
51  _height(_contentsItem.height()),
52  _selection(0),
53  _mouseGrabberItem(0),
54  _hoverItem(0)
55 {
56  Q_ASSERT(model);
57  QModelIndex index = model->index(row, ChatLineModel::ContentsColumn);
58  setZValue(0);
59  setAcceptHoverEvents(true);
61 }
62 
63 
65 {
66  if (chatView())
67  chatView()->setHasCache(this, false);
68 }
69 
70 
72 {
73  switch (column) {
75  return &_timestampItem;
77  return &_senderItem;
79  return &_contentsItem;
80  default:
81  return 0;
82  }
83 }
84 
85 
86 ChatItem *ChatLine::itemAt(const QPointF &pos)
87 {
88  if (_contentsItem.boundingRect().contains(pos))
89  return &_contentsItem;
90  if (_senderItem.boundingRect().contains(pos))
91  return &_senderItem;
92  if (_timestampItem.boundingRect().contains(pos))
93  return &_timestampItem;
94  return 0;
95 }
96 
97 
99 {
103 }
104 
105 
107 {
109 }
110 
111 
112 bool ChatLine::sceneEvent(QEvent *event)
113 {
114  if (event->type() == QEvent::GrabMouse) {
115  // get mouse cursor pos relative to us
116  ChatView *view = chatScene()->chatView();
117  QPointF linePos = mapFromScene(view->mapToScene(view->mapFromGlobal(QCursor::pos())));
118  setMouseGrabberItem(itemAt(linePos));
119  }
120  else if (event->type() == QEvent::UngrabMouse) {
122  }
123  return QGraphicsItem::sceneEvent(event);
124 }
125 
126 
127 void ChatLine::setFirstColumn(const qreal &timestampWidth, const qreal &senderWidth, const QPointF &senderPos)
128 {
129  _timestampItem.setGeometry(timestampWidth, _height);
130  _senderItem.setGeometry(senderWidth, _height);
131  _senderItem.setPos(senderPos);
132 }
133 
134 
135 void ChatLine::setSecondColumn(const qreal &senderWidth, const qreal &contentsWidth, const QPointF &contentsPos, qreal &linePos)
136 {
137  // linepos is the *bottom* position for the line
138  qreal height = _contentsItem.setGeometryByWidth(contentsWidth);
139  linePos -= height;
140  bool needGeometryChange = (height != _height);
141 
142  _timestampItem.setHeight(height);
143  _senderItem.setGeometry(senderWidth, height);
144  _contentsItem.setPos(contentsPos);
145 
146  if (needGeometryChange)
147  prepareGeometryChange();
148 
149  _height = height;
150 
151  setPos(0, linePos);
152 }
153 
154 
155 void ChatLine::setGeometryByWidth(const qreal &width, const qreal &contentsWidth, qreal &linePos)
156 {
157  // linepos is the *bottom* position for the line
158  qreal height = _contentsItem.setGeometryByWidth(contentsWidth);
159  linePos -= height;
160  bool needGeometryChange = (height != _height || width != _width);
161 
162  if (height != _height) {
163  _timestampItem.setHeight(height);
164  _senderItem.setHeight(height);
165  }
166 
167  if (needGeometryChange) {
168  prepareGeometryChange();
169  _height = height;
170  _width = width;
171  }
172 
173  setPos(0, linePos); // set pos is _very_ cheap if nothing changes.
174 }
175 
176 
177 void ChatLine::setSelected(bool selected, ChatLineModel::ColumnType minColumn)
178 {
179  if (selected) {
180  quint8 sel = (_selection & Highlighted) | Selected | minColumn;
181  if (sel != _selection) {
182  _selection = sel;
183  for (int i = 0; i < minColumn; i++)
184  item((ChatLineModel::ColumnType)i)->clearSelection();
185  for (int i = minColumn; i <= ChatLineModel::ContentsColumn; i++)
186  item((ChatLineModel::ColumnType)i)->setFullSelection();
187  update();
188  }
189  }
190  else {
191  quint8 sel = _selection & Highlighted;
192  if (sel != _selection) {
193  _selection = sel;
194  for (int i = 0; i <= ChatLineModel::ContentsColumn; i++)
196  update();
197  }
198  }
199 }
200 
201 
202 void ChatLine::setHighlighted(bool highlighted)
203 {
204  if (highlighted) _selection |= Highlighted;
205  else _selection &= ~Highlighted;
206  update();
207 }
208 
209 
210 void ChatLine::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
211 {
212  Q_UNUSED(option);
213  Q_UNUSED(widget);
214 
215  const QAbstractItemModel *model_ = model();
216  QModelIndex myIdx = model_->index(row(), 0);
219 
220  QTextCharFormat msgFmt = QtUi::style()->format(UiStyle::formatType(type), label);
221  if (msgFmt.hasProperty(QTextFormat::BackgroundBrush)) {
222  painter->fillRect(boundingRect(), msgFmt.background());
223  }
224 
225  if (_selection & Selected) {
226  QTextCharFormat selFmt = QtUi::style()->format(UiStyle::formatType(type), label | UiStyle::Selected);
227  if (selFmt.hasProperty(QTextFormat::BackgroundBrush)) {
228  qreal left = item((ChatLineModel::ColumnType)(_selection & ItemMask))->pos().x();
229  QRectF selectRect(left, 0, width() - left, height());
230  painter->fillRect(selectRect, selFmt.background());
231  }
232  }
233 
234  // draw chatitems
235  // the items draw themselves at the correct position
236  timestampItem()->paint(painter, option, widget);
237  senderItem()->paint(painter, option, widget);
238  contentsItem()->paint(painter, option, widget);
239 }
240 
241 
242 // We need to dispatch all mouse-related events to the appropriate (mouse grabbing) ChatItem
243 
245 {
246  if (mouseGrabberItem())
247  return mouseGrabberItem();
248  return itemAt(pos);
249 }
250 
251 
252 void ChatLine::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
253 {
254  ChatItem *item = mouseEventTargetItem(event->pos());
255  if (item)
256  item->mouseMoveEvent(event);
257 }
258 
259 
260 void ChatLine::mousePressEvent(QGraphicsSceneMouseEvent *event)
261 {
262  ChatItem *item = mouseEventTargetItem(event->pos());
263  if (item)
264  item->mousePressEvent(event);
265 }
266 
267 
268 void ChatLine::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
269 {
270  ChatItem *item = mouseEventTargetItem(event->pos());
271  if (item)
272  item->mouseReleaseEvent(event);
273 }
274 
275 
276 void ChatLine::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
277 {
278  ChatItem *item = mouseEventTargetItem(event->pos());
279  if (item && !_hoverItem) {
280  _hoverItem = item;
281  item->hoverEnterEvent(event);
282  }
283 }
284 
285 
286 void ChatLine::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
287 {
288  if (_hoverItem) {
289  _hoverItem->hoverLeaveEvent(event);
290  _hoverItem = 0;
291  }
292 }
293 
294 
295 void ChatLine::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
296 {
297  ChatItem *item = mouseEventTargetItem(event->pos());
298  if (item)
299  item->hoverMoveEvent(event);
300 }