[polari/wip/fmuellner/combined-gsoc: 49/103] first try at fixing the conflicts



commit 98ddafe741e76b6df58e96ca26204b54d90897e3
Author: raresv <rares visalom gmail com>
Date:   Fri Jul 1 23:14:45 2016 +0300

    first try at fixing the conflicts

 src/application.js |    7 +-
 src/chatView.js    |   34 +++++-
 src/userTracker.js |  279 +++++++++++++++++++++++++++++++++++++++++++---------
 3 files changed, 261 insertions(+), 59 deletions(-)
---
diff --git a/src/application.js b/src/application.js
index 77fd622..b578bd5 100644
--- a/src/application.js
+++ b/src/application.js
@@ -48,13 +48,8 @@ const Application = new Lang.Class({
         this._chatroomManager = ChatroomManager.getDefault();
         this._accountsMonitor = AccountsMonitor.getDefault();
         this._networkMonitor = Gio.NetworkMonitor.get_default();
+        this._userStatusMonitor = UserTracker.getUserStatusMonitor();
         this._networksManager = NetworksManager.getDefault();
-        /*created here as i couldn't make it work if it was created in the chatroomManager
-        (it didn't receive the room-added signal for the channels restored from the previous session)*/
-        /*this._globalUserTracker = new UserTracker.UserTracker(null);
-        this._globalUserTracker.connect('status-changed', Lang.bind(this, function(tracker, nick, status){
-            log("[Application] nick " + nick + " global status changed to " + status );
-        }));*/
 
         this._accountsMonitor.connect('account-removed', Lang.bind(this,
             function(am, account) {
diff --git a/src/chatView.js b/src/chatView.js
index 125df89..e29581e 100644
--- a/src/chatView.js
+++ b/src/chatView.js
@@ -307,8 +307,7 @@ const ChatView = new Lang.Class({
         this._statusCount = { left: 0, joined: 0, total: 0 };
         this._logWalker = null;
 
-        this._userTracker = new UserTracker.UserTracker(this._room);
-        this._userTracker.connect('status-changed', Lang.bind(this, this._onNickStatusChanged));
+        this._userStatusMonitor = UserTracker.getUserStatusMonitor();
 
         this._room.account.connect('notify::nickname', Lang.bind(this,
             function() {
@@ -347,6 +346,9 @@ const ChatView = new Lang.Class({
             this._roomSignals.push(room.connect(signal.name, signal.handler));
         }));
         this._onChannelChanged();
+
+        /*where should we unwatch? int onChannelChanged when we don't have a channel?*/
+        this._roomWatchHandler = 
this._userStatusMonitor.getUserTrackerForAccount(this._room.account).watchUser(this._room, null, 
Lang.bind(this, this._onStatusChangedCallback));
     },
 
     _createTags: function() {
@@ -1212,7 +1214,7 @@ const ChatView = new Lang.Class({
                     nickTag = this._createNickTag(nickTagName);
                     buffer.get_tag_table().add(nickTag);
 
-                    this._updateNickTag(nickTag, this._userTracker.getNickStatus(message.nick));
+                    this._updateNickTag(nickTag, 
this._userStatusMonitor.getUserTrackerForAccount(this._room.account).getNickStatus(message.nick));
                 }
                 tags.push(nickTag);
                 if (needsGap)
@@ -1254,6 +1256,28 @@ const ChatView = new Lang.Class({
                               this._view.buffer.create_mark(null, iter, true));
     },
 
+    _createNickTag: function(nickName) {
+        let nickTagName = this._getNickTagName(nickName);
+
+        let tag = new Gtk.TextTag({ name: nickTagName });
+        //this._updateNickTag(tag, 
this._userStatusMonitor.getUserTrackerForAccount(this._room.account).getNickRoomStatus(nickName, this._room));
+        this._updateNickTag(tag, Tp.ConnectionPresenceType.OFFLINE);
+
+        return tag;
+    },
+
+    _onStatusChangedCallback: function(nick, status) {
+        log("Nick " + nick + " has local status " + status);
+
+        let nickTagName = this._getNickTagName(nick);
+        let nickTag = this._lookupTag(nickTagName);
+
+        if (!nickTag)
+            return;
+
+        this._updateNickTag(nickTag, status);
+    },
+
     _updateNickTag: function(tag, status) {
         if (status == Tp.ConnectionPresenceType.AVAILABLE)
             tag.foreground_rgba = this._activeNickColor;
@@ -1263,7 +1287,7 @@ const ChatView = new Lang.Class({
 
     _createNickTag: function(name) {
         let tag = new ButtonTag({ name: name });
-        tag._popover = new UserList.UserPopover({ relative_to: this._view, margin: 0, room: this._room, 
userTracker: this._userTracker });
+        tag._popover = new UserList.UserPopover({ relative_to: this._view, margin: 0, room: this._room, 
userTracker: this._userStatusMonitor.getUserTrackerForAccount(this._room.account) });
         tag.connect('clicked', Lang.bind(this, this._onNickTagClicked));
         return tag;
     },
@@ -1297,8 +1321,6 @@ const ChatView = new Lang.Class({
 
         tag._popover.nickname = actualNickName;
 
-        //tag._popover.user = this._userTracker.getBestMatchingContact(actualNickName);
-
         tag._popover.pointing_to = rect1;
         tag._popover.show();
     },
diff --git a/src/userTracker.js b/src/userTracker.js
index d9cac5b..7e78bbd 100644
--- a/src/userTracker.js
+++ b/src/userTracker.js
@@ -4,8 +4,57 @@ const Tp = imports.gi.TelepathyGLib;
 const Signals = imports.signals;
 const GObject = imports.gi.GObject;
 
+const AccountsMonitor = imports.accountsMonitor;
 const ChatroomManager = imports.chatroomManager;
 
+let _singleton = null;
+
+function getUserStatusMonitor() {
+    if (_singleton == null)
+        _singleton = new UserStatusMonitor();
+    return _singleton;
+}
+
+const UserStatusMonitor = new Lang.Class({
+    Name: 'UserStatusMonitor',
+
+    _init: function() {
+        this._userTrackersMaping = new Map();
+        this._accountsMonitor = AccountsMonitor.getDefault();
+
+        this._accountsMonitor.connect('account-added', Lang.bind(this, this._onAccountAdded));
+        this._accountsMonitor.connect('account-removed', Lang.bind(this, this._onAccountRemoved));
+    },
+
+    _onAccountAdded: function(accountsMonitor, account) {
+        this._addUserTrackerForAccount(account);
+    },
+
+    _onAccountRemoved: function(accountsMonitor, account) {
+        this._removeUserTrackerForAccount(account);
+    },
+
+    _addUserTrackerForAccount: function(account) {
+        if (this._userTrackersMaping.has(account))
+            return;
+
+        this._userTrackersMaping.set(account, new UserTracker(account));
+    },
+
+    _removeUserTrackerForAccount: function(account) {
+        if (!this._userTrackersMaping.has(account))
+            return;
+
+        this._userTrackersMaping.delete(account);
+    },
+
+    getUserTrackerForAccount: function(account) {
+        if (this._userTrackersMaping.has(account))
+            return this._userTrackersMaping.get(account);
+        return null;
+    }
+});
+
 
 const UserTracker = new Lang.Class({
     Name: 'UserTracker',
@@ -18,9 +67,8 @@ const UserTracker = new Lang.Class({
         },
     },
 
-    _init: function(room) {
+    _init: function(account) {
         this.parent();
-
         this._referenceRoomSignals = [
             { name: 'notify::channel',
               handler: Lang.bind(this, this._onChannelChanged) },
@@ -38,33 +86,50 @@ const UserTracker = new Lang.Class({
               handler: Lang.bind(this, this._onMemberLeft) }
         ];
 
-        this._contactMapping = new Map();
+        this._account = account;
 
-        if (!room) {
-            log("global user tracker created");
-            this._chatroomManager = ChatroomManager.getDefault();
+        this._globalContactMapping = new Map();
+        this._roomMapping = new Map();
+        this._handlerCounter = 0;
 
-            this._chatroomManager.connect('room-added', Lang.bind(this, this._onRoomAdded));
-            this._chatroomManager.connect('room-removed', Lang.bind(this, this._onRoomRemoved));
-        } else {
-            this._room = room;
+        this._userStatusMonitor = getUserStatusMonitor();
 
-            this._onRoomAdded(null, this._room);
-            this._onChannelChanged(this._room);
-        }
+        this._chatroomManager = ChatroomManager.getDefault();
+        this._chatroomManager.connect('room-added', Lang.bind(this, this._onRoomAdded));
+        this._chatroomManager.connect('room-removed', Lang.bind(this, this._onRoomRemoved));
+    },
+
+    _onRoomAdded: function(roomManager, room) {
+        if (room.account == this._account)
+            this._connectRoomSignalsForRoom(room);
+    },
+
+    _onRoomRemoved: function(roomManager, room) {
+        if (room.account == this._account)
+            this._disconnectRoomSignalsForRoom(room);
+
+        this._clearUsersFromRoom(this._globalContactMapping, room);
+        this._clearUsersFromRoom(this._roomMapping.get(room)._contactMapping, room);
     },
 
-    _onRoomAdded: function(roomManager , room) {
-        this._roomSignals = [];
+    _connectRoomSignalsForRoom: function(room) {
+        this._ensureRoomMappingForRoom(room);
+
+        let roomData = this._roomMapping.get(room);
+
+        roomData._roomSignals = [];
         this._referenceRoomSignals.forEach(Lang.bind(this, function(signal) {
-            this._roomSignals.push(room.connect(signal.name, signal.handler));
+            roomData._roomSignals.push(room.connect(signal.name, signal.handler));
         }));
     },
 
-    _onRoomRemoved: function(roomManager, room) {
-        for (let i = 0; i < this._roomSignals.length; i++)
-            room.disconnect(this._roomSignals[i]);
-        this._roomSignals = [];
+    _disconnectRoomSignalsForRoom: function(room) {
+        let roomData = this._roomMapping.get(room);
+
+        for (let i = 0; i < roomData._roomSignals.length; i++) {
+            room.disconnect(roomData._roomSignals[i]);
+        }
+        roomData._roomSignals = [];
     },
 
     _onChannelChanged: function(emittingRoom) {
@@ -75,84 +140,166 @@ const UserTracker = new Lang.Class({
             else
                 members = [emittingRoom.channel.connection.self_contact, 
emittingRoom.channel.target_contact];
 
+            /*is this needed here?*/
+            this._ensureRoomMappingForRoom(emittingRoom);
+
+            /*if there is no map keeping track of the users in the emittingRoom
+            create it*/
+            if (!this._roomMapping.get(emittingRoom)._contactMapping)
+                this._roomMapping.get(emittingRoom)._contactMapping = new Map();
+
+            /*if there is no map keeping track of the local status change handlers*/
+            this._ensureHandlerMappingForRoom(emittingRoom);
+
+            /*keep track of initial members in the emittingRoom, both locally and
+            globally*/
             members.forEach(m => {
                 m._room = emittingRoom;
-                this._trackMember(m);
+                this._trackMember(this._roomMapping.get(emittingRoom)._contactMapping, m, emittingRoom);
+                this._trackMember(this._globalContactMapping, m, emittingRoom);
             });
         } else {
-            for ([baseNick, basenickContacts] of this._contactMapping) {
-                basenickContacts.forEach(Lang.bind(this, function(member) {
-                    if (member._room == emittingRoom)
-                        this._untrackMember(member);
-                }));
-
-                this._contactMapping.delete(baseNick);
+            /*handle the absence of a channel for the global case*/
+            this._clearUsersFromRoom(this._globalContactMapping, emittingRoom);
+            /*handle the absence of a channel for the local case*/
+            this._clearUsersFromRoom(this._roomMapping.get(emittingRoom)._contactMapping, emittingRoom);
+
+            /*since we have no channel, all users must be locally marked offline. so call the callbacks*/
+            for ([handlerID, handlerInfo] of this._roomMapping.get(emittingRoom)._handlerMapping) {
+                if (handlerInfo.nickName)
+                    handlerInfo.handler(handlerInfo.nickName, Tp.ConnectionPresenceType.OFFLINE);
             }
         }
     },
 
+    _clearUsersFromRoom: function(mapping, room) {
+        for ([baseNick, basenickContacts] of mapping) {
+            basenickContacts.forEach(Lang.bind(this, function(member) {
+                if (member._room == room)
+                    /*safe to delete while iterating?*/
+                    this._untrackMember(mapping, member, room);
+            }));
+
+            mapping.delete(baseNick);
+        }
+    },
+
+    _ensureRoomMappingForRoom: function(room) {
+        if (!this._roomMapping.has(room))
+            this._roomMapping.set(room, {});
+    },
+
+    _ensureHandlerMappingForRoom: function(room) {
+        /*if there is no map keeping track of the local status change handlers*/
+        if (!this._roomMapping.get(room)._handlerMapping) {
+            this._roomMapping.get(room)._handlerMapping = new Map();
+            this._handlerCounter = 0;
+        }
+    },
+
     _onMemberRenamed: function(room, oldMember, newMember) {
         oldMember._room = room;
         newMember._room = room;
-        this._untrackMember(oldMember);
-        this._trackMember(newMember);
+
+        this._untrackMember(this._roomMapping.get(room)._contactMapping, oldMember, room);
+        this._untrackMember(this._globalContactMapping, oldMember, room);
+        this._trackMember(this._roomMapping.get(room)._contactMapping, newMember, room);
+        this._trackMember(this._globalContactMapping, newMember, room);
     },
 
     _onMemberDisconnected: function(room, member, message) {
         member._room = room;
-        this._untrackMember(member);
+
+        this._untrackMember(this._roomMapping.get(room)._contactMapping, member, room);
+        this._untrackMember(this._globalContactMapping, member, room);
     },
 
     _onMemberKicked: function(room, member, actor) {
         member._room = room;
-        this._untrackMember(member);
+
+        this._untrackMember(this._roomMapping.get(room)._contactMapping, member, room);
+        this._untrackMember(this._globalContactMapping, member, room);
     },
 
     _onMemberBanned: function(room, member, actor) {
         member._room = room;
-        this._untrackMember(member);
+
+        this._untrackMember(this._roomMapping.get(room)._contactMapping, member, room);
+        this._untrackMember(this._globalContactMapping, member, room);
     },
 
     _onMemberJoined: function(room, member) {
         member._room = room;
-        this._trackMember(member);
+
+        this._trackMember(this._roomMapping.get(room)._contactMapping, member, room);
+        this._trackMember(this._globalContactMapping, member, room);
     },
 
     _onMemberLeft: function(room, member, message) {
         member._room = room;
-        this._untrackMember(member);
+
+        this._untrackMember(this._roomMapping.get(room)._contactMapping, member, room);
+        this._untrackMember(this._globalContactMapping, member, room);
     },
 
-    _trackMember: function(member) {
+    _trackMember: function(map, member, room) {
         let baseNick = Polari.util_get_basenick(member.alias);
 
-        if (this._contactMapping.has(baseNick))
-            this._contactMapping.get(baseNick).push(member);
+        if (map.has(baseNick))
+            map.get(baseNick).push(member);
         else
-            this._contactMapping.set(baseNick, [member]);
+            map.set(baseNick, [member]);
 
-        if (this._contactMapping.get(baseNick).length == 1)
-            this.emit("status-changed::"+baseNick, member.alias, Tp.ConnectionPresenceType.AVAILABLE);
+        //was on HEAD
+        /*if (this._contactMapping.get(baseNick).length == 1)
+            this.emit("status-changed::"+baseNick, member.alias, Tp.ConnectionPresenceType.AVAILABLE);*/
+        if (map == this._globalContactMapping)log("length: " + 
this._globalContactMapping.get(baseNick).length)
+
+        if (map.get(baseNick).length == 1)
+            if (map == this._globalContactMapping) {
+                this.emit("global-status-changed::" + member.alias, Tp.ConnectionPresenceType.AVAILABLE);
+                log("[global status] user " + member.alias + " is globally online");
+            }
+            else
+                //log("[Local UserTracker] User " + member.alias + " is now available in room " + 
member._room.channelName + " on " + this._account.get_display_name());
+                for ([handlerID, handlerInfo] of this._roomMapping.get(room)._handlerMapping)
+                    if (handlerInfo.nickName == member.alias)
+                        handlerInfo.handler(handlerInfo.nickName, Tp.ConnectionPresenceType.AVAILABLE);
+                    else if (!handlerInfo.nickName)
+                        handlerInfo.handler(member.alias, Tp.ConnectionPresenceType.AVAILABLE);
     },
 
-    _untrackMember: function(member) {
+    _untrackMember: function(map, member, room) {
         let baseNick = Polari.util_get_basenick(member.alias);
 
-        let contacts = this._contactMapping.get(baseNick) || [];
-        let indexToDelete = contacts.map(c => c.alias).indexOf(member.alias);
+        let contacts = map.get(baseNick) || [];
+        /*i really don't like this search. maybe use a for loop?*/
+        let indexToDelete = contacts.map(c => c.alias + "|" + c._room.channelName).indexOf(member.alias + 
"|" + member._room.channelName);
 
         if (indexToDelete > -1) {
-            contacts.splice(indexToDelete, 1);
+            let removedMember = contacts.splice(indexToDelete, 1)[0];
 
             if (contacts.length == 0)
-                this.emit("status-changed::"+baseNick, member.alias, Tp.ConnectionPresenceType.OFFLINE);
+                //was on HEAD
+                /*this.emit("status-changed::"+baseNick, member.alias, Tp.ConnectionPresenceType.OFFLINE);*/
+                if (map == this._globalContactMapping) {
+                    this.emit("global-status-changed::" + member.alias, Tp.ConnectionPresenceType.OFFLINE);
+                    log("[global status] user " + member.alias + " is globally offline");
+                }
+                else
+                    //log("[Local UserTracker] User " + member.alias + " is now offline in room " + 
member._room.channelName + " on " + this._account.get_display_name());
+                    for ([handlerID, handlerInfo] of this._roomMapping.get(room)._handlerMapping)
+                        if (handlerInfo.nickName == member.alias)
+                            handlerInfo.handler(handlerInfo.nickName, Tp.ConnectionPresenceType.OFFLINE);
+                        else if (!handlerInfo.nickName)
+                            handlerInfo.handler(member.alias, Tp.ConnectionPresenceType.OFFLINE);
         }
     },
 
     getNickStatus: function(nickName) {
         let baseNick = Polari.util_get_basenick(nickName);
 
-        let contacts = this._contactMapping.get(baseNick) || [];
+        let contacts = this._globalContactMapping.get(baseNick) || [];
         return contacts.length == 0 ? Tp.ConnectionPresenceType.OFFLINE
                                     : Tp.ConnectionPresenceType.AVAILABLE;
     },
@@ -170,5 +317,43 @@ const UserTracker = new Lang.Class({
                 return contacts[i];
 
         return contacts[0];
+    },
+
+    getNickRoomStatus: function(nickName, room) {
+        let baseNick = Polari.util_get_basenick(nickName);
+
+        let contacts = this._roomMapping.get(room)._contactMapping.get(baseNick) || [];
+        return contacts.length == 0 ? Tp.ConnectionPresenceType.OFFLINE
+                                    : Tp.ConnectionPresenceType.AVAILABLE;
+    },
+
+    watchUser: function(room, nick, callback) {
+        this._ensureRoomMappingForRoom(room);
+        this._ensureHandlerMappingForRoom(room);
+
+        this._roomMapping.get(room)._handlerMapping.set(this._handlerCounter, {
+            nickName: nick,
+            handler: callback
+        });
+
+        this._handlerCounter++;
+
+        return this._handlerCounter - 1;
+    },
+
+    unwatchUser: function(room, nick, handlerID) {
+        /*it wouldn't make sense to call _ensure() here, right?*/
+
+        /*rewrite into a single conditional?*/
+        if (!this._roomMapping)
+            return;
+
+        if (!this._roomMapping.has(room))
+            return;
+
+        if (!this._roomMapping.get(room)._handlerMapping)
+            return;
+
+        this._roomMapping.get(room)._handlerMapping.delete(handlerID);
     }
 });


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]