chatview.cpp 22.9 KB
Newer Older
1
/*
Guillaume Roguez's avatar
Guillaume Roguez committed
2
 *  Copyright (C) 2016-2017 Savoir-faire Linux Inc.
3
 *  Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
aviau's avatar
aviau committed
4
 *  Author: Alexandre Viau <alexandre.viau@savoirfairelinux.com>
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 *
 *  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.
 */

#include "chatview.h"
22
#include "utils/accounts.h"
23
24
25
26
27
28
29
30
31

#include <gtk/gtk.h>
#include <call.h>
#include <callmodel.h>
#include <contactmethod.h>
#include <person.h>
#include <media/text.h>
#include <media/textrecording.h>
#include "ringnotify.h"
aviau's avatar
aviau committed
32
33
#include "profilemodel.h"
#include "profile.h"
34
#include "numbercategory.h"
Stepan Salenikovich's avatar
Stepan Salenikovich committed
35
#include <QtCore/QDateTime>
36
#include "utils/calling.h"
aviau's avatar
aviau committed
37
#include "webkitchatcontainer.h"
38

39
40
41
42
// LRC
#include <account.h>


43
44
static constexpr GdkRGBA RING_BLUE  = {0.0508, 0.594, 0.676, 1.0}; // outgoing msg color: (13, 152, 173)

45
46
47
48
49
50
51
52
53
54
55
56
57
58
struct _ChatView
{
    GtkBox parent;
};

struct _ChatViewClass
{
    GtkBoxClass parent_class;
};

typedef struct _ChatViewPrivate ChatViewPrivate;

struct _ChatViewPrivate
{
aviau's avatar
aviau committed
59
60
    GtkWidget *box_webkit_chat_container;
    GtkWidget *webkit_chat_container;
61
    GtkWidget *scrolledwindow_chat;
Stepan Salenikovich's avatar
Stepan Salenikovich committed
62
63
64
    GtkWidget *hbox_chat_info;
    GtkWidget *label_peer;
    GtkWidget *combobox_cm;
65
    GtkWidget *label_cm;
66
    GtkWidget *button_close_chatview;
67
    GtkWidget *button_placecall;
68
    GtkWidget *button_send_invitation;
Stepan Salenikovich's avatar
Stepan Salenikovich committed
69
70
71

    /* only one of the three following pointers should be non void;
     * either this is an in-call chat (and so the in-call chat APIs will be used)
aviau's avatar
aviau committed
72
     * or it is an out of call chat (and so the account chat APIs will be used) */
Stepan Salenikovich's avatar
Stepan Salenikovich committed
73
74
75
    Call          *call;
    Person        *person;
    ContactMethod *cm;
76
77

    QMetaObject::Connection new_message_connection;
aviau's avatar
aviau committed
78
    QMetaObject::Connection message_changed_connection;
79
80
    QMetaObject::Connection update_name;
    QMetaObject::Connection update_send_invitation;
81
82

    gulong webkit_ready;
83
    gulong webkit_send_text;
84
85
86
87
88
89
90
91
};

G_DEFINE_TYPE_WITH_PRIVATE(ChatView, chat_view, GTK_TYPE_BOX);

#define CHAT_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CHAT_VIEW_TYPE, ChatViewPrivate))

enum {
    NEW_MESSAGES_DISPLAYED,
92
    HIDE_VIEW_CLICKED,
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
    LAST_SIGNAL
};

static guint chat_view_signals[LAST_SIGNAL] = { 0 };

