/***************************************************************************
- * Copyright (C) 2005-09 by the Quassel Project *
+ * Copyright (C) 2005-2010 by the Quassel Project *
* devel@quassel-irc.org *
* *
* This program is free software; you can redistribute it and/or modify *
#include "buffermodel.h"
#include "bufferview.h"
#include "chatitem.h"
+#include "chatline.h"
#include "chatlinemodel.h"
#include "contextmenuactionprovider.h"
#include "iconloader.h"
#include "qtui.h"
#include "qtuistyle.h"
-ChatItem::ChatItem(const qreal &width, const qreal &height, const QPointF &pos, QGraphicsItem *parent)
- : QGraphicsItem(parent),
- _boundingRect(0, 0, width, height),
- _selectionMode(NoSelection),
- _selectionStart(-1)
+ChatItem::ChatItem(const QRectF &boundingRect, ChatLine *parent)
+: _parent(parent),
+ _boundingRect(boundingRect),
+ _selectionMode(NoSelection),
+ _selectionStart(-1)
{
- setAcceptHoverEvents(true);
- setZValue(20);
- setPos(pos);
+
+}
+
+ChatLine *ChatItem::chatLine() const {
+ return _parent;
+}
+
+ChatScene *ChatItem::chatScene() const {
+ return chatLine()->chatScene();
+}
+
+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 {
return model()->data(index, role);
}
-qint16 ChatItem::posToCursor(const QPointF &pos) const {
+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;
}
void ChatItem::paintBackground(QPainter *painter) {
- painter->setClipRect(boundingRect()); // no idea why QGraphicsItem clipping won't work
-
QVariant bgBrush;
if(_selectionMode == FullSelection)
bgBrush = data(ChatLineModel::SelectedBackgroundRole);
// This is a deliberate trade-off. (-> selectFmt creation, data() call)
void ChatItem::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);
- layout.draw(painter, QPointF(0,0), additionalFormats(), boundingRect());
+ layout.draw(painter, pos(), additionalFormats(), boundingRect());
// layout()->draw(painter, QPointF(0,0), formats, boundingRect());
// }
// 3) draw bounding rect
// painter->drawRect(_boundingRect.adjusted(0, 0, -1, -1));
+
+ painter->restore();
}
void ChatItem::overlayFormat(UiStyle::FormatList &fmtList, int start, int end, quint32 overlayFmt) const {
_selectionMode = mode;
_selectionStart = start;
_selectionEnd = end;
- update();
+ chatLine()->update();
}
void ChatItem::setFullSelection() {
if(_selectionMode != FullSelection) {
_selectionMode = FullSelection;
- update();
+ chatLine()->update();
}
}
void ChatItem::clearSelection() {
if(_selectionMode != NoSelection) {
_selectionMode = NoSelection;
- update();
+ chatLine()->update();
}
}
void ChatItem::continueSelecting(const QPointF &pos) {
_selectionMode = PartialSelection;
_selectionEnd = posToCursor(pos);
- update();
+ chatLine()->update();
}
bool ChatItem::isPosOverSelection(const QPointF &pos) const {
chatScene()->setSelectingItem(this);
_selectionStart = _selectionEnd = posToCursor(pos);
_selectionMode = NoSelection; // will be set to PartialSelection by mouseMoveEvent
- update();
+ chatLine()->update();
}
}
void ChatItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
if(event->buttons() == Qt::LeftButton) {
- if(contains(event->pos())) {
+ if(boundingRect().contains(event->pos())) {
qint16 end = posToCursor(event->pos());
if(end != _selectionEnd) {
_selectionEnd = end;
_selectionMode = (_selectionStart != _selectionEnd ? PartialSelection : NoSelection);
- update();
+ chatLine()->update();
}
} else {
setFullSelection();
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;
gradient.setColorAt(0, Qt::white);
gradient.setColorAt(1, Qt::black);
}
- maskPainter.fillRect(boundingRect(), gradient);
+ maskPainter.fillRect(0, 0, pixmap.width(), pixmap.height(), gradient);
pixmap.setAlphaChannel(mask);
- painter->drawPixmap(0, 0, pixmap);
+ painter->drawPixmap(pos(), pixmap);
} else {
- layout.draw(painter, QPointF(0,0), additionalFormats(), boundingRect());
+ layout.draw(painter, pos(), additionalFormats(), boundingRect());
}
+ painter->restore();
+}
+
+void SenderChatItem::handleClick(const QPointF &pos, ChatScene::ClickMode clickMode) {
+ if(clickMode == ChatScene::DoubleClick) {
+ BufferInfo curBufInfo = Client::networkModel()->bufferInfo(data(MessageModel::BufferIdRole).value<BufferId>());
+ QString nick = data(MessageModel::EditRole).toString();
+ // check if the nick is a valid ircUser
+ if(!nick.isEmpty() && Client::network(curBufInfo.networkId())->ircUser(nick))
+ Client::bufferModel()->switchToOrStartQuery(curBufInfo.networkId(), nick);
+ }
+ else
+ ChatItem::handleClick(pos, clickMode);
}
// ************************************************************
ContentsChatItem::ActionProxy ContentsChatItem::_actionProxy;
-ContentsChatItem::ContentsChatItem(const qreal &width, const QPointF &pos, QGraphicsItem *parent)
- : ChatItem(0, 0, pos, parent),
+ContentsChatItem::ContentsChatItem(const QPointF &pos, const qreal &width, ChatLine *parent)
+ : ChatItem(QRectF(pos, QSizeF(width, 0)), parent),
_data(0)
{
+ setPos(pos);
setGeometryByWidth(width);
}
WrapColumnFinder finder(this);
while(finder.nextWrapColumn(w) > 0)
lines++;
- qreal h = lines * fontMetrics()->lineSpacing();
+ qreal spacing = qMax(fontMetrics()->lineSpacing(), fontMetrics()->height()); // cope with negative leading()
+ qreal h = lines * spacing;
delete _data;
_data = 0;
- if(w != width() || h != height()) {
- prepareGeometryChange();
+ if(w != width() || h != height())
setGeometry(w, h);
- }
+
return h;
}
if(!wrapList.count()) return; // empty chatitem
qreal h = 0;
+ qreal spacing = qMax(fontMetrics()->lineSpacing(), fontMetrics()->height()); // cope with negative leading()
WrapColumnFinder finder(this);
layout->beginLayout();
forever {
// Sometimes, setNumColumns will create a line that's too long (cf. Qt bug 238249)
// We verify this and try setting the width again, making it shorter each time until the lengths match.
// Dead fugly, but seems to work…
- for(int i = line.textLength()-1; line.textLength() > num; i--) {
+ for(int i = line.textLength()-1; i >= 0 && line.textLength() > num; i--) {
line.setNumColumns(i);
}
if(num != line.textLength()) {
}
line.setPosition(QPointF(0, h));
- h += fontMetrics()->lineSpacing();
+ h += spacing;
}
layout->endLayout();
}
void ContentsChatItem::endHoverMode() {
if(privateData()) {
if(privateData()->currentClickable.isValid()) {
- setCursor(Qt::ArrowCursor);
+ chatLine()->setCursor(Qt::ArrowCursor);
privateData()->currentClickable = Clickable();
}
clearWebPreview();
- update();
+ chatLine()->update();
}
}
setSelectionStart(start);
setSelectionEnd(end);
}
- update();
+ chatLine()->update();
} else if(clickMode == ChatScene::TripleClick) {
setSelection(PartialSelection, 0, data(ChatLineModel::DisplayRole).toString().length());
}
onClickable = true;
}
if(onClickable) {
- setCursor(Qt::PointingHandCursor);
+ chatLine()->setCursor(Qt::PointingHandCursor);
privateData()->currentClickable = click;
- update();
+ chatLine()->update();
return;
}
}
qreal height = line.height();
qreal y = height * line.lineNumber();
- QPointF topLeft = scenePos() + QPointF(x, y);
+ QPointF topLeft = mapToScene(pos()) + QPointF(x, y);
QRectF urlRect = QRectF(topLeft.x(), topLeft.y(), width, height);
QString urlstr = data(ChatLineModel::DisplayRole).toString().mid(click.start(), click.length());