Commit 7aeba275 authored by Ronan's avatar Ronan

fix(ChatProxyModel): use a unique `ChatModel` if many proxies use a same sip address

parent 0d0a2d42
......@@ -63,6 +63,8 @@ if (NOT WIN32)
endif ()
endif ()
set(CUSTOM_FLAGS "${CUSTOM_FLAGS} -DQT_NO_EXCEPTIONS")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CUSTOM_FLAGS}")
# See: http://stackoverflow.com/a/1372836
if (WIN32)
......
<?xml version="1.0" encoding="UTF-8"?>
<svg width="23px" height="14px" viewBox="0 0 23 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 42 (36781) - http://www.bohemiancoding.com/sketch -->
<title>settings_video_default</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
<g id="settings_video_default" stroke-width="1.5" stroke="#FFFFFF">
<polygon id="videocall_icon" points="22.25 6.89355494 22.25 1.08716608 16.4942742 5.63134348 16.4942742 0.75 0.75 0.75 0.75 13.25 16.4942742 13.25 16.4942742 8.36865652 22.25 12.9128339"></polygon>
</g>
</g>
</svg>
......@@ -373,7 +373,6 @@ void App::registerTypes () {
registerType<CallsListProxyModel>("CallsListProxyModel");
registerType<Camera>("Camera");
registerType<CameraPreview>("CameraPreview");
registerType<ChatModel>("ChatModel");
registerType<ChatProxyModel>("ChatProxyModel");
registerType<ConferenceHelperModel>("ConferenceHelperModel");
registerType<ConferenceModel>("ConferenceModel");
......@@ -392,6 +391,7 @@ void App::registerTypes () {
registerMetaType<ChatModel::EntryType>("ChatModel::EntryType");
registerUncreatableType(CallModel, "CallModel");
registerUncreatableType(ChatModel, "ChatModel");
registerUncreatableType(ConferenceHelperModel::ConferenceAddModel, "ConferenceAddModel");
registerUncreatableType(ContactModel, "ContactModel");
registerUncreatableType(SipAddressObserver, "SipAddressObserver");
......
......@@ -189,13 +189,13 @@ private:
// -----------------------------------------------------------------------------
ChatModel::ChatModel (QObject *parent) : QAbstractListModel(parent) {
ChatModel::ChatModel (const QString &sipAddress) {
CoreManager *core = CoreManager::getInstance();
mCoreHandlers = core->getHandlers();
mMessageHandlers = make_shared<MessageHandlers>(this);
core->getSipAddressesModel()->connectToChatModel(this);
setSipAddress(sipAddress);
{
CoreHandlers *coreHandlers = mCoreHandlers.get();
......@@ -262,27 +262,16 @@ bool ChatModel::removeRows (int row, int count, const QModelIndex &parent) {
}
QString ChatModel::getSipAddress () const {
if (!mChatRoom)
return QString("");
return ::Utils::coreStringToAppString(
mChatRoom->getPeerAddress()->asStringUriOnly()
);
}
void ChatModel::setSipAddress (const QString &sipAddress) {
if (sipAddress == getSipAddress() || sipAddress.isEmpty())
return;
beginResetModel();
// Invalid old sip address entries.
mEntries.clear();
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
mChatRoom = core->getChatRoomFromUri(::Utils::appStringToCoreString(sipAddress));
updateIsRemoteComposing();
Q_CHECK_PTR(mChatRoom.get());
if (mChatRoom->getUnreadMessagesCount() > 0)
resetMessagesCount();
......@@ -304,10 +293,6 @@ void ChatModel::setSipAddress (const QString &sipAddress) {
// Get calls.
for (auto &callLog : core->getCallHistoryForAddress(mChatRoom->getPeerAddress()))
insertCall(callLog);
endResetModel();
emit sipAddressChanged(sipAddress);
}
bool ChatModel::getIsRemoteComposing () const {
......@@ -342,9 +327,6 @@ void ChatModel::removeAllEntries () {
// -----------------------------------------------------------------------------
void ChatModel::sendMessage (const QString &message) {
if (!mChatRoom)
return;
shared_ptr<linphone::ChatMessage> _message = mChatRoom->createMessage(::Utils::appStringToCoreString(message));
_message->setListener(mMessageHandlers);
......@@ -355,9 +337,6 @@ void ChatModel::sendMessage (const QString &message) {
}
void ChatModel::resendMessage (int id) {
if (!mChatRoom)
return;
if (id < 0 || id > mEntries.count()) {
qWarning() << QStringLiteral("Entry %1 not exists.").arg(id);
return;
......@@ -387,9 +366,6 @@ void ChatModel::resendMessage (int id) {
}
void ChatModel::sendFileMessage (const QString &path) {
if (!mChatRoom)
return;
QFile file(path);
if (!file.exists())
return;
......@@ -483,15 +459,12 @@ bool ChatModel::fileWasDownloaded (int id) {
}
void ChatModel::compose () {
return mChatRoom->compose();
mChatRoom->compose();
}
// -----------------------------------------------------------------------------
const ChatModel::ChatEntryData ChatModel::getFileMessageEntry (int id) {
if (!mChatRoom)
return ChatEntryData();
if (id < 0 || id > mEntries.count()) {
qWarning() << QStringLiteral("Entry %1 not exists.").arg(id);
return ChatEntryData();
......@@ -650,14 +623,6 @@ void ChatModel::resetMessagesCount () {
emit messagesCountReset();
}
void ChatModel::updateIsRemoteComposing () {
bool isRemoteComposing = mChatRoom->isRemoteComposing();
if (isRemoteComposing != mIsRemoteComposing) {
mIsRemoteComposing = isRemoteComposing;
emit isRemoteComposingChanged(mIsRemoteComposing);
}
}
// -----------------------------------------------------------------------------
void ChatModel::handleCallStateChanged (const shared_ptr<linphone::Call> &call, linphone::CallState state) {
......@@ -669,8 +634,13 @@ void ChatModel::handleCallStateChanged (const shared_ptr<linphone::Call> &call,
}
void ChatModel::handleIsComposingChanged (const shared_ptr<linphone::ChatRoom> &chatRoom) {
if (mChatRoom == chatRoom)
updateIsRemoteComposing();
if (mChatRoom == chatRoom) {
bool isRemoteComposing = mChatRoom->isRemoteComposing();
if (isRemoteComposing != mIsRemoteComposing) {
mIsRemoteComposing = isRemoteComposing;
emit isRemoteComposingChanged(mIsRemoteComposing);
}
}
}
void ChatModel::handleMessageReceived (const shared_ptr<linphone::ChatMessage> &message) {
......
......@@ -37,7 +37,7 @@ class ChatModel : public QAbstractListModel {
Q_OBJECT;
Q_PROPERTY(QString sipAddress READ getSipAddress WRITE setSipAddress NOTIFY sipAddressChanged);
Q_PROPERTY(QString sipAddress READ getSipAddress CONSTANT);
Q_PROPERTY(bool isRemoteComposing READ getIsRemoteComposing NOTIFY isRemoteComposingChanged);
public:
......@@ -75,7 +75,7 @@ public:
Q_ENUM(MessageStatus);
ChatModel (QObject *parent = Q_NULLPTR);
ChatModel (const QString &sipAddress);
~ChatModel ();
int rowCount (const QModelIndex &index = QModelIndex()) const override;
......@@ -87,7 +87,6 @@ public:
bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex()) override;
QString getSipAddress () const;
void setSipAddress (const QString &sipAddress);
bool getIsRemoteComposing () const;
......@@ -111,7 +110,6 @@ public:
void compose ();
signals:
void sipAddressChanged (const QString &sipAddress);
bool isRemoteComposingChanged (bool status);
void allEntriesRemoved ();
......@@ -124,6 +122,8 @@ signals:
private:
typedef QPair<QVariantMap, std::shared_ptr<void> > ChatEntryData;
void setSipAddress (const QString &sipAddress);
const ChatEntryData getFileMessageEntry (int id);
void fillMessageEntry (QVariantMap &dest, const std::shared_ptr<linphone::ChatMessage> &message);
......@@ -137,8 +137,6 @@ private:
void resetMessagesCount ();
void updateIsRemoteComposing ();
void handleCallStateChanged (const std::shared_ptr<linphone::Call> &call, linphone::CallState state);
void handleIsComposingChanged (const std::shared_ptr<linphone::ChatRoom> &chatRoom);
void handleMessageReceived (const std::shared_ptr<linphone::ChatMessage> &message);
......
......@@ -20,6 +20,8 @@
* Author: Ronan Abhamon
*/
#include "../core/CoreManager.hpp"
#include "ChatProxyModel.hpp"
using namespace std;
......@@ -29,9 +31,7 @@ using namespace std;
// Fetch the L last filtered chat entries.
class ChatProxyModel::ChatModelFilter : public QSortFilterProxyModel {
public:
ChatModelFilter (QObject *parent) : QSortFilterProxyModel(parent) {
setSourceModel(&mChatModel);
}
ChatModelFilter (QObject *parent) : QSortFilterProxyModel(parent) {}
ChatModel::EntryType getEntryTypeFilter () {
return mEntryTypeFilter;
......@@ -54,7 +54,6 @@ protected:
}
private:
ChatModel mChatModel;
ChatModel::EntryType mEntryTypeFilter = ChatModel::EntryType::GenericEntry;
};
......@@ -63,47 +62,32 @@ private:
const int ChatProxyModel::ENTRIES_CHUNK_SIZE = 50;
ChatProxyModel::ChatProxyModel (QObject *parent) : QSortFilterProxyModel(parent) {
mChatModelFilter = new ChatModelFilter(this);
setSourceModel(mChatModelFilter);
ChatModel *chat = static_cast<ChatModel *>(mChatModelFilter->sourceModel());
QObject::connect(chat, &ChatModel::sipAddressChanged, this, [this](const QString &sipAddress) {
emit sipAddressChanged(sipAddress);
});
QObject::connect(chat, &ChatModel::isRemoteComposingChanged, this, [this](bool status) {
emit isRemoteComposingChanged(status);
});
QObject::connect(chat, &ChatModel::messageReceived, this, [this](const shared_ptr<linphone::ChatMessage> &) {
mMaxDisplayedEntries++;
});
QObject::connect(chat, &ChatModel::messageSent, this, [this](const shared_ptr<linphone::ChatMessage> &) {
mMaxDisplayedEntries++;
});
setSourceModel(new ChatModelFilter(this));
}
// -----------------------------------------------------------------------------
#define CREATE_PARENT_MODEL_FUNCTION_WITH_ID(METHOD) \
void ChatProxyModel::METHOD(int id) { \
QModelIndex sourceIndex = mapToSource(index(id, 0)); \
static_cast<ChatModel *>(mChatModelFilter->sourceModel())->METHOD( \
mChatModelFilter->mapToSource(sourceIndex).row() \
); \
}
#define GET_CHAT_MODEL() \
if (!mChatModel) \
return; \
mChatModel
#define CREATE_PARENT_MODEL_FUNCTION(METHOD) \
void ChatProxyModel::METHOD() { \
static_cast<ChatModel *>(mChatModelFilter->sourceModel())->METHOD(); \
GET_CHAT_MODEL()->METHOD(); \
}
#define CREATE_PARENT_MODEL_FUNCTION_WITH_PARAM(METHOD, ARG_TYPE) \
void ChatProxyModel::METHOD(ARG_TYPE value) { \
static_cast<ChatModel *>(mChatModelFilter->sourceModel())->METHOD(value); \
GET_CHAT_MODEL()->METHOD(value); \
}
#define CREATE_PARENT_MODEL_FUNCTION_WITH_ID(METHOD) \
void ChatProxyModel::METHOD(int id) { \
QModelIndex sourceIndex = mapToSource(index(id, 0)); \
GET_CHAT_MODEL()->METHOD( \
static_cast<ChatModelFilter *>(sourceModel())->mapToSource(sourceIndex).row() \
); \
}
CREATE_PARENT_MODEL_FUNCTION(compose);
......@@ -118,31 +102,16 @@ CREATE_PARENT_MODEL_FUNCTION_WITH_ID(openFileDirectory);
CREATE_PARENT_MODEL_FUNCTION_WITH_ID(removeEntry);
CREATE_PARENT_MODEL_FUNCTION_WITH_ID(resendMessage);
#undef GET_CHAT_MODEL
#undef CREATE_PARENT_MODEL_FUNCTION
#undef CREATE_PARENT_MODEL_FUNCTION_WITH_PARAM
#undef CREATE_PARENT_MODEL_FUNCTION_WITH_ID
// -----------------------------------------------------------------------------
QString ChatProxyModel::getSipAddress () const {
return static_cast<ChatModel *>(mChatModelFilter->sourceModel())->getSipAddress();
}
void ChatProxyModel::setSipAddress (const QString &sipAddress) {
static_cast<ChatModel *>(mChatModelFilter->sourceModel())->setSipAddress(
sipAddress
);
}
bool ChatProxyModel::getIsRemoteComposing () const {
return static_cast<ChatModel *>(mChatModelFilter->sourceModel())->getIsRemoteComposing();
}
// -----------------------------------------------------------------------------
void ChatProxyModel::loadMoreEntries () {
int count = rowCount();
int parentCount = mChatModelFilter->rowCount();
int parentCount = sourceModel()->rowCount();
if (count < parentCount) {
// Do not increase `mMaxDisplayedEntries` if it's not necessary...
......@@ -159,8 +128,10 @@ void ChatProxyModel::loadMoreEntries () {
}
void ChatProxyModel::setEntryTypeFilter (ChatModel::EntryType type) {
if (mChatModelFilter->getEntryTypeFilter() != type) {
mChatModelFilter->setEntryTypeFilter(type);
ChatModelFilter *chatModelFilter = static_cast<ChatModelFilter *>(sourceModel());
if (chatModelFilter->getEntryTypeFilter() != type) {
chatModelFilter->setEntryTypeFilter(type);
emit entryTypeFilterChanged(type);
}
}
......@@ -168,5 +139,50 @@ void ChatProxyModel::setEntryTypeFilter (ChatModel::EntryType type) {
// -----------------------------------------------------------------------------
bool ChatProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex &) const {
return mChatModelFilter->rowCount() - sourceRow <= mMaxDisplayedEntries;
return sourceModel()->rowCount() - sourceRow <= mMaxDisplayedEntries;
}
// -----------------------------------------------------------------------------
QString ChatProxyModel::getSipAddress () const {
return mChatModel ? mChatModel->getSipAddress() : QString("");
}
void ChatProxyModel::setSipAddress (const QString &sipAddress) {
mMaxDisplayedEntries = ENTRIES_CHUNK_SIZE;
if (mChatModel) {
ChatModel *chatModel = mChatModel.get();
QObject::disconnect(chatModel, &ChatModel::isRemoteComposingChanged, this, &ChatProxyModel::handleIsRemoteComposingChanged);
QObject::disconnect(chatModel, &ChatModel::messageReceived, this, &ChatProxyModel::handleMessageReceived);
QObject::disconnect(chatModel, &ChatModel::messageSent, this, &ChatProxyModel::handleMessageSent);
}
mChatModel = CoreManager::getInstance()->getChatModelFromSipAddress(sipAddress);
if (mChatModel) {
ChatModel *chatModel = mChatModel.get();
QObject::connect(chatModel, &ChatModel::isRemoteComposingChanged, this, &ChatProxyModel::handleIsRemoteComposingChanged);
QObject::connect(chatModel, &ChatModel::messageReceived, this, &ChatProxyModel::handleMessageReceived);
QObject::connect(chatModel, &ChatModel::messageSent, this, &ChatProxyModel::handleMessageSent);
}
static_cast<ChatModelFilter *>(sourceModel())->setSourceModel(mChatModel.get());
}
bool ChatProxyModel::getIsRemoteComposing () const {
return mChatModel ? mChatModel->getIsRemoteComposing() : false;
}
// -----------------------------------------------------------------------------
void ChatProxyModel::handleIsRemoteComposingChanged (bool status) {
emit isRemoteComposingChanged(status);
}
void ChatProxyModel::handleMessageReceived (const shared_ptr<linphone::ChatMessage> &) {
mMaxDisplayedEntries++;
}
void ChatProxyModel::handleMessageSent (const shared_ptr<linphone::ChatMessage> &) {
mMaxDisplayedEntries++;
}
......@@ -74,9 +74,14 @@ private:
bool getIsRemoteComposing () const;
ChatModelFilter *mChatModelFilter;
void handleIsRemoteComposingChanged (bool status);
void handleMessageReceived (const std::shared_ptr<linphone::ChatMessage> &message);
void handleMessageSent (const std::shared_ptr<linphone::ChatMessage> &message);
int mMaxDisplayedEntries = ENTRIES_CHUNK_SIZE;
std::shared_ptr<ChatModel> mChatModel;
static const int ENTRIES_CHUNK_SIZE;
};
......
......@@ -73,6 +73,34 @@ CoreManager::CoreManager (QObject *parent, const QString &configPath) :
// -----------------------------------------------------------------------------
shared_ptr<ChatModel> CoreManager::getChatModelFromSipAddress (const QString &sipAddress) {
if (!sipAddress.length())
return nullptr;
Q_ASSERT(mCore->createAddress(::Utils::appStringToCoreString(sipAddress)) != nullptr);
// Create a new chat model.
if (!mChatModels.contains(sipAddress)) {
auto deleter = [this](ChatModel *chatModel) {
mChatModels.remove(chatModel->getSipAddress());
};
shared_ptr<ChatModel> chatModel(new ChatModel(sipAddress), deleter);
mChatModels[sipAddress] = chatModel;
emit chatModelCreated(chatModel);
return chatModel;
}
// Returns an existing chat model.
shared_ptr<ChatModel> chatModel = mChatModels[sipAddress].lock();
Q_CHECK_PTR(chatModel.get());
return chatModel;
}
// -----------------------------------------------------------------------------
void CoreManager::init (QObject *parent, const QString &configPath) {
if (mInstance)
return;
......
......@@ -58,6 +58,8 @@ public:
return mHandlers;
}
std::shared_ptr<ChatModel> getChatModelFromSipAddress (const QString &sipAddress);
// ---------------------------------------------------------------------------
// Video render lock.
// ---------------------------------------------------------------------------
......@@ -126,6 +128,8 @@ signals:
void coreCreated ();
void coreStarted ();
void chatModelCreated (const std::shared_ptr<ChatModel> chatModel);
void logsUploaded (const QString &url);
private:
......@@ -154,6 +158,8 @@ private:
SettingsModel *mSettingsModel;
AccountSettingsModel *mAccountSettingsModel;
QHash<QString, std::weak_ptr<ChatModel> > mChatModels;
QTimer *mCbsTimer;
QFuture<void> mPromiseBuild;
......
......@@ -38,13 +38,15 @@ using namespace std;
SipAddressesModel::SipAddressesModel (QObject *parent) : QAbstractListModel(parent) {
initSipAddresses();
mCoreHandlers = CoreManager::getInstance()->getHandlers();
CoreManager *coreManager = CoreManager::getInstance();
ContactsListModel *contacts = CoreManager::getInstance()->getContactsListModel();
mCoreHandlers = coreManager->getHandlers();
QObject::connect(coreManager, &CoreManager::chatModelCreated, this, &SipAddressesModel::handleChatModelCreated);
ContactsListModel *contacts = CoreManager::getInstance()->getContactsListModel();
QObject::connect(contacts, &ContactsListModel::contactAdded, this, &SipAddressesModel::handleContactAdded);
QObject::connect(contacts, &ContactsListModel::contactRemoved, this, &SipAddressesModel::handleContactRemoved);
QObject::connect(contacts, &ContactsListModel::sipAddressAdded, this, &SipAddressesModel::handleSipAddressAdded);
QObject::connect(contacts, &ContactsListModel::sipAddressRemoved, this, &SipAddressesModel::handleSipAddressRemoved);
......@@ -81,20 +83,6 @@ QVariant SipAddressesModel::data (const QModelIndex &index, int role) const {
// -----------------------------------------------------------------------------
void SipAddressesModel::connectToChatModel (ChatModel *chatModel) {
QObject::connect(chatModel, &ChatModel::allEntriesRemoved, this, [this, chatModel] {
handleAllEntriesRemoved(chatModel->getSipAddress());
});
QObject::connect(chatModel, &ChatModel::messageSent, this, &SipAddressesModel::handleMessageSent);
QObject::connect(chatModel, &ChatModel::messagesCountReset, this, [this, chatModel] {
handleMessagesCountReset(chatModel->getSipAddress());
});
}
// -----------------------------------------------------------------------------
QVariantMap SipAddressesModel::find (const QString &sipAddress) const {
auto it = mSipAddresses.find(sipAddress);
return it == mSipAddresses.end() ? QVariantMap() : *it;
......@@ -225,6 +213,20 @@ bool SipAddressesModel::removeRows (int row, int count, const QModelIndex &paren
// -----------------------------------------------------------------------------
void SipAddressesModel::handleChatModelCreated (const std::shared_ptr<ChatModel> &chatModel) {
ChatModel *ptr = chatModel.get();
QObject::connect(ptr, &ChatModel::allEntriesRemoved, this, [this, ptr] {
handleAllEntriesRemoved(ptr->getSipAddress());
});
QObject::connect(ptr, &ChatModel::messageSent, this, &SipAddressesModel::handleMessageSent);
QObject::connect(ptr, &ChatModel::messagesCountReset, this, [this, ptr] {
handleMessagesCountReset(ptr->getSipAddress());
});
}
void SipAddressesModel::handleContactAdded (ContactModel *contact) {
for (const auto &sipAddress : contact->getVcardModel()->getSipAddresses())
addOrUpdateSipAddress(sipAddress.toString(), contact);
......
......@@ -46,8 +46,6 @@ public:
QHash<int, QByteArray> roleNames () const override;
QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const override;
void connectToChatModel (ChatModel *chatModel);
Q_INVOKABLE QVariantMap find (const QString &sipAddress) const;
Q_INVOKABLE ContactModel *mapSipAddressToContact (const QString &sipAddress) const;
Q_INVOKABLE SipAddressObserver *getSipAddressObserver (const QString &sipAddress);
......@@ -72,6 +70,8 @@ private:
// ---------------------------------------------------------------------------
void handleChatModelCreated (const std::shared_ptr<ChatModel> &chatModel);
void handleContactAdded (ContactModel *contact);
void handleContactRemoved (const ContactModel *contact);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment