File indexing completed on 2024-05-12 16:25:03

0001 // SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org>
0002 // SPDX-License-Identifier: LGPL-2.0-or-later
0003 
0004 #include "completionmodel.h"
0005 #include <QDebug>
0006 
0007 #include "actionsmodel.h"
0008 #include "completionproxymodel.h"
0009 #include "customemojimodel.h"
0010 #include "emojimodel.h"
0011 #include "neochatroom.h"
0012 #include "userlistmodel.h"
0013 
0014 CompletionModel::CompletionModel(QObject *parent)
0015     : QAbstractListModel(parent)
0016     , m_filterModel(new CompletionProxyModel())
0017     , m_userListModel(new UserListModel(this))
0018     , m_emojiModel(new QConcatenateTablesProxyModel(this))
0019 {
0020     connect(this, &CompletionModel::textChanged, this, &CompletionModel::updateCompletion);
0021     connect(this, &CompletionModel::roomChanged, this, [this]() {
0022         m_userListModel->setRoom(m_room);
0023     });
0024     m_emojiModel->addSourceModel(&CustomEmojiModel::instance());
0025     m_emojiModel->addSourceModel(&EmojiModel::instance());
0026 }
0027 
0028 QString CompletionModel::text() const
0029 {
0030     return m_text;
0031 }
0032 
0033 void CompletionModel::setText(const QString &text, const QString &fullText)
0034 {
0035     m_text = text;
0036     m_fullText = fullText;
0037     Q_EMIT textChanged();
0038 }
0039 
0040 int CompletionModel::rowCount(const QModelIndex &parent) const
0041 {
0042     Q_UNUSED(parent);
0043     if (m_autoCompletionType == None) {
0044         return 0;
0045     }
0046     return m_filterModel->rowCount();
0047 }
0048 
0049 QVariant CompletionModel::data(const QModelIndex &index, int role) const
0050 {
0051     if (index.row() < 0 || index.row() >= m_filterModel->rowCount()) {
0052         return {};
0053     }
0054     auto filterIndex = m_filterModel->index(index.row(), 0);
0055     if (m_autoCompletionType == User) {
0056         if (role == DisplayNameRole) {
0057             return m_filterModel->data(filterIndex, UserListModel::DisplayNameRole);
0058         }
0059         if (role == SubtitleRole) {
0060             return m_filterModel->data(filterIndex, UserListModel::UserIdRole);
0061         }
0062         if (role == IconNameRole) {
0063             return m_filterModel->data(filterIndex, UserListModel::AvatarRole);
0064         }
0065     }
0066 
0067     if (m_autoCompletionType == Command) {
0068         if (role == DisplayNameRole) {
0069             return m_filterModel->data(filterIndex, ActionsModel::Prefix).toString() + QStringLiteral(" ")
0070                 + m_filterModel->data(filterIndex, ActionsModel::Parameters).toString();
0071         }
0072         if (role == SubtitleRole) {
0073             return m_filterModel->data(filterIndex, ActionsModel::Description);
0074         }
0075         if (role == IconNameRole) {
0076             return QStringLiteral("invalid");
0077         }
0078         if (role == ReplacedTextRole) {
0079             return m_filterModel->data(filterIndex, ActionsModel::Prefix);
0080         }
0081     }
0082     if (m_autoCompletionType == Room) {
0083         if (role == DisplayNameRole) {
0084             return m_filterModel->data(filterIndex, RoomListModel::DisplayNameRole);
0085         }
0086         if (role == SubtitleRole) {
0087             return m_filterModel->data(filterIndex, RoomListModel::CanonicalAliasRole);
0088         }
0089         if (role == IconNameRole) {
0090             return m_filterModel->data(filterIndex, RoomListModel::AvatarRole);
0091         }
0092     }
0093     if (m_autoCompletionType == Emoji) {
0094         if (role == DisplayNameRole) {
0095             return m_filterModel->data(filterIndex, CustomEmojiModel::DisplayRole);
0096         }
0097         if (role == IconNameRole) {
0098             return m_filterModel->data(filterIndex, CustomEmojiModel::MxcUrl);
0099         }
0100         if (role == ReplacedTextRole) {
0101             return m_filterModel->data(filterIndex, CustomEmojiModel::ReplacedTextRole);
0102         }
0103         if (role == SubtitleRole) {
0104             return m_filterModel->data(filterIndex, EmojiModel::DescriptionRole);
0105         }
0106     }
0107 
0108     return {};
0109 }
0110 
0111 QHash<int, QByteArray> CompletionModel::roleNames() const
0112 {
0113     return {
0114         {DisplayNameRole, "displayName"},
0115         {SubtitleRole, "subtitle"},
0116         {IconNameRole, "iconName"},
0117         {ReplacedTextRole, "replacedText"},
0118     };
0119 }
0120 
0121 void CompletionModel::updateCompletion()
0122 {
0123     if (text().startsWith(QLatin1Char('@'))) {
0124         m_filterModel->setSourceModel(m_userListModel);
0125         m_filterModel->setFilterRole(UserListModel::UserIdRole);
0126         m_filterModel->setSecondaryFilterRole(UserListModel::DisplayNameRole);
0127         m_filterModel->setFullText(m_fullText);
0128         m_filterModel->setFilterText(m_text);
0129         m_autoCompletionType = User;
0130         m_filterModel->invalidate();
0131     } else if (text().startsWith(QLatin1Char('/'))) {
0132         m_filterModel->setSourceModel(&ActionsModel::instance());
0133         m_filterModel->setFilterRole(ActionsModel::Prefix);
0134         m_filterModel->setSecondaryFilterRole(-1);
0135         m_filterModel->setFullText(m_fullText);
0136         m_filterModel->setFilterText(m_text.mid(1));
0137         m_autoCompletionType = Command;
0138         m_filterModel->invalidate();
0139     } else if (text().startsWith(QLatin1Char('#'))) {
0140         m_autoCompletionType = Room;
0141         m_filterModel->setSourceModel(m_roomListModel);
0142         m_filterModel->setFilterRole(RoomListModel::CanonicalAliasRole);
0143         m_filterModel->setSecondaryFilterRole(RoomListModel::DisplayNameRole);
0144         m_filterModel->setFullText(m_fullText);
0145         m_filterModel->setFilterText(m_text);
0146         m_filterModel->invalidate();
0147     } else if (text().startsWith(QLatin1Char(':')) && !text()[1].isUpper()
0148                && (m_fullText.indexOf(QLatin1Char(':'), 1) == -1
0149                    || (m_fullText.indexOf(QLatin1Char(' ')) != -1 && m_fullText.indexOf(QLatin1Char(':'), 1) > m_fullText.indexOf(QLatin1Char(' '), 1)))) {
0150         m_filterModel->setSourceModel(m_emojiModel);
0151         m_autoCompletionType = Emoji;
0152         m_filterModel->setFilterRole(CustomEmojiModel::Name);
0153         m_filterModel->setSecondaryFilterRole(EmojiModel::DescriptionRole);
0154         m_filterModel->setFullText(m_fullText);
0155         m_filterModel->setFilterText(m_text);
0156         m_filterModel->invalidate();
0157     } else {
0158         m_autoCompletionType = None;
0159     }
0160     beginResetModel();
0161     endResetModel();
0162 }
0163 
0164 NeoChatRoom *CompletionModel::room() const
0165 {
0166     return m_room;
0167 }
0168 
0169 void CompletionModel::setRoom(NeoChatRoom *room)
0170 {
0171     m_room = room;
0172     Q_EMIT roomChanged();
0173 }
0174 
0175 CompletionModel::AutoCompletionType CompletionModel::autoCompletionType() const
0176 {
0177     return m_autoCompletionType;
0178 }
0179 
0180 void CompletionModel::setAutoCompletionType(AutoCompletionType autoCompletionType)
0181 {
0182     m_autoCompletionType = autoCompletionType;
0183     Q_EMIT autoCompletionTypeChanged();
0184 }
0185 
0186 RoomListModel *CompletionModel::roomListModel() const
0187 {
0188     return m_roomListModel;
0189 }
0190 
0191 void CompletionModel::setRoomListModel(RoomListModel *roomListModel)
0192 {
0193     m_roomListModel = roomListModel;
0194     Q_EMIT roomListModelChanged();
0195 }
0196 
0197 #include "moc_completionmodel.cpp"