~ubuntu-branches/ubuntu/trusty/gnome-shell/trusty-proposed

« back to all changes in this revision

Viewing changes to js/ui/telepathyClient.js

Tags: upstream-3.3.90
ImportĀ upstreamĀ versionĀ 3.3.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
2
2
 
3
 
const DBus = imports.dbus;
4
3
const Gio = imports.gi.Gio;
5
4
const GLib = imports.gi.GLib;
6
5
const Lang = imports.lang;
34
33
    RECEIVED: 'chat-received'
35
34
};
36
35
 
37
 
let contactFeatures = [Tp.ContactFeature.ALIAS,
38
 
                        Tp.ContactFeature.AVATAR_DATA,
39
 
                        Tp.ContactFeature.PRESENCE];
40
 
 
41
 
// This is GNOME Shell's implementation of the Telepathy 'Client'
42
 
// interface. Specifically, the shell is a Telepathy 'Observer', which
43
 
// lets us see messages even if they belong to another app (eg,
44
 
// Empathy).
45
 
 
46
36
function makeMessageFromTpMessage(tpMessage, direction) {
47
37
    let [text, flags] = tpMessage.to_text();
48
38
 
73
63
    };
74
64
}
75
65
 
76
 
function Client() {
77
 
    this._init();
78
 
};
 
