From: Manuel Nickschas Date: Mon, 28 Jul 2008 20:23:50 +0000 (+0200) Subject: Make intra-item selections work X-Git-Tag: 0.3.0~149 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=1183bd403b16d86ef59503185b9ab4d35eb8c93f Make intra-item selections work --- diff --git a/src/qtui/chatitem.cpp b/src/qtui/chatitem.cpp index 235868d0..7d52c5a5 100644 --- a/src/qtui/chatitem.cpp +++ b/src/qtui/chatitem.cpp @@ -18,9 +18,12 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ +#include +#include #include #include #include +#include #include #include "chatitem.h" @@ -31,6 +34,7 @@ ChatItem::ChatItem(const QPersistentModelIndex &index_, QGraphicsItem *parent) : _fontMetrics = QtUi::style()->fontMetrics(data(ChatLineModel::FormatRole).value().at(0).second); _layout = 0; _lines = 0; + _selectionStart = -1; } ChatItem::~ChatItem() { @@ -137,17 +141,72 @@ void ChatItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, _layout->draw(painter, QPointF(0,0), QVector(), boundingRect()); } -/* -void ChatItem::mouseMoveEvent ( QGraphicsSceneMouseEvent * event ) { - qDebug() << (void*)this << "moving" << event->pos(); - if(event->pos().y() < 0) { - QTextCursor cursor(document()); - //cursor.insertText("foo"); - //cursor.select(QTextCursor::Document); +int ChatItem::posToCursor(const QPointF &pos) { + if(pos.y() > height()) return data(MessageModel::DisplayRole).toString().length(); + if(pos.y() < 0) return 0; + if(!haveLayout()) updateLayout(); + for(int l = _layout->lineCount() - 1; l >= 0; l--) { + QTextLine line = _layout->lineAt(l); + if(pos.y() >= line.y()) { + return line.xToCursor(pos.x(), QTextLine::CursorOnCharacter); + } + } + return 0; +} + +void ChatItem::clearSelection() { + if(_selectionStart >= 0) { + QList formats = _layout->additionalFormats(); + formats.removeLast(); + _layout->setAdditionalFormats(formats); + _selectionStart = -1; + updateLayout(); + update(); + } +} + +void ChatItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { + int selectionEnd = posToCursor(event->pos()); + QList formats = _layout->additionalFormats(); + formats.last().start = qMin(_selectionStart, selectionEnd); + formats.last().length = qMax(_selectionStart, selectionEnd) - formats.last().start; + _layout->setAdditionalFormats(formats); + updateLayout(); + update(); +} + +void ChatItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { + if(event->buttons() & Qt::LeftButton) { + if(!haveLayout()) updateLayout(); + chatScene()->setSelectingItem(this); + _selectionStart = posToCursor(event->pos()); + QList formats = _layout->additionalFormats(); + QTextLayout::FormatRange selectFmt; + QPalette pal = QApplication::palette(); + selectFmt.format.setForeground(pal.brush(QPalette::HighlightedText)); + selectFmt.format.setBackground(pal.brush(QPalette::Highlight)); + selectFmt.length = 0; + formats.append(selectFmt); + _layout->setAdditionalFormats(formats); + updateLayout(); + update(); + event->accept(); + } else { event->ignore(); - } else QGraphicsTextItem::mouseMoveEvent(event); + } +} + +void ChatItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { + if(_selectionStart >= 0) { + int selectionEnd = posToCursor(event->pos()); + QString selection + = data(MessageModel::DisplayRole).toString().mid(qMin(_selectionStart, selectionEnd), qAbs(_selectionStart - selectionEnd)); + QApplication::clipboard()->setText(selection, QClipboard::Clipboard); // TODO configure where selections should go + event->accept(); + } else { + event->ignore(); + } } -*/ /*************************************************************************************************/ diff --git a/src/qtui/chatitem.h b/src/qtui/chatitem.h index 73e18067..713d808d 100644 --- a/src/qtui/chatitem.h +++ b/src/qtui/chatitem.h @@ -22,9 +22,11 @@ #define CHATITEM_H_ #include +#include #include "chatline.h" #include "chatlinemodel.h" +#include "chatscene.h" #include "uistyle.h" class QTextLayout; @@ -38,6 +40,7 @@ class ChatItem : public QGraphicsItem { inline QPersistentModelIndex index() const { return _index; } inline const MessageModel *model() const { return _index.isValid() ? qobject_cast(_index.model()) : 0; } inline int row() const { return _index.isValid() ? _index.row() : 0; } + inline ChatScene *chatScene() const { return qobject_cast(scene()); } inline QFontMetricsF *fontMetrics() const { return _fontMetrics; } inline virtual QRectF boundingRect() const { return _boundingRect; } @@ -54,10 +57,17 @@ class ChatItem : public QGraphicsItem { // returns height int setWidth(int width); + // selection stuff, to be called by the scene + void clearSelection(); + void setFullSelection(); + protected: - //void mouseMoveEvent ( QGraphicsSceneMouseEvent * event ); + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); private: + int posToCursor(const QPointF &pos); int heightForWidth(int width); QTextLayout *createLayout(QTextOption::WrapMode, Qt::Alignment = Qt::AlignLeft); @@ -68,6 +78,7 @@ class ChatItem : public QGraphicsItem { QTextLayout *_layout; QList _wrapPositions; + int _selectionStart; class WrapColumnFinder; }; diff --git a/src/qtui/chatscene.cpp b/src/qtui/chatscene.cpp index 8d830b6f..e4a0bd7d 100644 --- a/src/qtui/chatscene.cpp +++ b/src/qtui/chatscene.cpp @@ -37,6 +37,7 @@ ChatScene::ChatScene(QAbstractItemModel *model, const QString &idString, QObject _model(model) { _width = 0; + _selectingItem = 0; connect(this, SIGNAL(sceneRectChanged(const QRectF &)), this, SLOT(rectChanged(const QRectF &))); connect(model, SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(rowsInserted(const QModelIndex &, int, int))); @@ -139,3 +140,23 @@ void ChatScene::handlePositionChanged(qreal xpos) { // width() should be the same for both handles, so just use firstColHandle regardless update(qMin(oldx, xpos) - firstColHandle->width()/2, 0, qMax(oldx, xpos) + firstColHandle->width()/2, height()); } + +void ChatScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { + + QGraphicsScene::mouseMoveEvent(event); +} + +void ChatScene::mousePressEvent(QGraphicsSceneMouseEvent *event) { + + QGraphicsScene::mousePressEvent(event); +} + +void ChatScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { + + QGraphicsScene::mouseReleaseEvent(event); +} + +void ChatScene::setSelectingItem(ChatItem *item) { + if(_selectingItem) _selectingItem->clearSelection(); + _selectingItem = item; +} diff --git a/src/qtui/chatscene.h b/src/qtui/chatscene.h index 8701f697..8fd5bf4d 100644 --- a/src/qtui/chatscene.h +++ b/src/qtui/chatscene.h @@ -45,16 +45,25 @@ class ChatScene : public QGraphicsScene { public slots: void setWidth(qreal); - private slots: - void rectChanged(const QRectF &); - void handlePositionChanged(qreal xpos); + // these are used by the chatitems to notify the scene + void setSelectingItem(ChatItem *item); + ChatItem *selectingItem() const { return _selectingItem; } signals: void heightChanged(qreal height); + protected: + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent); + virtual void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent); + protected slots: void rowsInserted(const QModelIndex &, int, int); + private slots: + void rectChanged(const QRectF &); + void handlePositionChanged(qreal xpos); + private: QString _idString; qreal _width, _height; @@ -63,6 +72,8 @@ class ChatScene : public QGraphicsScene { ColumnHandleItem *firstColHandle, *secondColHandle; qreal firstColHandlePos, secondColHandlePos; + + ChatItem *_selectingItem; }; #endif