static void
chat_view_dispose(GObject *object)
{
    ChatView *view;
    ChatViewPrivate *priv;

    view = CHAT_VIEW(object);
    priv = CHAT_VIEW_GET_PRIVATE(view);

    QObject::disconnect(priv->new_message_connection);
aviau's avatar
aviau committed
108
    QObject::disconnect(priv->message_changed_connection);
109
110
    QObject::disconnect(priv->update_name);
    QObject::disconnect(priv->update_send_invitation);
aviau's avatar
aviau committed
111
112
113
114

    /* Destroying the box will also destroy its children, and we wouldn't
     * want that. So we remove the webkit_chat_container from the box. */
    if (priv->webkit_chat_container) {
115
116
117
        /* disconnect for webkit signals */
        g_signal_handler_disconnect(priv->webkit_chat_container, priv->webkit_ready);
        priv->webkit_ready = 0;
118
119
        g_signal_handler_disconnect(priv->webkit_chat_container, priv->webkit_send_text);
        priv->webkit_send_text = 0;
120

aviau's avatar
aviau committed
121
122
123
124
125
        gtk_container_remove(
            GTK_CONTAINER(priv->box_webkit_chat_container),
            GTK_WIDGET(priv->webkit_chat_container)
        );
        priv->webkit_chat_container = nullptr;
126

aviau's avatar
aviau committed
127
    }
128
129
130
131

    G_OBJECT_CLASS(chat_view_parent_class)->dispose(object);
}

132
133
134
135
136
137
static void
hide_chat_view(G_GNUC_UNUSED GtkWidget *widget, ChatView *self)
{
    g_signal_emit(G_OBJECT(self), chat_view_signals[HIDE_VIEW_CLICKED], 0);
}

138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
ContactMethod*
get_active_contactmethod(ChatView *self)
{
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

    if (priv->cm) {
        return priv->cm;
    } else if (priv->person) {
        auto cms = priv->person->phoneNumbers();
        if (cms.size() == 1) {
            return cms.first();
        } else if (cms.size() > 1) {
            auto active = gtk_combo_box_get_active(GTK_COMBO_BOX(priv->combobox_cm));
            if (active >= 0 && active < cms.size()) {
                return cms.at(active);
            }
        }
    }

    return nullptr;
}

160
161
162
163
164
165
166
static void
placecall_clicked(ChatView *self)
{
    auto priv = CHAT_VIEW_GET_PRIVATE(self);

    if (priv->person) {
        // get the chosen cm
167
168
        auto cm = get_active_contactmethod(self);
        if (cm) {
169
170
171
172
173
174
175
176
177
178
179
            place_new_call(cm);
        } else {
            g_warning("no ContactMethod chosen; cannot place call");
        }
    } else if (priv->cm) {
        place_new_call(priv->cm);
    } else {
        g_warning("no Person or ContactMethod set; cannot place call");
    }
}

180
181
182
183
184
static void
button_send_invitation_clicked(ChatView *self)
{
    auto priv = CHAT_VIEW_GET_PRIVATE(self);

185
    if (priv->person) {
186
        priv->cm = get_active_contactmethod(self);
187
    }
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213

    if (!priv->cm) {
        g_warning("invalid contact, cannot send invitation!");
        return;
    }

    // try first to use the account associated to the contact method
    auto account = priv->cm->account();
    if (not account) {

        // get the choosen account
        account = get_active_ring_account();

        if (not account) {
            g_warning("invalid account, cannot send invitation!");
            return;
        }
    }

    // perform the request
    if (not account->sendContactRequest(priv->cm))
        g_warning("contact request not forwarded, cannot send invitation!");

    // TODO : add an entry in the conversation to tell the user an invitation was sent.
}

214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
static void
webkit_chat_container_send_text(G_GNUC_UNUSED GtkWidget* webview, gchar *message, ChatView* self)
{
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

    /* make sure there is more than just whitespace, but if so, send the original text */
    const auto text = QString(message);
    if (!text.trimmed().isEmpty()) {
        QMap<QString, QString> messages;
        messages["text/plain"] = text;

        if (priv->call) {
            // in call message
            priv->call->addOutgoingMedia<Media::Text>()->send(messages);
        } else if (priv->person) {
            // get the chosen cm
230
231
            auto cm = get_active_contactmethod(self);
            if (cm) {
232
233
234
235
236
237
238
239
240
241
242
243
244
245
                if (!cm->sendOfflineTextMessage(messages))
                    g_warning("message failed to send"); // TODO: warn the user about this in the UI
            } else {
                g_warning("no ContactMethod chosen; message not sent");
            }
        } else if (priv->cm) {
            if (!priv->cm->sendOfflineTextMessage(messages))
                g_warning("message failed to send"); // TODO: warn the user about this in the UI
        } else {
            g_warning("no Call, Person, or ContactMethod set; message not sent");
        }
    }
}