66
const Client = new Lang.Class({
 
67
    Name: 'Client',
79
68
 
80
 
Client.prototype = {
81
69
    _init : function() {
82
70
        // channel path -> ChatSource
83
71
        this._chatSources = {};
86
74
        // account path -> AccountNotification
87
75
        this._accountNotifications = {};
88
76
 
 
77
        // Define features we want
 
78
        this._accountManager = Tp.AccountManager.dup();
 
79
        let factory = this._accountManager.get_factory();
 
80
        factory.add_account_features([Tp.Account.get_feature_quark_connection()]);
 
81
        factory.add_connection_features([Tp.Connection.get_feature_quark_contact_list()]);
 
82
        factory.add_channel_features([Tp.Channel.get_feature_quark_contacts()]);
 
83
        factory.add_contact_features([Tp.ContactFeature.ALIAS,
 
84
                                      Tp.ContactFeature.AVATAR_DATA,
 
85
                                      Tp.ContactFeature.PRESENCE,
 
86
                                      Tp.ContactFeature.SUBSCRIPTION_STATES]);
 
87
 
89
88
        // Set up a SimpleObserver, which will call _observeChannels whenever a
90
89
        // channel matching its filters is detected.
91
90
        // The second argument, recover, means _observeChannels will be run
92
91
        // for any existing channel as well.
93
 
        this._accountManager = Tp.AccountManager.dup();
94
92
        this._tpClient = new Shell.TpClient({ 'account-manager': this._accountManager,
95
93
                                              'name': 'GnomeShell',
96
94
                                              'uniquify-name': true })
117
115
            throw new Error('Couldn\'t register Telepathy client. Error: \n' + e);
118
116
        }
119
117
 
120
 
 
121
118
        // Watch subscription requests and connection errors
122
119
        this._subscriptionSource = null;
123
120
        this._accountSource = null;
124
 
        let factory = this._accountManager.get_factory();
125
 
        factory.add_account_features([Tp.Account.get_feature_quark_connection()]);
126
 
        factory.add_connection_features([Tp.Connection.get_feature_quark_contact_list()]);
127
 
        factory.add_contact_features([Tp.ContactFeature.SUBSCRIPTION_STATES,
128
 
                                      Tp.ContactFeature.ALIAS,
129
 
                                      Tp.ContactFeature.AVATAR_DATA]);
130
121
 
131
122
        this._accountManager.connect('account-validity-changed',
132
123
            Lang.bind(this, this._accountValidityChanged));
136
127
 
137
128
    _observeChannels: function(observer, account, conn, channels,
138
129
                               dispatchOp, requests, context) {
139
 
        // If the self_contact doesn't have the ALIAS, make sure
140
 
        // to fetch it before trying to grab the channels.
141
 
        let self_contact = conn.get_self_contact();
142
 
        if (self_contact.has_feature(Tp.ContactFeature.ALIAS)) {
143
 
            this._finishObserveChannels(account, conn, channels, context);
144
 
        } else {
145
 
            Shell.get_self_contact_features(conn,
146
 
                                            contactFeatures,
147
 
                                            Lang.bind(this, function() {
148
 
                                                this._finishObserveChannels(account, conn, channels, context);
149
 
                                            }));
150
 
            context.delay();
151
 
        }
152
 
    },
153
 
 
154
 
    _finishObserveChannels: function(account, conn, channels, context) {
155
130
        let len = channels.length;
156
131
        for (let i = 0; i < len; i++) {
157
132
            let channel = channels[i];
162
137
               targetHandleType != Tp.HandleType.CONTACT)
163
138
               continue;
164
139
 
165
 
            /* Request a TpContact */
166
 
            Shell.get_tp_contacts(conn, [targetHandle],
167
 
                    contactFeatures,
168
 
                    Lang.bind(this,  function (connection, contacts, failed) {
169
 
                        if (contacts.length < 1)
170
 
                            return;
171
 
 
172
 
                        /* We got the TpContact */
173
 
                        this._createChatSource(account, conn, channel, contacts[0]);
174
 
                    }), null);
 
140
            this._createChatSource(account, conn, channel, channel.get_target_contact());
175
141
        }
176
142
 
177
143
        context.accept();
200
166
 
201
167
    _handleChannels: function(handler, account, conn, channels,
202
168
                              requests, user_action_time, context) {
203
 
        this._handlingChannels(account, conn, channels);
 
169
        this._handlingChannels(account, conn, channels, true);
204
170
        context.accept();
205
171
    },
206
172
 
207
 
    _handlingChannels: function(account, conn, channels) {
 
173
    _handlingChannels: function(account, conn, channels, notify) {
208
174
        let len = channels.length;
209
175
        for (let i = 0; i < len; i++) {
210
176
            let channel = channels[i];
215
181
                continue;
216
182
            }
217
183
 
218
 
            if (this._tpClient.is_handling_channel(channel)) {
 
184
            // 'notify' will be true when coming from an actual HandleChannels
 
185
            // call, and not when from a successful Claim call. The point is
 
186
            // we don't want to notify for a channel we just claimed which
 
187
            // has no new messages (for example, a new channel which only has
 
188
            // a delivery notification). We rely on _displayPendingMessages()
 
189
            // and _messageReceived() to notify for new messages.
 
190
 
 
191
            // But we should still notify from HandleChannels because the
 
192
            // Telepathy spec states that handlers must foreground channels
 
193
            // in HandleChannels calls which are already being handled.
 
194
 
 
195
            if (notify && this._tpClient.is_handling_channel(channel)) {
219
196
                // We are already handling the channel, display the source
220
197
                let source = this._chatSources[channel.get_object_path()];
221
198
                if (source)
226
203
 
227
204
    _displayRoomInvitation: function(conn, channel, dispatchOp, context) {
228
205
        // We can only approve the rooms if we have been invited to it
229
 
        let selfHandle = channel.group_get_self_handle();
230
 
        if (selfHandle == 0) {
 
206
        let selfContact = channel.group_get_self_contact();
 
207
        if (selfContact == null) {
231
208
            Shell.decline_dispatch_op(context, 'Not invited to the room');
232
209
            return;
233
210
        }
234
211
 
235
 
        let [invited, inviter, reason, msg] = channel.group_get_local_pending_info(selfHandle);
 
212
        let [invited, inviter, reason, msg] = channel.group_get_local_pending_contact_info(selfContact);
236
213
        if (!invited) {
237
214
            Shell.decline_dispatch_op(context, 'Not invited to the room');
238
215
            return;
239
216
        }
240
217
 
241
 
        // Request a TpContact for the inviter
242
 
        Shell.get_tp_contacts(conn, [inviter],
243
 
                contactFeatures,
244
 
                Lang.bind(this, this._createRoomInviteSource, channel, context, dispatchOp));
245
 
 
246
 
        context.delay();
247
 
     },
248
 
 
249
 
    _createRoomInviteSource: function(connection, contacts, failed, channel, context, dispatchOp) {
250
 
        if (contacts.length < 1) {
251
 
            Shell.decline_dispatch_op(context, 'Failed to get inviter');
252
 
            return;
253
 
        }
254
 
 
255
 
        // We got the TpContact
256
 
 
257
218
        // FIXME: We don't have a 'chat room' icon (bgo #653737) use
258
219
        // system-users for now as Empathy does.
259
220
        let source = new ApproverSource(dispatchOp, _("Invitation"),
260
221
                                        Gio.icon_new_for_string('system-users'));
261
222
        Main.messageTray.add(source);
262
223
 
263
 
        let notif = new RoomInviteNotification(source, dispatchOp, channel, contacts[0]);
 
224
        let notif = new RoomInviteNotification(source, dispatchOp, channel, inviter);
264
225
        source.notify(notif);
265
226
        context.accept();
266
227
    },
272
233
 
273
234
        if (chanType == Tp.IFACE_CHANNEL_TYPE_TEXT)
274
235
            this._approveTextChannel(account, conn, channel, dispatchOp, context);
275
 
        else if (chanType == Tp.IFACE_CHANNEL_TYPE_STREAMED_MEDIA ||
276
 
                 chanType == 'org.freedesktop.Telepathy.Channel.Type.Call.DRAFT')
 
236
        else if (chanType == Tp.IFACE_CHANNEL_TYPE_CALL)
277
237
            this._approveCall(account, conn, channel, dispatchOp, context);
278
238
        else if (chanType == Tp.IFACE_CHANNEL_TYPE_FILE_TRANSFER)
279
239
            this._approveFileTransfer(account, conn, channel, dispatchOp, context);
288
248
                                        Lang.bind(this, function(dispatchOp, result) {
289
249
                try {
290
250
                    dispatchOp.claim_with_finish(result);
291
 
                    this._handlingChannels(account, conn, [channel]);
 
251
                    this._handlingChannels(account, conn, [channel], false);
292
252
                } catch (err) {
293
253
                    throw new Error('Failed to Claim channel: ' + err);
294
254
                }}));
300
260
    },
301
261
 
302
262
    _approveCall: function(account, conn, channel, dispatchOp, context) {
303
 
        let [targetHandle, targetHandleType] = channel.get_handle();
304
 
 
305
 
        Shell.get_tp_contacts(conn, [targetHandle],
306
 
                contactFeatures,
307
 
                Lang.bind(this, this._createAudioVideoSource, channel, context, dispatchOp));
308
 
 
309
 
        context.delay();
310
 
    },
311
 
 
312
 
    _createAudioVideoSource: function(connection, contacts, failed, channel, context, dispatchOp) {
313
 
        if (contacts.length < 1) {
314
 
            Shell.decline_dispatch_op(context, 'Failed to get inviter');
315
 
            return;
316
 
        }
317
 
 
318
263
        let isVideo = false;
319
264
 
320
265
        let props = channel.borrow_immutable_properties();
321
266
 
322
 
        if (props['org.freedesktop.Telepathy.Channel.Type.Call.DRAFT.InitialVideo'] ||
323
 
            props[Tp.PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_VIDEO])
 
267
        if (props[Tp.PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO])
324
268
          isVideo = true;
325
269
 
326
270
        // We got the TpContact
329
273
                                        Gio.icon_new_for_string('audio-input-microphone'));
330
274
        Main.messageTray.add(source);
331
275
 
332
 
        let notif = new AudioVideoNotification(source, dispatchOp, channel, contacts[0], isVideo);
 
276
        let notif = new AudioVideoNotification(source, dispatchOp, channel,
 
277
            channel.get_target_contact(), isVideo);
333
278
        source.notify(notif);
334
279
        context.accept();
335
280
    },
336
281
 
337
282
    _approveFileTransfer: function(account, conn, channel, dispatchOp, context) {
338
 
        let [targetHandle, targetHandleType] = channel.get_handle();
339
 
 
340
 
        Shell.get_tp_contacts(conn, [targetHandle],
341
 
                contactFeatures,
342
 
                Lang.bind(this, this._createFileTransferSource, channel, context, dispatchOp));
343
 
 
344
 
        context.delay();
345
 
    },
346
 
 
347
 
    _createFileTransferSource: function(connection, contacts, failed, channel, context, dispatchOp) {
348
 
        if (contacts.length < 1) {
349
 
            Shell.decline_dispatch_op(context, 'Failed to get file sender');
350
 
            return;
351
 
        }
352
 
 
353
283
        // Use the icon of the file being transferred
354
284
        let gicon = Gio.content_type_get_icon(channel.get_mime_type());
355
285
 
357
287
        let source = new ApproverSource(dispatchOp, _("File Transfer"), gicon);
358
288
        Main.messageTray.add(source);
359
289
 
360
 
        let notif = new FileTransferNotification(source, dispatchOp, channel, contacts[0]);
 
290
        let notif = new FileTransferNotification(source, dispatchOp, channel,
 
291
            channel.get_target_contact());
361
292
        source.notify(notif);
362
293
        context.accept();
363
294
    },
480
411
 
481
412
        return this._accountSource;
482
413
    }
483
 
};
484
 
 
485
 
function ChatSource(account, conn, channel, contact, client) {
486
 
    this._init(account, conn, channel, contact, client);
487
 
}
488
 
 
489
 
ChatSource.prototype = {
490
 
    __proto__:  MessageTray.Source.prototype,
 
414
});
 
415
 
 
416
const ChatSource = new Lang.Class({
 
417
    Name: 'ChatSource',
 
418
    Extends: MessageTray.Source,
491
419
 
492
420
    _init: function(account, conn, channel, contact, client) {
493
 
        MessageTray.Source.prototype._init.call(this, contact.get_alias());
 
421
        this.parent(contact.get_alias());
494
422
 
495
423
        this.isChat = true;
496
424
 
508
436
        this._notification.setUrgency(MessageTray.Urgency.HIGH);
509
437
        this._notifyTimeoutId = 0;
510
438
 
511
 
        // We ack messages when the message box is collapsed if user has
512
 
        // interacted with it before and so read the messages:
513
 
        // - user clicked on it the tray
514
 
        // - user expanded the notification by hovering over the toaster notification
515
 
        this._shouldAck = false;
516
 
 
517
 
        this.connect('summary-item-clicked', Lang.bind(this, this._summaryItemClicked));
518
 
        this._notification.connect('expanded', Lang.bind(this, this._notificationExpanded));
519
 
        this._notification.connect('collapsed', Lang.bind(this, this._notificationCollapsed));
 
439
        // We ack messages when the user expands the new notification or views the summary
 
440
        // notification, in which case the notification is also expanded.
 
441
        this._notification.connect('expanded', Lang.bind(this, this._ackMessages));
520
442
 
521
443
        this._presence = contact.get_presence_type();
522
444
 
698
620
    },
699
621
 
700
622
    notify: function() {
701
 
        MessageTray.Source.prototype.notify.call(this, this._notification);
 
623
        this.parent(this._notification);
702
624
    },
703
625
 
704
626
    respond: function(text) {
740
662
        if (presence == Tp.ConnectionPresenceType.AVAILABLE) {
741
663
            msg = _("%s is online.").format(title);
742
664
            shouldNotify = (this._presence == Tp.ConnectionPresenceType.OFFLINE);
743
 
        } else if (presence == Tp.ConnectionPresenceType.OFFLINE ||
744
 
                   presence == Tp.ConnectionPresenceType.EXTENDED_AWAY) {
 
665
        } else if (presence == Tp.ConnectionPresenceType.OFFLINE) {
745
666
            presence = Tp.ConnectionPresenceType.OFFLINE;
746
667
            msg = _("%s is offline.").format(title);
747
668
            shouldNotify = (this._presence != Tp.ConnectionPresenceType.OFFLINE);
748
 
        } else if (presence == Tp.ConnectionPresenceType.AWAY) {
 
669
        } else if (presence == Tp.ConnectionPresenceType.AWAY ||
 
670
                   presence == Tp.ConnectionPresenceType.EXTENDED_AWAY) {
749
671
            msg = _("%s is away.").format(title);
750
672
            shouldNotify = false;
751
673
        } else if (presence == Tp.ConnectionPresenceType.BUSY) {
780
702
        // 'pending-message-removed' for each one.
781
703
        this._channel.ack_all_pending_messages_async(Lang.bind(this, function(src, result) {
782
704
            this._channel.ack_all_pending_messages_finish(result);}));
783
 
    },
784
 
 
785
 
    _summaryItemClicked: function(source, button) {
786
 
        if (button != 1)
787
 
            return;
788
 
 
789
 
        this._shouldAck = true;
790
 
    },
791
 
 
792
 
    _notificationExpanded: function() {
793
 
        this._shouldAck = true;
794
 
    },
795
 
 
796
 
    _notificationCollapsed: function() {
797
 
        if (this._shouldAck)
798
 
            this._ackMessages();
799
 
 
800
 
        this._shouldAck = false;
801
705
    }
802
 
};
803
 
 
804
 
function ChatNotification(source) {
805
 
    this._init(source);
806
 
}
807
 
 
808
 
ChatNotification.prototype = {
809
 
    __proto__:  MessageTray.Notification.prototype,
 
706
});
 
707
 
 
708
const ChatNotification = new Lang.Class({
 
709
    Name: 'ChatNotification',
 
710
    Extends: MessageTray.Notification,
810
711
 
811
712
    _init: function(source) {
812
 
        MessageTray.Notification.prototype._init.call(this, source, source.title, null, { customContent: true });
 
713
        this.parent(source, source.title, null, { customContent: true });
813
714
        this.setResident(true);
814
715
 
815
716
        this._responseEntry = new St.Entry({ style_class: 'chat-response',
900
801
        }
901
802
 
902
803
        let groups = this._contentArea.get_children();
903
 
        for (let i = 0; i < groups.length; i ++) {
 
804
        for (let i = 0; i < groups.length; i++) {
904
805
            let group = groups[i];
905
806
            if (group.get_children().length == 0)
906
807
                group.destroy();
938
839
        let body = highlighter.actor;
939
840
 
940
841
        let styles = props.styles;
941
 
        for (let i = 0; i < styles.length; i ++)
 
842
        for (let i = 0; i < styles.length; i++)
942
843
            body.add_style_class_name(styles[i]);
943
844
 
944
845
        let group = props.group;
1092
993
            this.source.setChatState(Tp.ChannelChatState.ACTIVE);
1093
994
        }
1094
995
    }
1095
 
};
1096
 
 
1097
 
function ApproverSource(dispatchOp, text, gicon) {
1098
 
    this._init(dispatchOp, text, gicon);
1099
 
}
1100
 
 
1101
 
ApproverSource.prototype = {
1102
 
    __proto__: MessageTray.Source.prototype,
 
996
});
 
997
 
 
998
const ApproverSource = new Lang.Class({
 
999
    Name: 'ApproverSource',
 
1000
    Extends: MessageTray.Source,
1103
1001
 
1104
1002
    _init: function(dispatchOp, text, gicon) {
1105
 
        MessageTray.Source.prototype._init.call(this, text);
 
1003
        this.parent(text);
1106
1004
 
1107
1005
        this._gicon = gicon;
1108
1006
        this._setSummaryIcon(this.createNotificationIcon());
1123
1021
            this._invalidId = 0;
1124
1022
        }
1125
1023
 
1126
 
        MessageTray.Source.prototype.destroy.call(this);
 
1024
        this.parent();
1127
1025
    },
1128
1026
 
1129
1027
    createNotificationIcon: function() {
1131
1029
                             icon_type: St.IconType.FULLCOLOR,
1132
1030
                             icon_size: this.ICON_SIZE });
1133
1031
    }
1134
 
}
1135
 
 
1136
 
function RoomInviteNotification(source, dispatchOp, channel, inviter) {
1137
 
    this._init(source, dispatchOp, channel, inviter);
1138
 
}
1139
 
 
1140
 
RoomInviteNotification.prototype = {
1141
 
    __proto__: MessageTray.Notification.prototype,
 
1032
});
 
1033
 
 
1034
const RoomInviteNotification = new Lang.Class({
 
1035
    Name: 'RoomInviteNotification',
 
1036
    Extends: MessageTray.Notification,
1142
1037
 
1143
1038
    _init: function(source, dispatchOp, channel, inviter) {
1144
 
        MessageTray.Notification.prototype._init.call(this,
1145
 
                                                      source,
1146
 
                                                      /* translators: argument is a room name like
1147
 
                                                       * room@jabber.org for example. */
1148
 
                                                      _("Invitation to %s").format(channel.get_identifier()),
1149
 
                                                      null,
1150
 
                                                      { customContent: true });
 
1039
        this.parent(source,
 
1040
                    /* translators: argument is a room name like
 
1041
                     * room@jabber.org for example. */
 
1042
                    _("Invitation to %s").format(channel.get_identifier()),
 
1043
                    null,
 
1044
                    { customContent: true });
1151
1045
        this.setResident(true);
1152
1046
 
1153
1047
        /* translators: first argument is the name of a contact and the second
1174
1068
            this.destroy();
1175
1069
        }));
1176
1070
    }
1177
 
};
 
1071
});
1178
1072
 
1179
1073
// Audio Video
1180
 
function AudioVideoNotification(source, dispatchOp, channel, contact, isVideo) {
1181
 
    this._init(source, dispatchOp, channel, contact, isVideo);
1182
 
}
1183
 
 
1184
 
AudioVideoNotification.prototype = {
1185
 
    __proto__: MessageTray.Notification.prototype,
 
1074
const AudioVideoNotification = new Lang.Class({
 
1075
    Name: 'AudioVideoNotification',
 
1076
    Extends: MessageTray.Notification,
1186
1077
 
1187
1078
    _init: function(source, dispatchOp, channel, contact, isVideo) {
1188
1079
        let title = '';
1194
1085
             /* translators: argument is a contact name like Alice for example. */
1195
1086
            title = _("Call from %s").format(contact.get_alias());
1196
1087
 
1197
 
        MessageTray.Notification.prototype._init.call(this,
1198
 
                                                      source,
1199
 
                                                      title,
1200
 
                                                      null,
1201
 
                                                      { customContent: true });
 
1088
        this.parent(source, title, null, { customContent: true });
1202
1089
        this.setResident(true);
1203
1090
 
1204
1091
        this.addButton('reject', _("Reject"));
1221
1108
            this.destroy();
1222
1109
        }));
1223
1110
    }
1224
 
};
 
