File indexing completed on 2024-05-05 05:01:25
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_room); 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_room->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 QVariant SearchModel::data(const QModelIndex &index, int role) const 0078 { 0079 auto row = index.row(); 0080 const auto &event = *m_result->results[row].result; 0081 0082 EventHandler eventHandler(m_room, &event); 0083 0084 switch (role) { 0085 case DisplayRole: 0086 return eventHandler.getRichBody(); 0087 case ShowAuthorRole: 0088 return true; 0089 case AuthorRole: 0090 return eventHandler.getAuthor(); 0091 case ShowSectionRole: 0092 if (row == 0) { 0093 return true; 0094 } 0095 return event.originTimestamp().date() != m_result->results[row - 1].result->originTimestamp().date(); 0096 case SectionRole: 0097 return eventHandler.getTimeString(true); 0098 case TimeRole: 0099 return eventHandler.getTime(); 0100 case TimeStringRole: 0101 return eventHandler.getTimeString(false); 0102 case ShowReactionsRole: 0103 return false; 0104 case ShowReadMarkersRole: 0105 return false; 0106 case IsReplyRole: 0107 return eventHandler.hasReply(); 0108 case ReplyIdRole: 0109 return eventHandler.hasReply(); 0110 case ReplyAuthorRole: 0111 return eventHandler.getReplyAuthor(); 0112 case ReplyDelegateTypeRole: 0113 return eventHandler.getReplyDelegateType(); 0114 case ReplyDisplayRole: 0115 return eventHandler.getReplyRichBody(); 0116 case ReplyMediaInfoRole: 0117 return eventHandler.getReplyMediaInfo(); 0118 case IsPendingRole: 0119 return false; 0120 case ShowLinkPreviewRole: 0121 return false; 0122 case HighlightRole: 0123 return eventHandler.isHighlighted(); 0124 case EventIdRole: 0125 return eventHandler.getId(); 0126 case IsThreadedRole: 0127 return eventHandler.isThreaded(); 0128 case ThreadRootRole: 0129 return eventHandler.threadRoot(); 0130 } 0131 return DelegateType::Message; 0132 } 0133 0134 int SearchModel::rowCount(const QModelIndex &parent) const 0135 { 0136 Q_UNUSED(parent); 0137 if (m_result.has_value()) { 0138 return m_result->results.size(); 0139 } 0140 return 0; 0141 } 0142 0143 QHash<int, QByteArray> SearchModel::roleNames() const 0144 { 0145 return { 0146 {DelegateTypeRole, "delegateType"}, 0147 {DisplayRole, "display"}, 0148 {AuthorRole, "author"}, 0149 {ShowSectionRole, "showSection"}, 0150 {SectionRole, "section"}, 0151 {TimeRole, "time"}, 0152 {TimeStringRole, "timeString"}, 0153 {ShowAuthorRole, "showAuthor"}, 0154 {EventIdRole, "eventId"}, 0155 {ExcessReadMarkersRole, "excessReadMarkers"}, 0156 {HighlightRole, "isHighlighted"}, 0157 {ReadMarkersString, "readMarkersString"}, 0158 {PlainTextRole, "plainText"}, 0159 {VerifiedRole, "verified"}, 0160 {ProgressInfoRole, "progressInfo"}, 0161 {ShowReactionsRole, "showReactions"}, 0162 {IsReplyRole, "isReply"}, 0163 {ReplyAuthorRole, "replyAuthor"}, 0164 {ReplyIdRole, "replyId"}, 0165 {ReplyDelegateTypeRole, "replyDelegateType"}, 0166 {ReplyDisplayRole, "replyDisplay"}, 0167 {ReplyMediaInfoRole, "replyMediaInfo"}, 0168 {ReactionRole, "reaction"}, 0169 {ReadMarkersRole, "readMarkers"}, 0170 {IsPendingRole, "isPending"}, 0171 {ShowReadMarkersRole, "showReadMarkers"}, 0172 {MimeTypeRole, "mimeType"}, 0173 {ShowLinkPreviewRole, "showLinkPreview"}, 0174 {LinkPreviewRole, "linkPreview"}, 0175 {IsThreadedRole, "isThreaded"}, 0176 {ThreadRootRole, "threadRoot"}, 0177 }; 0178 } 0179 0180 NeoChatRoom *SearchModel::room() const 0181 { 0182 return m_room; 0183 } 0184 0185 void SearchModel::setRoom(NeoChatRoom *room) 0186 { 0187 if (m_room) { 0188 disconnect(m_room, nullptr, this, nullptr); 0189 } 0190 m_room = room; 0191 Q_EMIT roomChanged(); 0192 0193 connect(m_room, &NeoChatRoom::replyLoaded, this, [this](const auto &eventId, const auto &replyId) { 0194 Q_UNUSED(replyId); 0195 const auto &results = m_result->results; 0196 auto it = std::find_if(results.begin(), results.end(), [eventId](const auto &event) { 0197 return event.result->id() == eventId; 0198 }); 0199 if (it == results.end()) { 0200 return; 0201 } 0202 auto row = it - results.begin(); 0203 Q_EMIT dataChanged(index(row, 0), index(row, 0), {ReplyDelegateTypeRole, ReplyDisplayRole, ReplyMediaInfoRole, ReplyAuthorRole}); 0204 }); 0205 } 0206 0207 bool SearchModel::searching() const 0208 { 0209 return m_searching; 0210 } 0211 0212 bool SearchModel::event(QEvent *event) 0213 { 0214 if (event->type() == QEvent::ApplicationPaletteChange) { 0215 Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, 0), {AuthorRole, ReadMarkersRole}); 0216 } 0217 return QObject::event(event); 0218 } 0219 0220 void SearchModel::setSearching(bool searching) 0221 { 0222 m_searching = searching; 0223 Q_EMIT searchingChanged(); 0224 } 0225 0226 #include "moc_searchmodel.cpp"