Spearate completion from ChatDocumentHandler
This commit is contained in:
@@ -2,35 +2,55 @@
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#include "completionmodel.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QTextCursor>
|
||||
|
||||
#include "completionproxymodel.h"
|
||||
#include "models/actionsmodel.h"
|
||||
#include "models/customemojimodel.h"
|
||||
#include "models/emojimodel.h"
|
||||
#include "neochatroom.h"
|
||||
#include "qmltextitemwrapper.h"
|
||||
#include "userlistmodel.h"
|
||||
|
||||
CompletionModel::CompletionModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, m_textItem(new QmlTextItemWrapper(this))
|
||||
, m_filterModel(new CompletionProxyModel(this))
|
||||
, m_emojiModel(new QConcatenateTablesProxyModel(this))
|
||||
{
|
||||
connect(this, &CompletionModel::textChanged, this, &CompletionModel::updateCompletion);
|
||||
connect(m_textItem, &QmlTextItemWrapper::textItemChanged, this, &CompletionModel::textItemChanged);
|
||||
connect(m_textItem, &QmlTextItemWrapper::textDocumentCursorPositionChanged, this, &CompletionModel::updateTextStart);
|
||||
connect(m_textItem, &QmlTextItemWrapper::textDocumentContentsChanged, this, &CompletionModel::updateCompletion);
|
||||
|
||||
m_emojiModel->addSourceModel(&CustomEmojiModel::instance());
|
||||
m_emojiModel->addSourceModel(&EmojiModel::instance());
|
||||
}
|
||||
|
||||
QString CompletionModel::text() const
|
||||
QQuickItem *CompletionModel::textItem() const
|
||||
{
|
||||
return m_text;
|
||||
return m_textItem->textItem();
|
||||
}
|
||||
|
||||
void CompletionModel::setText(const QString &text, const QString &fullText)
|
||||
void CompletionModel::setTextItem(QQuickItem *textItem)
|
||||
{
|
||||
m_text = text;
|
||||
m_fullText = fullText;
|
||||
Q_EMIT textChanged();
|
||||
m_textItem->setTextItem(textItem);
|
||||
}
|
||||
|
||||
void CompletionModel::updateTextStart()
|
||||
{
|
||||
auto cursor = m_textItem->textCursor();
|
||||
if (cursor.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
|
||||
while (cursor.selectedText() != u' ' && !cursor.atBlockStart()) {
|
||||
cursor.movePosition(QTextCursor::PreviousCharacter);
|
||||
cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
|
||||
}
|
||||
m_textStart = cursor.position() == 0 && cursor.selectedText() != u' ' ? 0 : cursor.position() + 1;
|
||||
updateCompletion();
|
||||
}
|
||||
|
||||
int CompletionModel::rowCount(const QModelIndex &parent) const
|
||||
@@ -58,6 +78,12 @@ QVariant CompletionModel::data(const QModelIndex &index, int role) const
|
||||
if (role == IconNameRole) {
|
||||
return m_filterModel->data(filterIndex, UserListModel::AvatarRole);
|
||||
}
|
||||
if (role == ReplacedTextRole) {
|
||||
return m_filterModel->data(filterIndex, UserListModel::DisplayNameRole);
|
||||
}
|
||||
if (role == HRefRole) {
|
||||
return u"https://matrix.to/#/%1"_s.arg(m_filterModel->data(filterIndex, UserListModel::UserIdRole).toString());
|
||||
}
|
||||
}
|
||||
|
||||
if (m_autoCompletionType == Command) {
|
||||
@@ -85,6 +111,12 @@ QVariant CompletionModel::data(const QModelIndex &index, int role) const
|
||||
if (role == IconNameRole) {
|
||||
return m_filterModel->data(filterIndex, RoomListModel::AvatarRole).toString();
|
||||
}
|
||||
if (role == ReplacedTextRole) {
|
||||
return m_filterModel->data(filterIndex, RoomListModel::CanonicalAliasRole);
|
||||
}
|
||||
if (role == HRefRole) {
|
||||
return u"https://matrix.to/#/%1"_s.arg(m_filterModel->data(filterIndex, RoomListModel::CanonicalAliasRole).toString());
|
||||
}
|
||||
}
|
||||
if (m_autoCompletionType == Emoji) {
|
||||
if (role == DisplayNameRole) {
|
||||
@@ -111,44 +143,57 @@ QHash<int, QByteArray> CompletionModel::roleNames() const
|
||||
{SubtitleRole, "subtitle"},
|
||||
{IconNameRole, "iconName"},
|
||||
{ReplacedTextRole, "replacedText"},
|
||||
{HRefRole, "hRef"},
|
||||
};
|
||||
}
|
||||
|
||||
void CompletionModel::updateCompletion()
|
||||
{
|
||||
if (text().startsWith(QLatin1Char('@'))) {
|
||||
auto cursor = m_textItem->textCursor();
|
||||
if (cursor.isNull()) {
|
||||
return;
|
||||
}
|
||||
cursor.setPosition(m_textStart);
|
||||
while (!cursor.selectedText().endsWith(u' ') && !cursor.atBlockEnd()) {
|
||||
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
|
||||
}
|
||||
const auto text = cursor.selectedText().trimmed();
|
||||
cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
|
||||
const auto fullText = cursor.selectedText();
|
||||
|
||||
if (text.startsWith(QLatin1Char('@'))) {
|
||||
m_filterModel->setSourceModel(m_userListModel);
|
||||
m_filterModel->setFilterRole(UserListModel::UserIdRole);
|
||||
m_filterModel->setSecondaryFilterRole(UserListModel::DisplayNameRole);
|
||||
m_filterModel->setFullText(m_fullText);
|
||||
m_filterModel->setFilterText(m_text);
|
||||
m_filterModel->setFullText(fullText);
|
||||
m_filterModel->setFilterText(text);
|
||||
m_autoCompletionType = User;
|
||||
m_filterModel->invalidate();
|
||||
} else if (text().startsWith(QLatin1Char('/'))) {
|
||||
} else if (text.startsWith(QLatin1Char('/'))) {
|
||||
m_filterModel->setSourceModel(&ActionsModel::instance());
|
||||
m_filterModel->setFilterRole(ActionsModel::Prefix);
|
||||
m_filterModel->setSecondaryFilterRole(-1);
|
||||
m_filterModel->setFullText(m_fullText);
|
||||
m_filterModel->setFilterText(m_text.mid(1));
|
||||
m_filterModel->setFullText(fullText);
|
||||
m_filterModel->setFilterText(text.mid(1));
|
||||
m_autoCompletionType = Command;
|
||||
m_filterModel->invalidate();
|
||||
} else if (text().startsWith(QLatin1Char('#'))) {
|
||||
} else if (text.startsWith(QLatin1Char('#'))) {
|
||||
m_autoCompletionType = Room;
|
||||
m_filterModel->setSourceModel(m_roomListModel);
|
||||
m_filterModel->setFilterRole(RoomListModel::CanonicalAliasRole);
|
||||
m_filterModel->setSecondaryFilterRole(RoomListModel::DisplayNameRole);
|
||||
m_filterModel->setFullText(m_fullText);
|
||||
m_filterModel->setFilterText(m_text);
|
||||
m_filterModel->setFullText(fullText);
|
||||
m_filterModel->setFilterText(text);
|
||||
m_filterModel->invalidate();
|
||||
} else if (text().startsWith(QLatin1Char(':')) && text().size() > 1 && !text()[1].isUpper()
|
||||
&& (m_fullText.indexOf(QLatin1Char(':'), 1) == -1
|
||||
|| (m_fullText.indexOf(QLatin1Char(' ')) != -1 && m_fullText.indexOf(QLatin1Char(':'), 1) > m_fullText.indexOf(QLatin1Char(' '), 1)))) {
|
||||
} else if (text.startsWith(QLatin1Char(':')) && text.size() > 1 && !text[1].isUpper()
|
||||
&& (fullText.indexOf(QLatin1Char(':'), 1) == -1
|
||||
|| (fullText.indexOf(QLatin1Char(' ')) != -1 && fullText.indexOf(QLatin1Char(':'), 1) > fullText.indexOf(QLatin1Char(' '), 1)))) {
|
||||
m_filterModel->setSourceModel(m_emojiModel);
|
||||
m_autoCompletionType = Emoji;
|
||||
m_filterModel->setFilterRole(CustomEmojiModel::Name);
|
||||
m_filterModel->setSecondaryFilterRole(EmojiModel::DescriptionRole);
|
||||
m_filterModel->setFullText(m_fullText);
|
||||
m_filterModel->setFilterText(m_text);
|
||||
m_filterModel->setFullText(fullText);
|
||||
m_filterModel->setFilterText(text);
|
||||
m_filterModel->invalidate();
|
||||
} else {
|
||||
m_autoCompletionType = None;
|
||||
@@ -157,17 +202,6 @@ void CompletionModel::updateCompletion()
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
NeoChatRoom *CompletionModel::room() const
|
||||
{
|
||||
return m_room;
|
||||
}
|
||||
|
||||
void CompletionModel::setRoom(NeoChatRoom *room)
|
||||
{
|
||||
m_room = room;
|
||||
Q_EMIT roomChanged();
|
||||
}
|
||||
|
||||
CompletionModel::AutoCompletionType CompletionModel::autoCompletionType() const
|
||||
{
|
||||
return m_autoCompletionType;
|
||||
|
||||
@@ -5,13 +5,14 @@
|
||||
|
||||
#include <QConcatenateTablesProxyModel>
|
||||
#include <QQmlEngine>
|
||||
#include <QQuickItem>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "roomlistmodel.h"
|
||||
|
||||
class CompletionProxyModel;
|
||||
class UserListModel;
|
||||
class NeoChatRoom;
|
||||
class QmlTextItemWrapper;
|
||||
class RoomListModel;
|
||||
|
||||
/**
|
||||
@@ -28,14 +29,9 @@ class CompletionModel : public QAbstractListModel
|
||||
QML_ELEMENT
|
||||
|
||||
/**
|
||||
* @brief The current text to search for completions.
|
||||
* @brief The QML text Item that completions are being provided for.
|
||||
*/
|
||||
Q_PROPERTY(QString text READ text NOTIFY textChanged)
|
||||
|
||||
/**
|
||||
* @brief The current room that the model is getting completions for.
|
||||
*/
|
||||
Q_PROPERTY(NeoChatRoom *room READ room WRITE setRoom NOTIFY roomChanged)
|
||||
Q_PROPERTY(QQuickItem *textItem READ textItem WRITE setTextItem NOTIFY textItemChanged)
|
||||
|
||||
/**
|
||||
* @brief The current type of completion being done on the entered text.
|
||||
@@ -72,14 +68,18 @@ public:
|
||||
*/
|
||||
enum Roles {
|
||||
DisplayNameRole = Qt::DisplayRole, /**< The main text to show. */
|
||||
SubtitleRole, /**< The subtitle text to show. */
|
||||
SubtitleRole = Qt::UserRole, /**< The subtitle text to show. */
|
||||
IconNameRole, /**< The icon to show. */
|
||||
ReplacedTextRole, /**< The text to replace the input text with for the completion. */
|
||||
HRefRole, /**< The hyperlink if applicable for the completion. */
|
||||
};
|
||||
Q_ENUM(Roles)
|
||||
|
||||
explicit CompletionModel(QObject *parent = nullptr);
|
||||
|
||||
QQuickItem *textItem() const;
|
||||
void setTextItem(QQuickItem *textItem);
|
||||
|
||||
/**
|
||||
* @brief Get the given role value at the given index.
|
||||
*
|
||||
@@ -101,12 +101,6 @@ public:
|
||||
*/
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
QString text() const;
|
||||
void setText(const QString &text, const QString &fullText);
|
||||
|
||||
NeoChatRoom *room() const;
|
||||
void setRoom(NeoChatRoom *room);
|
||||
|
||||
RoomListModel *roomListModel() const;
|
||||
void setRoomListModel(RoomListModel *roomListModel);
|
||||
|
||||
@@ -117,17 +111,20 @@ public:
|
||||
void setAutoCompletionType(AutoCompletionType autoCompletionType);
|
||||
|
||||
Q_SIGNALS:
|
||||
void textChanged();
|
||||
void textItemChanged();
|
||||
|
||||
void roomChanged();
|
||||
void autoCompletionTypeChanged();
|
||||
void roomListModelChanged();
|
||||
void userListModelChanged();
|
||||
|
||||
private:
|
||||
QString m_text;
|
||||
QString m_fullText;
|
||||
QPointer<QmlTextItemWrapper> m_textItem;
|
||||
|
||||
int m_textStart = 0;
|
||||
void updateTextStart();
|
||||
|
||||
CompletionProxyModel *m_filterModel;
|
||||
QPointer<NeoChatRoom> m_room;
|
||||
AutoCompletionType m_autoCompletionType = None;
|
||||
|
||||
void updateCompletion();
|
||||
|
||||
Reference in New Issue
Block a user