1111
});
1225
1112
 
1226
1113
// File Transfer
1227
 
function FileTransferNotification(source, dispatchOp, channel, contact) {
1228
 
    this._init(source, dispatchOp, channel, contact);
1229
 
}
1230
 
 
1231
 
FileTransferNotification.prototype = {
1232
 
    __proto__: MessageTray.Notification.prototype,
 
1114
const FileTransferNotification = new Lang.Class({
 
1115
    Name: 'FileTransferNotification',
 
1116
    Extends: MessageTray.Notification,
1233
1117
 
1234
1118
    _init: function(source, dispatchOp, channel, contact) {
1235
 
        MessageTray.Notification.prototype._init.call(this,
1236
 
                                                      source,
1237
 
                                                      /* To translators: The first parameter is
1238
 
                                                       * the contact's alias and the second one is the
1239
 
                                                       * file name. The string will be something
1240
 
                                                       * like: "Alice is sending you test.ogg"
1241
 
                                                       */
1242
 
                                                      _("%s is sending you %s").format(contact.get_alias(),
1243
 
                                                                                       channel.get_filename()),
1244
 
                                                      null,
1245
 
                                                      { customContent: true });
 
1119
        this.parent(source,
 
1120
                    /* To translators: The first parameter is
 
1121
                     * the contact's alias and the second one is the
 
1122
                     * file name. The string will be something
 
1123
                     * like: "Alice is sending you test.ogg"
 
1124
                     */
 
1125
                    _("%s is sending you %s").format(contact.get_alias(),
 
1126
                                                     channel.get_filename()),
 
1127
                    null,
 
1128
                    { customContent: true });
1246
1129
        this.setResident(true);
1247
1130
 
1248
1131
        this.addButton('decline', _("Decline"));
1264
1147
            this.destroy();
1265
1148
        }));
1266
1149
    }