246
247
248
249
250
251
252
static void
chat_view_init(ChatView *view)
{
    gtk_widget_init_template(GTK_WIDGET(view));

    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(view);

253
    g_signal_connect(priv->button_close_chatview, "clicked", G_CALLBACK(hide_chat_view), view);
254
    g_signal_connect_swapped(priv->button_placecall, "clicked", G_CALLBACK(placecall_clicked), view);
255
    g_signal_connect_swapped(priv->button_send_invitation, "clicked", G_CALLBACK(button_send_invitation_clicked), view);
256
257
258
259
260
261
262
263
264
265
}

static void
chat_view_class_init(ChatViewClass *klass)
{
    G_OBJECT_CLASS(klass)->dispose = chat_view_dispose;

    gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
                                                "/cx/ring/RingGnome/chatview.ui");

aviau's avatar
aviau committed
266
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, box_webkit_chat_container);
267
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, scrolledwindow_chat);
Stepan Salenikovich's avatar
Stepan Salenikovich committed
268
269
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, hbox_chat_info);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, label_peer);
270
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, label_cm);
Stepan Salenikovich's avatar
Stepan Salenikovich committed
271
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, combobox_cm);
272
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, button_close_chatview);
273
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, button_placecall);
274
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, button_send_invitation);
275
276
277
278
279
280
281
282
283
284

    chat_view_signals[NEW_MESSAGES_DISPLAYED] = g_signal_new (
        "new-messages-displayed",
        G_TYPE_FROM_CLASS(klass),
        (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
        0,
        nullptr,
        nullptr,
        g_cclosure_marshal_VOID__VOID,
        G_TYPE_NONE, 0);
285
286
287
288
289
290
291
292
293
294

    chat_view_signals[HIDE_VIEW_CLICKED] = g_signal_new (
        "hide-view-clicked",
        G_TYPE_FROM_CLASS(klass),
        (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
        0,
        nullptr,
        nullptr,
        g_cclosure_marshal_VOID__VOID,
        G_TYPE_NONE, 0);
295
296
297
298
}



aviau's avatar
aviau committed
299
300
301
302
static void
print_message_to_buffer(ChatView* self, const QModelIndex &idx)
{
    if (!idx.isValid()) {
303
        g_warning("QModelIndex in im model is not valid");
aviau's avatar
aviau committed
304
        return;
305
    }
aviau's avatar
aviau committed
306
307
308
309
310
311
312

    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

    webkit_chat_container_print_new_message(
        WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
        idx
    );
313
314
}

315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
static void
set_participant_images(ChatView* self)
{
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

    webkit_chat_container_clear_sender_images(
        WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container)
    );

    /* Set the sender image for the peer */
    ContactMethod* sender_contact_method_peer;
    QVariant photo_variant_peer;

    if (priv->person)
    {
        photo_variant_peer = priv->person->photo();
        sender_contact_method_peer = get_active_contactmethod(self);
    }
    else
    {
        if (priv->cm)
        {
            sender_contact_method_peer = priv->cm;
        }
        else
        {
            sender_contact_method_peer = priv->call->peerContactMethod();
        }
        photo_variant_peer = sender_contact_method_peer->roleData((int) Call::Role::Photo);
    }

    if (photo_variant_peer.isValid())
    {
        webkit_chat_container_set_sender_image(
            WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
            sender_contact_method_peer,
            photo_variant_peer
        );
    }

    /* set sender image for "ME" */
    auto profile = ProfileModel::instance().selectedProfile();
    if (profile)
    {
        auto person = profile->person();
        if (person)
        {
            auto photo_variant_me = person->photo();
            if (photo_variant_me.isValid())
            {
                webkit_chat_container_set_sender_image(
                    WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
                    nullptr,
                    photo_variant_me
                );
            }
        }
    }
}

