blob: 9bc6b57e73d63fceb6d6cdb9fc0eacabd5484274 [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
Stepan Salenikovich4fbc3bf2016-11-03 15:01:10 -0400123 /* make sure there is more than just whitespace, but if so, send the original text */
124 const auto text = QString(gtk_entry_get_text(GTK_ENTRY(priv->entry_chat_input)));
125 if (!text.trimmed().isEmpty()) {
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500126 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
aviaufc213552016-11-01 12:39:39 -0400251ContactMethod*
252get_active_contactmethod(ChatView *self)
253{
254 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
255
256 auto cms = priv->person->phoneNumbers();
257 auto active = gtk_combo_box_get_active(GTK_COMBO_BOX(priv->combobox_cm));
258 if (active >= 0 && active < cms.size()) {
259 return cms.at(active);
260 } else {
261 return nullptr;
262 }
263}
264
265static void
266set_participant_images(ChatView* self)
267{
268 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
269
270 webkit_chat_container_clear_sender_images(
271 WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container)
272 );
273
274 /* Set the sender image for the peer */
275 ContactMethod* sender_contact_method_peer;
276 QVariant photo_variant_peer;
277
278 if (priv->person)
279 {
280 photo_variant_peer = priv->person->photo();
281 sender_contact_method_peer = get_active_contactmethod(self);
282 }
283 else
284 {
285 if (priv->cm)
286 {
287 sender_contact_method_peer = priv->cm;
288 }
289 else
290 {
291 sender_contact_method_peer = priv->call->peerContactMethod();
292 }
293 photo_variant_peer = sender_contact_method_peer->roleData((int) Call::Role::Photo);
294 }
295
296 if (photo_variant_peer.isValid())
297 {
298 webkit_chat_container_set_sender_image(
299 WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
300 sender_contact_method_peer,
301 photo_variant_peer
302 );
303 }
304
305 /* set sender image for "ME" */
306 auto profile = ProfileModel::instance().selectedProfile();
307 if (profile)
308 {
309 auto person = profile->person();
310 if (person)
311 {
312 auto photo_variant_me = person->photo();
313 if (photo_variant_me.isValid())
314 {
315 webkit_chat_container_set_sender_image(
316 WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
317 nullptr,
318 photo_variant_me
319 );
320 }
321 }
322 }
323}
324
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500325static void
Stepan Salenikovichd8765072016-01-14 10:58:51 -0500326print_text_recording(Media::TextRecording *recording, ChatView *self)
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500327{
328 g_return_if_fail(IS_CHAT_VIEW(self));
329 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
330
aviaufc213552016-11-01 12:39:39 -0400331 /* set the photos of the chat participants */
332 set_participant_images(self);
333
Stepan Salenikovichd8765072016-01-14 10:58:51 -0500334 /* only text messages are supported for now */
335 auto model = recording->instantTextMessagingModel();
336
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500337 /* new model, disconnect from the old model updates and clear the text buffer */
338 QObject::disconnect(priv->new_message_connection);
339
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500340 /* put all the messages in the im model into the text view */
341 for (int row = 0; row < model->rowCount(); ++row) {
342 QModelIndex idx = model->index(row, 0);
aviau039001d2016-09-29 16:39:05 -0400343 print_message_to_buffer(self, idx);
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500344 }
Stepan Salenikovichd8765072016-01-14 10:58:51 -0500345 /* mark all messages as read */
346 recording->setAllRead();
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500347
aviau039001d2016-09-29 16:39:05 -0400348
349 /* messages modified */
350 /* connecting on instantMessagingModel and not textMessagingModel */
351 priv->message_changed_connection = QObject::connect(
352 model,
353 &QAbstractItemModel::dataChanged,
354 [self, priv] (const QModelIndex & topLeft, G_GNUC_UNUSED const QModelIndex & bottomRight)
355 {
356 webkit_chat_container_update_message(
357 WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
358 topLeft
359 );
360 }
361 );
362
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500363 /* append new messages */
364 priv->new_message_connection = QObject::connect(
365 model,
366 &QAbstractItemModel::rowsInserted,
367 [self, priv, model] (const QModelIndex &parent, int first, int last) {
368 for (int row = first; row <= last; ++row) {
369 QModelIndex idx = model->index(row, 0, parent);
aviau039001d2016-09-29 16:39:05 -0400370 print_message_to_buffer(self, idx);
Stepan Salenikovichd8765072016-01-14 10:58:51 -0500371 /* make sure these messages are marked as read */
372 model->setData(idx, true, static_cast<int>(Media::TextRecording::Role::IsRead));
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500373 g_signal_emit(G_OBJECT(self), chat_view_signals[NEW_MESSAGES_DISPLAYED], 0);
374 }
375 }
376 );
377}
378
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500379static void
aviaufc213552016-11-01 12:39:39 -0400380selected_cm_changed(G_GNUC_UNUSED GtkComboBox *box, ChatView *self)
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500381{
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500382 g_return_if_fail(IS_CHAT_VIEW(self));
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500383
aviaufc213552016-11-01 12:39:39 -0400384 auto cm = get_active_contactmethod(self);
385 if (cm){
386 print_text_recording(cm->textRecording(), self);
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500387 } else {
388 g_warning("no valid ContactMethod selected to display chat conversation");
389 }
390}
391
392static void
Stepan Salenikovich5039c9b2016-02-12 14:09:51 -0500393render_contact_method(G_GNUC_UNUSED GtkCellLayout *cell_layout,
394 GtkCellRenderer *cell,
395 GtkTreeModel *model,
396 GtkTreeIter *iter,
397 G_GNUC_UNUSED gpointer data)
398{
399 GValue value = G_VALUE_INIT;
400 gtk_tree_model_get_value(model, iter, 0, &value);
401 auto cm = (ContactMethod *)g_value_get_pointer(&value);
402
403 gchar *number = nullptr;
404 if (cm && cm->category()) {
405 // try to get the number category, eg: "home"
406 number = g_strdup_printf("(%s) %s", cm->category()->name().toUtf8().constData(),
407 cm->uri().toUtf8().constData());
408 } else if (cm) {
409 number = g_strdup_printf("%s", cm->uri().toUtf8().constData());
410 }
411
412 g_object_set(G_OBJECT(cell), "text", number, NULL);
413 g_free(number);
414}
415
416static void
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500417update_contact_methods(ChatView *self)
418{
419 g_return_if_fail(IS_CHAT_VIEW(self));
420 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
421
Stepan Salenikovichbbfa4402016-05-04 15:07:29 -0400422 g_return_if_fail(priv->person || priv->cm);
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500423
424 /* model for the combobox for the choice of ContactMethods */
425 auto cm_model = gtk_list_store_new(
Stepan Salenikovich5039c9b2016-02-12 14:09:51 -0500426 1, G_TYPE_POINTER
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500427 );
428
Stepan Salenikovichbbfa4402016-05-04 15:07:29 -0400429 Person::ContactMethods cms;
430
431 if (priv->person)
432 cms = priv->person->phoneNumbers();
433 else
434 cms << priv->cm;
435
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500436 for (int i = 0; i < cms.size(); ++i) {
437 GtkTreeIter iter;
438 gtk_list_store_append(cm_model, &iter);
439 gtk_list_store_set(cm_model, &iter,
Stepan Salenikovich5039c9b2016-02-12 14:09:51 -0500440 0, cms.at(i),
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500441 -1);
442 }
443
444 gtk_combo_box_set_model(GTK_COMBO_BOX(priv->combobox_cm), GTK_TREE_MODEL(cm_model));
445 g_object_unref(cm_model);
446
447 auto renderer = gtk_cell_renderer_text_new();
448 g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
449 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(priv->combobox_cm), renderer, FALSE);
Stepan Salenikovich5039c9b2016-02-12 14:09:51 -0500450 gtk_cell_layout_set_cell_data_func(
451 GTK_CELL_LAYOUT(priv->combobox_cm),
452 renderer,
453 (GtkCellLayoutDataFunc)render_contact_method,
454 nullptr, nullptr);
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500455
456 /* select the last used cm */
457 if (!cms.isEmpty()) {
458 auto last_used_cm = cms.at(0);
459 int last_used_cm_idx = 0;
460 for (int i = 1; i < cms.size(); ++i) {
461 auto new_cm = cms.at(i);
462 if (difftime(new_cm->lastUsed(), last_used_cm->lastUsed()) > 0) {
463 last_used_cm = new_cm;
464 last_used_cm_idx = i;
465 }
466 }
467
468 gtk_combo_box_set_active(GTK_COMBO_BOX(priv->combobox_cm), last_used_cm_idx);
469 }
470
Stepan Salenikovichbbfa4402016-05-04 15:07:29 -0400471 /* if there is only one CM, make the combo box insensitive */
472 if (cms.size() < 2)
473 gtk_widget_set_sensitive(priv->combobox_cm, FALSE);
Stepan Salenikoviche9933242016-06-21 18:08:48 -0400474
475 /* if no CMs make the call button insensitive */
476 gtk_widget_set_sensitive(priv->button_placecall, !cms.isEmpty());
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500477}
478
479static void
480update_name(ChatView *self)
481{
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500482 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
483
484 g_return_if_fail(priv->person || priv->cm);
485
486 QString name;
487 if (priv->person) {
488 name = priv->person->roleData(static_cast<int>(Ring::Role::Name)).toString();
489 } else {
490 name = priv->cm->roleData(static_cast<int>(Ring::Role::Name)).toString();
491 }
492 gtk_label_set_text(GTK_LABEL(priv->label_peer), name.toUtf8().constData());
493}
494
aviau039001d2016-09-29 16:39:05 -0400495static void
aviau039001d2016-09-29 16:39:05 -0400496webkit_chat_container_ready(ChatView* self)
497{
498 /* The webkit chat container has loaded the javascript libraries, we can
499 * now use it. */
500
501 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
502
503 webkit_chat_container_clear(
504 WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container)
505 );
506
aviau039001d2016-09-29 16:39:05 -0400507 /* print the text recordings */
508 if (priv->initial_text_recording)
509 {
510 print_text_recording(priv->initial_text_recording, self);
511 }
512
513 /* connect to the changed signal before setting the cm combo box, so that the correct
514 * conversation will get displayed */
515 if(priv->person)
516 {
517 g_signal_connect(priv->combobox_cm, "changed", G_CALLBACK(selected_cm_changed), self);
518 update_contact_methods(self);
519 update_name(self);
520 }
521}
522
523static void
524build_chat_view(ChatView* self)
525{
526 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
527
528 gtk_container_add(GTK_CONTAINER(priv->box_webkit_chat_container), priv->webkit_chat_container);
529 gtk_widget_show(priv->webkit_chat_container);
530
531
532 g_signal_connect_swapped(
533 priv->webkit_chat_container,
534 "ready",
535 G_CALLBACK(webkit_chat_container_ready),
536 self
537 );
538
539 if (webkit_chat_container_is_ready(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container)))
540 {
541 webkit_chat_container_ready(self);
542 }
543
544}
545
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500546GtkWidget *
aviau039001d2016-09-29 16:39:05 -0400547chat_view_new_call(WebKitChatContainer *webkit_chat_container, Call *call)
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500548{
549 g_return_val_if_fail(call, nullptr);
550
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500551 ChatView *self = CHAT_VIEW(g_object_new(CHAT_VIEW_TYPE, NULL));
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500552
aviau039001d2016-09-29 16:39:05 -0400553 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
554 priv->webkit_chat_container = GTK_WIDGET(webkit_chat_container);
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500555 priv->call = call;
556 auto cm = priv->call->peerContactMethod();
aviau039001d2016-09-29 16:39:05 -0400557 priv->initial_text_recording = cm->textRecording();
558
559 build_chat_view(self);
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500560
561 return (GtkWidget *)self;
562}
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500563
564GtkWidget *
aviau039001d2016-09-29 16:39:05 -0400565chat_view_new_cm(WebKitChatContainer *webkit_chat_container, ContactMethod *cm)
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500566{
567 g_return_val_if_fail(cm, nullptr);
568
569 ChatView *self = CHAT_VIEW(g_object_new(CHAT_VIEW_TYPE, NULL));
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500570
aviau039001d2016-09-29 16:39:05 -0400571 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
572 priv->webkit_chat_container = GTK_WIDGET(webkit_chat_container);
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500573 priv->cm = cm;
aviau039001d2016-09-29 16:39:05 -0400574 priv->initial_text_recording = priv->cm->textRecording();
575
576 build_chat_view(self);
577
Stepan Salenikovichbbfa4402016-05-04 15:07:29 -0400578 update_contact_methods(self);
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500579 update_name(self);
580
581 gtk_widget_show(priv->hbox_chat_info);
582
583 return (GtkWidget *)self;
584}
585
586GtkWidget *
aviau039001d2016-09-29 16:39:05 -0400587chat_view_new_person(WebKitChatContainer *webkit_chat_container, Person *p)
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500588{
589 g_return_val_if_fail(p, nullptr);
590
591 ChatView *self = CHAT_VIEW(g_object_new(CHAT_VIEW_TYPE, NULL));
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500592
aviau039001d2016-09-29 16:39:05 -0400593 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
594 priv->webkit_chat_container = GTK_WIDGET(webkit_chat_container);
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500595 priv->person = p;
596
aviau039001d2016-09-29 16:39:05 -0400597 build_chat_view(self);
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500598
599 gtk_widget_show(priv->hbox_chat_info);
600
601 return (GtkWidget *)self;
602}
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400603
604Call*
605chat_view_get_call(ChatView *self)
606{
607 g_return_val_if_fail(IS_CHAT_VIEW(self), nullptr);
608 auto priv = CHAT_VIEW_GET_PRIVATE(self);
609
610 return priv->call;
611}
612
613ContactMethod*
614chat_view_get_cm(ChatView *self)
615{
616 g_return_val_if_fail(IS_CHAT_VIEW(self), nullptr);
617 auto priv = CHAT_VIEW_GET_PRIVATE(self);
618
619 return priv->cm;
620}
621
622Person*
623chat_view_get_person(ChatView *self)
624{
625 g_return_val_if_fail(IS_CHAT_VIEW(self), nullptr);
626 auto priv = CHAT_VIEW_GET_PRIVATE(self);
627
628 return priv->person;
629}
Stepan Salenikovichdaf3cb32016-10-12 16:39:42 -0400630
631void
632chat_view_set_header_visible(ChatView *self, gboolean visible)
633{
634 auto priv = CHAT_VIEW_GET_PRIVATE(self);
635
636 gtk_widget_set_visible(priv->hbox_chat_info, visible);
637}