File indexing completed on 2024-12-08 07:33:43
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 QStringLiteral("%1 %2").arg(m_filterModel->data(filterIndex, ActionsModel::Prefix).toString(), 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 auto mediaId = m_filterModel->data(filterIndex, RoomListModel::AvatarRole).toString(); 0091 if (mediaId.isEmpty()) { 0092 return QVariant(); 0093 } 0094 return m_room->connection()->makeMediaUrl(QUrl(QStringLiteral("mxc://%1").arg(mediaId))); 0095 } 0096 } 0097 if (m_autoCompletionType == Emoji) { 0098 if (role == DisplayNameRole) { 0099 return m_filterModel->data(filterIndex, CustomEmojiModel::DisplayRole); 0100 } 0101 if (role == IconNameRole) { 0102 return m_filterModel->data(filterIndex, CustomEmojiModel::MxcUrl); 0103 } 0104 if (role == ReplacedTextRole) { 0105 return m_filterModel->data(filterIndex, CustomEmojiModel::ReplacedTextRole); 0106 } 0107 if (role == SubtitleRole) { 0108 return m_filterModel->data(filterIndex, EmojiModel::DescriptionRole); 0109 } 0110 } 0111 0112 return {}; 0113 } 0114 0115 QHash<int, QByteArray> CompletionModel::roleNames() const 0116 { 0117 return { 0118 {DisplayNameRole, "displayName"}, 0119 {SubtitleRole, "subtitle"}, 0120 {IconNameRole, "iconName"}, 0121 {ReplacedTextRole, "replacedText"}, 0122 }; 0123 } 0124 0125 void CompletionModel::updateCompletion() 0126 { 0127 if (text().startsWith(QLatin1Char('@'))) { 0128 m_filterModel->setSourceModel(m_userListModel); 0129 m_filterModel->setFilterRole(UserListModel::UserIdRole); 0130 m_filterModel->setSecondaryFilterRole(UserListModel::DisplayNameRole); 0131 m_filterModel->setFullText(m_fullText); 0132 m_filterModel->setFilterText(m_text); 0133 m_autoCompletionType = User; 0134 m_filterModel->invalidate(); 0135 } else if (text().startsWith(QLatin1Char('/'))) { 0136 m_filterModel->setSourceModel(&ActionsModel::instance()); 0137 m_filterModel->setFilterRole(ActionsModel::Prefix); 0138 m_filterModel->setSecondaryFilterRole(-1); 0139 m_filterModel->setFullText(m_fullText); 0140 m_filterModel->setFilterText(m_text.mid(1)); 0141 m_autoCompletionType = Command; 0142 m_filterModel->invalidate(); 0143 } else if (text().startsWith(QLatin1Char('#'))) { 0144 m_autoCompletionType = Room; 0145 m_filterModel->setSourceModel(m_roomListModel); 0146 m_filterModel->setFilterRole(RoomListModel::CanonicalAliasRole); 0147 m_filterModel->setSecondaryFilterRole(RoomListModel::DisplayNameRole); 0148 m_filterModel->setFullText(m_fullText); 0149 m_filterModel->setFilterText(m_text); 0150 m_filterModel->invalidate(); 0151 } else if (text().startsWith(QLatin1Char(':')) && text().size() > 1 && !text()[1].isUpper() 0152 && (m_fullText.indexOf(QLatin1Char(':'), 1) == -1 0153 || (m_fullText.indexOf(QLatin1Char(' ')) != -1 && m_fullText.indexOf(QLatin1Char(':'), 1) > m_fullText.indexOf(QLatin1Char(' '), 1)))) { 0154 m_filterModel->setSourceModel(m_emojiModel); 0155 m_autoCompletionType = Emoji; 0156 m_filterModel->setFilterRole(CustomEmojiModel::Name); 0157 m_filterModel->setSecondaryFilterRole(EmojiModel::DescriptionRole); 0158 m_filterModel->setFullText(m_fullText); 0159 m_filterModel->setFilterText(m_text); 0160 m_filterModel->invalidate(); 0161 } else { 0162 m_autoCompletionType = None; 0163 } 0164 beginResetModel(); 0165 endResetModel(); 0166 } 0167 0168 NeoChatRoom *CompletionModel::room() const 0169 { 0170 return m_room; 0171 } 0172 0173 void CompletionModel::setRoom(NeoChatRoom *room) 0174 { 0175 m_room = room; 0176 Q_EMIT roomChanged(); 0177 } 0178 0179 CompletionModel::AutoCompletionType CompletionModel::autoCompletionType() const 0180 { 0181 return m_autoCompletionType; 0182 } 0183 0184 void CompletionModel::setAutoCompletionType(AutoCompletionType autoCompletionType) 0185 { 0186 m_autoCompletionType = autoCompletionType; 0187 Q_EMIT autoCompletionTypeChanged(); 0188 } 0189 0190 RoomListModel *CompletionModel::roomListModel() const 0191 { 0192 return m_roomListModel; 0193 } 0194 0195 void CompletionModel::setRoomListModel(RoomListModel *roomListModel) 0196 { 0197 m_roomListModel = roomListModel; 0198 Q_EMIT roomListModelChanged(); 0199 } 0200 0201 #include "moc_completionmodel.cpp"