File indexing completed on 2024-12-08 07:33:46
0001 // SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org> 0002 // SPDX-License-Identifier: LGPL-2.0-or-later 0003 0004 #include "searchmodel.h" 0005 0006 #include "eventhandler.h" 0007 #include "messageeventmodel.h" 0008 #include "neochatroom.h" 0009 0010 #include <QGuiApplication> 0011 0012 #include <Quotient/connection.h> 0013 #include <Quotient/events/stickerevent.h> 0014 0015 #include <KLocalizedString> 0016 0017 using namespace Quotient; 0018 0019 // TODO search only in the current room 0020 0021 SearchModel::SearchModel(QObject *parent) 0022 : QAbstractListModel(parent) 0023 { 0024 } 0025 0026 QString SearchModel::searchText() const 0027 { 0028 return m_searchText; 0029 } 0030 0031 void SearchModel::setSearchText(const QString &searchText) 0032 { 0033 m_searchText = searchText; 0034 Q_EMIT searchTextChanged(); 0035 } 0036 0037 void SearchModel::search() 0038 { 0039 Q_ASSERT(m_connection); 0040 setSearching(true); 0041 if (m_job) { 0042 m_job->abandon(); 0043 m_job = nullptr; 0044 } 0045 0046 RoomEventFilter filter; 0047 filter.unreadThreadNotifications = none; 0048 filter.lazyLoadMembers = true; 0049 filter.includeRedundantMembers = false; 0050 filter.notRooms = QStringList(); 0051 filter.rooms = QStringList{m_room->id()}; 0052 filter.containsUrl = false; 0053 0054 SearchJob::RoomEventsCriteria criteria{ 0055 .searchTerm = m_searchText, 0056 .keys = {}, 0057 .filter = filter, 0058 .orderBy = "recent"_ls, 0059 .eventContext = SearchJob::IncludeEventContext{3, 3, true}, 0060 .includeState = false, 0061 .groupings = none, 0062 0063 }; 0064 0065 auto job = m_connection->callApi<SearchJob>(SearchJob::Categories{criteria}); 0066 m_job = job; 0067 connect(job, &BaseJob::finished, this, [this, job] { 0068 beginResetModel(); 0069 m_result = job->searchCategories().roomEvents; 0070 endResetModel(); 0071 setSearching(false); 0072 m_job = nullptr; 0073 // TODO error handling 0074 }); 0075 } 0076 0077 Connection *SearchModel::connection() const 0078 { 0079 return m_connection; 0080 } 0081 0082 void SearchModel::setConnection(Connection *connection) 0083 { 0084 m_connection = connection; 0085 Q_EMIT connectionChanged(); 0086 } 0087 0088 QVariant SearchModel::data(const QModelIndex &index, int role) const 0089 { 0090 auto row = index.row(); 0091 const auto &event = *m_result->results[row].result; 0092 0093 EventHandler eventHandler; 0094 eventHandler.setRoom(m_room); 0095 eventHandler.setEvent(&event); 0096 0097 switch (role) { 0098 case DisplayRole: 0099 return eventHandler.getRichBody(); 0100 case ShowAuthorRole: 0101 return true; 0102 case AuthorRole: 0103 return eventHandler.getAuthor(); 0104 case ShowSectionRole: 0105 if (row == 0) { 0106 return true; 0107 } 0108 return event.originTimestamp().date() != m_result->results[row - 1].result->originTimestamp().date(); 0109 case SectionRole: 0110 return eventHandler.getTimeString(true); 0111 case TimeRole: 0112 return eventHandler.getTime(); 0113 case TimeStringRole: 0114 return eventHandler.getTimeString(false); 0115 case ShowReactionsRole: 0116 return false; 0117 case ShowReadMarkersRole: 0118 return false; 0119 case IsReplyRole: 0120 return eventHandler.hasReply(); 0121 case ReplyIdRole: 0122 return eventHandler.hasReply(); 0123 case ReplyAuthorRole: 0124 return eventHandler.getReplyAuthor(); 0125 case ReplyDelegateTypeRole: 0126 return eventHandler.getReplyDelegateType(); 0127 case ReplyDisplayRole: 0128 return eventHandler.getReplyRichBody(); 0129 case ReplyMediaInfoRole: 0130 return eventHandler.getReplyMediaInfo(); 0131 case IsPendingRole: 0132 return false; 0133 case ShowLinkPreviewRole: 0134 return false; 0135 case HighlightRole: 0136 return eventHandler.isHighlighted(); 0137 case EventIdRole: 0138 return eventHandler.getId(); 0139 case IsThreadedRole: 0140 return eventHandler.isThreaded(); 0141 case ThreadRootRole: 0142 return eventHandler.threadRoot(); 0143 } 0144 return DelegateType::Message; 0145 } 0146 0147 int SearchModel::rowCount(const QModelIndex &parent) const 0148 { 0149 Q_UNUSED(parent); 0150 if (m_result.has_value()) { 0151 return m_result->results.size(); 0152 } 0153 return 0; 0154 } 0155 0156 QHash<int, QByteArray> SearchModel::roleNames() const 0157 { 0158 return { 0159 {DelegateTypeRole, "delegateType"}, 0160 {DisplayRole, "display"}, 0161 {AuthorRole, "author"}, 0162 {ShowSectionRole, "showSection"}, 0163 {SectionRole, "section"}, 0164 {TimeRole, "time"}, 0165 {TimeStringRole, "timeString"}, 0166 {ShowAuthorRole, "showAuthor"}, 0167 {EventIdRole, "eventId"}, 0168 {ExcessReadMarkersRole, "excessReadMarkers"}, 0169 {HighlightRole, "isHighlighted"}, 0170 {ReadMarkersString, "readMarkersString"}, 0171 {PlainTextRole, "plainText"}, 0172 {VerifiedRole, "verified"}, 0173 {ProgressInfoRole, "progressInfo"}, 0174 {ShowReactionsRole, "showReactions"}, 0175 {IsReplyRole, "isReply"}, 0176 {ReplyAuthorRole, "replyAuthor"}, 0177 {ReplyIdRole, "replyId"}, 0178 {ReplyDelegateTypeRole, "replyDelegateType"}, 0179 {ReplyDisplayRole, "replyDisplay"}, 0180 {ReplyMediaInfoRole, "replyMediaInfo"}, 0181 {ReactionRole, "reaction"}, 0182 {ReadMarkersRole, "readMarkers"}, 0183 {IsPendingRole, "isPending"}, 0184 {ShowReadMarkersRole, "showReadMarkers"}, 0185 {MimeTypeRole, "mimeType"}, 0186 {ShowLinkPreviewRole, "showLinkPreview"}, 0187 {LinkPreviewRole, "linkPreview"}, 0188 {IsThreadedRole, "isThreaded"}, 0189 {ThreadRootRole, "threadRoot"}, 0190 }; 0191 } 0192 0193 NeoChatRoom *SearchModel::room() const 0194 { 0195 return m_room; 0196 } 0197 0198 void SearchModel::setRoom(NeoChatRoom *room) 0199 { 0200 if (m_room) { 0201 disconnect(m_room, nullptr, this, nullptr); 0202 } 0203 m_room = room; 0204 Q_EMIT roomChanged(); 0205 0206 connect(m_room, &NeoChatRoom::replyLoaded, this, [this](const auto &eventId, const auto &replyId) { 0207 Q_UNUSED(replyId); 0208 const auto &results = m_result->results; 0209 auto it = std::find_if(results.begin(), results.end(), [eventId](const auto &event) { 0210 return event.result->id() == eventId; 0211 }); 0212 if (it == results.end()) { 0213 return; 0214 } 0215 auto row = it - results.begin(); 0216 Q_EMIT dataChanged(index(row, 0), index(row, 0), {ReplyDelegateTypeRole, ReplyDisplayRole, ReplyMediaInfoRole, ReplyAuthorRole}); 0217 }); 0218 } 0219 0220 bool SearchModel::searching() const 0221 { 0222 return m_searching; 0223 } 0224 0225 bool SearchModel::event(QEvent *event) 0226 { 0227 if (event->type() == QEvent::ApplicationPaletteChange) { 0228 Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, 0), {AuthorRole, ReadMarkersRole}); 0229 } 0230 return QObject::event(event); 0231 } 0232 0233 void SearchModel::setSearching(bool searching) 0234 { 0235 m_searching = searching; 0236 Q_EMIT searchingChanged(); 0237 } 0238 0239 #include "moc_searchmodel.cpp"