diff --git a/src/api/conversationmodel.h b/src/api/conversationmodel.h index 642f014a11871056cff73324039fcbe9f10ff4f1..90e04543c6ce96cf21d6e6aaf5a7c27d6510b840 100644 --- a/src/api/conversationmodel.h +++ b/src/api/conversationmodel.h @@ -88,6 +88,15 @@ public: const api::BehaviorController& behaviorController); ~ConversationModel(); + /** + * Get unfiltered underlying conversation data. This is intended to + * serve as the underlying data for QAbstractListModel based objects. + * The corresponding data mutation signals will need to be responded + * to with appropriate QAbstractListModel signal forwarding. + * @return raw conversation queue + */ + const ConversationQueue& getConversations() const; + /** * Get conversations which should be shown client side * @return conversations filtered with the current filter @@ -237,8 +246,7 @@ public: * @param convId * @param interactionId */ - void clearInteractionFromConversation(const QString& convId, - const uint64_t& interactionId); + void clearInteractionFromConversation(const QString& convId, const uint64_t& interactionId); /** * Retry to send a message. In fact, will delete the previous interaction and resend a new one. * @param convId @@ -264,9 +272,7 @@ public: void acceptTransfer(const QString& convUid, uint64_t interactionId); - void acceptTransfer(const QString& convUid, - uint64_t interactionId, - const QString& path); + void acceptTransfer(const QString& convUid, uint64_t interactionId, const QString& path); void cancelTransfer(const QString& convUid, uint64_t interactionId); @@ -378,6 +384,36 @@ Q_SIGNALS: */ void searchResultUpdated() const; + /** + * The following signals are intended for QAbtractListModel compatibility + */ + + /*! + * Emitted before conversations are inserted into the underlying queue + * @param position The starting row of the insertion + * @param rows The number of items inserted + */ + void beginInsertRows(int position, int rows = 1) const; + + //! Emitted once insertion is complete + void endInsertRows() const; + + /*! + * Emitted before conversations are removed from the underlying queue + * @param position The starting row of the removal + * @param rows The number of items removed + */ + void beginRemoveRows(int position, int rows = 1) const; + + //! Emitted once removal is complete + void endRemoveRows() const; + + /** + * Emitted once a conversation has been updated + * @param position + */ + void dataChanged(int position) const; + private: std::unique_ptr<ConversationModelPimpl> pimpl_; }; diff --git a/src/conversationmodel.cpp b/src/conversationmodel.cpp index b6801ba6ae6d30ce2b429b72289860593d4001bd..be31a18f0de155befd6e95b4e739a2f958069645 100644 --- a/src/conversationmodel.cpp +++ b/src/conversationmodel.cpp @@ -331,6 +331,12 @@ ConversationModel::ConversationModel(const account::Info& owner, ConversationModel::~ConversationModel() {} +const ConversationModel::ConversationQueue& +ConversationModel::getConversations() const +{ + return pimpl_->conversations; +} + const ConversationModel::ConversationQueueProxy& ConversationModel::allFilteredConversations() const { @@ -898,6 +904,7 @@ ConversationModel::sendMessage(const QString& uid, const QString& body) // The order has changed, informs the client to redraw the list pimpl_->invalidateModel(); emit modelChanged(); + Q_EMIT dataChanged(pimpl_->indexOf(convId)); }); if (isTemporary) { @@ -1013,10 +1020,11 @@ ConversationModel::clearHistory(const QString& uid) std::lock_guard<std::mutex> lk(pimpl_->interactionsLocks[uid]); conversation.interactions.clear(); } - storage::getHistory(pimpl_->db, conversation); // will contains "Conversation started" + storage::getHistory(pimpl_->db, conversation); // will contain "Conversation started" emit modelChanged(); emit conversationCleared(uid); + Q_EMIT dataChanged(conversationIdx); } void @@ -1079,8 +1087,9 @@ ConversationModel::clearInteractionFromConversation(const QString& convId, emit interactionRemoved(convId, interactionId); } if (lastInteractionUpdated) { - // last interaction as changed, so the order can changes. + // last interaction as changed, so the order can change. emit modelChanged(); + Q_EMIT dataChanged(conversationIdx); } } @@ -1242,6 +1251,7 @@ ConversationModel::clearUnreadInteractions(const QString& convId) pimpl_->conversations[conversationIdx].unreadMessages = 0; pimpl_->invalidateModel(); emit conversationUpdated(convId); + Q_EMIT dataChanged(conversationIdx); } } @@ -1686,7 +1696,10 @@ ConversationModelPimpl::slotContactAdded(const QString& contactUri) // delete temporary conversation if it exists and it has the uri of the added contact as uid if (indexOf(profileInfo.uri) >= 0) { - conversations.erase(conversations.begin() + indexOf(profileInfo.uri)); + auto position = indexOf(profileInfo.uri); + Q_EMIT linked.beginRemoveRows(position); + conversations.erase(conversations.begin() + position); + Q_EMIT linked.endRemoveRows(); } for (unsigned int i = 0; i < searchResults.size(); ++i) { if (searchResults.at(i).uid == profileInfo.uri) @@ -1730,6 +1743,7 @@ ConversationModelPimpl::slotPendingContactAccepted(const QString& uri) } filteredConversations.invalidate(); emit linked.newInteraction(convs[0], msgId, interaction); + Q_EMIT linked.dataChanged(convIdx); } catch (std::out_of_range& e) { qDebug() << "ConversationModelPimpl::slotContactAdded can't find contact"; } @@ -1745,7 +1759,10 @@ ConversationModelPimpl::slotContactRemoved(const QString& uri) return; // Not a contact } auto& conversationUid = conversations[conversationIdx].uid; + + Q_EMIT linked.beginRemoveRows(conversationIdx); conversations.erase(conversations.begin() + conversationIdx); + Q_EMIT linked.endRemoveRows(); invalidateModel(); emit linked.modelChanged(); @@ -1761,6 +1778,7 @@ ConversationModelPimpl::slotContactModelUpdated(const QString& uri, bool needsSo auto& conversation = getConversationForPeerUri(uri, true).get(); invalidateModel(); emit linked.conversationUpdated(conversation.uid); + Q_EMIT linked.dataChanged(indexOf(conversation.uid)); } catch (std::out_of_range&) { qDebug() << "contact updated for not existing conversation"; } @@ -1834,7 +1852,11 @@ ConversationModelPimpl::addConversationWith(const QString& convId, const QString } conversation.unreadMessages = getNumberOfUnreadMessagesFor(convId); + + Q_EMIT linked.beginInsertRows(conversations.size()); conversations.emplace_back(std::move(conversation)); + Q_EMIT linked.endInsertRows(); + invalidateModel(); } @@ -1907,7 +1929,6 @@ ConversationModelPimpl::slotIncomingCall(const QString& fromId, const QString& c conversation.callId = callId; addOrUpdateCallMessage(callId, fromId); - invalidateModel(); emit behaviorController.showIncomingCallView(linked.owner.id, conversation.uid); } @@ -1934,6 +1955,7 @@ ConversationModelPimpl::slotCallStatusChanged(const QString& callId, int code) conversation.callId = callId; invalidateModel(); emit linked.conversationUpdated(conversation.uid); + Q_EMIT linked.dataChanged(indexOf(conversation.uid)); } } } else if (call.status == call::Status::PEER_BUSY) { @@ -1976,6 +1998,7 @@ ConversationModelPimpl::slotCallEnded(const QString& callId) conversation.confId = ""; // The participant is detached invalidateModel(); emit linked.conversationUpdated(conversation.uid); + Q_EMIT linked.dataChanged(indexOf(conversation.uid)); } } catch (std::out_of_range& e) { qDebug() << "ConversationModelPimpl::slotCallEnded can't end inexistant call"; @@ -2026,6 +2049,7 @@ ConversationModelPimpl::addOrUpdateCallMessage(const QString& callId, invalidateModel(); emit linked.modelChanged(); + Q_EMIT linked.dataChanged(static_cast<int>(std::distance(conversations.begin(), conv_it))); } void @@ -2109,6 +2133,7 @@ ConversationModelPimpl::addIncomingMessage(const QString& from, invalidateModel(); emit linked.modelChanged(); + Q_EMIT linked.dataChanged(conversationIdx); return msgId; } @@ -2447,6 +2472,7 @@ ConversationModelPimpl::slotTransferStatusCreated(long long dringId, datatransfe invalidateModel(); emit linked.modelChanged(); + Q_EMIT linked.dataChanged(conversationIdx); } void