375
static void
376
print_text_recording(Media::TextRecording *recording, ChatView *self)
377
378
379
380
{
    g_return_if_fail(IS_CHAT_VIEW(self));
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

381
382
383
     /* set the photos of the chat participants */
     set_participant_images(self);

384
385
386
    /* only text messages are supported for now */
    auto model = recording->instantTextMessagingModel();

387
388
389
390
391
392
    /* new model, disconnect from the old model updates and clear the text buffer */
    QObject::disconnect(priv->new_message_connection);

    /* put all the messages in the im model into the text view */
    for (int row = 0; row < model->rowCount(); ++row) {
        QModelIndex idx = model->index(row, 0);
aviau's avatar
aviau committed
393
        print_message_to_buffer(self, idx);
394
    }
395
396
    /* mark all messages as read */
    recording->setAllRead();
397

aviau's avatar
aviau committed
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412

    /* messages modified */
    /* connecting on instantMessagingModel and not textMessagingModel */
    priv->message_changed_connection = QObject::connect(
        model,
        &QAbstractItemModel::dataChanged,
        [self, priv] (const QModelIndex & topLeft, G_GNUC_UNUSED const QModelIndex & bottomRight)
        {
            webkit_chat_container_update_message(
                WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
                topLeft
            );
        }
    );

413
414
415
416
417
418
419
    /* append new messages */
    priv->new_message_connection = QObject::connect(
        model,
        &QAbstractItemModel::rowsInserted,
        [self, priv, model] (const QModelIndex &parent, int first, int last) {
            for (int row = first; row <= last; ++row) {
                QModelIndex idx = model->index(row, 0, parent);
aviau's avatar
aviau committed
420
                print_message_to_buffer(self, idx);
421
422
                /* make sure these messages are marked as read */
                model->setData(idx, true, static_cast<int>(Media::TextRecording::Role::IsRead));
423
424
425
426
427
428
                g_signal_emit(G_OBJECT(self), chat_view_signals[NEW_MESSAGES_DISPLAYED], 0);
            }
        }
    );
}

429
430
431
432
433
434
435
436
437
438
439
440
static void
update_send_invitation(ChatView *self)
{
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

    auto cm = get_active_contactmethod(self);

    if (cm && cm->isConfirmed()) {
        gtk_widget_hide(priv->button_send_invitation);
    }
}

Stepan Salenikovich's avatar
Stepan Salenikovich committed
441
static void
442
selected_cm_changed(ChatView *self)
Stepan Salenikovich's avatar
Stepan Salenikovich committed
443
{
444
445
446
447
448
    auto priv = CHAT_VIEW_GET_PRIVATE(self);

    /* make sure the webkit view is ready, in case we get this signal before it is */
    if (!webkit_chat_container_is_ready(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container)))
        return;
Stepan Salenikovich's avatar
Stepan Salenikovich committed
449

450
451
452
    auto cm = get_active_contactmethod(self);
    if (cm){
        print_text_recording(cm->textRecording(), self);
453
454
455
456
457
458
459

        QObject::disconnect(priv->update_send_invitation);
        priv->update_send_invitation = QObject::connect(
            get_active_contactmethod(self),
            &ContactMethod::changed,
            [self] () { update_send_invitation(self); }
        );
Stepan Salenikovich's avatar
Stepan Salenikovich committed
460
461
462
463
464
    } else {
        g_warning("no valid ContactMethod selected to display chat conversation");
    }
}

