selection message body now actually working

This commit is contained in:
Blue 2022-05-02 22:25:50 +03:00
parent 0340db7f2f
commit 3c48577eee
Signed by untrusted user: blue
GPG Key ID: 9B203B252A63EE38
7 changed files with 138 additions and 40 deletions

View File

@ -69,6 +69,12 @@ static const std::vector<QColor> colorPalette = {
QColor(17, 17, 80),
QColor(54, 54, 94)
};
enum class Hover {
nothing,
text,
anchor
};
}
#endif // SHARED_UTILS_H

View File

@ -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();
if (body.size() > 0) {
showMenu = true;

View File

@ -21,6 +21,8 @@
#include <QPaintEvent>
#include <QPainter>
#include <QScrollBar>
#include <QApplication>
#include <QClipboard>
#include <QDebug>
#include "messagedelegate.h"
@ -53,9 +55,10 @@ FeedView::FeedView(QWidget* parent):
dividerMetrics(dividerFont),
mousePressed(false),
dragging(false),
anchorHovered(false),
hovered(Shared::Hover::nothing),
dragStartPoint(),
dragEndPoint()
dragEndPoint(),
selectedText()
{
horizontalScrollBar()->setRange(0, 0);
verticalScrollBar()->setSingleStep(approximateSingleMessageHeight);
@ -167,7 +170,7 @@ void FeedView::dataChanged(const QModelIndex& topLeft, const QModelIndex& bottom
void FeedView::updateGeometries()
{
qDebug() << "updateGeometries";
//qDebug() << "updateGeometries";
QScrollBar* bar = verticalScrollBar();
const QStyle* st = style();
@ -307,7 +310,7 @@ bool FeedView::tryToCalculateGeometriesWithNoScrollbars(const QStyleOptionViewIt
void FeedView::paintEvent(QPaintEvent* event)
{
qDebug() << "paint" << event->rect();
//qDebug() << "paint" << event->rect();
const QAbstractItemModel* m = model();
QWidget* vp = viewport();
QRect zone = event->rect().translated(0, -vo);
@ -412,14 +415,20 @@ void FeedView::verticalScrollbarValueChanged(int value)
QAbstractItemView::verticalScrollbarValueChanged(vo);
}
void FeedView::setAnchorHovered(bool hovered)
void FeedView::setAnchorHovered(Shared::Hover type)
{
if (anchorHovered != hovered) {
anchorHovered = hovered;
if (anchorHovered) {
setCursor(Qt::PointingHandCursor);
} else {
if (hovered != type) {
hovered = type;
switch (hovered) {
case Shared::Hover::nothing:
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);
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);
if (index.isValid()) {
QRect rect = visualRect(index);
if (rect.contains(dragEndPoint)) {
MessageDelegate* del = static_cast<MessageDelegate*>(itemDelegate());
if (dragging) {
setAnchorHovered(false);
if (del->mouseDrag(dragStartPoint, dragEndPoint, index, rect)) {
qDebug() << "asking to repaint" << rect;
setDirtyRegion(rect);
setAnchorHovered(del->hoverType(dragEndPoint, index, rect));
} else {
setAnchorHovered(Shared::Hover::nothing);
}
} 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;
if (mousePressed) {
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)
{
QAbstractItemView::resizeEvent(event);
@ -603,3 +640,8 @@ void FeedView::onModelSyncStateChange(Models::MessageFeed::SyncState state)
scheduleDelayedItemsLayout();
}
}
QString FeedView::getSelectedText() const
{
return selectedText;
}

View File

@ -28,6 +28,7 @@
#include <ui/widgets/messageline/messagefeed.h>
#include <ui/utils/progress.h>
#include <shared/utils.h>
/**
* @todo write docs
@ -50,6 +51,7 @@ public:
void setModel(QAbstractItemModel * model) override;
QFont getFont() const;
QString getSelectedText() const;
signals:
void resized();
@ -72,13 +74,14 @@ protected:
void mouseMoveEvent(QMouseEvent * event) override;
void mousePressEvent(QMouseEvent * event) override;
void mouseReleaseEvent(QMouseEvent * event) override;
void keyPressEvent(QKeyEvent * event) override;
void resizeEvent(QResizeEvent * event) override;
private:
bool tryToCalculateGeometriesWithNoScrollbars(const QStyleOptionViewItem& option, const QAbstractItemModel* model, uint32_t totalHeight);
void positionProgress();
void drawDateDevider(int top, const QDateTime& date, QPainter& painter);
void setAnchorHovered(bool hovered);
void setAnchorHovered(Shared::Hover type);
private:
struct Hint {
@ -100,9 +103,10 @@ private:
QFontMetrics dividerMetrics;
bool mousePressed;
bool dragging;
bool anchorHovered;
Shared::Hover hovered;
QPoint dragStartPoint;
QPoint dragEndPoint;
QString selectedText;
static const std::set<int> geometryChangingRoles;

View File

@ -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);
return anchor.size() > 0;
QVariant vi = index.data(Models::MessageFeed::Bulk);
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);
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);
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->setTextWidth(localHint.size().width());
selection.first = bodyRenderer->documentLayout()->hitTest(translated, Qt::HitTestAccuracy::FuzzyHit);
selection.second = bodyRenderer->documentLayout()->hitTest(end - localHint.topLeft(), Qt::HitTestAccuracy::FuzzyHit);
selection.first = bodyRenderer->documentLayout()->hitTest(first, Qt::HitTestAccuracy::FuzzyHit);
selection.second = bodyRenderer->documentLayout()->hitTest(last, Qt::HitTestAccuracy::FuzzyHit);
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()

View File

@ -58,8 +58,8 @@ public:
void endClearWidgets();
void beginClearWidgets();
void leftClick(const QPoint& point, const QModelIndex& index, const QRect& sizeHint) const;
bool isAnchorHovered(const QPoint& point, const QModelIndex& index, const QRect& sizeHint) const;
bool mouseDrag(const QPoint& start, const QPoint& end, const QModelIndex& index, const QRect& sizeHint);
Shared::Hover hoverType(const QPoint& point, const QModelIndex& index, const QRect& sizeHint) const;
QString mouseDrag(const QPoint& start, const QPoint& end, const QModelIndex& index, const QRect& sizeHint);
QString clearSelection();
static int avatarHeight;

View File

@ -57,6 +57,8 @@ public:
void changeMessage(const QString& id, const QMap<QString, QVariant>& data);
void removeMessage(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;
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
@ -126,8 +128,6 @@ protected:
bool sentByMe(const Shared::Message& msg) const;
Attachment fillAttach(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;
private: