diff --git a/linphone-app/src/components/timeline/TimelineListModel.cpp b/linphone-app/src/components/timeline/TimelineListModel.cpp index bb84b3855..4a318c0d4 100644 --- a/linphone-app/src/components/timeline/TimelineListModel.cpp +++ b/linphone-app/src/components/timeline/TimelineListModel.cpp @@ -53,8 +53,32 @@ TimelineListModel::TimelineListModel (QObject *parent) : ProxyListModel(parent) updateTimelines (); } +TimelineListModel::TimelineListModel(const TimelineListModel* model){ + mSelectedCount = model->mSelectedCount; + CoreHandlers* coreHandlers= CoreManager::getInstance()->getHandlers().get(); + connect(coreHandlers, &CoreHandlers::chatRoomStateChanged, this, &TimelineListModel::onChatRoomStateChanged); + connect(coreHandlers, &CoreHandlers::messagesReceived, this, &TimelineListModel::update); + connect(coreHandlers, &CoreHandlers::messagesReceived, this, &TimelineListModel::updated); + + QObject::connect(coreHandlers, &CoreHandlers::callStateChanged, this, &TimelineListModel::onCallStateChanged); + QObject::connect(coreHandlers, &CoreHandlers::callCreated, this, &TimelineListModel::onCallCreated); + + connect(CoreManager::getInstance()->getSettingsModel(), &SettingsModel::hideEmptyChatRoomsChanged, this, &TimelineListModel::update); + connect(CoreManager::getInstance()->getAccountSettingsModel(), &AccountSettingsModel::defaultRegistrationChanged, this, &TimelineListModel::update); + for(auto item : model->mList) { + auto newItem = qobject_cast(item)->clone(); + connect(newItem.get(), SIGNAL(selectedChanged(bool)), this, SLOT(onSelectedHasChanged(bool))); + connect(newItem->getChatRoomModel(), &ChatRoomModel::allEntriesRemoved, this, &TimelineListModel::removeChatRoomModel); + mList << newItem; + } +} + TimelineListModel::~TimelineListModel(){ } + +TimelineListModel* TimelineListModel::clone() const{ + return new TimelineListModel(this); +} // ----------------------------------------------------------------------------- void TimelineListModel::reset(){ @@ -109,7 +133,7 @@ QSharedPointer TimelineListModel::getTimeline(std::shared_ptr model = TimelineModel::create(chatRoom); + QSharedPointer model = TimelineModel::create(this, chatRoom); if(model){ connect(model.get(), SIGNAL(selectedChanged(bool)), this, SLOT(onSelectedHasChanged(bool))); connect(model->getChatRoomModel(), &ChatRoomModel::allEntriesRemoved, this, &TimelineListModel::removeChatRoomModel); @@ -157,7 +181,7 @@ QSharedPointer TimelineListModel::getChatRoomModel(std::shared_pt return model; } if(create){ - QSharedPointer model = TimelineModel::create(chatRoom); + QSharedPointer model = TimelineModel::create(this, chatRoom); if(model){ connect(model.get(), SIGNAL(selectedChanged(bool)), this, SLOT(onSelectedHasChanged(bool))); connect(model->getChatRoomModel(), &ChatRoomModel::allEntriesRemoved, this, &TimelineListModel::removeChatRoomModel); @@ -198,8 +222,13 @@ void TimelineListModel::onSelectedHasChanged(bool selected){ }else setSelectedCount(mSelectedCount+1); emit selectedChanged(qobject_cast(sender())); - } else + } else { + if( this == CoreManager::getInstance()->getTimelineListModel()) {// Clean memory only if the selection is about the main list. + auto timeline = qobject_cast(sender()); + timeline->getChatRoomModel()->resetData();// Cleanup leaving chat room + } setSelectedCount(mSelectedCount-1); + } } void TimelineListModel::updateTimelines () { @@ -252,7 +281,7 @@ void TimelineListModel::updateTimelines () { auto haveTimeline = getTimeline(dbChatRoom, false); if(!haveTimeline && dbChatRoom){// Create a new Timeline if needed - QSharedPointer model = TimelineModel::create(dbChatRoom, callLogs); + QSharedPointer model = TimelineModel::create(this, dbChatRoom, callLogs); if( model){ connect(model.get(), SIGNAL(selectedChanged(bool)), this, SLOT(onSelectedHasChanged(bool))); connect(model->getChatRoomModel(), &ChatRoomModel::allEntriesRemoved, this, &TimelineListModel::removeChatRoomModel); @@ -302,7 +331,7 @@ void TimelineListModel::select(ChatRoomModel * chatRoomModel){ void TimelineListModel::onChatRoomStateChanged(const std::shared_ptr &chatRoom,linphone::ChatRoom::State state){ if( state == linphone::ChatRoom::State::Created && !getTimeline(chatRoom, false)){// Create a new Timeline if needed - QSharedPointer model = TimelineModel::create(chatRoom); + QSharedPointer model = TimelineModel::create(this, chatRoom); if(model){ connect(model.get(), SIGNAL(selectedChanged(bool)), this, SLOT(onSelectedHasChanged(bool))); connect(model->getChatRoomModel(), &ChatRoomModel::allEntriesRemoved, this, &TimelineListModel::removeChatRoomModel); diff --git a/linphone-app/src/components/timeline/TimelineListModel.hpp b/linphone-app/src/components/timeline/TimelineListModel.hpp index ce1818d0b..7314a10b6 100644 --- a/linphone-app/src/components/timeline/TimelineListModel.hpp +++ b/linphone-app/src/components/timeline/TimelineListModel.hpp @@ -39,7 +39,9 @@ public: Q_PROPERTY(int count READ rowCount NOTIFY countChanged) TimelineListModel (QObject *parent = Q_NULLPTR); + TimelineListModel(const TimelineListModel* model); virtual ~TimelineListModel(); + TimelineListModel * clone() const; void reset(); void selectAll(const bool& selected); TimelineModel * getAt(const int& index); diff --git a/linphone-app/src/components/timeline/TimelineModel.cpp b/linphone-app/src/components/timeline/TimelineModel.cpp index 6433085e0..9f49c665c 100644 --- a/linphone-app/src/components/timeline/TimelineModel.cpp +++ b/linphone-app/src/components/timeline/TimelineModel.cpp @@ -66,8 +66,8 @@ void TimelineModel::connectTo(ChatRoomListener * listener){ } // ============================================================================= -QSharedPointer TimelineModel::create(std::shared_ptr chatRoom, const std::list>& callLogs, QObject *parent){ - if((!chatRoom || chatRoom->getState() != linphone::ChatRoom::State::Deleted) && (!CoreManager::getInstance()->getTimelineListModel() || !CoreManager::getInstance()->getTimelineListModel()->getTimeline(chatRoom, false)) ) { +QSharedPointer TimelineModel::create(TimelineListModel * mainList, std::shared_ptr chatRoom, const std::list>& callLogs, QObject *parent){ + if((!chatRoom || chatRoom->getState() != linphone::ChatRoom::State::Deleted) && (!mainList || !mainList->getTimeline(chatRoom, false)) ) { QSharedPointer model = QSharedPointer::create(chatRoom, parent); if(model && model->getChatRoomModel()){ @@ -122,6 +122,25 @@ TimelineModel::TimelineModel (std::shared_ptr chatRoom, QObj mSelected = false; } +TimelineModel::TimelineModel(const TimelineModel * model){ + App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE + mChatRoomModel = model->mChatRoomModel; + if( mChatRoomModel ){ + QObject::connect(this, &TimelineModel::selectedChanged, this, &TimelineModel::updateUnreadCount); + QObject::connect(CoreManager::getInstance()->getAccountSettingsModel(), &AccountSettingsModel::defaultAccountChanged, this, &TimelineModel::onDefaultAccountChanged); + } + if(mChatRoomModel->getChatRoom()){ + mChatRoomListener = model->mChatRoomListener; + connectTo(mChatRoomListener.get()); + mChatRoomModel->getChatRoom()->addListener(mChatRoomListener); + } + mSelected = model->mSelected; +} + +QSharedPointer TimelineModel::clone()const{ + return QSharedPointer::create(this); +} + TimelineModel::~TimelineModel(){ if( mChatRoomModel->getChatRoom()) mChatRoomModel->getChatRoom()->removeListener(mChatRoomListener); @@ -152,7 +171,7 @@ ChatRoomModel *TimelineModel::getChatRoomModel() const{ } void TimelineModel::setSelected(const bool& selected){ - if(mChatRoomModel && selected != mSelected){ + if(mChatRoomModel && (selected != mSelected || selected)){ mSelected = selected; if(mSelected){ qInfo() << "Chat room selected : Subject :" << mChatRoomModel->getSubject() @@ -166,10 +185,7 @@ void TimelineModel::setSelected(const bool& selected){ << ", canHandleParticipants:"<< mChatRoomModel->canHandleParticipants() << ", isReadOnly:" << mChatRoomModel->isReadOnly() << ", state:" << mChatRoomModel->getState(); - QQmlEngine *engine = App::getInstance()->getEngine(); - engine->clearComponentCache(); - }else - mChatRoomModel->resetData();// Cleanup leaving chat room + } emit selectedChanged(mSelected); } } diff --git a/linphone-app/src/components/timeline/TimelineModel.hpp b/linphone-app/src/components/timeline/TimelineModel.hpp index 5f15882c6..5f16faf95 100644 --- a/linphone-app/src/components/timeline/TimelineModel.hpp +++ b/linphone-app/src/components/timeline/TimelineModel.hpp @@ -33,15 +33,19 @@ class ChatRoomModel; class ChatRoomListener; +class TimelineListModel; class TimelineModel : public QObject { Q_OBJECT public: - static QSharedPointer create(std::shared_ptr chatRoom, const std::list>& callLogs = std::list>(), QObject *parent = Q_NULLPTR); + static QSharedPointer create(TimelineListModel * mainList, std::shared_ptr chatRoom, const std::list>& callLogs = std::list>(), QObject *parent = Q_NULLPTR); TimelineModel (std::shared_ptr chatRoom, QObject *parent = Q_NULLPTR); + TimelineModel(const TimelineModel * model); virtual ~TimelineModel(); + QSharedPointer clone() const; + Q_PROPERTY(QString fullPeerAddress READ getFullPeerAddress NOTIFY fullPeerAddressChanged) Q_PROPERTY(QString fullLocalAddress READ getFullLocalAddress NOTIFY fullLocalAddressChanged) Q_PROPERTY(ChatRoomModel* chatRoomModel READ getChatRoomModel CONSTANT) diff --git a/linphone-app/src/components/timeline/TimelineProxyModel.cpp b/linphone-app/src/components/timeline/TimelineProxyModel.cpp index 694dc9c55..95b7d38dd 100644 --- a/linphone-app/src/components/timeline/TimelineProxyModel.cpp +++ b/linphone-app/src/components/timeline/TimelineProxyModel.cpp @@ -37,32 +37,14 @@ // ----------------------------------------------------------------------------- TimelineProxyModel::TimelineProxyModel (QObject *parent) : QSortFilterProxyModel(parent) { - CoreManager *coreManager = CoreManager::getInstance(); - AccountSettingsModel *accountSettingsModel = coreManager->getAccountSettingsModel(); - TimelineListModel * model = CoreManager::getInstance()->getTimelineListModel(); - connect(model, SIGNAL(selectedCountChanged(int)), this, SIGNAL(selectedCountChanged(int))); - connect(model, &TimelineListModel::updated, this, &TimelineProxyModel::invalidate); - connect(model, &TimelineListModel::selectedChanged, this, &TimelineProxyModel::selectedChanged); - connect(model, &TimelineListModel::countChanged, this, &TimelineProxyModel::countChanged); - - QObject::connect(accountSettingsModel, &AccountSettingsModel::defaultAccountChanged, this, [this]() { - qobject_cast(sourceModel())->update(); - invalidate(); - }); - QObject::connect(coreManager->getSipAddressesModel(), &SipAddressesModel::sipAddressReset, this, [this]() { - qobject_cast(sourceModel())->reset(); - invalidate();// Invalidate and reload GUI if the model has been reset - }); - - setSourceModel(model); - sort(0); } // ----------------------------------------------------------------------------- void TimelineProxyModel::unselectAll(){ - qobject_cast(sourceModel())->selectAll(false); + if( sourceModel()) + qobject_cast(sourceModel())->selectAll(false); } void TimelineProxyModel::setFilterFlags(const int& filterFlags){ @@ -79,9 +61,49 @@ void TimelineProxyModel::setFilterText(const QString& text){ emit filterTextChanged(); } } + +TimelineProxyModel::TimelineListSource TimelineProxyModel::getListSource() const{ + return mListSource; +} + +void TimelineProxyModel::setListSource(const TimelineListSource& source){ + if(source != mListSource) { + TimelineListModel * model = nullptr; + if( source != Undefined){ + CoreManager *coreManager = CoreManager::getInstance(); + AccountSettingsModel *accountSettingsModel = coreManager->getAccountSettingsModel(); + model = source == Main ? CoreManager::getInstance()->getTimelineListModel() : CoreManager::getInstance()->getTimelineListModel()->clone(); + + connect(model, SIGNAL(selectedCountChanged(int)), this, SIGNAL(selectedCountChanged(int))); + connect(model, &TimelineListModel::updated, this, &TimelineProxyModel::invalidate); + connect(model, &TimelineListModel::selectedChanged, this, &TimelineProxyModel::selectedChanged); + connect(model, &TimelineListModel::countChanged, this, &TimelineProxyModel::countChanged); + + QObject::connect(accountSettingsModel, &AccountSettingsModel::defaultAccountChanged, this, [this]() { + qobject_cast(sourceModel())->update(); + invalidate(); + }); + QObject::connect(coreManager->getSipAddressesModel(), &SipAddressesModel::sipAddressReset, this, [this]() { + qobject_cast(sourceModel())->reset(); + invalidate();// Invalidate and reload GUI if the model has been reset + }); + } + + if( mListSource != Main && sourceModel()){ + sourceModel()->deleteLater(); + } + setSourceModel(model); + sort(0); + mListSource = source; + emit listSourceChanged(); + } +} + // ----------------------------------------------------------------------------- bool TimelineProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const { + if(!sourceModel()) + return false; const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); auto timeline = sourceModel()->data(index).value(); if(!timeline || !timeline->getChatRoomModel() || timeline->getChatRoomModel()->getState() == (int)linphone::ChatRoom::State::Deleted) @@ -116,6 +138,8 @@ bool TimelineProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex &sou } bool TimelineProxyModel::lessThan (const QModelIndex &left, const QModelIndex &right) const { + if( !sourceModel()) + return false; const TimelineModel* a = sourceModel()->data(left).value(); const TimelineModel* b = sourceModel()->data(right).value(); bool aHaveUnread = a->getChatRoomModel()->getAllUnreadCount() > 0; diff --git a/linphone-app/src/components/timeline/TimelineProxyModel.hpp b/linphone-app/src/components/timeline/TimelineProxyModel.hpp index 2ef9809e2..b350e0de8 100644 --- a/linphone-app/src/components/timeline/TimelineProxyModel.hpp +++ b/linphone-app/src/components/timeline/TimelineProxyModel.hpp @@ -45,8 +45,17 @@ public: }; Q_ENUM(TimelineFilter) + enum TimelineListSource{ + Undefined, + Main, // Timeline list comes from the singleton stored in CoreManager. + Copy // Timeline list is created from Main but have no attach to the main list (aside of root items). + }; + Q_ENUM(TimelineListSource) + TimelineProxyModel (QObject *parent = Q_NULLPTR); + Q_PROPERTY(TimelineListSource listSource READ getListSource WRITE setListSource NOTIFY listSourceChanged) + Q_PROPERTY(int filterFlags MEMBER mFilterFlags WRITE setFilterFlags NOTIFY filterFlagsChanged) Q_PROPERTY(QString filterText MEMBER mFilterText WRITE setFilterText NOTIFY filterTextChanged) Q_PROPERTY(int count READ rowCount NOTIFY countChanged) @@ -55,12 +64,16 @@ public: Q_INVOKABLE void setFilterFlags(const int& filterFlags); Q_INVOKABLE void setFilterText(const QString& text); + TimelineListSource getListSource() const; + void setListSource(const TimelineListSource& source); + signals: void countChanged(); void selectedCountChanged(int selectedCount); void selectedChanged(TimelineModel * timelineModel); void filterFlagsChanged(); void filterTextChanged(); + void listSourceChanged(); protected: @@ -74,6 +87,7 @@ protected: private: int mFilterFlags = 0; QString mFilterText; + TimelineListSource mListSource = Undefined; }; #endif // TIMELINE_PROXY_MODEL_H_ diff --git a/linphone-app/ui/modules/Linphone/Dialog/SipAddressDialog.qml b/linphone-app/ui/modules/Linphone/Dialog/SipAddressDialog.qml index f32760f97..1529b61bc 100644 --- a/linphone-app/ui/modules/Linphone/Dialog/SipAddressDialog.qml +++ b/linphone-app/ui/modules/Linphone/Dialog/SipAddressDialog.qml @@ -90,11 +90,12 @@ DialogPlus { Timeline { id: timeline showHistoryButton: false - updateSelectionModels: false anchors.fill: parent - model: TimelineProxyModel{} - onEntryClicked:{ - if( entry ) { + model: TimelineProxyModel{ + listSource: TimelineProxyModel.Copy + } + onEntrySelected:{ + if( entry) { mainItem.chatRoomSelectedCallback(entry.chatRoomModel) exit(1) } diff --git a/linphone-app/ui/modules/Linphone/Timeline/Timeline.qml b/linphone-app/ui/modules/Linphone/Timeline/Timeline.qml index 07a5553e8..b243b0be6 100644 --- a/linphone-app/ui/modules/Linphone/Timeline/Timeline.qml +++ b/linphone-app/ui/modules/Linphone/Timeline/Timeline.qml @@ -23,14 +23,12 @@ Rectangle { property alias model: view.model property string _selectedSipAddress property bool showHistoryButton : CoreManager.callLogsCount - property bool updateSelectionModels : true property bool isFilterVisible: searchView.visible || showFilterView property bool showFiltersButtons: view.count > 0 || timeline.isFilterVisible || timeline.model.filterFlags > 0 // --------------------------------------------------------------------------- signal entrySelected (TimelineModel entry) - signal entryClicked(TimelineModel entry) signal showHistoryRequest() // --------------------------------------------------------------------------- @@ -52,7 +50,7 @@ Rectangle { timeline.entrySelected('') } } - onSelectedChanged : if(timelineModel && timeline.updateSelectionModels) timeline.entrySelected(timelineModel) + onSelectedChanged : if(timelineModel) timeline.entrySelected(timelineModel) } // ------------------------------------------------------------------------- // Legend. @@ -358,7 +356,6 @@ Rectangle { ScrollableListView { id: view - property alias updateSelectionModels: timeline.updateSelectionModels Layout.fillHeight: true Layout.fillWidth: true currentIndex: -1 @@ -370,8 +367,7 @@ Rectangle { Connections{ target: $modelData onSelectedChanged:{ - gc() - if(view.updateSelectionModels && selected) { + if(selected) { view.currentIndex = index; } } diff --git a/linphone-app/ui/modules/Linphone/Timeline/TimelineItem.qml b/linphone-app/ui/modules/Linphone/Timeline/TimelineItem.qml index c16ebf18d..fca32b6ce 100644 --- a/linphone-app/ui/modules/Linphone/Timeline/TimelineItem.qml +++ b/linphone-app/ui/modules/Linphone/Timeline/TimelineItem.qml @@ -90,10 +90,7 @@ Item { preventStealing: false onClicked: { if(mouse.button == Qt.LeftButton){ - timeline.entryClicked(mainItem.timelineModel) - if(view.updateSelectionModels) - mainItem.timelineModel.selected = true - view.currentIndex = mainItem.modelIndex; + mainItem.timelineModel.selected = true }else{ mainItem.optionsToggled = !mainItem.optionsToggled } diff --git a/linphone-app/ui/views/App/Main/MainWindow.qml b/linphone-app/ui/views/App/Main/MainWindow.qml index a7862e896..20705a112 100644 --- a/linphone-app/ui/views/App/Main/MainWindow.qml +++ b/linphone-app/ui/views/App/Main/MainWindow.qml @@ -357,7 +357,9 @@ ApplicationWindow { Layout.fillHeight: true Layout.fillWidth: true - model: TimelineProxyModel{} + model: TimelineProxyModel{ + listSource: TimelineProxyModel.Main + } onEntrySelected:{ if( entry ) {