blob: 24fcf408bc882de1c9949628d6fbfd1b00994c00 [file] [log] [blame]
Stepan Salenikovichd2cad062016-01-08 13:43:49 -05001/*
2 * Copyright (C) 2016 Savoir-faire Linux Inc.
3 * Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
aviau039001d2016-09-29 16:39:05 -04004 * Author: Alexandre Viau <alexandre.viau@savoirfairelinux.com>
Stepan Salenikovichd2cad062016-01-08 13:43:49 -05005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include "chatview.h"
22
23#include <gtk/gtk.h>
24#include <call.h>
25#include <callmodel.h>
26#include <contactmethod.h>
27#include <person.h>
Stepan Salenikovichd2cad062016-01-08 13:43:49 -050028#include <media/text.h>
29#include <media/textrecording.h>
30#include "ringnotify.h"
aviau039001d2016-09-29 16:39:05 -040031#include "profilemodel.h"
32#include "profile.h"
Stepan Salenikovich5039c9b2016-02-12 14:09:51 -050033#include "numbercategory.h"
Stepan Salenikovich1b7100a2016-02-19 11:50:46 -050034#include <QtCore/QDateTime>
Stepan Salenikoviche9933242016-06-21 18:08:48 -040035#include "utils/calling.h"
aviau039001d2016-09-29 16:39:05 -040036#include "webkitchatcontainer.h"
Stepan Salenikovichd2cad062016-01-08 13:43:49 -050037
Stepan Salenikovichce06adb2016-02-19 12:53:53 -050038static constexpr GdkRGBA RING_BLUE = {0.0508, 0.594, 0.676, 1.0}; // outgoing msg color: (13, 152, 173)
39
Stepan Salenikovichd2cad062016-01-08 13:43:49 -050040struct _ChatView
41{
42 GtkBox parent;
43};
44
45struct _ChatViewClass
46{
47 GtkBoxClass parent_class;
48};
49
50typedef struct _ChatViewPrivate ChatViewPrivate;
51
52struct _ChatViewPrivate
53{
aviau039001d2016-09-29 16:39:05 -040054 GtkWidget *box_webkit_chat_container;
55 GtkWidget *webkit_chat_container;
Stepan Salenikovichd2cad062016-01-08 13:43:49 -050056 GtkWidget *button_chat_input;
57 GtkWidget *entry_chat_input;
58 GtkWidget *scrolledwindow_chat;
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -050059 GtkWidget *hbox_chat_info;
60 GtkWidget *label_peer;
61 GtkWidget *combobox_cm;
Stepan Salenikovich8043a562016-03-18 13:56:40 -040062 GtkWidget *button_close_chatview;
Stepan Salenikoviche9933242016-06-21 18:08:48 -040063 GtkWidget *button_placecall;
Stepan Salenikovichd2cad062016-01-08 13:43:49 -050064
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -050065 /* only one of the three following pointers should be non void;
66 * either this is an in-call chat (and so the in-call chat APIs will be used)
aviau039001d2016-09-29 16:39:05 -040067 * or it is an out of call chat (and so the account chat APIs will be used) */
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -050068 Call *call;
69 Person *person;
70 ContactMethod *cm;
Stepan Salenikovichd2cad062016-01-08 13:43:49 -050071
aviau039001d2016-09-29 16:39:05 -040072 /* initial TextRecording to print when the chat is ready */
73 Media::TextRecording* initial_text_recording;
74
Stepan Salenikovichd2cad062016-01-08 13:43:49 -050075 QMetaObject::Connection new_message_connection;
aviau039001d2016-09-29 16:39:05 -040076 QMetaObject::Connection message_changed_connection;
Stepan Salenikovichd2cad062016-01-08 13:43:49 -050077};
78
79G_DEFINE_TYPE_WITH_PRIVATE(ChatView, chat_view, GTK_TYPE_BOX);
80
81#define CHAT_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CHAT_VIEW_TYPE, ChatViewPrivate))
82
83enum {
84 NEW_MESSAGES_DISPLAYED,
Stepan Salenikovich8043a562016-03-18 13:56:40 -040085 HIDE_VIEW_CLICKED,
Stepan Salenikovichd2cad062016-01-08 13:43:49 -050086 LAST_SIGNAL
87};
88
89static guint chat_view_signals[LAST_SIGNAL] = { 0 };
90
91static void
92chat_view_dispose(GObject *object)
93{
94 ChatView *view;
95 ChatViewPrivate *priv;
96
97 view = CHAT_VIEW(object);
98 priv = CHAT_VIEW_GET_PRIVATE(view);
99
100 QObject::disconnect(priv->new_message_connection);
aviau039001d2016-09-29 16:39:05 -0400101 QObject::disconnect(priv->message_changed_connection);
102
103 /* Destroying the box will also destroy its children, and we wouldn't
104 * want that. So we remove the webkit_chat_container from the box. */
105 if (priv->webkit_chat_container) {
106 gtk_container_remove(
107 GTK_CONTAINER(priv->box_webkit_chat_container),
108 GTK_WIDGET(priv->webkit_chat_container)
109 );
110 priv->webkit_chat_container = nullptr;
111 }
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500112
113 G_OBJECT_CLASS(chat_view_parent_class)->dispose(object);
114}
115
116
117static void
118send_chat(G_GNUC_UNUSED GtkWidget *widget, ChatView *self)
119{
120 g_return_if_fail(IS_CHAT_VIEW(self));
121 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
122
123 /* make sure there is text to send */
124 const gchar *text = gtk_entry_get_text(GTK_ENTRY(priv->entry_chat_input));
125 if (text && strlen(text) > 0) {
126 QMap<QString, QString> messages;
127 messages["text/plain"] = text;
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500128
129 if (priv->call) {
130 // in call message
131 priv->call->addOutgoingMedia<Media::Text>()->send(messages);
132 } else if (priv->person) {
133 // get the chosen cm
134 auto active = gtk_combo_box_get_active(GTK_COMBO_BOX(priv->combobox_cm));
135 if (active >= 0) {
136 auto cm = priv->person->phoneNumbers().at(active);
137 if (!cm->sendOfflineTextMessage(messages))
138 g_warning("message failed to send"); // TODO: warn the user about this in the UI
139 } else {
Stepan Salenikoviche9933242016-06-21 18:08:48 -0400140 g_warning("no ContactMethod chosen; message not sent");
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500141 }
142 } else if (priv->cm) {
143 if (!priv->cm->sendOfflineTextMessage(messages))
144 g_warning("message failed to send"); // TODO: warn the user about this in the UI
145 } else {
146 g_warning("no Call, Person, or ContactMethod set; message not sent");
147 }
148
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500149 /* clear the entry */
150 gtk_entry_set_text(GTK_ENTRY(priv->entry_chat_input), "");
151 }
152}
153
154static void
Stepan Salenikovich8043a562016-03-18 13:56:40 -0400155hide_chat_view(G_GNUC_UNUSED GtkWidget *widget, ChatView *self)
156{
157 g_signal_emit(G_OBJECT(self), chat_view_signals[HIDE_VIEW_CLICKED], 0);
158}
159
160static void
Stepan Salenikoviche9933242016-06-21 18:08:48 -0400161placecall_clicked(ChatView *self)
162{
163 auto priv = CHAT_VIEW_GET_PRIVATE(self);
164
165 if (priv->person) {
166 // get the chosen cm
167 auto active = gtk_combo_box_get_active(GTK_COMBO_BOX(priv->combobox_cm));
168 if (active >= 0) {
169 auto cm = priv->person->phoneNumbers().at(active);
170 place_new_call(cm);
171 } else {
172 g_warning("no ContactMethod chosen; cannot place call");
173 }
174 } else if (priv->cm) {
175 place_new_call(priv->cm);
176 } else {
177 g_warning("no Person or ContactMethod set; cannot place call");
178 }
179}
180
181static void
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500182chat_view_init(ChatView *view)
183{
184 gtk_widget_init_template(GTK_WIDGET(view));
185
186 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(view);
187
188 g_signal_connect(priv->button_chat_input, "clicked", G_CALLBACK(send_chat), view);
189 g_signal_connect(priv->entry_chat_input, "activate", G_CALLBACK(send_chat), view);
Stepan Salenikovich8043a562016-03-18 13:56:40 -0400190 g_signal_connect(priv->button_close_chatview, "clicked", G_CALLBACK(hide_chat_view), view);
Stepan Salenikoviche9933242016-06-21 18:08:48 -0400191 g_signal_connect_swapped(priv->button_placecall, "clicked", G_CALLBACK(placecall_clicked), view);
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500192}
193
194static void
195chat_view_class_init(ChatViewClass *klass)
196{
197 G_OBJECT_CLASS(klass)->dispose = chat_view_dispose;
198
199 gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
200 "/cx/ring/RingGnome/chatview.ui");
201
aviau039001d2016-09-29 16:39:05 -0400202 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, box_webkit_chat_container);
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500203 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, button_chat_input);
204 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, entry_chat_input);
205 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, scrolledwindow_chat);
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500206 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, hbox_chat_info);
207 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, label_peer);
208 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, combobox_cm);
Stepan Salenikovich8043a562016-03-18 13:56:40 -0400209 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, button_close_chatview);
Stepan Salenikoviche9933242016-06-21 18:08:48 -0400210 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, button_placecall);
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500211
212 chat_view_signals[NEW_MESSAGES_DISPLAYED] = g_signal_new (
213 "new-messages-displayed",
214 G_TYPE_FROM_CLASS(klass),
215 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
216 0,
217 nullptr,
218 nullptr,
219 g_cclosure_marshal_VOID__VOID,
220 G_TYPE_NONE, 0);
Stepan Salenikovich8043a562016-03-18 13:56:40 -0400221
222 chat_view_signals[HIDE_VIEW_CLICKED] = g_signal_new (
223 "hide-view-clicked",
224 G_TYPE_FROM_CLASS(klass),
225 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
226 0,
227 nullptr,
228 nullptr,
229 g_cclosure_marshal_VOID__VOID,
230 G_TYPE_NONE, 0);
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500231}
232
aviau039001d2016-09-29 16:39:05 -0400233
234
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500235static void
aviau039001d2016-09-29 16:39:05 -0400236print_message_to_buffer(ChatView* self, const QModelIndex &idx)
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500237{
aviau039001d2016-09-29 16:39:05 -0400238 if (!idx.isValid()) {
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500239 g_warning("QModelIndex in im model is not valid");
aviau039001d2016-09-29 16:39:05 -0400240 return;
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500241 }
aviau039001d2016-09-29 16:39:05 -0400242
243 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
244
245 webkit_chat_container_print_new_message(
246 WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
247 idx
248 );
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500249}
250
251static void
Stepan Salenikovichd8765072016-01-14 10:58:51 -0500252print_text_recording(Media::TextRecording *recording, ChatView *self)
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500253{
254 g_return_if_fail(IS_CHAT_VIEW(self));
255 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
256
Stepan Salenikovichd8765072016-01-14 10:58:51 -0500257 /* only text messages are supported for now */
258 auto model = recording->instantTextMessagingModel();
259
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500260 /* new model, disconnect from the old model updates and clear the text buffer */
261 QObject::disconnect(priv->new_message_connection);
262
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500263 /* put all the messages in the im model into the text view */
264 for (int row = 0; row < model->rowCount(); ++row) {
265 QModelIndex idx = model->index(row, 0);
aviau039001d2016-09-29 16:39:05 -0400266 print_message_to_buffer(self, idx);
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500267 }
Stepan Salenikovichd8765072016-01-14 10:58:51 -0500268 /* mark all messages as read */
269 recording->setAllRead();
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500270
aviau039001d2016-09-29 16:39:05 -0400271
272 /* messages modified */
273 /* connecting on instantMessagingModel and not textMessagingModel */
274 priv->message_changed_connection = QObject::connect(
275 model,
276 &QAbstractItemModel::dataChanged,
277 [self, priv] (const QModelIndex & topLeft, G_GNUC_UNUSED const QModelIndex & bottomRight)
278 {
279 webkit_chat_container_update_message(
280 WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
281 topLeft
282 );
283 }
284 );
285
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500286 /* append new messages */
287 priv->new_message_connection = QObject::connect(
288 model,
289 &QAbstractItemModel::rowsInserted,
290 [self, priv, model] (const QModelIndex &parent, int first, int last) {
291 for (int row = first; row <= last; ++row) {
292 QModelIndex idx = model->index(row, 0, parent);
aviau039001d2016-09-29 16:39:05 -0400293 print_message_to_buffer(self, idx);
Stepan Salenikovichd8765072016-01-14 10:58:51 -0500294 /* make sure these messages are marked as read */
295 model->setData(idx, true, static_cast<int>(Media::TextRecording::Role::IsRead));
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500296 g_signal_emit(G_OBJECT(self), chat_view_signals[NEW_MESSAGES_DISPLAYED], 0);
297 }
298 }
299 );
300}
301
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500302static void
303selected_cm_changed(GtkComboBox *box, ChatView *self)
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500304{
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500305 g_return_if_fail(IS_CHAT_VIEW(self));
306 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
307
308 auto cms = priv->person->phoneNumbers();
309 auto active = gtk_combo_box_get_active(box);
310 if (active >= 0 && active < cms.size()) {
Stepan Salenikovichd8765072016-01-14 10:58:51 -0500311 print_text_recording(cms.at(active)->textRecording(), self);
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500312 } else {
313 g_warning("no valid ContactMethod selected to display chat conversation");
314 }
315}
316
317static void
Stepan Salenikovich5039c9b2016-02-12 14:09:51 -0500318render_contact_method(G_GNUC_UNUSED GtkCellLayout *cell_layout,
319 GtkCellRenderer *cell,
320 GtkTreeModel *model,
321 GtkTreeIter *iter,
322 G_GNUC_UNUSED gpointer data)
323{
324 GValue value = G_VALUE_INIT;
325 gtk_tree_model_get_value(model, iter, 0, &value);
326 auto cm = (ContactMethod *)g_value_get_pointer(&value);
327
328 gchar *number = nullptr;
329 if (cm && cm->category()) {
330 // try to get the number category, eg: "home"
331 number = g_strdup_printf("(%s) %s", cm->category()->name().toUtf8().constData(),
332 cm->uri().toUtf8().constData());
333 } else if (cm) {
334 number = g_strdup_printf("%s", cm->uri().toUtf8().constData());
335 }
336
337 g_object_set(G_OBJECT(cell), "text", number, NULL);
338 g_free(number);
339}
340
341static void
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500342update_contact_methods(ChatView *self)
343{
344 g_return_if_fail(IS_CHAT_VIEW(self));
345 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
346
Stepan Salenikovichbbfa4402016-05-04 15:07:29 -0400347 g_return_if_fail(priv->person || priv->cm);
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500348
349 /* model for the combobox for the choice of ContactMethods */
350 auto cm_model = gtk_list_store_new(
Stepan Salenikovich5039c9b2016-02-12 14:09:51 -0500351 1, G_TYPE_POINTER
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500352 );
353
Stepan Salenikovichbbfa4402016-05-04 15:07:29 -0400354 Person::ContactMethods cms;
355
356 if (priv->person)
357 cms = priv->person->phoneNumbers();
358 else
359 cms << priv->cm;
360
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500361 for (int i = 0; i < cms.size(); ++i) {
362 GtkTreeIter iter;
363 gtk_list_store_append(cm_model, &iter);
364 gtk_list_store_set(cm_model, &iter,
Stepan Salenikovich5039c9b2016-02-12 14:09:51 -0500365 0, cms.at(i),
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500366 -1);
367 }
368
369 gtk_combo_box_set_model(GTK_COMBO_BOX(priv->combobox_cm), GTK_TREE_MODEL(cm_model));
370 g_object_unref(cm_model);
371
372 auto renderer = gtk_cell_renderer_text_new();
373 g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
374 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(priv->combobox_cm), renderer, FALSE);
Stepan Salenikovich5039c9b2016-02-12 14:09:51 -0500375 gtk_cell_layout_set_cell_data_func(
376 GTK_CELL_LAYOUT(priv->combobox_cm),
377 renderer,
378 (GtkCellLayoutDataFunc)render_contact_method,
379 nullptr, nullptr);
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500380
381 /* select the last used cm */
382 if (!cms.isEmpty()) {
383 auto last_used_cm = cms.at(0);
384 int last_used_cm_idx = 0;
385 for (int i = 1; i < cms.size(); ++i) {
386 auto new_cm = cms.at(i);
387 if (difftime(new_cm->lastUsed(), last_used_cm->lastUsed()) > 0) {
388 last_used_cm = new_cm;
389 last_used_cm_idx = i;
390 }
391 }
392
393 gtk_combo_box_set_active(GTK_COMBO_BOX(priv->combobox_cm), last_used_cm_idx);
394 }
395
Stepan Salenikovichbbfa4402016-05-04 15:07:29 -0400396 /* if there is only one CM, make the combo box insensitive */
397 if (cms.size() < 2)
398 gtk_widget_set_sensitive(priv->combobox_cm, FALSE);
Stepan Salenikoviche9933242016-06-21 18:08:48 -0400399
400 /* if no CMs make the call button insensitive */
401 gtk_widget_set_sensitive(priv->button_placecall, !cms.isEmpty());
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500402}
403
404static void
405update_name(ChatView *self)
406{
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500407 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
408
409 g_return_if_fail(priv->person || priv->cm);
410
411 QString name;
412 if (priv->person) {
413 name = priv->person->roleData(static_cast<int>(Ring::Role::Name)).toString();
414 } else {
415 name = priv->cm->roleData(static_cast<int>(Ring::Role::Name)).toString();
416 }
417 gtk_label_set_text(GTK_LABEL(priv->label_peer), name.toUtf8().constData());
418}
419
aviau039001d2016-09-29 16:39:05 -0400420static void
421set_participant_images(ChatView* self)
422{
423 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
424
425 /* set sender image for "ME" */
426 auto profile = ProfileModel::instance().selectedProfile();
427 if (profile)
428 {
429 auto person = profile->person();
430 if (person)
431 {
432 auto photo_variant_me = person->photo();
433 if (photo_variant_me.isValid())
434 {
435 webkit_chat_container_set_sender_image(
436 WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
437 "Me",
438 photo_variant_me
439 );
440 }
441 }
442 }
443
444 /* Set the sender image for the peer */
445 QString sender_name_peer;
446 QVariant photo_variant_peer;
447
448 if (priv->person)
449 {
450 photo_variant_peer = priv->person->photo();
451 sender_name_peer = priv->person->roleData(static_cast<int>(Ring::Role::Name)).toString();
452 }
453 else
454 {
455 ContactMethod *contact_method;
456 if (priv->cm)
457 {
458 contact_method = priv->cm;
459 }
460 else
461 {
462 contact_method = priv->call->peerContactMethod();
463 }
464 sender_name_peer = contact_method->roleData(static_cast<int>(Ring::Role::Name)).toString();
465 photo_variant_peer = contact_method->roleData((int) Call::Role::Photo);
466 }
467
468 if (photo_variant_peer.isValid())
469 {
470 webkit_chat_container_set_sender_image(
471 WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
472 sender_name_peer,
473 photo_variant_peer
474 );
475 }
476}
477
478static void
479webkit_chat_container_ready(ChatView* self)
480{
481 /* The webkit chat container has loaded the javascript libraries, we can
482 * now use it. */
483
484 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
485
486 webkit_chat_container_clear(
487 WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container)
488 );
489
490 /* set the photos of the chat participants */
491 set_participant_images(self);
492
493 /* print the text recordings */
494 if (priv->initial_text_recording)
495 {
496 print_text_recording(priv->initial_text_recording, self);
497 }
498
499 /* connect to the changed signal before setting the cm combo box, so that the correct
500 * conversation will get displayed */
501 if(priv->person)
502 {
503 g_signal_connect(priv->combobox_cm, "changed", G_CALLBACK(selected_cm_changed), self);
504 update_contact_methods(self);
505 update_name(self);
506 }
507}
508
509static void
510build_chat_view(ChatView* self)
511{
512 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
513
514 gtk_container_add(GTK_CONTAINER(priv->box_webkit_chat_container), priv->webkit_chat_container);
515 gtk_widget_show(priv->webkit_chat_container);
516
517
518 g_signal_connect_swapped(
519 priv->webkit_chat_container,
520 "ready",
521 G_CALLBACK(webkit_chat_container_ready),
522 self
523 );
524
525 if (webkit_chat_container_is_ready(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container)))
526 {
527 webkit_chat_container_ready(self);
528 }
529
530}
531
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500532GtkWidget *
aviau039001d2016-09-29 16:39:05 -0400533chat_view_new_call(WebKitChatContainer *webkit_chat_container, Call *call)
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500534{
535 g_return_val_if_fail(call, nullptr);
536
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500537 ChatView *self = CHAT_VIEW(g_object_new(CHAT_VIEW_TYPE, NULL));
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500538
aviau039001d2016-09-29 16:39:05 -0400539 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
540 priv->webkit_chat_container = GTK_WIDGET(webkit_chat_container);
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500541 priv->call = call;
542 auto cm = priv->call->peerContactMethod();
aviau039001d2016-09-29 16:39:05 -0400543 priv->initial_text_recording = cm->textRecording();
544
545 build_chat_view(self);
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500546
547 return (GtkWidget *)self;
548}
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500549
550GtkWidget *
aviau039001d2016-09-29 16:39:05 -0400551chat_view_new_cm(WebKitChatContainer *webkit_chat_container, ContactMethod *cm)
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500552{
553 g_return_val_if_fail(cm, nullptr);
554
555 ChatView *self = CHAT_VIEW(g_object_new(CHAT_VIEW_TYPE, NULL));
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500556
aviau039001d2016-09-29 16:39:05 -0400557 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
558 priv->webkit_chat_container = GTK_WIDGET(webkit_chat_container);
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500559 priv->cm = cm;
aviau039001d2016-09-29 16:39:05 -0400560 priv->initial_text_recording = priv->cm->textRecording();
561
562 build_chat_view(self);
563
Stepan Salenikovichbbfa4402016-05-04 15:07:29 -0400564 update_contact_methods(self);
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500565 update_name(self);
566
567 gtk_widget_show(priv->hbox_chat_info);
568
569 return (GtkWidget *)self;
570}
571
572GtkWidget *
aviau039001d2016-09-29 16:39:05 -0400573chat_view_new_person(WebKitChatContainer *webkit_chat_container, Person *p)
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500574{
575 g_return_val_if_fail(p, nullptr);
576
577 ChatView *self = CHAT_VIEW(g_object_new(CHAT_VIEW_TYPE, NULL));
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500578
aviau039001d2016-09-29 16:39:05 -0400579 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
580 priv->webkit_chat_container = GTK_WIDGET(webkit_chat_container);
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500581 priv->person = p;
582
aviau039001d2016-09-29 16:39:05 -0400583 build_chat_view(self);
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500584
585 gtk_widget_show(priv->hbox_chat_info);
586
587 return (GtkWidget *)self;
588}
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400589
590Call*
591chat_view_get_call(ChatView *self)
592{
593 g_return_val_if_fail(IS_CHAT_VIEW(self), nullptr);
594 auto priv = CHAT_VIEW_GET_PRIVATE(self);
595
596 return priv->call;
597}
598
599ContactMethod*
600chat_view_get_cm(ChatView *self)
601{
602 g_return_val_if_fail(IS_CHAT_VIEW(self), nullptr);
603 auto priv = CHAT_VIEW_GET_PRIVATE(self);
604
605 return priv->cm;
606}
607
608Person*
609chat_view_get_person(ChatView *self)
610{
611 g_return_val_if_fail(IS_CHAT_VIEW(self), nullptr);
612 auto priv = CHAT_VIEW_GET_PRIVATE(self);
613
614 return priv->person;
615}
Stepan Salenikovichdaf3cb32016-10-12 16:39:42 -0400616
617void
618chat_view_set_header_visible(ChatView *self, gboolean visible)
619{
620 auto priv = CHAT_VIEW_GET_PRIVATE(self);
621
622 gtk_widget_set_visible(priv->hbox_chat_info, visible);
623}