forked from blue/squawk
selection message body now actually working
This commit is contained in:
parent
0340db7f2f
commit
3c48577eee
@ -69,6 +69,12 @@ static const std::vector<QColor> colorPalette = {
|
|||||||
QColor(17, 17, 80),
|
QColor(17, 17, 80),
|
||||||
QColor(54, 54, 94)
|
QColor(54, 54, 94)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class Hover {
|
||||||
|
nothing,
|
||||||
|
text,
|
||||||
|
anchor
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // SHARED_UTILS_H
|
#endif // SHARED_UTILS_H
|
||||||
|
@ -499,6 +499,16 @@ void Conversation::onFeedContext(const QPoint& pos)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString selected = feed->getSelectedText();
|
||||||
|
if (selected.size() > 0) {
|
||||||
|
showMenu = true;
|
||||||
|
QAction* copy = contextMenu->addAction(Shared::icon("edit-copy"), tr("Copy selected"));
|
||||||
|
connect(copy, &QAction::triggered, [selected] () {
|
||||||
|
QClipboard* cb = QApplication::clipboard();
|
||||||
|
cb->setText(selected);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
QString body = item->getBody();
|
QString body = item->getBody();
|
||||||
if (body.size() > 0) {
|
if (body.size() > 0) {
|
||||||
showMenu = true;
|
showMenu = true;
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
#include <QPaintEvent>
|
#include <QPaintEvent>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QClipboard>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include "messagedelegate.h"
|
#include "messagedelegate.h"
|
||||||
@ -53,9 +55,10 @@ FeedView::FeedView(QWidget* parent):
|
|||||||
dividerMetrics(dividerFont),
|
dividerMetrics(dividerFont),
|
||||||
mousePressed(false),
|
mousePressed(false),
|
||||||
dragging(false),
|
dragging(false),
|
||||||
anchorHovered(false),
|
hovered(Shared::Hover::nothing),
|
||||||
dragStartPoint(),
|
dragStartPoint(),
|
||||||
dragEndPoint()
|
dragEndPoint(),
|
||||||
|
selectedText()
|
||||||
{
|
{
|
||||||
horizontalScrollBar()->setRange(0, 0);
|
horizontalScrollBar()->setRange(0, 0);
|
||||||
verticalScrollBar()->setSingleStep(approximateSingleMessageHeight);
|
verticalScrollBar()->setSingleStep(approximateSingleMessageHeight);
|
||||||
@ -167,7 +170,7 @@ void FeedView::dataChanged(const QModelIndex& topLeft, const QModelIndex& bottom
|
|||||||
|
|
||||||
void FeedView::updateGeometries()
|
void FeedView::updateGeometries()
|
||||||
{
|
{
|
||||||
qDebug() << "updateGeometries";
|
//qDebug() << "updateGeometries";
|
||||||
QScrollBar* bar = verticalScrollBar();
|
QScrollBar* bar = verticalScrollBar();
|
||||||
|
|
||||||
const QStyle* st = style();
|
const QStyle* st = style();
|
||||||
@ -307,7 +310,7 @@ bool FeedView::tryToCalculateGeometriesWithNoScrollbars(const QStyleOptionViewIt
|
|||||||
|
|
||||||
void FeedView::paintEvent(QPaintEvent* event)
|
void FeedView::paintEvent(QPaintEvent* event)
|
||||||
{
|
{
|
||||||
qDebug() << "paint" << event->rect();
|
//qDebug() << "paint" << event->rect();
|
||||||
const QAbstractItemModel* m = model();
|
const QAbstractItemModel* m = model();
|
||||||
QWidget* vp = viewport();
|
QWidget* vp = viewport();
|
||||||
QRect zone = event->rect().translated(0, -vo);
|
QRect zone = event->rect().translated(0, -vo);
|
||||||
@ -412,14 +415,20 @@ void FeedView::verticalScrollbarValueChanged(int value)
|
|||||||
QAbstractItemView::verticalScrollbarValueChanged(vo);
|
QAbstractItemView::verticalScrollbarValueChanged(vo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FeedView::setAnchorHovered(bool hovered)
|
void FeedView::setAnchorHovered(Shared::Hover type)
|
||||||
{
|
{
|
||||||
if (anchorHovered != hovered) {
|
if (hovered != type) {
|
||||||
anchorHovered = hovered;
|
hovered = type;
|
||||||
if (anchorHovered) {
|
switch (hovered) {
|
||||||
setCursor(Qt::PointingHandCursor);
|
case Shared::Hover::nothing:
|
||||||
} else {
|
|
||||||
setCursor(Qt::ArrowCursor);
|
setCursor(Qt::ArrowCursor);
|
||||||
|
break;
|
||||||
|
case Shared::Hover::text:
|
||||||
|
setCursor(Qt::IBeamCursor);
|
||||||
|
break;
|
||||||
|
case Shared::Hover::anchor:
|
||||||
|
setCursor(Qt::PointingHandCursor);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -441,25 +450,31 @@ void FeedView::mouseMoveEvent(QMouseEvent* event)
|
|||||||
QAbstractItemView::mouseMoveEvent(event);
|
QAbstractItemView::mouseMoveEvent(event);
|
||||||
|
|
||||||
if (specialDelegate) {
|
if (specialDelegate) {
|
||||||
|
MessageDelegate* del = static_cast<MessageDelegate*>(itemDelegate());
|
||||||
|
if (dragging) {
|
||||||
|
QModelIndex index = indexAt(dragStartPoint);
|
||||||
|
if (index.isValid()) {
|
||||||
|
QRect rect = visualRect(index);
|
||||||
|
if (rect.contains(dragStartPoint)) {
|
||||||
|
QString selected = del->mouseDrag(dragStartPoint, dragEndPoint, index, rect);
|
||||||
|
if (selectedText != selected) {
|
||||||
|
selectedText = selected;
|
||||||
|
setDirtyRegion(rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
QModelIndex index = indexAt(dragEndPoint);
|
QModelIndex index = indexAt(dragEndPoint);
|
||||||
if (index.isValid()) {
|
if (index.isValid()) {
|
||||||
QRect rect = visualRect(index);
|
QRect rect = visualRect(index);
|
||||||
if (rect.contains(dragEndPoint)) {
|
if (rect.contains(dragEndPoint)) {
|
||||||
MessageDelegate* del = static_cast<MessageDelegate*>(itemDelegate());
|
setAnchorHovered(del->hoverType(dragEndPoint, index, rect));
|
||||||
if (dragging) {
|
} else {
|
||||||
setAnchorHovered(false);
|
setAnchorHovered(Shared::Hover::nothing);
|
||||||
if (del->mouseDrag(dragStartPoint, dragEndPoint, index, rect)) {
|
|
||||||
qDebug() << "asking to repaint" << rect;
|
|
||||||
setDirtyRegion(rect);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setAnchorHovered(del->isAnchorHovered(dragEndPoint, index, rect));
|
setAnchorHovered(Shared::Hover::nothing);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
setAnchorHovered(false);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setAnchorHovered(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -470,6 +485,17 @@ void FeedView::mousePressEvent(QMouseEvent* event)
|
|||||||
mousePressed = event->button() == Qt::LeftButton;
|
mousePressed = event->button() == Qt::LeftButton;
|
||||||
if (mousePressed) {
|
if (mousePressed) {
|
||||||
dragStartPoint = event->localPos().toPoint();
|
dragStartPoint = event->localPos().toPoint();
|
||||||
|
if (specialDelegate && specialModel) {
|
||||||
|
MessageDelegate* del = static_cast<MessageDelegate*>(itemDelegate());
|
||||||
|
QString lastSelectedId = del->clearSelection();
|
||||||
|
if (lastSelectedId.size()) {
|
||||||
|
Models::MessageFeed* feed = static_cast<Models::MessageFeed*>(model());
|
||||||
|
QModelIndex index = feed->modelIndexById(lastSelectedId);
|
||||||
|
if (index.isValid()) {
|
||||||
|
setDirtyRegion(visualRect(index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,6 +520,17 @@ void FeedView::mouseReleaseEvent(QMouseEvent* event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FeedView::keyPressEvent(QKeyEvent* event)
|
||||||
|
{
|
||||||
|
QKeyEvent *key_event = static_cast<QKeyEvent*>(event);
|
||||||
|
if (key_event->matches(QKeySequence::Copy)) {
|
||||||
|
if (selectedText.size() > 0) {
|
||||||
|
QClipboard* cb = QApplication::clipboard();
|
||||||
|
cb->setText(selectedText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FeedView::resizeEvent(QResizeEvent* event)
|
void FeedView::resizeEvent(QResizeEvent* event)
|
||||||
{
|
{
|
||||||
QAbstractItemView::resizeEvent(event);
|
QAbstractItemView::resizeEvent(event);
|
||||||
@ -603,3 +640,8 @@ void FeedView::onModelSyncStateChange(Models::MessageFeed::SyncState state)
|
|||||||
scheduleDelayedItemsLayout();
|
scheduleDelayedItemsLayout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString FeedView::getSelectedText() const
|
||||||
|
{
|
||||||
|
return selectedText;
|
||||||
|
}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#include <ui/widgets/messageline/messagefeed.h>
|
#include <ui/widgets/messageline/messagefeed.h>
|
||||||
#include <ui/utils/progress.h>
|
#include <ui/utils/progress.h>
|
||||||
|
#include <shared/utils.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @todo write docs
|
* @todo write docs
|
||||||
@ -50,6 +51,7 @@ public:
|
|||||||
void setModel(QAbstractItemModel * model) override;
|
void setModel(QAbstractItemModel * model) override;
|
||||||
|
|
||||||
QFont getFont() const;
|
QFont getFont() const;
|
||||||
|
QString getSelectedText() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void resized();
|
void resized();
|
||||||
@ -72,13 +74,14 @@ protected:
|
|||||||
void mouseMoveEvent(QMouseEvent * event) override;
|
void mouseMoveEvent(QMouseEvent * event) override;
|
||||||
void mousePressEvent(QMouseEvent * event) override;
|
void mousePressEvent(QMouseEvent * event) override;
|
||||||
void mouseReleaseEvent(QMouseEvent * event) override;
|
void mouseReleaseEvent(QMouseEvent * event) override;
|
||||||
|
void keyPressEvent(QKeyEvent * event) override;
|
||||||
void resizeEvent(QResizeEvent * event) override;
|
void resizeEvent(QResizeEvent * event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool tryToCalculateGeometriesWithNoScrollbars(const QStyleOptionViewItem& option, const QAbstractItemModel* model, uint32_t totalHeight);
|
bool tryToCalculateGeometriesWithNoScrollbars(const QStyleOptionViewItem& option, const QAbstractItemModel* model, uint32_t totalHeight);
|
||||||
void positionProgress();
|
void positionProgress();
|
||||||
void drawDateDevider(int top, const QDateTime& date, QPainter& painter);
|
void drawDateDevider(int top, const QDateTime& date, QPainter& painter);
|
||||||
void setAnchorHovered(bool hovered);
|
void setAnchorHovered(Shared::Hover type);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Hint {
|
struct Hint {
|
||||||
@ -100,9 +103,10 @@ private:
|
|||||||
QFontMetrics dividerMetrics;
|
QFontMetrics dividerMetrics;
|
||||||
bool mousePressed;
|
bool mousePressed;
|
||||||
bool dragging;
|
bool dragging;
|
||||||
bool anchorHovered;
|
Shared::Hover hovered;
|
||||||
QPoint dragStartPoint;
|
QPoint dragStartPoint;
|
||||||
QPoint dragEndPoint;
|
QPoint dragEndPoint;
|
||||||
|
QString selectedText;
|
||||||
|
|
||||||
static const std::set<int> geometryChangingRoles;
|
static const std::set<int> geometryChangingRoles;
|
||||||
|
|
||||||
|
@ -434,13 +434,37 @@ void MessageDelegate::leftClick(const QPoint& point, const QModelIndex& index, c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MessageDelegate::isAnchorHovered(const QPoint& point, const QModelIndex& index, const QRect& sizeHint) const
|
Shared::Hover MessageDelegate::hoverType(const QPoint& point, const QModelIndex& index, const QRect& sizeHint) const
|
||||||
{
|
{
|
||||||
QString anchor = getAnchor(point, index, sizeHint);
|
QVariant vi = index.data(Models::MessageFeed::Bulk);
|
||||||
return anchor.size() > 0;
|
Models::FeedItem data = qvariant_cast<Models::FeedItem>(vi);
|
||||||
|
if (data.text.size() > 0) {
|
||||||
|
QRect localHint = getHoveredMessageBodyRect(index, data, sizeHint);
|
||||||
|
|
||||||
|
if (localHint.contains(point)) {
|
||||||
|
QPoint translated = point - localHint.topLeft();
|
||||||
|
|
||||||
|
bodyRenderer->setHtml(Shared::processMessageBody(data.text));
|
||||||
|
bodyRenderer->setTextWidth(localHint.size().width());
|
||||||
|
|
||||||
|
QAbstractTextDocumentLayout* lay = bodyRenderer->documentLayout();
|
||||||
|
QString anchor = lay->anchorAt(translated);
|
||||||
|
|
||||||
|
if (anchor.size() > 0) {
|
||||||
|
return Shared::Hover::anchor;
|
||||||
|
} else {
|
||||||
|
int position = lay->hitTest(translated, Qt::HitTestAccuracy::ExactHit);
|
||||||
|
if (position != -1) { //this is a bad way, it's false positive on the end of the last
|
||||||
|
return Shared::Hover::text; //line of a multiline block, so it's not better the checking the rect
|
||||||
|
}
|
||||||
|
//return Shared::Hover::text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Shared::Hover::nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MessageDelegate::mouseDrag(const QPoint& start, const QPoint& end, const QModelIndex& index, const QRect& sizeHint)
|
QString MessageDelegate::mouseDrag(const QPoint& start, const QPoint& end, const QModelIndex& index, const QRect& sizeHint)
|
||||||
{
|
{
|
||||||
QVariant vi = index.data(Models::MessageFeed::Bulk);
|
QVariant vi = index.data(Models::MessageFeed::Bulk);
|
||||||
Models::FeedItem data = qvariant_cast<Models::FeedItem>(vi);
|
Models::FeedItem data = qvariant_cast<Models::FeedItem>(vi);
|
||||||
@ -448,19 +472,31 @@ bool MessageDelegate::mouseDrag(const QPoint& start, const QPoint& end, const QM
|
|||||||
QRect localHint = getHoveredMessageBodyRect(index, data, sizeHint);
|
QRect localHint = getHoveredMessageBodyRect(index, data, sizeHint);
|
||||||
|
|
||||||
if (localHint.contains(start)) {
|
if (localHint.contains(start)) {
|
||||||
QPoint translated = start - localHint.topLeft();
|
QPoint tl = localHint.topLeft();
|
||||||
|
QPoint first = start - tl;
|
||||||
|
QPoint last = end - tl;
|
||||||
|
last.setX(std::max(last.x(), 0));
|
||||||
|
last.setX(std::min(last.x(), localHint.width() - 1));
|
||||||
|
last.setY(std::max(last.y(), 0));
|
||||||
|
last.setY(std::min(last.y(), localHint.height()));
|
||||||
|
|
||||||
|
|
||||||
bodyRenderer->setHtml(Shared::processMessageBody(data.text));
|
bodyRenderer->setHtml(Shared::processMessageBody(data.text));
|
||||||
bodyRenderer->setTextWidth(localHint.size().width());
|
bodyRenderer->setTextWidth(localHint.size().width());
|
||||||
selection.first = bodyRenderer->documentLayout()->hitTest(translated, Qt::HitTestAccuracy::FuzzyHit);
|
selection.first = bodyRenderer->documentLayout()->hitTest(first, Qt::HitTestAccuracy::FuzzyHit);
|
||||||
selection.second = bodyRenderer->documentLayout()->hitTest(end - localHint.topLeft(), Qt::HitTestAccuracy::FuzzyHit);
|
selection.second = bodyRenderer->documentLayout()->hitTest(last, Qt::HitTestAccuracy::FuzzyHit);
|
||||||
|
|
||||||
currentId = data.id;
|
currentId = data.id;
|
||||||
|
|
||||||
return true;
|
if (selection.first != selection.second) {
|
||||||
|
QTextCursor cursor(bodyRenderer);
|
||||||
|
cursor.setPosition(selection.first, QTextCursor::MoveAnchor);
|
||||||
|
cursor.setPosition(selection.second, QTextCursor::KeepAnchor);
|
||||||
|
return cursor.selectedText();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
}
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MessageDelegate::clearSelection()
|
QString MessageDelegate::clearSelection()
|
||||||
|
@ -58,8 +58,8 @@ public:
|
|||||||
void endClearWidgets();
|
void endClearWidgets();
|
||||||
void beginClearWidgets();
|
void beginClearWidgets();
|
||||||
void leftClick(const QPoint& point, const QModelIndex& index, const QRect& sizeHint) const;
|
void leftClick(const QPoint& point, const QModelIndex& index, const QRect& sizeHint) const;
|
||||||
bool isAnchorHovered(const QPoint& point, const QModelIndex& index, const QRect& sizeHint) const;
|
Shared::Hover hoverType(const QPoint& point, const QModelIndex& index, const QRect& sizeHint) const;
|
||||||
bool mouseDrag(const QPoint& start, const QPoint& end, const QModelIndex& index, const QRect& sizeHint);
|
QString mouseDrag(const QPoint& start, const QPoint& end, const QModelIndex& index, const QRect& sizeHint);
|
||||||
QString clearSelection();
|
QString clearSelection();
|
||||||
|
|
||||||
static int avatarHeight;
|
static int avatarHeight;
|
||||||
|
@ -57,6 +57,8 @@ public:
|
|||||||
void changeMessage(const QString& id, const QMap<QString, QVariant>& data);
|
void changeMessage(const QString& id, const QMap<QString, QVariant>& data);
|
||||||
void removeMessage(const QString& id);
|
void removeMessage(const QString& id);
|
||||||
Shared::Message getMessage(const QString& id);
|
Shared::Message getMessage(const QString& id);
|
||||||
|
QModelIndex modelIndexById(const QString& id) const;
|
||||||
|
QModelIndex modelIndexByTime(const QString& id, const QDateTime& time) const;
|
||||||
|
|
||||||
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
|
||||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||||
@ -126,8 +128,6 @@ protected:
|
|||||||
bool sentByMe(const Shared::Message& msg) const;
|
bool sentByMe(const Shared::Message& msg) const;
|
||||||
Attachment fillAttach(const Shared::Message& msg) const;
|
Attachment fillAttach(const Shared::Message& msg) const;
|
||||||
Edition fillCorrection(const Shared::Message& msg) const;
|
Edition fillCorrection(const Shared::Message& msg) const;
|
||||||
QModelIndex modelIndexById(const QString& id) const;
|
|
||||||
QModelIndex modelIndexByTime(const QString& id, const QDateTime& time) const;
|
|
||||||
std::set<MessageRoles> detectChanges(const Shared::Message& msg, const QMap<QString, QVariant>& data) const;
|
std::set<MessageRoles> detectChanges(const Shared::Message& msg, const QMap<QString, QVariant>& data) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Loading…
Reference in New Issue
Block a user