465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
static void
render_contact_method(G_GNUC_UNUSED GtkCellLayout *cell_layout,
                     GtkCellRenderer *cell,
                     GtkTreeModel *model,
                     GtkTreeIter *iter,
                     G_GNUC_UNUSED gpointer data)
{
    GValue value = G_VALUE_INIT;
    gtk_tree_model_get_value(model, iter, 0, &value);
    auto cm = (ContactMethod *)g_value_get_pointer(&value);

    gchar *number = nullptr;
    if (cm && cm->category()) {
        // try to get the number category, eg: "home"
        number = g_strdup_printf("(%s) %s", cm->category()->name().toUtf8().constData(),
480
                                            cm->bestId().toUtf8().constData());
481
    } else if (cm) {
482
        number = g_strdup_printf("%s", cm->bestId().toUtf8().constData());
483
484
485
486
487
488
    }

    g_object_set(G_OBJECT(cell), "text", number, NULL);
    g_free(number);
}

Stepan Salenikovich's avatar
Stepan Salenikovich committed
489
490
491
492
493
494
static void
update_contact_methods(ChatView *self)
{
    g_return_if_fail(IS_CHAT_VIEW(self));
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

495
    g_return_if_fail(priv->call || priv->person || priv->cm);
Stepan Salenikovich's avatar
Stepan Salenikovich committed
496
497
498

    /* model for the combobox for the choice of ContactMethods */
    auto cm_model = gtk_list_store_new(
499
        1, G_TYPE_POINTER
Stepan Salenikovich's avatar
Stepan Salenikovich committed
500
501
    );

502
503
504
505
    Person::ContactMethods cms;

    if (priv->person)
        cms = priv->person->phoneNumbers();
506
    else if (priv->cm)
507
        cms << priv->cm;
508
509
    else if (priv->call)
        cms << priv->call->peerContactMethod();
510

Stepan Salenikovich's avatar
Stepan Salenikovich committed
511
512
513
514
    for (int i = 0; i < cms.size(); ++i) {
        GtkTreeIter iter;
        gtk_list_store_append(cm_model, &iter);
        gtk_list_store_set(cm_model, &iter,
515
                           0, cms.at(i),
Stepan Salenikovich's avatar
Stepan Salenikovich committed
516
517
518
519
520
521
522
523
524
                           -1);
    }

    gtk_combo_box_set_model(GTK_COMBO_BOX(priv->combobox_cm), GTK_TREE_MODEL(cm_model));
    g_object_unref(cm_model);

    auto renderer = gtk_cell_renderer_text_new();
    g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
    gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(priv->combobox_cm), renderer, FALSE);
525
526
527
528
529
    gtk_cell_layout_set_cell_data_func(
        GTK_CELL_LAYOUT(priv->combobox_cm),
        renderer,
        (GtkCellLayoutDataFunc)render_contact_method,
        nullptr, nullptr);
Stepan Salenikovich's avatar
Stepan Salenikovich committed
530
531
532
533
534
535
536
537
538
539
540
541
542
543

    /* select the last used cm */
    if (!cms.isEmpty()) {
        auto last_used_cm = cms.at(0);
        int last_used_cm_idx = 0;
        for (int i = 1; i < cms.size(); ++i) {
            auto new_cm = cms.at(i);
            if (difftime(new_cm->lastUsed(), last_used_cm->lastUsed()) > 0) {
                last_used_cm = new_cm;
                last_used_cm_idx = i;
            }
        }

        gtk_combo_box_set_active(GTK_COMBO_BOX(priv->combobox_cm), last_used_cm_idx);
544
545
546

        if (last_used_cm->isConfirmed())
            gtk_widget_hide(priv->button_send_invitation);
Stepan Salenikovich's avatar
Stepan Salenikovich committed
547
548
    }

549
    /* if there is only one CM, make the combo box insensitive */
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
    if (cms.size() < 2) {
        auto active = cms.at(gtk_combo_box_get_active(GTK_COMBO_BOX(priv->combobox_cm)));
        std::string ring_id = active->roleData(static_cast<int>(Ring::Role::Number)).toString().toUtf8().constData();
        std::string displayed = gtk_label_get_text(GTK_LABEL(priv->label_peer));
        gtk_label_set_text(GTK_LABEL(priv->label_cm), ring_id.c_str());
        gtk_widget_hide(priv->combobox_cm);
        if (displayed == ring_id) {
            gtk_widget_hide(priv->label_cm);
        } else {
            gtk_widget_show(priv->label_cm);
        }
    } else {
        gtk_widget_show(priv->combobox_cm);
        gtk_widget_hide(priv->label_cm);
    }