1267
 
};
 
1150
});
1268
1151
 
1269
1152
// A notification source that can embed multiple notifications
1270
 
function MultiNotificationSource(title, icon) {
1271
 
    this._init(title, icon);
1272
 
}
1273
 
 
1274
 
MultiNotificationSource.prototype = {
1275
 
    __proto__: MessageTray.Source.prototype,
 
1153
const MultiNotificationSource = new Lang.Class({
 
1154
    Name: 'MultiNotificationSource',
 
1155
    Extends: MessageTray.Source,
1276
1156
 
1277
1157
    _init: function(title, icon) {
1278
 
        MessageTray.Source.prototype._init.call(this, title);
 
1158
        this.parent(title);
1279
1159
 
1280
1160
        this._icon = icon;
1281
1161
        this._setSummaryIcon(this.createNotificationIcon());
1283
1163
    },
1284
1164
 
1285
1165
    notify: function(notification) {
1286
 
        MessageTray.Source.prototype.notify.call(this, notification);
 
1166
        this.parent(notification);
1287
1167
 
1288
1168
        this._nbNotifications += 1;
1289
1169
 
1297
1177
    },
1298
1178
 
1299
1179
    createNotificationIcon: function() {
1300
 
        return new St.Icon({ gicon: Shell.util_icon_from_string(this._icon),
 
1180
        return new St.Icon({ gicon: Gio.icon_new_for_string(this._icon),
1301
1181
                             icon_type: St.IconType.FULLCOLOR,
1302
1182
                             icon_size: this.ICON_SIZE });
1303
1183
    }
1304
 
};
 
1184
});
1305
1185
 
1306
1186
// Subscription request
1307
 
function SubscriptionRequestNotification(source, contact) {
1308
 
    this._init(source, contact);
1309
 
}
1310
 
 
1311
 
SubscriptionRequestNotification.prototype = {
1312
 
    __proto__: MessageTray.Notification.prototype,
 
1187
const SubscriptionRequestNotification = new Lang.Class({
 
1188
    Name: 'SubscriptionRequestNotification',
 
1189
    Extends: MessageTray.Notification,
1313
1190
 
1314
1191
    _init: function(source, contact) {
1315
 
        MessageTray.Notification.prototype._init.call(this, source,
1316
 
            /* To translators: The parameter is the contact's alias */
1317
 
            _("%s would like permission to see when you are online").format(contact.get_alias()),
1318
 
            null, { customContent: true });
 
1192
        this.parent(source,
 
1193
                    /* To translators: The parameter is the contact's alias */
 
1194
                    _("%s would like permission to see when you are online").format(contact.get_alias()),
 
1195
                    null, { customContent: true });
1319
1196
 
1320
1197
        this._contact = contact;
1321
1198
        this._connection = contact.get_connection();
1389
1266
            this._invalidatedId = 0;
1390
1267
        }
1391
1268
 
1392
 
        MessageTray.Notification.prototype.destroy.call(this);
 
1269
        this.parent();
1393
1270
    },
1394
1271
 
1395
1272
    _subscriptionStatesChangedCb: function(contact, subscribe, publish, msg) {
1398
1275
        if (publish != Tp.SubscriptionState.ASK)
1399
1276
            this.destroy();
1400
1277
    }
1401
 
};
1402
 
 
1403
 
 
1404
 
function AccountNotification(source, account, connectionError) {
1405
 
    this._init(source, account, connectionError);
1406
 
}
 
1278
});
1407
1279
 
1408
1280
// Messages from empathy/libempathy/empathy-utils.c
1409
1281
// create_errors_to_message_hash()
1444
1316
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CONNECTION_LOST)]
1445
1317
  = _("Connection has been lost");
