Commit 6f2ceb12 authored by Hugo Lefeuvre's avatar Hugo Lefeuvre Committed by Sébastien Blin

Refactoring of the accountContainer logic

Before:

 - RingMainWindow has an unique_ptr to an AccountContainer
   accountContainer_.

 - each view / secondary class has its own *copy* of the account
   container pointer (given by ringmainwindow using
   accountContainer_.get()).

 - each time the reference to the struct Info is updated,
   accountContainer_ has to be reset()-ed and and the account
   container re-created by the RingMainWindow. This makes *all*
   copies of the account container pointer invalid (hence all
   view / secondary classes trying to access the account container
   before getting updated perform use-after-free / NULL pointer
   dereference).

 - These copies have to be manually updated ! (well, currently they
   are not updated at all)

After:

 - RingMainWindow has a pointer to a struct Info from LRC.

 - Each view / secondary class has a pointer pointing to
   the struct Info pointer of RingMainWindow

 - Each time the reference to the struct Info is updated, the
   RingMainWindow updates its pointer. Since secondary classes and
   views hold a pointer to this pointer, they are automatically
   updated and there is no dangling pointer anymore.

This requires no lrc side changes.

Change-Id: I1329721920a3d42ad623f9fd7202b43700713eed
Reviewed-by: Sébastien Blin's avatarSebastien Blin <sebastien.blin@savoirfairelinux.com>
Reviewed-by: Guillaume Roguez's avatarGuillaume Roguez <guillaume.roguez@savoirfairelinux.com>
parent 03f071db
......@@ -339,7 +339,7 @@ SET( SRC_FILES
src/conversationsview.cpp
src/conversationpopupmenu.h
src/conversationpopupmenu.cpp
src/accountcontainer.h
src/accountinfopointer.h
)
# compile glib resource files to c code
......
/****************************************************************************
* Copyright (C) 2017-2018 Savoir-faire Linux *
* Author: Nicolas Jäger <nicolas.jager@savoirfairelinux.com> *
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#pragma once
// Lrc
#include <api/account.h>
/**
* This class contains a const reference linked to an account.
* NOTE: it avoids weird initialization with Gtk
* @param accInfo the account linked
*/
class AccountContainer {
public:
explicit AccountContainer (const lrc::api::account::Info& accInfo)
: info(accInfo)
{}
const lrc::api::account::Info& info;
};
/*
* Copyright (C) 2018 Savoir-faire Linux Inc.
* Author: Hugo Lefeuvre <hugo.lefeuvre@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
typedef const lrc::api::account::Info* AccountInfoPointer;
......@@ -63,7 +63,7 @@ struct _ChatViewPrivate
GSettings *settings;
lrc::api::conversation::Info* conversation_;
AccountContainer* accountContainer_;
AccountInfoPointer const * accountInfo_;
bool isTemporary_;
QMetaObject::Connection new_interaction_connection;
......@@ -141,7 +141,7 @@ placecall_clicked(ChatView *self)
{
auto priv = CHAT_VIEW_GET_PRIVATE(self);
if (!priv->conversation_) return;
priv->accountContainer_->info.conversationModel->placeCall(priv->conversation_->uid);
(*priv->accountInfo_)->conversationModel->placeCall(priv->conversation_->uid);
}
static void
......@@ -152,7 +152,7 @@ place_audio_call_clicked(ChatView *self)
if (!priv->conversation_)
return;
priv->accountContainer_->info.conversationModel->placeAudioOnlyCall(priv->conversation_->uid);
(*priv->accountInfo_)->conversationModel->placeAudioOnlyCall(priv->conversation_->uid);
}
static void
......@@ -160,7 +160,7 @@ button_add_to_conversations_clicked(ChatView *self)
{
auto priv = CHAT_VIEW_GET_PRIVATE(self);
if (!priv->conversation_) return;
priv->accountContainer_->info.conversationModel->makePermanent(priv->conversation_->uid);
(*priv->accountInfo_)->conversationModel->makePermanent(priv->conversation_->uid);
}
static gchar*
......@@ -198,27 +198,27 @@ webkit_chat_container_script_dialog(G_GNUC_UNUSED GtkWidget* webview, gchar *int
auto order = std::string(interaction);
if (!priv->conversation_) return;
if (order == "ACCEPT") {
priv->accountContainer_->info.conversationModel->makePermanent(priv->conversation_->uid);
(*priv->accountInfo_)->conversationModel->makePermanent(priv->conversation_->uid);
} else if (order == "REFUSE") {
priv->accountContainer_->info.conversationModel->removeConversation(priv->conversation_->uid);
(*priv->accountInfo_)->conversationModel->removeConversation(priv->conversation_->uid);
} else if (order == "BLOCK") {
priv->accountContainer_->info.conversationModel->removeConversation(priv->conversation_->uid, true);
(*priv->accountInfo_)->conversationModel->removeConversation(priv->conversation_->uid, true);
} else if (order.find("SEND:") == 0) {
// Get text body
auto toSend = order.substr(std::string("SEND:").size());
priv->accountContainer_->info.conversationModel->sendMessage(priv->conversation_->uid, toSend);
(*priv->accountInfo_)->conversationModel->sendMessage(priv->conversation_->uid, toSend);
} else if (order.find("SEND_FILE") == 0) {
if (auto model = priv->accountContainer_->info.conversationModel.get()) {
if (auto model = (*priv->accountInfo_)->conversationModel.get()) {
if (auto filename = file_to_manipulate(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(self))), true))
model->sendFile(priv->conversation_->uid, filename, g_path_get_basename(filename));
}
} else if (order.find("ACCEPT_FILE:") == 0) {
if (auto model = priv->accountContainer_->info.conversationModel.get()) {
if (auto model = (*priv->accountInfo_)->conversationModel.get()) {
try {
auto interactionId = std::stoull(order.substr(std::string("ACCEPT_FILE:").size()));
lrc::api::datatransfer::Info info = {};
priv->accountContainer_->info.conversationModel->getTransferInfo(interactionId, info);
(*priv->accountInfo_)->conversationModel->getTransferInfo(interactionId, info);
// get prefered directory destination.
auto* download_directory_variant = g_settings_get_value(priv->settings, "download-folder");
......@@ -240,7 +240,7 @@ webkit_chat_container_script_dialog(G_GNUC_UNUSED GtkWidget* webview, gchar *int
}
}
} else if (order.find("REFUSE_FILE:") == 0) {
if (auto model = priv->accountContainer_->info.conversationModel.get()) {
if (auto model = (*priv->accountInfo_)->conversationModel.get()) {
try {
auto interactionId = std::stoull(order.substr(std::string("REFUSE_FILE:").size()));
model->cancelTransfer(priv->conversation_->uid, interactionId);
......@@ -320,11 +320,11 @@ print_interaction_to_buffer(ChatView* self, uint64_t interactionId, const lrc::a
if (!priv->conversation_) return;
if (interaction.status == lrc::api::interaction::Status::UNREAD)
priv->accountContainer_->info.conversationModel->setInteractionRead(priv->conversation_->uid, interactionId);
(*priv->accountInfo_)->conversationModel->setInteractionRead(priv->conversation_->uid, interactionId);
webkit_chat_container_print_new_interaction(
WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
*priv->accountContainer_->info.conversationModel,
*(*priv->accountInfo_)->conversationModel,
interactionId,
interaction
);
......@@ -336,7 +336,7 @@ update_interaction(ChatView* self, uint64_t interactionId, const lrc::api::inter
ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
webkit_chat_container_update_interaction(
WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
*priv->accountContainer_->info.conversationModel,
*(*priv->accountInfo_)->conversationModel,
interactionId,
interaction
);
......@@ -352,11 +352,11 @@ load_participants_images(ChatView *self)
if (!priv->conversation_) return;
auto contactUri = priv->conversation_->participants.front();
try{
auto& contact = priv->accountContainer_->info.contactModel->getContact(contactUri);
auto& contact = (*priv->accountInfo_)->contactModel->getContact(contactUri);
if (!contact.profileInfo.avatar.empty()) {
webkit_chat_container_set_sender_image(
WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
priv->accountContainer_->info.contactModel->getContactProfileId(contactUri),
(*priv->accountInfo_)->contactModel->getContactProfileId(contactUri),
contact.profileInfo.avatar
);
}
......@@ -365,11 +365,11 @@ load_participants_images(ChatView *self)
}
// For this account
if (!priv->accountContainer_->info.profileInfo.avatar.empty()) {
if (!(*priv->accountInfo_)->profileInfo.avatar.empty()) {
webkit_chat_container_set_sender_image(
WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
priv->accountContainer_->info.contactModel->getContactProfileId(priv->accountContainer_->info.profileInfo.uri),
priv->accountContainer_->info.profileInfo.avatar
(*priv->accountInfo_)->contactModel->getContactProfileId((*priv->accountInfo_)->profileInfo.uri),
(*priv->accountInfo_)->profileInfo.avatar
);
}
}
......@@ -384,12 +384,12 @@ print_text_recording(ChatView *self)
if (!priv->conversation_) return;
for (const auto& it: priv->conversation_->interactions) {
if (it.second.status == lrc::api::interaction::Status::UNREAD)
priv->accountContainer_->info.conversationModel->setInteractionRead(priv->conversation_->uid, it.first);
(*priv->accountInfo_)->conversationModel->setInteractionRead(priv->conversation_->uid, it.first);
}
webkit_chat_container_print_history(
WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
*priv->accountContainer_->info.conversationModel,
*(*priv->accountInfo_)->conversationModel,
priv->conversation_->interactions
);
......@@ -404,7 +404,7 @@ update_add_to_conversations(ChatView *self)
if (!priv->conversation_) return;
auto participant = priv->conversation_->participants[0];
try {
auto contactInfo = priv->accountContainer_->info.contactModel->getContact(participant);
auto contactInfo = (*priv->accountInfo_)->contactModel->getContact(participant);
if(contactInfo.profileInfo.type != lrc::api::profile::Type::TEMPORARY
&& contactInfo.profileInfo.type != lrc::api::profile::Type::PENDING)
gtk_widget_hide(priv->button_add_to_conversations);
......@@ -421,7 +421,7 @@ update_contact_methods(ChatView *self)
if (!priv->conversation_) return;
auto contactUri = priv->conversation_->participants.front();
try {
auto contactInfo = priv->accountContainer_->info.contactModel->getContact(contactUri);
auto contactInfo = (*priv->accountInfo_)->contactModel->getContact(contactUri);
auto bestId = std::string(contactInfo.registeredName).empty() ? contactInfo.profileInfo.uri : contactInfo.registeredName;
if (contactInfo.profileInfo.alias == bestId) {
gtk_widget_hide(priv->label_cm);
......@@ -442,7 +442,7 @@ update_name(ChatView *self)
if (!priv->conversation_) return;
auto contactUri = priv->conversation_->participants.front();
try {
auto contactInfo = priv->accountContainer_->info.contactModel->getContact(contactUri);
auto contactInfo = (*priv->accountInfo_)->contactModel->getContact(contactUri);
auto alias = contactInfo.profileInfo.alias;
alias.erase(std::remove(alias.begin(), alias.end(), '\r'), alias.end());
gtk_label_set_text(GTK_LABEL(priv->label_peer), alias.c_str());
......@@ -468,7 +468,7 @@ webkit_chat_container_ready(ChatView* self)
load_participants_images(self);
priv->new_interaction_connection = QObject::connect(
&*priv->accountContainer_->info.conversationModel, &lrc::api::ConversationModel::newInteraction,
&*(*priv->accountInfo_)->conversationModel, &lrc::api::ConversationModel::newInteraction,
[self, priv](const std::string& uid, uint64_t interactionId, lrc::api::interaction::Info interaction) {
if (!priv->conversation_) return;
if(uid == priv->conversation_->uid) {
......@@ -477,7 +477,7 @@ webkit_chat_container_ready(ChatView* self)
});
priv->update_interaction_connection = QObject::connect(
&*priv->accountContainer_->info.conversationModel, &lrc::api::ConversationModel::interactionStatusUpdated,
&*(*priv->accountInfo_)->conversationModel, &lrc::api::ConversationModel::interactionStatusUpdated,
[self, priv](const std::string& uid, uint64_t msgId, lrc::api::interaction::Info msg) {
if (!priv->conversation_) return;
if(uid == priv->conversation_->uid) {
......@@ -488,7 +488,7 @@ webkit_chat_container_ready(ChatView* self)
if (!priv->conversation_) return;
auto contactUri = priv->conversation_->participants.front();
try {
auto contactInfo = priv->accountContainer_->info.contactModel->getContact(contactUri);
auto contactInfo = (*priv->accountInfo_)->contactModel->getContact(contactUri);
priv->isTemporary_ = contactInfo.profileInfo.type == lrc::api::profile::Type::TEMPORARY
|| contactInfo.profileInfo.type == lrc::api::profile::Type::PENDING;
webkit_chat_container_set_temporary(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container), priv->isTemporary_);
......@@ -542,7 +542,7 @@ build_chat_view(ChatView* self)
GtkWidget *
chat_view_new (WebKitChatContainer* webkit_chat_container,
AccountContainer* accountContainer,
AccountInfoPointer const & accountInfo,
lrc::api::conversation::Info* conversation)
{
ChatView *self = CHAT_VIEW(g_object_new(CHAT_VIEW_TYPE, NULL));
......@@ -550,7 +550,7 @@ chat_view_new (WebKitChatContainer* webkit_chat_container,
ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
priv->webkit_chat_container = GTK_WIDGET(webkit_chat_container);
priv->conversation_ = conversation;
priv->accountContainer_ = accountContainer;
priv->accountInfo_ = &accountInfo;
build_chat_view(self);
return (GtkWidget *)self;
......@@ -570,7 +570,7 @@ chat_view_update_temporary(ChatView* self, bool showAddButton, bool showInvitati
if (!priv->conversation_) return;
auto contactUri = priv->conversation_->participants.front();
try {
auto contactInfo = priv->accountContainer_->info.contactModel->getContact(contactUri);
auto contactInfo = (*priv->accountInfo_)->contactModel->getContact(contactUri);
auto bestName = contactInfo.profileInfo.alias;
if (bestName.empty())
bestName = contactInfo.registeredName;
......
......@@ -25,8 +25,9 @@
#include <gtk/gtk.h>
// Client related
#include "accountcontainer.h"
#include "api/account.h"
#include "webkitchatcontainer.h"
#include "accountinfopointer.h"
namespace lrc
{
......@@ -52,7 +53,7 @@ typedef struct _ChatViewClass ChatViewClass;
GType chat_view_get_type (void) G_GNUC_CONST;
GtkWidget *chat_view_new (WebKitChatContainer* view,
AccountContainer* accountContainer,
AccountInfoPointer const & accountInfo,
lrc::api::conversation::Info* conversation);
lrc::api::conversation::Info chat_view_get_conversation(ChatView*);
bool chat_view_get_temporary(ChatView*);
......
......@@ -27,6 +27,8 @@
#include <api/contactmodel.h>
#include <api/contact.h>
#include "accountinfopointer.h"
struct _ConversationPopupMenu
{
GtkMenu parent;
......@@ -43,7 +45,7 @@ struct _ConversationPopupMenuPrivate
{
GtkTreeView *treeview;
AccountContainer* accountContainer_;
AccountInfoPointer const *accountInfo_;
int row_;
};
......@@ -56,9 +58,9 @@ copy_contact_info(G_GNUC_UNUSED GtkWidget *menu, ConversationPopupMenuPrivate* p
{
try
{
auto conversation = priv->accountContainer_->info.conversationModel->filteredConversation(priv->row_);
auto conversation = (*priv->accountInfo_)->conversationModel->filteredConversation(priv->row_);
if (conversation.participants.empty()) return;
auto& contact = priv->accountContainer_->info.contactModel->getContact(conversation.participants.front());
auto& contact = (*priv->accountInfo_)->contactModel->getContact(conversation.participants.front());
auto bestName = contact.registeredName.empty() ? contact.profileInfo.uri : contact.registeredName;
auto text = (gchar *)bestName.c_str();
GtkClipboard* clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
......@@ -77,8 +79,8 @@ remove_history_conversation(G_GNUC_UNUSED GtkWidget *menu, ConversationPopupMenu
{
try
{
auto conversation = priv->accountContainer_->info.conversationModel->filteredConversation(priv->row_);
priv->accountContainer_->info.conversationModel->clearHistory(conversation.uid);
auto conversation = (*priv->accountInfo_)->conversationModel->filteredConversation(priv->row_);
(*priv->accountInfo_)->conversationModel->clearHistory(conversation.uid);
}
catch (...)
{
......@@ -91,8 +93,8 @@ remove_conversation(G_GNUC_UNUSED GtkWidget *menu, ConversationPopupMenuPrivate*
{
try
{
auto conversationUid = priv->accountContainer_->info.conversationModel->filteredConversation(priv->row_).uid;
priv->accountContainer_->info.conversationModel->removeConversation(conversationUid);
auto conversationUid = (*priv->accountInfo_)->conversationModel->filteredConversation(priv->row_).uid;
(*priv->accountInfo_)->conversationModel->removeConversation(conversationUid);
}
catch (...)
{
......@@ -105,8 +107,8 @@ block_conversation(G_GNUC_UNUSED GtkWidget *menu, ConversationPopupMenuPrivate*
{
try
{
auto conversationUid = priv->accountContainer_->info.conversationModel->filteredConversation(priv->row_).uid;
priv->accountContainer_->info.conversationModel->removeConversation(conversationUid, true);
auto conversationUid = (*priv->accountInfo_)->conversationModel->filteredConversation(priv->row_).uid;
(*priv->accountInfo_)->conversationModel->removeConversation(conversationUid, true);
}
catch (...)
{
......@@ -119,8 +121,8 @@ add_conversation(G_GNUC_UNUSED GtkWidget *menu, ConversationPopupMenuPrivate* pr
{
try
{
auto conversation = priv->accountContainer_->info.conversationModel->filteredConversation(priv->row_);
priv->accountContainer_->info.conversationModel->makePermanent(conversation.uid);
auto conversation = (*priv->accountInfo_)->conversationModel->filteredConversation(priv->row_);
(*priv->accountInfo_)->conversationModel->makePermanent(conversation.uid);
}
catch (...)
{
......@@ -133,8 +135,8 @@ place_video_call(G_GNUC_UNUSED GtkWidget *menu, ConversationPopupMenuPrivate* pr
{
try
{
auto conversation = priv->accountContainer_->info.conversationModel->filteredConversation(priv->row_);
priv->accountContainer_->info.conversationModel->placeCall(conversation.uid);
auto conversation = (*priv->accountInfo_)->conversationModel->filteredConversation(priv->row_);
(*priv->accountInfo_)->conversationModel->placeCall(conversation.uid);
} catch (...) {
g_warning("Can't get conversation at row %i", priv->row_);
}
......@@ -145,8 +147,8 @@ place_audio_call(G_GNUC_UNUSED GtkWidget *menu, ConversationPopupMenuPrivate* pr
{
try
{
auto conversation = priv->accountContainer_->info.conversationModel->filteredConversation(priv->row_);
priv->accountContainer_->info.conversationModel->placeAudioOnlyCall(conversation.uid);
auto conversation = (*priv->accountInfo_)->conversationModel->filteredConversation(priv->row_);
(*priv->accountInfo_)->conversationModel->placeAudioOnlyCall(conversation.uid);
} catch (...) {
g_warning("Can't get conversation at row %i", priv->row_);
}
......@@ -168,10 +170,10 @@ update(GtkTreeSelection *selection, ConversationPopupMenu *self)
if (!gtk_tree_selection_get_selected(selection, &model, &iter)) return;
auto path = gtk_tree_model_get_path(model, &iter);
auto idx = gtk_tree_path_get_indices(path);
auto conversation = priv->accountContainer_->info.conversationModel->filteredConversation(idx[0]);
auto conversation = (*priv->accountInfo_)->conversationModel->filteredConversation(idx[0]);
priv->row_ = idx[0];
try {
auto contactInfo = priv->accountContainer_->info.contactModel->getContact(conversation.participants.front());
auto contactInfo = (*priv->accountInfo_)->contactModel->getContact(conversation.participants.front());
if (contactInfo.profileInfo.uri.empty()) return;
// we always build a menu, however in some cases some or all of the conversations will be deactivated
......@@ -248,11 +250,11 @@ conversation_popup_menu_init(G_GNUC_UNUSED ConversationPopupMenu *self)
}
GtkWidget *
conversation_popup_menu_new (GtkTreeView *treeview, AccountContainer* accountContainer)
conversation_popup_menu_new (GtkTreeView *treeview, AccountInfoPointer const & accountInfo)
{
gpointer self = g_object_new(CONVERSATION_POPUP_MENU_TYPE, NULL);
ConversationPopupMenuPrivate *priv = CONVERSATION_POPUP_MENU_GET_PRIVATE(self);
priv->accountContainer_ = accountContainer;
priv->accountInfo_ = &accountInfo;
priv->treeview = treeview;
GtkTreeSelection *selection = gtk_tree_view_get_selection(priv->treeview);
......
......@@ -22,7 +22,9 @@
#include <gtk/gtk.h>
// LRC
#include "accountcontainer.h"
#include "api/account.h"
#include "accountinfopointer.h"
G_BEGIN_DECLS
......@@ -36,7 +38,7 @@ typedef struct _ConversationPopupMenu ConversationPopupMenu;
typedef struct _ConversationPopupMenuClass ConversationPopupMenuClass;
GType conversation_popup_menu_get_type (void) G_GNUC_CONST;
GtkWidget *conversation_popup_menu_new (GtkTreeView *treeview, AccountContainer* accountContainer);
GtkWidget *conversation_popup_menu_new (GtkTreeView *treeview, AccountInfoPointer const & accountInfo);
gboolean conversation_popup_menu_show (ConversationPopupMenu *self, GdkEventButton *event);
G_END_DECLS
......@@ -37,7 +37,6 @@
#include "native/pixbufmanipulator.h"
#include "conversationpopupmenu.h"
static constexpr const char* CALL_TARGET = "CALL_TARGET";
static constexpr int CALL_TARGET_ID = 0;
......@@ -55,7 +54,7 @@ typedef struct _ConversationsViewPrivate ConversationsViewPrivate;
struct _ConversationsViewPrivate
{
AccountContainer* accountContainer_;
AccountInfoPointer const *accountInfo_;
GtkWidget* popupMenu_;
......@@ -88,12 +87,12 @@ render_contact_photo(G_GNUC_UNUSED GtkTreeViewColumn *tree_column,
{
// Draw first contact.
// NOTE: We just draw the first contact, must change this for conferences when they will have their own object
auto conversationInfo = priv->accountContainer_->info.conversationModel->filteredConversation(row);
auto contactInfo = priv->accountContainer_->info.contactModel->getContact(conversationInfo.participants.front());
auto conversationInfo = (*priv->accountInfo_)->conversationModel->filteredConversation(row);
auto contactInfo = (*priv->accountInfo_)->contactModel->getContact(conversationInfo.participants.front());
std::shared_ptr<GdkPixbuf> image;
auto var_photo = GlobalInstances::pixmapManipulator().conversationPhoto(
conversationInfo,
priv->accountContainer_->info,
**(priv->accountInfo_),
QSize(50, 50),
contactInfo.isPresent
);
......@@ -185,10 +184,10 @@ render_time(G_GNUC_UNUSED GtkTreeViewColumn *tree_column,
try
{
auto conversation = priv->accountContainer_->info.conversationModel->filteredConversation(row);
auto conversation = (*priv->accountInfo_)->conversationModel->filteredConversation(row);
auto callId = conversation.confId.empty() ? conversation.callId : conversation.confId;
if (!callId.empty()) {
auto call = priv->accountContainer_->info.callModel->getCall(callId);
auto call = (*priv->accountInfo_)->callModel->getCall(callId);
text = g_markup_printf_escaped("%s",
lrc::api::call::to_string(call.status).c_str()
);
......@@ -242,9 +241,9 @@ update_conversation(ConversationsView *self, const std::string& uid) {
-1);
if(std::string(ringId) == uid) {
// Get informations
auto conversation = priv->accountContainer_->info.conversationModel->filteredConversation(idx);
auto conversation = (*priv->accountInfo_)->conversationModel->filteredConversation(idx);
auto contactUri = conversation.participants.front();
auto contactInfo = priv->accountContainer_->info.contactModel->getContact(contactUri);
auto contactInfo = (*priv->accountInfo_)->contactModel->getContact(contactUri);
auto lastMessage = conversation.interactions.empty() ? "" :
conversation.interactions.at(conversation.lastMessageUid).body;
std::replace(lastMessage.begin(), lastMessage.end(), '\n', ' ');
......@@ -282,11 +281,15 @@ create_and_fill_model(ConversationsView *self)
if(!priv) GTK_TREE_MODEL (store);
GtkTreeIter iter;
for (auto conversation : priv->accountContainer_->info.conversationModel->allFilteredConversations()) {
if (conversation.participants.empty()) break; // Should not
for (auto conversation : (*priv->accountInfo_)->conversationModel->allFilteredConversations()) {
if (conversation.participants.empty()) {
g_debug("Found conversation with empty list of participants - most likely the result of earlier bug.");
break;
}
auto contactUri = conversation.participants.front();
try {
auto contactInfo = priv->accountContainer_->info.contactModel->getContact(contactUri);
auto contactInfo = (*priv->accountInfo_)->contactModel->getContact(contactUri);
auto lastMessage = conversation.interactions.empty() ? "" :
conversation.interactions.at(conversation.lastMessageUid).body;
std::replace(lastMessage.begin(), lastMessage.end(), '\n', ' ');
......@@ -319,8 +322,8 @@ call_conversation(GtkTreeView *self,
if (row == -1) return;
auto priv = CONVERSATIONS_VIEW_GET_PRIVATE(self);
if (!priv) return;
auto conversation = priv->accountContainer_->info.conversationModel->filteredConversation(row);
priv->accountContainer_->info.conversationModel->placeCall(conversation.uid);
auto conversation = (*priv->accountInfo_)->conversationModel->filteredConversation(row);
(*priv->accountInfo_)->conversationModel->placeCall(conversation.uid);
}
static void
......@@ -334,7 +337,7 @@ select_conversation(GtkTreeSelection *selection, ConversationsView *self)
// Destroy the not up to date menu.
gtk_widget_hide(priv->popupMenu_);
gtk_widget_destroy(priv->popupMenu_);
priv->popupMenu_ = conversation_popup_menu_new(GTK_TREE_VIEW(self), priv->accountContainer_);
priv->popupMenu_ = conversation_popup_menu_new(GTK_TREE_VIEW(self), *priv->accountInfo_);
auto children = gtk_container_get_children (GTK_CONTAINER(priv->popupMenu_));
auto nbItems = g_list_length(children);
// Show the new popupMenu_ should be visible
......@@ -350,7 +353,7 @@ select_conversation(GtkTreeSelection *selection, ConversationsView *self)
gtk_tree_model_get(model, &iter,
0, &conversationUid,
-1);
priv->accountContainer_->info.conversationModel->selectConversation(std::string(conversationUid));
(*priv->accountInfo_)->conversationModel->selectConversation(std::string(conversationUid));
}
static void
......@@ -500,7 +503,7 @@ on_drag_data_received(GtkWidget *treeview,
0, &conversationUidDest,
-1);
priv->accountContainer_->info.conversationModel->joinConversations(
(*priv->accountInfo_)->conversationModel->joinConversations(
conversationUidSrc,
conversationUidDest
);
......@@ -566,7 +569,7 @@ build_conversations_view(ConversationsView *self)
// This view should be synchronized and redraw at each update.
priv->modelSortedConnection_ = QObject::connect(
&*priv->accountContainer_->info.conversationModel,
&*(*priv->accountInfo_)->conversationModel,
&lrc::api::ConversationModel::modelSorted,
[self] () {
auto model = create_and_fill_model(self);
......@@ -575,14 +578,14 @@ build_conversations_view(ConversationsView *self)
GTK_TREE_MODEL(model));
});
priv->conversationUpdatedConnection_ = QObject::connect(
&*priv->accountContainer_->info.conversationModel,
&*(*priv->accountInfo_)->conversationModel,
&lrc::api::ConversationModel::conversationUpdated,
[self] (const std::string& uid) {
update_conversation(self, uid);
});
priv->filterChangedConnection_ = QObject::connect(
&*priv->accountContainer_->info.conversationModel,
&*(*priv->accountInfo_)->conversationModel,
&lrc::api::ConversationModel::filterChanged,
[self] () {
auto model = create_and_fill_model(self);
......@@ -599,7 +602,7 @@ build_conversations_view(ConversationsView *self)
// Two clicks to placeCall
g_signal_connect(self, "row-activated", G_CALLBACK(call_conversation), NULL);
priv->popupMenu_ = conversation_popup_menu_new(GTK_TREE_VIEW(self), priv->accountContainer_);
priv->popupMenu_ = conversation_popup_menu_new(GTK_TREE_VIEW(self), *priv->accountInfo_);
// Right click to show actions
g_signal_connect_swapped(self, "button-press-event", G_CALLBACK(show_popup_menu), self);
......@@ -651,14 +654,14 @@ conversations_view_class_init(ConversationsViewClass *klass)
}
GtkWidget *
conversations_view_new(AccountContainer* accountContainer)
conversations_view_new(AccountInfoPointer const & accountInfo)
{
auto self = CONVERSATIONS_VIEW(g_object_new(CONVERSATIONS_VIEW_TYPE, NULL));
auto priv = CONVERSATIONS_VIEW_GET_PRIVATE(self);
priv->accountContainer_ = accountContainer;
priv->accountInfo_ = &accountInfo;
if (priv->accountContainer_)
if (*priv->accountInfo_)
build_conversations_view(self);