Don't destroy formatting when editing previous messages
Adds a few new methods to grab the markdown/slightly rich text from the message, and will intelligently re-insert user mentions as needed.
This commit is contained in:
@@ -55,6 +55,7 @@ private Q_SLOTS:
|
|||||||
void genericBody_data();
|
void genericBody_data();
|
||||||
void genericBody();
|
void genericBody();
|
||||||
void nullGenericBody();
|
void nullGenericBody();
|
||||||
|
void markdownBody();
|
||||||
void subtitle();
|
void subtitle();
|
||||||
void nullSubtitle();
|
void nullSubtitle();
|
||||||
void mediaInfo();
|
void mediaInfo();
|
||||||
@@ -293,6 +294,13 @@ void EventHandlerTest::nullGenericBody()
|
|||||||
QCOMPARE(noEventHandler.getGenericBody(), QString());
|
QCOMPARE(noEventHandler.getGenericBody(), QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EventHandlerTest::markdownBody()
|
||||||
|
{
|
||||||
|
EventHandler eventHandler(room, room->messageEvents().at(0).get());
|
||||||
|
|
||||||
|
QCOMPARE(eventHandler.getMarkdownBody(), QStringLiteral("This is an example\ntext message"));
|
||||||
|
}
|
||||||
|
|
||||||
void EventHandlerTest::subtitle()
|
void EventHandlerTest::subtitle()
|
||||||
{
|
{
|
||||||
EventHandler eventHandler(room, room->messageEvents().at(0).get());
|
EventHandler eventHandler(room, room->messageEvents().at(0).get());
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "chatbarcache.h"
|
#include "chatbarcache.h"
|
||||||
|
|
||||||
|
#include "chatdocumenthandler.h"
|
||||||
#include "eventhandler.h"
|
#include "eventhandler.h"
|
||||||
#include "neochatroom.h"
|
#include "neochatroom.h"
|
||||||
|
|
||||||
@@ -117,7 +118,7 @@ QString ChatBarCache::relationMessage() const
|
|||||||
|
|
||||||
if (auto event = room->findInTimeline(m_relationId); event != room->historyEdge()) {
|
if (auto event = room->findInTimeline(m_relationId); event != room->historyEdge()) {
|
||||||
EventHandler eventhandler(room, &**event);
|
EventHandler eventhandler(room, &**event);
|
||||||
return eventhandler.getPlainBody();
|
return eventhandler.getMarkdownBody();
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -163,6 +164,54 @@ QList<Mention> *ChatBarCache::mentions()
|
|||||||
return &m_mentions;
|
return &m_mentions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChatBarCache::updateMentions(QQuickTextDocument *document, ChatDocumentHandler *documentHandler)
|
||||||
|
{
|
||||||
|
documentHandler->setDocument(document);
|
||||||
|
|
||||||
|
if (parent() == nullptr) {
|
||||||
|
qWarning() << "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (m_relationId.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto room = dynamic_cast<NeoChatRoom *>(parent());
|
||||||
|
if (room == nullptr) {
|
||||||
|
qWarning() << "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto event = room->findInTimeline(m_relationId); event != room->historyEdge()) {
|
||||||
|
if (const auto &roomMessageEvent = &*event->viewAs<Quotient::RoomMessageEvent>()) {
|
||||||
|
// Replaces the mentions that are baked into the HTML but plaintext in the original markdown
|
||||||
|
const QRegularExpression re(QStringLiteral(R"lit(<a\shref="https:\/\/matrix.to\/#\/([\S]*)"\s?>([\S]*)<\/a>)lit"));
|
||||||
|
|
||||||
|
m_mentions.clear();
|
||||||
|
|
||||||
|
int linkSize = 0;
|
||||||
|
auto matches = re.globalMatch(EventHandler::rawMessageBody(*roomMessageEvent));
|
||||||
|
while (matches.hasNext()) {
|
||||||
|
const QRegularExpressionMatch match = matches.next();
|
||||||
|
if (match.hasMatch()) {
|
||||||
|
const QString id = match.captured(1);
|
||||||
|
const QString name = match.captured(2);
|
||||||
|
|
||||||
|
const int position = match.capturedStart(0) - linkSize;
|
||||||
|
const int end = position + name.length();
|
||||||
|
linkSize += match.capturedLength(0) - name.length();
|
||||||
|
|
||||||
|
QTextCursor cursor(documentHandler->document()->textDocument());
|
||||||
|
cursor.setPosition(position);
|
||||||
|
cursor.setPosition(end, QTextCursor::KeepAnchor);
|
||||||
|
cursor.setKeepPositionOnInsert(true);
|
||||||
|
|
||||||
|
m_mentions.push_back(Mention{.cursor = cursor, .text = name, .start = position, .position = end, .id = id});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString ChatBarCache::savedText() const
|
QString ChatBarCache::savedText() const
|
||||||
{
|
{
|
||||||
return m_savedText;
|
return m_savedText;
|
||||||
|
|||||||
@@ -5,8 +5,11 @@
|
|||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
|
#include <QQuickTextDocument>
|
||||||
#include <QTextCursor>
|
#include <QTextCursor>
|
||||||
|
|
||||||
|
class ChatDocumentHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Defines a user mention in the current chat or edit text.
|
* @brief Defines a user mention in the current chat or edit text.
|
||||||
*/
|
*/
|
||||||
@@ -174,6 +177,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
QList<Mention> *mentions();
|
QList<Mention> *mentions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update the mentions in @p document when editing a message.
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE void updateMentions(QQuickTextDocument *document, ChatDocumentHandler *documentHandler);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the saved chat bar text.
|
* @brief Get the saved chat bar text.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -280,6 +280,22 @@ QString EventHandler::getPlainBody(bool stripNewlines) const
|
|||||||
return getBody(m_event, Qt::PlainText, stripNewlines);
|
return getBody(m_event, Qt::PlainText, stripNewlines);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString EventHandler::getMarkdownBody() const
|
||||||
|
{
|
||||||
|
if (m_event == nullptr) {
|
||||||
|
qCWarning(EventHandling) << "getMarkdownBody called with m_event set to nullptr.";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_event->is<RoomMessageEvent>()) {
|
||||||
|
qCWarning(EventHandling) << "getMarkdownBody called when m_event isn't a RoomMessageEvent.";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto roomMessageEvent = eventCast<const RoomMessageEvent>(m_event);
|
||||||
|
return roomMessageEvent->plainBody();
|
||||||
|
}
|
||||||
|
|
||||||
QString EventHandler::getBody(const Quotient::RoomEvent *event, Qt::TextFormat format, bool stripNewlines) const
|
QString EventHandler::getBody(const Quotient::RoomEvent *event, Qt::TextFormat format, bool stripNewlines) const
|
||||||
{
|
{
|
||||||
if (event->isRedacted()) {
|
if (event->isRedacted()) {
|
||||||
|
|||||||
@@ -185,6 +185,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
QString getPlainBody(bool stripNewlines = false) const;
|
QString getPlainBody(bool stripNewlines = false) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Output the original body for the message content, useful for editing the original message.
|
||||||
|
*
|
||||||
|
* The event type must be a room message event.
|
||||||
|
*/
|
||||||
|
QString getMarkdownBody() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Output a generic string for the message content ready for display.
|
* @brief Output a generic string for the message content ready for display.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -170,8 +170,11 @@ QQC2.TextArea {
|
|||||||
onChatBarCacheChanged: documentHandler.chatBarCache = chatBarCache
|
onChatBarCacheChanged: documentHandler.chatBarCache = chatBarCache
|
||||||
|
|
||||||
function updateEditText() {
|
function updateEditText() {
|
||||||
|
// This could possibly be undefined due to some esoteric QtQuick issue. Referencing it somewhere in JS is enough.
|
||||||
|
documentHandler.textDocument;
|
||||||
if (chatBarCache?.isEditing && chatBarCache.relationMessage.length > 0) {
|
if (chatBarCache?.isEditing && chatBarCache.relationMessage.length > 0) {
|
||||||
root.text = chatBarCache.relationMessage;
|
root.text = chatBarCache.relationMessage;
|
||||||
|
chatBarCache.updateMentions(root.textDocument, documentHandler);
|
||||||
root.forceActiveFocus();
|
root.forceActiveFocus();
|
||||||
root.cursorPosition = root.length;
|
root.cursorPosition = root.length;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user