1446
1318
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.ALREADY_CONNECTED)]
1447
 
  = _("This resource is already connected to the server");
 
1319
  = _("This account is already connected to the server");
1448
1320
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CONNECTION_REPLACED)]
1449
1321
  = _("Connection has been replaced by a new connection using the same resource");
1450
1322
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.REGISTRATION_EXISTS)]
1457
1329
  = _("Certificate uses an insecure cipher algorithm or is cryptographically weak");
1458
1330
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_LIMIT_EXCEEDED)]
1459
1331
  = _("The length of the server certificate, or the depth of the server certificate chain, exceed the limits imposed by the cryptography library");
 
1332
_connectionErrorMessages['org.freedesktop.DBus.Error.NoReply']
 
1333
  = _("Internal error");
1460
1334
 
1461
 
AccountNotification.prototype = {
1462
 
    __proto__: MessageTray.Notification.prototype,
 
1335
const AccountNotification = new Lang.Class({
 
1336
    Name: 'AccountNotification',
 
1337
    Extends: MessageTray.Notification,
1463
1338
 
1464
1339
    _init: function(source, account, connectionError) {
1465
 
        MessageTray.Notification.prototype._init.call(this, source,
1466
 
            /* translators: argument is the account name, like
1467
 
             * name@jabber.org for example. */
1468
 
            _("Connection to %s failed").format(account.get_display_name()),
1469
 
            null, { customContent: true });
 
1340
        this.parent(source,
 
1341
                    /* translators: argument is the account name, like
 
1342
                     * name@jabber.org for example. */
 
1343
                    _("Connection to %s failed").format(account.get_display_name()),
 
1344
                    null, { customContent: true });
1470
1345
 
1471
1346
        this._label = new St.Label();
1472
1347
        this.addActor(this._label);
1542
1417
            this._connectionStatusId = 0;
1543
1418
        }
1544
1419
 
1545
 
        MessageTray.Notification.prototype.destroy.call(this);
 
1420
        this.parent();
1546
1421
    }
1547
 
};
 
1422
});