diff --git a/gajim/chat_control.py b/gajim/chat_control.py
index d8aa5d6e7..7f5e81c5a 100644
--- a/gajim/chat_control.py
+++ b/gajim/chat_control.py
@@ -62,6 +62,7 @@ from gajim.gtk.util import ensure_proper_control
from gajim.gtk.util import format_mood
from gajim.gtk.util import format_activity
from gajim.gtk.util import format_tune
+from gajim.gtk.util import format_location
from gajim.gtk.util import get_activity_icon_name
from gajim.command_system.implementation.hosts import ChatCommands
@@ -132,11 +133,7 @@ class ChatControl(ChatControlBase):
self.video_available = False
self.update_toolbar()
-
- self._pep_images = {}
- self._pep_images['geoloc'] = self.xml.get_object('location_image')
self.update_all_pep_types()
-
self.show_avatar()
# Hook up signals
@@ -228,8 +225,6 @@ class ChatControl(ChatControlBase):
self.restore_conversation()
self.msg_textview.grab_focus()
- app.ged.register_event_handler('pep-received', ged.GUI1,
- self._nec_pep_received)
app.ged.register_event_handler('nickname-received', ged.GUI1,
self._on_nickname_received)
app.ged.register_event_handler('mood-received', ged.GUI1,
@@ -238,6 +233,8 @@ class ChatControl(ChatControlBase):
self._on_activity_received)
app.ged.register_event_handler('tune-received', ged.GUI1,
self._on_tune_received)
+ app.ged.register_event_handler('location-received', ged.GUI1,
+ self._on_location_received)
if self.TYPE_ID == message_control.TYPE_CHAT:
# Dont connect this when PrivateChatControl is used
app.ged.register_event_handler('update-roster-avatar', ged.GUI1,
@@ -418,38 +415,11 @@ class ChatControl(ChatControlBase):
self.audio_available = False
def update_all_pep_types(self):
- for pep_type in self._pep_images:
- self.update_pep(pep_type)
+ self._update_pep(PEPEventType.LOCATION)
self._update_pep(PEPEventType.MOOD)
self._update_pep(PEPEventType.ACTIVITY)
self._update_pep(PEPEventType.TUNE)
- def update_pep(self, pep_type):
- if isinstance(self.contact, GC_Contact):
- return
- if pep_type not in self._pep_images:
- return
- pep = self.contact.pep
- img = self._pep_images[pep_type]
- if pep_type in pep:
- icon = gtkgui_helpers.get_pep_icon(pep[pep_type])
- if isinstance(icon, str):
- img.set_from_icon_name(icon, Gtk.IconSize.MENU)
- else:
- img.set_from_pixbuf(icon)
- img.set_tooltip_markup(pep[pep_type].as_markup_text())
- img.show()
- else:
- img.hide()
-
- def _nec_pep_received(self, obj):
- if obj.conn.name != self.account:
- return
- if obj.jid != self.contact.jid:
- return
-
- self.update_pep(obj.pep_type)
-
def _update_pep(self, type_):
image = self._get_pep_widget(type_)
data = self.contact.pep.get(type_)
@@ -466,6 +436,9 @@ class ChatControl(ChatControlBase):
elif type_ == PEPEventType.TUNE:
icon = 'audio-x-generic'
formated_text = format_tune(*data)
+ elif type_ == PEPEventType.LOCATION:
+ icon = 'applications-internet'
+ formated_text = format_location(data)
image.set_from_icon_name(icon, Gtk.IconSize.MENU)
image.set_tooltip_markup(formated_text)
@@ -478,6 +451,8 @@ class ChatControl(ChatControlBase):
return self.xml.get_object('activity_image')
if type_ == PEPEventType.TUNE:
return self.xml.get_object('tune_image')
+ if type_ == PEPEventType.LOCATION:
+ return self.xml.get_object('location_image')
@ensure_proper_control
def _on_mood_received(self, _event):
@@ -491,6 +466,10 @@ class ChatControl(ChatControlBase):
def _on_tune_received(self, _event):
self._update_pep(PEPEventType.TUNE)
+ @ensure_proper_control
+ def _on_location_received(self, _event):
+ self._update_pep(PEPEventType.LOCATION)
+
@ensure_proper_control
def _on_nickname_received(self, _event):
self.update_ui()
@@ -1104,9 +1083,6 @@ class ChatControl(ChatControlBase):
# PluginSystem: removing GUI extension points connected with ChatControl
# instance object
app.plugin_manager.remove_gui_extension_point('chat_control', self)
-
- app.ged.remove_event_handler('pep-received', ged.GUI1,
- self._nec_pep_received)
app.ged.remove_event_handler('nickname-received', ged.GUI1,
self._on_nickname_received)
app.ged.remove_event_handler('mood-received', ged.GUI1,
@@ -1115,6 +1091,8 @@ class ChatControl(ChatControlBase):
self._on_activity_received)
app.ged.remove_event_handler('tune-received', ged.GUI1,
self._on_tune_received)
+ app.ged.remove_event_handler('location-received', ged.GUI1,
+ self._on_location_received)
if self.TYPE_ID == message_control.TYPE_CHAT:
app.ged.remove_event_handler('update-roster-avatar', ged.GUI1,
self._nec_update_avatar)
diff --git a/gajim/common/dbus/location.py b/gajim/common/dbus/location.py
index 82791c6f1..779854301 100644
--- a/gajim/common/dbus/location.py
+++ b/gajim/common/dbus/location.py
@@ -18,6 +18,7 @@ import logging
from datetime import datetime
from gi.repository import GLib
+from nbxmpp.structs import LocationData
from gajim.common import app
@@ -93,7 +94,8 @@ class LocationListener:
del new_data['timestamp']
if last_data == new_data:
continue
- app.connections[acct].get_module('UserLocation').send(self._data)
+ app.connections[acct].get_module('UserLocation').set_location(
+ LocationData(**self._data))
self.location_info = self._data.copy()
def _timestamp_to_utc(self, timestamp):
diff --git a/gajim/common/modules/user_location.py b/gajim/common/modules/user_location.py
index e73d610b1..8e1b57962 100644
--- a/gajim/common/modules/user_location.py
+++ b/gajim/common/modules/user_location.py
@@ -17,64 +17,57 @@
import logging
import nbxmpp
-from gi.repository import GLib
-from gajim.common.const import PEPEventType, LOCATION_DATA
-from gajim.common.exceptions import StanzaMalformed
-from gajim.common.modules.pep import AbstractPEPModule, AbstractPEPData
+from gajim.common import app
+from gajim.common.nec import NetworkEvent
+from gajim.common.modules.base import BaseModule
+from gajim.common.modules.util import event_node
+from gajim.common.modules.util import store_publish
+from gajim.common.const import PEPEventType
log = logging.getLogger('gajim.c.m.user_location')
-class UserLocationData(AbstractPEPData):
+class UserLocation(BaseModule):
- type_ = PEPEventType.LOCATION
+ _nbxmpp_extends = 'Location'
+ _nbxmpp_methods = [
+ 'set_location',
+ ]
- def as_markup_text(self):
- location = self.data
- location_string = ''
+ def __init__(self, con):
+ BaseModule.__init__(self, con)
+ self._register_pubsub_handler(self._location_received)
- for entry in location.keys():
- text = location[entry]
- text = GLib.markup_escape_text(text)
- # Translate standard location tag
- tag = LOCATION_DATA.get(entry, entry)
- location_string += '\n%(tag)s: %(text)s' % {
- 'tag': tag.capitalize(), 'text': text}
+ @event_node(nbxmpp.NS_LOCATION)
+ def _location_received(self, _con, _stanza, properties):
+ data = properties.pubsub_event.data
+ empty = properties.pubsub_event.empty
- return location_string.strip()
+ for contact in app.contacts.get_contacts(self._account,
+ str(properties.jid)):
+ if not empty:
+ contact.pep[PEPEventType.LOCATION] = data
+ else:
+ contact.pep.pop(PEPEventType.LOCATION, None)
+ if properties.is_self_message:
+ if not empty:
+ self._con.pep[PEPEventType.LOCATION] = data
+ else:
+ self._con.pep.pop(PEPEventType.LOCATION, None)
-class UserLocation(AbstractPEPModule):
+ app.nec.push_incoming_event(
+ NetworkEvent('location-received',
+ account=self._account,
+ jid=properties.jid.getBare(),
+ location=data,
+ is_self_message=properties.is_self_message))
- name = 'geoloc'
- namespace = nbxmpp.NS_LOCATION
- pep_class = UserLocationData
- store_publish = True
- _log = log
-
- def _extract_info(self, item):
- location_dict = {}
- location_tag = item.getTag('geoloc', namespace=nbxmpp.NS_LOCATION)
- if location_tag is None:
- raise StanzaMalformed('No geoloc node')
-
- for child in location_tag.getChildren():
- name = child.getName().strip()
- data = child.getData().strip()
- if child.getName() in LOCATION_DATA:
- location_dict[name] = data
-
- return location_dict or None
-
- def _build_node(self, data):
- item = nbxmpp.Node('geoloc', {'xmlns': nbxmpp.NS_LOCATION})
- if data is None:
- return item
- for field in LOCATION_DATA:
- if data.get(field, False):
- item.addChild(field, payload=data[field])
- return item
+ @store_publish
+ def set_location(self, location):
+ log.info('Send %s', location)
+ self._nbxmpp('Location').set_location(location)
def get_instance(*args, **kwargs):
diff --git a/gajim/gtk/tooltips.py b/gajim/gtk/tooltips.py
index bc4be71ec..690d9b276 100644
--- a/gajim/gtk/tooltips.py
+++ b/gajim/gtk/tooltips.py
@@ -45,6 +45,7 @@ from gajim.gtk.util import get_icon_name
from gajim.gtk.util import format_mood
from gajim.gtk.util import format_activity
from gajim.gtk.util import format_tune
+from gajim.gtk.util import format_location
log = logging.getLogger('gajim.gtk.tooltips')
@@ -494,8 +495,8 @@ class RosterTooltip(StatusTable):
self._ui.tune.show()
self._ui.tune_label.show()
- if 'geoloc' in contact.pep:
- location = contact.pep['geoloc'].as_markup_text()
+ if PEPEventType.LOCATION in contact.pep:
+ location = format_location(contact.pep[PEPEventType.LOCATION])
self._ui.location.set_markup(location)
self._ui.location.show()
self._ui.location_label.show()
diff --git a/gajim/gtk/util.py b/gajim/gtk/util.py
index 9398f1e26..e15da2a92 100644
--- a/gajim/gtk/util.py
+++ b/gajim/gtk/util.py
@@ -38,6 +38,7 @@ from gajim.common import i18n
from gajim.common.i18n import _
from gajim.common.const import MOODS
from gajim.common.const import ACTIVITIES
+from gajim.common.const import LOCATION_DATA
from gajim.gtk.const import GajimIconSet
@@ -560,3 +561,20 @@ def format_tune(artist, length, rating, source, title, track, uri):
'artist': artist,
'source': source}
return tune_string
+
+
+def format_location(location):
+ location = location._asdict()
+ location_string = ''
+ for attr, value in location.items():
+ if value is None:
+ continue
+ text = GLib.markup_escape_text(value)
+ # Translate standard location tag
+ tag = LOCATION_DATA.get(attr)
+ if tag is None:
+ continue
+ location_string += '\n%(tag)s: %(text)s' % {
+ 'tag': tag.capitalize(), 'text': text}
+
+ return location_string.strip()
diff --git a/gajim/gtkgui_helpers.py b/gajim/gtkgui_helpers.py
index 88587418c..982582531 100644
--- a/gajim/gtkgui_helpers.py
+++ b/gajim/gtkgui_helpers.py
@@ -264,12 +264,6 @@ def create_list_multi(value_list, selected_values=None):
treeview.show_all()
return treeview
-def get_pep_icon(pep_class):
- if pep_class == PEPEventType.LOCATION:
- return 'applications-internet'
-
- return None
-
def label_set_autowrap(widget):
"""
Make labels automatically re-wrap if their containers are resized.
diff --git a/gajim/roster_window.py b/gajim/roster_window.py
index f9d912990..450df2f3f 100644
--- a/gajim/roster_window.py
+++ b/gajim/roster_window.py
@@ -1063,10 +1063,8 @@ class RosterWindow:
else:
self.model[child_iter][Column.TUNE_ICON] = None
- if app.config.get('show_location_in_roster') and 'geoloc' in \
- pep_dict:
- self.model[child_iter][Column.LOCATION_ICON] = \
- gtkgui_helpers.get_pep_icon(pep_dict['geoloc'])
+ if app.config.get('show_location_in_roster') and PEPEventType.LOCATION in pep_dict:
+ self.model[child_iter][Column.LOCATION_ICON] = 'applications-internet'
else:
self.model[child_iter][Column.LOCATION_ICON] = None
@@ -1321,37 +1319,16 @@ class RosterWindow:
if pep_type == PEPEventType.TUNE:
return app.config.get('show_tunes_in_roster')
- if pep_type == 'geoloc':
+ if pep_type == PEPEventType.LOCATION:
return app.config.get('show_location_in_roster')
return False
def draw_all_pep_types(self, jid, account, contact=None):
- for pep_type in self._pep_type_to_model_column:
- self.draw_pep(jid, account, pep_type, contact=contact)
self._draw_pep(account, jid, PEPEventType.MOOD)
self._draw_pep(account, jid, PEPEventType.ACTIVITY)
self._draw_pep(account, jid, PEPEventType.TUNE)
-
- def draw_pep(self, jid, account, pep_type, contact=None):
- if pep_type not in self._pep_type_to_model_column:
- return
- if not self._is_pep_shown_in_roster(pep_type):
- return
-
- model_column = self._pep_type_to_model_column[pep_type]
- iters = self._get_contact_iter(jid, account, model=self.model)
- if not iters:
- return
- if not contact:
- contact = app.contacts.get_contact(account, jid)
-
- pixbuf = None
- if pep_type in contact.pep:
- pixbuf = gtkgui_helpers.get_pep_icon(contact.pep[pep_type])
-
- for child_iter in iters:
- self.model[child_iter][model_column] = pixbuf
+ self._draw_pep(account, jid, PEPEventType.LOCATION)
def _draw_pep(self, account, jid, type_):
if not self._is_pep_shown_in_roster(type_):
@@ -1377,6 +1354,10 @@ class RosterWindow:
column = Column.TUNE_ICON
if data is not None:
icon = 'audio-x-generic'
+ elif type_ == PEPEventType.LOCATION:
+ column = Column.LOCATION_ICON
+ if data is not None:
+ icon = 'applications-internet'
for child_iter in iters:
self.model[child_iter][column] = icon
@@ -2663,6 +2644,11 @@ class RosterWindow:
self.draw_account(event.account)
self._draw_pep(event.account, event.jid, PEPEventType.TUNE)
+ def _on_location_received(self, event):
+ if event.is_self_message:
+ self.draw_account(event.account)
+ self._draw_pep(event.account, event.jid, PEPEventType.LOCATION)
+
def _on_nickname_received(self, event):
self.draw_contact(event.jid, event.account)
@@ -3619,7 +3605,7 @@ class RosterWindow:
if active:
location.enable()
else:
- app.connections[account].get_module('UserLocation').send(None)
+ app.connections[account].get_module('UserLocation').set_location(None)
helpers.update_optional_features(account)
@@ -5699,7 +5685,6 @@ class RosterWindow:
# cell_data_func, func_arg)
self.renderers_list = []
self.renderers_propertys = {}
- self._pep_type_to_model_column = {'geoloc': Column.LOCATION_ICON}
renderer_text = Gtk.CellRendererText()
self.renderers_propertys[renderer_text] = ('ellipsize',
@@ -5855,6 +5840,8 @@ class RosterWindow:
self._on_activity_received)
app.ged.register_event_handler('tune-received', ged.GUI1,
self._on_tune_received)
+ app.ged.register_event_handler('location-received', ged.GUI1,
+ self._on_location_received)
app.ged.register_event_handler('update-roster-avatar', ged.GUI1,
self._nec_update_avatar)
app.ged.register_event_handler('update-room-avatar', ged.GUI1,