565
566
567

    /* if no CMs make the call button insensitive */
    gtk_widget_set_sensitive(priv->button_placecall, !cms.isEmpty());
Stepan Salenikovich's avatar
Stepan Salenikovich committed
568
569
570
}

static void
571
update_name(ChatView *self)
Stepan Salenikovich's avatar
Stepan Salenikovich committed
572
573
574
{
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

575
    g_return_if_fail(priv->person || priv->cm || priv->call);
Stepan Salenikovich's avatar
Stepan Salenikovich committed
576
577
578
579

    QString name;
    if (priv->person) {
        name = priv->person->roleData(static_cast<int>(Ring::Role::Name)).toString();
580
    } else if (priv->cm) {
Stepan Salenikovich's avatar
Stepan Salenikovich committed
581
        name = priv->cm->roleData(static_cast<int>(Ring::Role::Name)).toString();
582
583
    } else if (priv->call) {
        name = priv->call->peerContactMethod()->roleData(static_cast<int>(Ring::Role::Name)).toString();
Stepan Salenikovich's avatar
Stepan Salenikovich committed
584
585
586
587
    }
    gtk_label_set_text(GTK_LABEL(priv->label_peer), name.toUtf8().constData());
}

aviau's avatar
aviau committed
588
589
590
591
592
593
594
595
596
597
598
599
600
static void
webkit_chat_container_ready(ChatView* self)
{
    /* The webkit chat container has loaded the javascript libraries, we can
     * now use it. */

    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

    webkit_chat_container_clear(
        WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container)
    );

    /* print the text recordings */
601
602
603
604
605
606
607
    if (priv->call) {
        print_text_recording(priv->call->peerContactMethod()->textRecording(), self);
    } else if (priv->cm) {
        print_text_recording(priv->cm->textRecording(), self);
    } else if (priv->person) {
        /* get the selected cm and print the text recording */
        selected_cm_changed(self);
aviau's avatar
aviau committed
608
609
610
611
612
613
614
615
616
617
618
    }
}

static void
build_chat_view(ChatView* self)
{
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

    gtk_container_add(GTK_CONTAINER(priv->box_webkit_chat_container), priv->webkit_chat_container);
    gtk_widget_show(priv->webkit_chat_container);

619
620
    /* keep name updated */
    if (priv->call) {
621
        priv->update_name = QObject::connect(
622
623
            priv->call,
            &Call::changed,
624
            [self] () { update_name(self); }
625
626
        );
    } else if (priv->cm) {
627
        priv->update_name = QObject::connect(
628
629
            priv->cm,
            &ContactMethod::changed,
630
            [self] () { update_name(self); }
631
632
        );
    } else if (priv->person) {
633
        priv->update_name = QObject::connect(
634
635
            priv->person,
            &Person::changed,
636
            [self] () { update_name(self); }
637
638
        );
    }
639
640
641
642
643
644
645
646
647

    priv->update_send_invitation = QObject::connect(
        get_active_contactmethod(self),
        &ContactMethod::changed,
        [self] () { update_send_invitation(self); }
    );

    update_name(self);
    update_send_invitation(self);
648
649
650
651

    /* keep selected cm updated */
    update_contact_methods(self);
    g_signal_connect_swapped(priv->combobox_cm, "changed", G_CALLBACK(selected_cm_changed), self);
aviau's avatar
aviau committed
652

653
    priv->webkit_ready = g_signal_connect_swapped(
aviau's avatar
aviau committed
654
655
656
657
658
659
        priv->webkit_chat_container,
        "ready",
        G_CALLBACK(webkit_chat_container_ready),
        self
    );

660
661
662
663
664
    priv->webkit_send_text = g_signal_connect(priv->webkit_chat_container,
        "send-message",
        G_CALLBACK(webkit_chat_container_send_text),
        self);

aviau's avatar
aviau committed
665
666
667
    if (webkit_chat_container_is_ready(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container)))
        webkit_chat_container_ready(self);

