Move the remaining functionality of ChatDocumentHandler to ChatTextItemHelper or split into own objects
This commit is contained in:
@@ -110,8 +110,14 @@ QQC2.Control {
|
||||
height: implicitHeight
|
||||
y: -height - 5
|
||||
z: 10
|
||||
<<<<<<< HEAD
|
||||
|
||||
chatDocumentHandler: documentHandler
|
||||
=======
|
||||
room: root.Message.room
|
||||
type: root.chatBarCache.isEditing ? ChatBarType.Edit : ChatBarType.Thread
|
||||
// textItem: textArea
|
||||
>>>>>>> c7858a151 (Move the remaining functionality of ChatDocumentHandler to ChatTextItemHelper or split into own objects)
|
||||
margins: 0
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
@@ -125,13 +131,6 @@ QQC2.Control {
|
||||
// opt-out of whatever spell checker a styled TextArea might come with
|
||||
Kirigami.SpellCheck.enabled: false
|
||||
|
||||
ChatDocumentHandler {
|
||||
id: documentHandler
|
||||
type: root.chatBarCache.isEditing ? ChatBarType.Edit : ChatBarType.Thread
|
||||
textItem: textArea
|
||||
room: root.Message.room
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: textMetrics
|
||||
text: textArea.text
|
||||
|
||||
@@ -51,11 +51,9 @@ QQC2.Control {
|
||||
* @brief The attributes of the component.
|
||||
*/
|
||||
required property var componentAttributes
|
||||
readonly property ChatDocumentHandler chatDocumentHandler: componentAttributes?.chatDocumentHandler ?? null
|
||||
onChatDocumentHandlerChanged: if (chatDocumentHandler) {
|
||||
chatDocumentHandler.type = ChatBarType.Room;
|
||||
chatDocumentHandler.room = root.Message.room;
|
||||
chatDocumentHandler.textItem = codeText;
|
||||
readonly property ChatTextItemHelper chatTextItemHelper: componentAttributes?.chatTextItemHelper ?? null
|
||||
onChatTextItemHelperChanged: if (chatTextItemHelper) {
|
||||
chatTextItemHelper.textItem = codeText;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,27 +92,23 @@ QQC2.Control {
|
||||
id: codeText
|
||||
|
||||
Keys.onUpPressed: (event) => {
|
||||
event.accepted = false;
|
||||
if (root.chatDocumentHandler.atFirstLine) {
|
||||
Message.contentModel.focusRow = root.index - 1
|
||||
}
|
||||
event.accepted = true;
|
||||
Message.contentModel.keyHelper.up();
|
||||
}
|
||||
Keys.onDownPressed: (event) => {
|
||||
event.accepted = false;
|
||||
if (root.chatDocumentHandler.atLastLine) {
|
||||
Message.contentModel.focusRow = root.index + 1
|
||||
}
|
||||
event.accepted = true;
|
||||
Message.contentModel.keyHelper.down();
|
||||
}
|
||||
|
||||
Keys.onDeletePressed: (event) => {
|
||||
event.accepted = true;
|
||||
root.chatDocumentHandler.deleteChar();
|
||||
root.Message.contentModel.keyHelper.deleteChar();
|
||||
}
|
||||
|
||||
Keys.onPressed: (event) => {
|
||||
if (event.key == Qt.Key_Backspace && cursorPosition == 0) {
|
||||
event.accepted = true;
|
||||
root.chatDocumentHandler.backspace();
|
||||
root.Message.contentModel.keyHelper.backspace();
|
||||
return;
|
||||
}
|
||||
event.accepted = false;
|
||||
|
||||
@@ -45,11 +45,9 @@ QQC2.TextArea {
|
||||
* @brief The attributes of the component.
|
||||
*/
|
||||
required property var componentAttributes
|
||||
readonly property ChatDocumentHandler chatDocumentHandler: componentAttributes?.chatDocumentHandler ?? null
|
||||
onChatDocumentHandlerChanged: if (chatDocumentHandler) {
|
||||
chatDocumentHandler.type = ChatBarType.Room;
|
||||
chatDocumentHandler.room = root.Message.room;
|
||||
chatDocumentHandler.textItem = root;
|
||||
readonly property ChatTextItemHelper chatTextItemHelper: componentAttributes?.chatTextItemHelper ?? null
|
||||
onChatTextItemHelperChanged: if (chatTextItemHelper) {
|
||||
chatTextItemHelper.textItem = root;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,16 +64,12 @@ QQC2.TextArea {
|
||||
signal selectedTextChanged(string selectedText)
|
||||
|
||||
Keys.onUpPressed: (event) => {
|
||||
event.accepted = false;
|
||||
if (root.chatDocumentHandler.atFirstLine) {
|
||||
Message.contentModel.focusRow = root.index - 1
|
||||
}
|
||||
event.accepted = true;
|
||||
Message.contentModel.keyHelper.up();
|
||||
}
|
||||
Keys.onDownPressed: (event) => {
|
||||
event.accepted = false;
|
||||
if (root.chatDocumentHandler.atLastLine) {
|
||||
Message.contentModel.focusRow = root.index + 1
|
||||
}
|
||||
event.accepted = true;
|
||||
Message.contentModel.keyHelper.down();
|
||||
}
|
||||
Keys.onLeftPressed: (event) => {
|
||||
if (cursorPosition == 1) {
|
||||
@@ -94,12 +88,12 @@ QQC2.TextArea {
|
||||
|
||||
Keys.onDeletePressed: (event) => {
|
||||
event.accepted = true;
|
||||
chatDocumentHandler.deleteChar();
|
||||
Message.contentModel.keyHelper.deleteChar();
|
||||
}
|
||||
Keys.onPressed: (event) => {
|
||||
if (event.key == Qt.Key_Backspace) {
|
||||
event.accepted = true;
|
||||
chatDocumentHandler.backspace();
|
||||
Message.contentModel.keyHelper.backspace();
|
||||
return;
|
||||
}
|
||||
event.accepted = false;
|
||||
|
||||
@@ -49,11 +49,9 @@ TextEdit {
|
||||
* @brief The attributes of the component.
|
||||
*/
|
||||
required property var componentAttributes
|
||||
readonly property ChatDocumentHandler chatDocumentHandler: componentAttributes?.chatDocumentHandler ?? null
|
||||
onChatDocumentHandlerChanged: if (chatDocumentHandler) {
|
||||
chatDocumentHandler.type = ChatBarType.Room;
|
||||
chatDocumentHandler.room = root.Message.room;
|
||||
chatDocumentHandler.textItem = root;
|
||||
readonly property ChatTextItemHelper chatTextItemHelper: componentAttributes?.chatTextItemHelper ?? null
|
||||
onChatTextItemHelperChanged: if (chatTextItemHelper) {
|
||||
chatTextItemHelper.textItem = root;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,32 +76,28 @@ TextEdit {
|
||||
Layout.maximumWidth: Message.maxContentWidth
|
||||
|
||||
Keys.onUpPressed: (event) => {
|
||||
event.accepted = false;
|
||||
if (chatDocumentHandler.atFirstLine) {
|
||||
Message.contentModel.focusRow = root.index - 1
|
||||
}
|
||||
event.accepted = true;
|
||||
Message.contentModel.keyHelper.up();
|
||||
}
|
||||
Keys.onDownPressed: (event) => {
|
||||
event.accepted = false;
|
||||
if (chatDocumentHandler.atLastLine) {
|
||||
Message.contentModel.focusRow = root.index + 1
|
||||
}
|
||||
event.accepted = true;
|
||||
Message.contentModel.keyHelper.down();
|
||||
}
|
||||
|
||||
Keys.onTabPressed: (event) => {
|
||||
event.accepted = true;
|
||||
chatDocumentHandler.tab();
|
||||
Message.contentModel.keyHelper.tab();
|
||||
}
|
||||
|
||||
Keys.onDeletePressed: (event) => {
|
||||
event.accepted = true;
|
||||
chatDocumentHandler.deleteChar();
|
||||
Message.contentModel.keyHelper.deleteChar();
|
||||
}
|
||||
|
||||
Keys.onPressed: (event) => {
|
||||
if (event.key == Qt.Key_Backspace && cursorPosition == 0) {
|
||||
event.accepted = true;
|
||||
chatDocumentHandler.backspace();
|
||||
Message.contentModel.keyHelper.backspace();
|
||||
return;
|
||||
}
|
||||
event.accepted = false;
|
||||
@@ -111,11 +105,11 @@ TextEdit {
|
||||
|
||||
Keys.onEnterPressed: (event) => {
|
||||
event.accepted = true;
|
||||
chatDocumentHandler.insertReturn();
|
||||
Message.contentModel.keyHelper.insertReturn();
|
||||
}
|
||||
Keys.onReturnPressed: (event) => {
|
||||
event.accepted = true;
|
||||
chatDocumentHandler.insertReturn();
|
||||
Message.contentModel.keyHelper.insertReturn();
|
||||
}
|
||||
|
||||
onFocusChanged: if (focus && !root.currentFocus) {
|
||||
|
||||
@@ -6,20 +6,26 @@
|
||||
#include <QTextDocumentFragment>
|
||||
|
||||
#include "chatbarcache.h"
|
||||
#include "chatdocumenthandler.h"
|
||||
#include "chatkeyhelper.h"
|
||||
#include "chatmarkdownhelper.h"
|
||||
#include "chattextitemhelper.h"
|
||||
#include "enums/chatbartype.h"
|
||||
#include "enums/messagecomponenttype.h"
|
||||
#include "enums/richformat.h"
|
||||
#include "messagecontentmodel.h"
|
||||
#include "qmltextitemwrapper.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr auto TextItemKey = "chatTextItemHelper"_L1;
|
||||
}
|
||||
|
||||
ChatBarMessageContentModel::ChatBarMessageContentModel(QObject *parent)
|
||||
: MessageContentModel(parent)
|
||||
, m_currentTextItem(new QmlTextItemWrapper(this))
|
||||
, m_markdownHelper(new ChatMarkdownHelper(this))
|
||||
, m_keyHelper(new ChatKeyHelper(this))
|
||||
{
|
||||
m_editableActive = true;
|
||||
connectCurentTextItem();
|
||||
connectKeyHelper();
|
||||
initializeModel();
|
||||
|
||||
connect(this, &ChatBarMessageContentModel::roomChanged, this, [this]() {
|
||||
@@ -53,17 +59,38 @@ ChatBarMessageContentModel::ChatBarMessageContentModel(QObject *parent)
|
||||
|
||||
Q_EMIT focusRowChanged();
|
||||
});
|
||||
connect(this, &ChatBarMessageContentModel::focusRowChanged, this, [this]() {
|
||||
m_markdownHelper->setTextItem(focusedTextItem());
|
||||
m_keyHelper->setTextItem(focusedTextItem());
|
||||
});
|
||||
connect(this, &ChatBarMessageContentModel::roomChanged, this, [this]() {
|
||||
for (const auto &component : m_components) {
|
||||
if (const auto textItem = textItemForComponent(component)) {
|
||||
textItem->setRoom(m_room);
|
||||
}
|
||||
}
|
||||
});
|
||||
connect(this, &ChatBarMessageContentModel::typeChanged, this, [this]() {
|
||||
for (const auto &component : m_components) {
|
||||
if (const auto textItem = textItemForComponent(component)) {
|
||||
textItem->setType(m_type);
|
||||
}
|
||||
}
|
||||
});
|
||||
connect(m_markdownHelper, &ChatMarkdownHelper::unhandledBlockFormat, this, &ChatBarMessageContentModel::insertStyleAtCursor);
|
||||
}
|
||||
|
||||
void ChatBarMessageContentModel::initializeModel()
|
||||
{
|
||||
beginInsertRows({}, rowCount(), rowCount());
|
||||
const auto documentHandler = new ChatDocumentHandler();
|
||||
connectHandler(documentHandler);
|
||||
const auto textItem = new ChatTextItemHelper(this);
|
||||
textItem->setRoom(m_room);
|
||||
textItem->setType(m_type);
|
||||
connectTextItem(textItem);
|
||||
m_components += MessageComponent{
|
||||
.type = MessageComponentType::Text,
|
||||
.display = {},
|
||||
.attributes = {{"chatDocumentHandler"_L1, QVariant::fromValue<ChatDocumentHandler *>(documentHandler)}},
|
||||
.attributes = {{TextItemKey, QVariant::fromValue<ChatTextItemHelper *>(textItem)}},
|
||||
};
|
||||
m_currentFocusComponent = QPersistentModelIndex(index(0));
|
||||
endInsertRows();
|
||||
@@ -71,86 +98,6 @@ void ChatBarMessageContentModel::initializeModel()
|
||||
Q_EMIT focusRowChanged();
|
||||
}
|
||||
|
||||
void ChatBarMessageContentModel::connectCurentTextItem()
|
||||
{
|
||||
if (const auto docHandler = focusedDocumentHandler()) {
|
||||
m_currentTextItem->setTextItem(docHandler->textItem());
|
||||
}
|
||||
connect(this, &ChatBarMessageContentModel::focusRowChanged, this, [this]() {
|
||||
if (const auto docHandler = focusedDocumentHandler()) {
|
||||
m_currentTextItem->setTextItem(docHandler->textItem());
|
||||
m_markdownHelper->setTextItem(m_currentTextItem);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ChatBarMessageContentModel::connectHandler(ChatDocumentHandler *handler)
|
||||
{
|
||||
connect(handler, &ChatDocumentHandler::contentsChanged, this, &ChatBarMessageContentModel::updateCache);
|
||||
connect(handler, &ChatDocumentHandler::unhandledBackspaceAtBeginning, this, [this](ChatDocumentHandler *handler) {
|
||||
const auto index = indexForDocumentHandler(handler);
|
||||
if (index.isValid()) {
|
||||
if (index.row() > 0 && MessageComponentType::isFileType(m_components[index.row() - 1].type)) {
|
||||
removeAttachment();
|
||||
} else if (m_components[index.row()].type == MessageComponentType::Code || m_components[index.row()].type == MessageComponentType::Quote) {
|
||||
insertComponentAtCursor(MessageComponentType::Text);
|
||||
}
|
||||
}
|
||||
});
|
||||
connect(handler, &ChatDocumentHandler::removeMe, this, [this](ChatDocumentHandler *handler) {
|
||||
removeComponent(handler);
|
||||
});
|
||||
}
|
||||
|
||||
ChatDocumentHandler *ChatBarMessageContentModel::documentHandlerForComponent(const MessageComponent &component) const
|
||||
{
|
||||
if (const auto chatDocumentHandler = qvariant_cast<ChatDocumentHandler *>(component.attributes["chatDocumentHandler"_L1])) {
|
||||
return chatDocumentHandler;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ChatDocumentHandler *ChatBarMessageContentModel::documentHandlerForIndex(const QModelIndex &index) const
|
||||
{
|
||||
return documentHandlerForComponent(m_components[index.row()]);
|
||||
}
|
||||
|
||||
QModelIndex ChatBarMessageContentModel::indexForDocumentHandler(ChatDocumentHandler *handler) const
|
||||
{
|
||||
for (auto it = m_components.begin(); it != m_components.end(); ++it) {
|
||||
const auto currentIndex = index(it - m_components.begin());
|
||||
if (documentHandlerForIndex(currentIndex) == handler) {
|
||||
return currentIndex;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void ChatBarMessageContentModel::updateDocumentHandlerRefs(const ComponentIt &it)
|
||||
{
|
||||
if (it == m_components.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto handler = documentHandlerForComponent(*it);
|
||||
if (!handler) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (it != m_components.begin()) {
|
||||
if (const auto beforeHandler = documentHandlerForComponent(*(it - 1))) {
|
||||
beforeHandler->setNextDocumentHandler(handler);
|
||||
handler->setPreviousDocumentHandler(beforeHandler);
|
||||
}
|
||||
}
|
||||
if (it + 1 != m_components.end()) {
|
||||
if (const auto afterHandler = documentHandlerForComponent(*(it + 1))) {
|
||||
afterHandler->setPreviousDocumentHandler(handler);
|
||||
handler->setNextDocumentHandler(afterHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ChatBarType::Type ChatBarMessageContentModel::type() const
|
||||
{
|
||||
return m_type;
|
||||
@@ -165,6 +112,46 @@ void ChatBarMessageContentModel::setType(ChatBarType::Type type)
|
||||
Q_EMIT typeChanged();
|
||||
}
|
||||
|
||||
ChatKeyHelper *ChatBarMessageContentModel::keyHelper() const
|
||||
{
|
||||
return m_keyHelper;
|
||||
}
|
||||
|
||||
void ChatBarMessageContentModel::connectKeyHelper()
|
||||
{
|
||||
connect(m_keyHelper, &ChatKeyHelper::unhandledUp, this, [this]() {
|
||||
setFocusRow(m_currentFocusComponent.row() - 1);
|
||||
});
|
||||
connect(m_keyHelper, &ChatKeyHelper::unhandledDown, this, [this]() {
|
||||
setFocusRow(m_currentFocusComponent.row() + 1);
|
||||
});
|
||||
connect(m_keyHelper, &ChatKeyHelper::unhandledDelete, this, [this]() {
|
||||
const auto currentRow = m_currentFocusComponent.row();
|
||||
if (currentRow < m_components.size() - 1) {
|
||||
if (const auto nextTextItem = textItemForComponent(m_components[currentRow + 1])) {
|
||||
focusedTextItem()->insertFragment(nextTextItem->takeFirstBlock(), ChatTextItemHelper::Cursor, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
connect(m_keyHelper, &ChatKeyHelper::unhandledBackspace, this, [this]() {
|
||||
const auto currentRow = m_currentFocusComponent.row();
|
||||
if (currentRow > 0) {
|
||||
const auto previousRow = currentRow - 1;
|
||||
if (MessageComponentType::isFileType(m_components[previousRow].type)) {
|
||||
removeAttachment();
|
||||
return;
|
||||
}
|
||||
if (const auto previousTextItem = textItemForComponent(m_components[previousRow])) {
|
||||
previousTextItem->insertFragment(focusedTextItem()->takeFirstBlock(), ChatTextItemHelper::End, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (m_components[currentRow].type == MessageComponentType::Code || m_components[currentRow].type == MessageComponentType::Quote) {
|
||||
insertComponentAtCursor(MessageComponentType::Text);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
int ChatBarMessageContentModel::focusRow() const
|
||||
{
|
||||
return m_currentFocusComponent.row();
|
||||
@@ -199,39 +186,22 @@ void ChatBarMessageContentModel::setFocusIndex(const QModelIndex &index, bool mo
|
||||
|
||||
void ChatBarMessageContentModel::focusCurrentComponent(const QModelIndex &previousIndex, bool down)
|
||||
{
|
||||
const auto chatDocumentHandler = focusedDocumentHandler();
|
||||
if (!chatDocumentHandler) {
|
||||
const auto textItem = focusedTextItem();
|
||||
if (!textItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
chatDocumentHandler->setCursorFromDocumentHandler(documentHandlerForIndex(previousIndex), down, MessageComponentType::Quote ? 1 : 0);
|
||||
textItem->setCursorFromTextItem(textItemForIndex(previousIndex), down, MessageComponentType::Quote ? 1 : 0);
|
||||
}
|
||||
|
||||
void ChatBarMessageContentModel::refocusCurrentComponent() const
|
||||
{
|
||||
const auto chatDocumentHandler = focusedDocumentHandler();
|
||||
if (!chatDocumentHandler) {
|
||||
const auto textItem = focusedTextItem();
|
||||
if (!textItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
chatDocumentHandler->textItem()->forceActiveFocus();
|
||||
}
|
||||
|
||||
QmlTextItemWrapper *ChatBarMessageContentModel::currentTextItem() const
|
||||
{
|
||||
return m_currentTextItem;
|
||||
}
|
||||
|
||||
ChatDocumentHandler *ChatBarMessageContentModel::focusedDocumentHandler() const
|
||||
{
|
||||
if (!m_currentFocusComponent.isValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (const auto chatDocumentHandler = documentHandlerForIndex(m_currentFocusComponent)) {
|
||||
return chatDocumentHandler;
|
||||
}
|
||||
return nullptr;
|
||||
textItem->forceActiveFocus();
|
||||
}
|
||||
|
||||
void ChatBarMessageContentModel::emitFocusChangeSignals()
|
||||
@@ -240,6 +210,53 @@ void ChatBarMessageContentModel::emitFocusChangeSignals()
|
||||
Q_EMIT dataChanged(index(0), index(rowCount() - 1), {CurrentFocusRole});
|
||||
}
|
||||
|
||||
ChatTextItemHelper *ChatBarMessageContentModel::focusedTextItem() const
|
||||
{
|
||||
if (!m_currentFocusComponent.isValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (const auto textItem = textItemForIndex(m_currentFocusComponent)) {
|
||||
return textItem;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ChatBarMessageContentModel::connectTextItem(ChatTextItemHelper *chattextitemhelper)
|
||||
{
|
||||
connect(chattextitemhelper, &ChatTextItemHelper::contentsChanged, this, &ChatBarMessageContentModel::updateCache);
|
||||
connect(chattextitemhelper, &ChatTextItemHelper::cleared, this, [this](ChatTextItemHelper *helper) {
|
||||
removeComponent(helper);
|
||||
});
|
||||
}
|
||||
|
||||
ChatTextItemHelper *ChatBarMessageContentModel::textItemForComponent(const MessageComponent &component) const
|
||||
{
|
||||
if (const auto textItem = qvariant_cast<ChatTextItemHelper *>(component.attributes[TextItemKey])) {
|
||||
return textItem;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ChatTextItemHelper *ChatBarMessageContentModel::textItemForIndex(const QModelIndex &index) const
|
||||
{
|
||||
return textItemForComponent(m_components[index.row()]);
|
||||
}
|
||||
|
||||
QModelIndex ChatBarMessageContentModel::indexForTextItem(ChatTextItemHelper *textItem) const
|
||||
{
|
||||
if (!textItem) {
|
||||
return {};
|
||||
}
|
||||
|
||||
for (auto it = m_components.begin(); it != m_components.end(); ++it) {
|
||||
const auto currentIndex = index(it - m_components.begin());
|
||||
if (textItemForIndex(currentIndex) == textItem) {
|
||||
return currentIndex;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void ChatBarMessageContentModel::addAttachment(const QUrl &path)
|
||||
{
|
||||
if (m_type == ChatBarType::None || !m_room) {
|
||||
@@ -278,15 +295,16 @@ ChatBarMessageContentModel::insertComponent(int row, MessageComponentType::Type
|
||||
}
|
||||
|
||||
if (MessageComponentType::isTextType(type)) {
|
||||
const auto documentHandler = new ChatDocumentHandler();
|
||||
documentHandler->setInitialText(intialText);
|
||||
const auto textItemWrapper = new ChatTextItemHelper(this);
|
||||
textItemWrapper->setInitialText(intialText);
|
||||
textItemWrapper->setRoom(m_room);
|
||||
textItemWrapper->setType(m_type);
|
||||
if (type == MessageComponentType::Quote) {
|
||||
documentHandler->setFixedStartChars(u"\""_s);
|
||||
documentHandler->setFixedEndChars(u"\""_s);
|
||||
textItemWrapper->setFixedChars(u"\""_s, u"\""_s);
|
||||
}
|
||||
|
||||
attributes.insert("chatDocumentHandler"_L1, QVariant::fromValue<ChatDocumentHandler *>(documentHandler));
|
||||
connectHandler(documentHandler);
|
||||
attributes.insert(TextItemKey, QVariant::fromValue<ChatTextItemHelper *>(textItemWrapper));
|
||||
connectTextItem(textItemWrapper);
|
||||
}
|
||||
beginInsertRows({}, row, row);
|
||||
const auto it = m_components.insert(row,
|
||||
@@ -295,7 +313,6 @@ ChatBarMessageContentModel::insertComponent(int row, MessageComponentType::Type
|
||||
.display = {},
|
||||
.attributes = attributes,
|
||||
});
|
||||
updateDocumentHandlerRefs(it);
|
||||
endInsertRows();
|
||||
return it;
|
||||
}
|
||||
@@ -320,8 +337,8 @@ void ChatBarMessageContentModel::insertStyleAtCursor(RichFormat::Format style)
|
||||
void ChatBarMessageContentModel::insertComponentAtCursor(MessageComponentType::Type type)
|
||||
{
|
||||
if (m_components[m_currentFocusComponent.row()].type == type) {
|
||||
if (type == MessageComponentType::Text && focusedDocumentHandler()) {
|
||||
currentTextItem()->mergeFormatOnCursor(RichFormat::Paragraph);
|
||||
if (type == MessageComponentType::Text && focusedTextItem()) {
|
||||
focusedTextItem()->mergeFormatOnCursor(RichFormat::Paragraph);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -330,8 +347,8 @@ void ChatBarMessageContentModel::insertComponentAtCursor(MessageComponentType::T
|
||||
QTextDocumentFragment midFragment;
|
||||
std::optional<QTextDocumentFragment> afterFragment = std::nullopt;
|
||||
|
||||
if (const auto currentChatDocumentHandler = focusedDocumentHandler()) {
|
||||
currentChatDocumentHandler->fillFragments(hasBefore, midFragment, afterFragment);
|
||||
if (const auto currentTextItem = focusedTextItem()) {
|
||||
currentTextItem->fillFragments(hasBefore, midFragment, afterFragment);
|
||||
}
|
||||
|
||||
const auto currentType = m_components[m_currentFocusComponent.row()].type;
|
||||
@@ -343,8 +360,8 @@ void ChatBarMessageContentModel::insertComponentAtCursor(MessageComponentType::T
|
||||
|
||||
const auto insertIt = insertComponent(insertRow, type);
|
||||
if (insertIt != m_components.end()) {
|
||||
if (const auto insertChatDocumentHandler = documentHandlerForComponent(*insertIt)) {
|
||||
insertChatDocumentHandler->insertFragment(midFragment);
|
||||
if (const auto insertTextItem = textItemForComponent(*insertIt)) {
|
||||
insertTextItem->insertFragment(midFragment);
|
||||
}
|
||||
m_currentFocusComponent = QPersistentModelIndex(index(insertIt - m_components.begin()));
|
||||
emitFocusChangeSignals();
|
||||
@@ -353,8 +370,8 @@ void ChatBarMessageContentModel::insertComponentAtCursor(MessageComponentType::T
|
||||
if (afterFragment) {
|
||||
const auto afterIt = insertComponent(insertRow + 1, currentType);
|
||||
if (afterIt != m_components.end()) {
|
||||
if (const auto afterChatDocumentHandler = documentHandlerForComponent(*afterIt)) {
|
||||
afterChatDocumentHandler->insertFragment(*afterFragment);
|
||||
if (const auto afterTextItem = textItemForComponent(*afterIt)) {
|
||||
afterTextItem->insertFragment(*afterFragment);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -405,21 +422,10 @@ ChatBarMessageContentModel::ComponentIt ChatBarMessageContentModel::removeCompon
|
||||
setFocusRow(newFocusRow);
|
||||
}
|
||||
|
||||
if (const auto chatDocumentHandler = documentHandlerForIndex(index(row))) {
|
||||
const auto beforeHandler = chatDocumentHandler->previousDocumentHandler();
|
||||
const auto afterHandler = chatDocumentHandler->nextDocumentHandler();
|
||||
if (beforeHandler && afterHandler) {
|
||||
beforeHandler->setNextDocumentHandler(afterHandler);
|
||||
afterHandler->setPreviousDocumentHandler(beforeHandler);
|
||||
} else if (beforeHandler) {
|
||||
beforeHandler->setNextDocumentHandler(nullptr);
|
||||
} else if (afterHandler) {
|
||||
afterHandler->setPreviousDocumentHandler(nullptr);
|
||||
}
|
||||
|
||||
m_components[row].attributes.remove("chatDocumentHandler"_L1);
|
||||
chatDocumentHandler->disconnect(this);
|
||||
chatDocumentHandler->deleteLater();
|
||||
if (const auto textItem = textItemForIndex(index(row))) {
|
||||
m_components[row].attributes.remove(TextItemKey);
|
||||
textItem->disconnect(this);
|
||||
textItem->deleteLater();
|
||||
}
|
||||
it = m_components.erase(it);
|
||||
endRemoveRows();
|
||||
@@ -427,9 +433,9 @@ ChatBarMessageContentModel::ComponentIt ChatBarMessageContentModel::removeCompon
|
||||
return it;
|
||||
}
|
||||
|
||||
void ChatBarMessageContentModel::removeComponent(ChatDocumentHandler *handler)
|
||||
void ChatBarMessageContentModel::removeComponent(ChatTextItemHelper *textItem)
|
||||
{
|
||||
const auto index = indexForDocumentHandler(handler);
|
||||
const auto index = indexForTextItem(textItem);
|
||||
if (index.isValid()) {
|
||||
removeComponent(index.row());
|
||||
}
|
||||
@@ -479,8 +485,8 @@ QString ChatBarMessageContentModel::messageText() const
|
||||
QString text;
|
||||
for (const auto &component : m_components) {
|
||||
if (MessageComponentType::isTextType(component.type)) {
|
||||
if (const auto chatDocumentHandler = documentHandlerForComponent(component)) {
|
||||
auto newText = chatDocumentHandler->htmlText();
|
||||
if (const auto textItem = textItemForComponent(component)) {
|
||||
auto newText = textItem->markdownText();
|
||||
if (component.type == MessageComponentType::Quote) {
|
||||
newText = formatQuote(newText);
|
||||
} else if (component.type == MessageComponentType::Code) {
|
||||
@@ -517,9 +523,9 @@ void ChatBarMessageContentModel::clearModel()
|
||||
{
|
||||
beginResetModel();
|
||||
for (const auto &component : m_components) {
|
||||
if (const auto chatDocumentHandler = documentHandlerForComponent(component)) {
|
||||
chatDocumentHandler->disconnect(this);
|
||||
chatDocumentHandler->deleteLater();
|
||||
if (const auto textItem = textItemForComponent(component)) {
|
||||
textItem->disconnect(this);
|
||||
textItem->deleteLater();
|
||||
}
|
||||
}
|
||||
m_components.clear();
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QQmlEngine>
|
||||
#include <qabstractitemmodel.h>
|
||||
|
||||
#include "chatdocumenthandler.h"
|
||||
#include "chatkeyhelper.h"
|
||||
#include "chatmarkdownhelper.h"
|
||||
#include "chattextitemhelper.h"
|
||||
#include "enums/messagecomponenttype.h"
|
||||
#include "enums/richformat.h"
|
||||
#include "messagecomponent.h"
|
||||
#include "models/messagecontentmodel.h"
|
||||
#include "qmltextitemwrapper.h"
|
||||
|
||||
/**
|
||||
* @class ChatBarMessageContentModel
|
||||
@@ -42,31 +42,34 @@ class ChatBarMessageContentModel : public MessageContentModel
|
||||
/**
|
||||
* @brief The text item that the helper is interfacing with.
|
||||
*
|
||||
* This is a QQuickItem that is a TextEdit (or inherited from) wrapped in a QmlTextItemWrapper
|
||||
* This is a QQuickItem that is a TextEdit (or inherited from) wrapped in a ChatTextItemHelper
|
||||
* to provide easy access to properties and basic QTextDocument manipulation.
|
||||
*
|
||||
* @sa TextEdit, QTextDocument, QmlTextItemWrapper
|
||||
* @sa TextEdit, QTextDocument, ChatTextItemHelper
|
||||
*/
|
||||
Q_PROPERTY(QmlTextItemWrapper *currentTextItem READ currentTextItem NOTIFY focusRowChanged)
|
||||
Q_PROPERTY(ChatKeyHelper *keyHelper READ keyHelper CONSTANT)
|
||||
|
||||
/**
|
||||
* @brief The ChatDocumentHandler of the model component that currently has focus.
|
||||
* @brief The text item that the helper is interfacing with.
|
||||
*
|
||||
* This is a QQuickItem that is a TextEdit (or inherited from) wrapped in a ChatTextItemHelper
|
||||
* to provide easy access to properties and basic QTextDocument manipulation.
|
||||
*
|
||||
* @sa TextEdit, QTextDocument, ChatTextItemHelper
|
||||
*/
|
||||
Q_PROPERTY(ChatDocumentHandler *focusedDocumentHandler READ focusedDocumentHandler NOTIFY focusRowChanged)
|
||||
Q_PROPERTY(ChatTextItemHelper *focusedTextItem READ focusedTextItem NOTIFY focusRowChanged)
|
||||
|
||||
public:
|
||||
explicit ChatBarMessageContentModel(QObject *parent = nullptr);
|
||||
|
||||
ChatBarType::Type type() const;
|
||||
void setType(ChatBarType::Type type);
|
||||
|
||||
ChatKeyHelper *keyHelper() const;
|
||||
int focusRow() const;
|
||||
MessageComponentType::Type focusType() const;
|
||||
Q_INVOKABLE void setFocusRow(int focusRow, bool mouse = false);
|
||||
void setFocusIndex(const QModelIndex &index, bool mouse = false);
|
||||
Q_INVOKABLE void refocusCurrentComponent() const;
|
||||
QmlTextItemWrapper *currentTextItem() const;
|
||||
ChatDocumentHandler *focusedDocumentHandler() const;
|
||||
ChatTextItemHelper *focusedTextItem() const;
|
||||
|
||||
Q_INVOKABLE void insertStyleAtCursor(RichFormat::Format style);
|
||||
|
||||
@@ -91,22 +94,22 @@ private:
|
||||
|
||||
std::optional<QString> getReplyEventId() override;
|
||||
|
||||
QPointer<QmlTextItemWrapper> m_currentTextItem;
|
||||
void connectCurentTextItem();
|
||||
QPointer<ChatMarkdownHelper> m_markdownHelper;
|
||||
void setFocusIndex(const QModelIndex &index, bool mouse = false);
|
||||
void focusCurrentComponent(const QModelIndex &previousIndex, bool down);
|
||||
void emitFocusChangeSignals();
|
||||
|
||||
void connectHandler(ChatDocumentHandler *handler);
|
||||
ChatDocumentHandler *documentHandlerForComponent(const MessageComponent &component) const;
|
||||
ChatDocumentHandler *documentHandlerForIndex(const QModelIndex &index) const;
|
||||
QModelIndex indexForDocumentHandler(ChatDocumentHandler *handler) const;
|
||||
void updateDocumentHandlerRefs(const ComponentIt &it);
|
||||
void connectTextItem(ChatTextItemHelper *chattextitemhelper);
|
||||
ChatTextItemHelper *textItemForComponent(const MessageComponent &component) const;
|
||||
ChatTextItemHelper *textItemForIndex(const QModelIndex &index) const;
|
||||
QModelIndex indexForTextItem(ChatTextItemHelper *textItem) const;
|
||||
|
||||
QPointer<ChatMarkdownHelper> m_markdownHelper;
|
||||
QPointer<ChatKeyHelper> m_keyHelper;
|
||||
void connectKeyHelper();
|
||||
|
||||
ComponentIt insertComponent(int row, MessageComponentType::Type type, QVariantMap attributes = {}, const QString &intialText = {});
|
||||
ComponentIt removeComponent(ComponentIt it);
|
||||
void removeComponent(ChatDocumentHandler *handler);
|
||||
|
||||
void focusCurrentComponent(const QModelIndex &previousIndex, bool down);
|
||||
void emitFocusChangeSignals();
|
||||
void removeComponent(ChatTextItemHelper *textItem);
|
||||
|
||||
void updateCache() const;
|
||||
QString messageText() const;
|
||||
|
||||
Reference in New Issue
Block a user