668
669
    /* we only show the chat info in the case of cm / person */
    gtk_widget_set_visible(priv->hbox_chat_info, (priv->cm || priv->person));
aviau's avatar
aviau committed
670
671
}

672
GtkWidget *
aviau's avatar
aviau committed
673
chat_view_new_call(WebKitChatContainer *webkit_chat_container, Call *call)
674
{
Stepan Salenikovich's avatar
Stepan Salenikovich committed
675
676
    g_return_val_if_fail(call, nullptr);

677
678
    ChatView *self = CHAT_VIEW(g_object_new(CHAT_VIEW_TYPE, NULL));

aviau's avatar
aviau committed
679
680
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
    priv->webkit_chat_container = GTK_WIDGET(webkit_chat_container);
681
    priv->call = call;
aviau's avatar
aviau committed
682
683

    build_chat_view(self);
684
685
686

    return (GtkWidget *)self;
}
Stepan Salenikovich's avatar
Stepan Salenikovich committed
687
688

GtkWidget *
aviau's avatar
aviau committed
689
chat_view_new_cm(WebKitChatContainer *webkit_chat_container, ContactMethod *cm)
Stepan Salenikovich's avatar
Stepan Salenikovich committed
690
691
692
693
694
{
    g_return_val_if_fail(cm, nullptr);

    ChatView *self = CHAT_VIEW(g_object_new(CHAT_VIEW_TYPE, NULL));

aviau's avatar
aviau committed
695
696
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
    priv->webkit_chat_container = GTK_WIDGET(webkit_chat_container);
Stepan Salenikovich's avatar
Stepan Salenikovich committed
697
    priv->cm = cm;
aviau's avatar
aviau committed
698
699
700

    build_chat_view(self);

Stepan Salenikovich's avatar
Stepan Salenikovich committed
701
702
703
704
    return (GtkWidget *)self;
}

GtkWidget *
aviau's avatar
aviau committed
705
chat_view_new_person(WebKitChatContainer *webkit_chat_container, Person *p)
Stepan Salenikovich's avatar
Stepan Salenikovich committed
706
707
708
709
710
{
    g_return_val_if_fail(p, nullptr);

    ChatView *self = CHAT_VIEW(g_object_new(CHAT_VIEW_TYPE, NULL));

aviau's avatar
aviau committed
711
712
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
    priv->webkit_chat_container = GTK_WIDGET(webkit_chat_container);
Stepan Salenikovich's avatar
Stepan Salenikovich committed
713
714
    priv->person = p;

aviau's avatar
aviau committed
715
    build_chat_view(self);
Stepan Salenikovich's avatar
Stepan Salenikovich committed
716
717
718

    return (GtkWidget *)self;
}
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745

Call*
chat_view_get_call(ChatView *self)
{
    g_return_val_if_fail(IS_CHAT_VIEW(self), nullptr);
    auto priv = CHAT_VIEW_GET_PRIVATE(self);

    return priv->call;
}

ContactMethod*
chat_view_get_cm(ChatView *self)
{
    g_return_val_if_fail(IS_CHAT_VIEW(self), nullptr);
    auto priv = CHAT_VIEW_GET_PRIVATE(self);

    return priv->cm;
}

Person*
chat_view_get_person(ChatView *self)
{
    g_return_val_if_fail(IS_CHAT_VIEW(self), nullptr);
    auto priv = CHAT_VIEW_GET_PRIVATE(self);

    return priv->person;
}
746
747
748
749
750
751
752
753

void
chat_view_set_header_visible(ChatView *self, gboolean visible)
{
    auto priv = CHAT_VIEW_GET_PRIVATE(self);

    gtk_widget_set_visible(priv->hbox_chat_info, visible);
}