Merge local changes.

This commit is contained in:
Stephan Erb 2009-12-10 20:08:09 +01:00
commit f52532f6f0
21 changed files with 2567 additions and 1970 deletions

View File

@ -1,5 +1,5 @@
AC_INIT([Gajim - A Jabber Instant Messager], AC_INIT([Gajim - A Jabber Instant Messager],
[0.13.0.1-dev],[http://trac.gajim.org/],[gajim]) [0.13.10.0-dev],[http://trac.gajim.org/],[gajim])
AC_PREREQ([2.59]) AC_PREREQ([2.59])
AC_CONFIG_HEADER(config.h) AC_CONFIG_HEADER(config.h)

View File

@ -103,13 +103,31 @@
<child> <child>
<widget class="GtkImage" id="tune_image"> <widget class="GtkImage" id="tune_image">
<property name="no_show_all">True</property> <property name="no_show_all">True</property>
<property name="pixbuf">../emoticons/static/music.png</property> <property name="stock">None</property>
<property name="icon-size">1</property> <property name="icon-size">1</property>
</widget> </widget>
<packing> <packing>
<property name="position">2</property> <property name="position">2</property>
</packing> </packing>
</child> </child>
<child>
<widget class="GtkEventBox" id="location_eventbox">
<property name="visible">True</property>
<property name="visible_window">False</property>
<child>
<widget class="GtkImage" id="location_image">
<property name="no_show_all">True</property>
<property name="stock">None</property>
<property name="icon-size">1</property>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
<child> <child>
<widget class="GtkImage" id="audio_banner_image"> <widget class="GtkImage" id="audio_banner_image">
<property name="visible">True</property> <property name="visible">True</property>
@ -117,7 +135,7 @@
<property name="icon-size">1</property> <property name="icon-size">1</property>
</widget> </widget>
<packing> <packing>
<property name="position">3</property> <property name="position">4</property>
</packing> </packing>
</child> </child>
<child> <child>
@ -127,7 +145,7 @@
<property name="icon-size">1</property> <property name="icon-size">1</property>
</widget> </widget>
<packing> <packing>
<property name="position">4</property> <property name="position">5</property>
</packing> </packing>
</child> </child>
<child> <child>
@ -139,7 +157,7 @@
</child> </child>
</widget> </widget>
<packing> <packing>
<property name="position">5</property> <property name="position">6</property>
</packing> </packing>
</child> </child>
</widget> </widget>

View File

@ -127,6 +127,24 @@
<property name="position">4</property> <property name="position">4</property>
</packing> </packing>
</child> </child>
<child>
<widget class="GtkCheckButton" id="show_location_in_roster_checkbutton">
<property name="label" translatable="yes">Display _location of contacts in roster</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="has_tooltip">True</property>
<property name="tooltip" translatable="yes">If checked, Gajim will display the location of contacts in the roster window</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_show_location_in_roster_checkbutton_toggled"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">5</property>
</packing>
</child>
<child> <child>
<widget class="GtkHBox" id="hbox3"> <widget class="GtkHBox" id="hbox3">
<property name="visible">True</property> <property name="visible">True</property>
@ -172,7 +190,7 @@
</child> </child>
</widget> </widget>
<packing> <packing>
<property name="position">5</property> <property name="position">6</property>
</packing> </packing>
</child> </child>
</widget> </widget>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

2064
po/es.po

File diff suppressed because it is too large Load Diff

2052
po/gl.po

File diff suppressed because it is too large Load Diff

View File

@ -2864,11 +2864,11 @@ msgid "Hidden"
msgstr "Hidden" msgstr "Hidden"
#: ../src/atom_window.py:119 #: ../src/atom_window.py:119
#, fuzzy, python-format #, python-format
msgid "You have received new entries (and %d not displayed):" msgid "You have received new entries (and %d not displayed):"
msgid_plural "You have received new entries (and %d not displayed):" msgid_plural "You have received new entries (and %d not displayed):"
msgstr[0] "Jūs gavote naujų įrašų (ir %(count) nerodomi):" msgstr[0] "Jūs gavote naujų įrašų (ir %d nerodomi):"
msgstr[1] "Jūs gavote naujų įrašų (ir %(count) nerodomi):" msgstr[1] "Jūs gavote naujų įrašų (ir %d nerodomi):"
#. the next script, executed in the "po" directory, #. the next script, executed in the "po" directory,
#. generates the following list. #. generates the following list.
@ -3174,7 +3174,7 @@ msgstr ""
#: ../src/chat_control.py:2784 #: ../src/chat_control.py:2784
#, python-format #, python-format
msgid "%(name)s is now %(status)s" msgid "%(name)s is now %(status)s"
msgstr "%(name) dabar %(status)" msgstr "%(name)s dabar %(status)s"
#: ../src/common/check_paths.py:44 #: ../src/common/check_paths.py:44
msgid "creating logs database" msgid "creating logs database"

View File

@ -1338,6 +1338,7 @@ class ChatControl(ChatControlBase):
self._pep_images['mood'] = self.xml.get_widget('mood_image') self._pep_images['mood'] = self.xml.get_widget('mood_image')
self._pep_images['activity'] = self.xml.get_widget('activity_image') self._pep_images['activity'] = self.xml.get_widget('activity_image')
self._pep_images['tune'] = self.xml.get_widget('tune_image') self._pep_images['tune'] = self.xml.get_widget('tune_image')
self._pep_images['location'] = self.xml.get_widget('location_image')
self.update_all_pep_types() self.update_all_pep_types()
# keep timeout id and window obj for possible big avatar # keep timeout id and window obj for possible big avatar
@ -1375,6 +1376,11 @@ class ChatControl(ChatControlBase):
self.on_avatar_eventbox_button_press_event) self.on_avatar_eventbox_button_press_event)
self.handlers[id_] = widget self.handlers[id_] = widget
widget = self.xml.get_widget('location_eventbox')
id_ = widget.connect('button-release-event',
self.on_location_eventbox_button_release_event)
self.handlers[id_] = widget
for key in ('1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '0', '#'): for key in ('1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '0', '#'):
widget = self.xml.get_widget(key + '_button') widget = self.xml.get_widget(key + '_button')
id_ = widget.connect('pressed', self.on_num_button_pressed, key) id_ = widget.connect('pressed', self.on_num_button_pressed, key)
@ -1679,6 +1685,15 @@ class ChatControl(ChatControlBase):
menu.popup(None, None, None, event.button, event.time) menu.popup(None, None, None, event.button, event.time)
return True return True
def on_location_eventbox_button_release_event(self, widget, event):
if 'location' in self.contact.pep:
location = self.contact.pep['location']._pep_specific_data
if ('lat' in location) and ('lon' in location):
uri = 'http://www.openstreetmap.org/?' + \
'mlat=%(lat)s&mlon=%(lon)s&zoom=16' % {'lat': location['lat'],
'lon': location['lon']}
helpers.launch_browser_mailer('url', uri)
def _on_window_motion_notify(self, widget, event): def _on_window_motion_notify(self, widget, event):
""" """
It gets called no matter if it is the active window or not It gets called no matter if it is the active window or not

View File

@ -225,6 +225,7 @@ class Config:
'show_mood_in_roster': [opt_bool, True, '', True], 'show_mood_in_roster': [opt_bool, True, '', True],
'show_activity_in_roster': [opt_bool, True, '', True], 'show_activity_in_roster': [opt_bool, True, '', True],
'show_tunes_in_roster': [opt_bool, True, '', True], 'show_tunes_in_roster': [opt_bool, True, '', True],
'show_location_in_roster': [opt_bool, True, '', True],
'avatar_position_in_roster': [opt_str, 'right', _('Define the position of the avatar in roster. Can be left or right'), True], 'avatar_position_in_roster': [opt_str, 'right', _('Define the position of the avatar in roster. Can be left or right'), True],
'ask_avatars_on_startup': [opt_bool, True, _('If True, Gajim will ask for avatar each contact that did not have an avatar last time or has one cached that is too old.')], 'ask_avatars_on_startup': [opt_bool, True, _('If True, Gajim will ask for avatar each contact that did not have an avatar last time or has one cached that is too old.')],
'print_status_in_chats': [opt_bool, True, _('If False, Gajim will no longer print status line in chats when a contact changes his or her status and/or his or her status message.')], 'print_status_in_chats': [opt_bool, True, _('If False, Gajim will no longer print status line in chats when a contact changes his or her status and/or his or her status message.')],
@ -349,10 +350,12 @@ class Config:
'answer_receipts' : [opt_bool, True, _('Answer to receipt requests')], 'answer_receipts' : [opt_bool, True, _('Answer to receipt requests')],
'request_receipt' : [opt_bool, True, _('Sent receipt requests')], 'request_receipt' : [opt_bool, True, _('Sent receipt requests')],
'publish_tune': [opt_bool, False], 'publish_tune': [opt_bool, False],
'publish_location': [opt_bool, False],
'subscribe_mood': [opt_bool, True], 'subscribe_mood': [opt_bool, True],
'subscribe_activity': [opt_bool, True], 'subscribe_activity': [opt_bool, True],
'subscribe_tune': [opt_bool, True], 'subscribe_tune': [opt_bool, True],
'subscribe_nick': [opt_bool, True], 'subscribe_nick': [opt_bool, True],
'subscribe_location': [opt_bool, True],
'ignore_unknown_contacts': [ opt_bool, False ], 'ignore_unknown_contacts': [ opt_bool, False ],
'send_os_info': [ opt_bool, True ], 'send_os_info': [ opt_bool, True ],
'log_encrypted_sessions': [opt_bool, True, _('When negotiating an encrypted session, should Gajim assume you want your messages to be logged?')], 'log_encrypted_sessions': [opt_bool, True, _('When negotiating an encrypted session, should Gajim assume you want your messages to be logged?')],

View File

@ -653,8 +653,8 @@ class Connection(CommonConnection, ConnectionHandlers):
self.last_history_time = {} self.last_history_time = {}
self.password = passwords.get_password(name) self.password = passwords.get_password(name)
# Used to ask privacy only once at connection
self.music_track_info = 0 self.music_track_info = 0
self.location_info = {}
self.pubsub_supported = False self.pubsub_supported = False
self.pubsub_publish_options_supported = False self.pubsub_publish_options_supported = False
# Do we auto accept insecure connection # Do we auto accept insecure connection
@ -2087,12 +2087,11 @@ class Connection(CommonConnection, ConnectionHandlers):
""" """
A groupchat got disconnected. This can be or purpose or not A groupchat got disconnected. This can be or purpose or not
Save the time we quit to avoid duplicate logs AND be faster than get that Save the time we had last message to avoid duplicate logs AND be faster
date from DB. Save it in mem AND in a small table (with fast access) than get that date from DB. Save time that we have in mem in a small
table (with fast access)
""" """
log_time = time_time() gajim.logger.set_room_last_message_time(room_jid, self.last_history_time[room_jid])
self.last_history_time[room_jid] = log_time
gajim.logger.set_room_last_message_time(room_jid, log_time)
def gc_set_role(self, room_jid, nick, role, reason = ''): def gc_set_role(self, room_jid, nick, role, reason = ''):
""" """

View File

@ -2202,6 +2202,11 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream,
# so don't store it in logs # so don't store it in logs
try: try:
gajim.logger.write('gc_msg', frm, msgtxt, tim=tim) gajim.logger.write('gc_msg', frm, msgtxt, tim=tim)
# store in memory time of last message logged.
# this will also be saved in rooms_last_message_time table
# when we quit this muc
self.last_history_time[jid] = mktime(tim)
except exceptions.PysqliteOperationalError, e: except exceptions.PysqliteOperationalError, e:
self.dispatch('ERROR', (_('Disk Write Error'), str(e))) self.dispatch('ERROR', (_('Disk Write Error'), str(e)))
except exceptions.DatabaseMalformed: except exceptions.DatabaseMalformed:

View File

@ -27,7 +27,7 @@ docdir = '../'
basedir = '../' basedir = '../'
localedir = '../po' localedir = '../po'
version = '0.13.0.1-dev' version = '0.13.10.0-dev'
import sys, os.path import sys, os.path
for base in ('.', 'common'): for base in ('.', 'common'):

View File

@ -1290,10 +1290,14 @@ def update_optional_features(account = None):
gajim.gajim_optional_features[a].append(xmpp.NS_ACTIVITY + '+notify') gajim.gajim_optional_features[a].append(xmpp.NS_ACTIVITY + '+notify')
if gajim.config.get_per('accounts', a, 'publish_tune'): if gajim.config.get_per('accounts', a, 'publish_tune'):
gajim.gajim_optional_features[a].append(xmpp.NS_TUNE) gajim.gajim_optional_features[a].append(xmpp.NS_TUNE)
if gajim.config.get_per('accounts', a, 'publish_location'):
gajim.gajim_optional_features[a].append(xmpp.NS_LOCATION)
if gajim.config.get_per('accounts', a, 'subscribe_tune'): if gajim.config.get_per('accounts', a, 'subscribe_tune'):
gajim.gajim_optional_features[a].append(xmpp.NS_TUNE + '+notify') gajim.gajim_optional_features[a].append(xmpp.NS_TUNE + '+notify')
if gajim.config.get_per('accounts', a, 'subscribe_nick'): if gajim.config.get_per('accounts', a, 'subscribe_nick'):
gajim.gajim_optional_features[a].append(xmpp.NS_NICK + '+notify') gajim.gajim_optional_features[a].append(xmpp.NS_NICK + '+notify')
if gajim.config.get_per('accounts', a, 'subscribe_location'):
gajim.gajim_optional_features[a].append(xmpp.NS_LOCATION + '+notify')
if gajim.config.get('outgoing_chat_state_notifactions') != 'disabled': if gajim.config.get('outgoing_chat_state_notifactions') != 'disabled':
gajim.gajim_optional_features[a].append(xmpp.NS_CHATSTATES) gajim.gajim_optional_features[a].append(xmpp.NS_CHATSTATES)
if not gajim.config.get('ignore_incoming_xhtml'): if not gajim.config.get('ignore_incoming_xhtml'):

View File

@ -0,0 +1,137 @@
# -*- coding: utf-8 -*-
## src/common/location_listener.py
##
## Copyright (C) 2009 Yann Leboulanger <asterix AT lagaule.org>
##
## This file is part of Gajim.
##
## Gajim 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; version 3 only.
##
## Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
##
from common import gajim
from common import pep
from common import dbus_support
if dbus_support.supported:
import dbus
import dbus.glib
class LocationListener:
_instance = None
@classmethod
def get(cls):
if cls._instance is None:
cls._instance = cls()
return cls._instance
def __init__(self):
self._data = {}
def get_data(self):
self._get_address()
self._get_position()
def _get_address(self):
bus = dbus.SessionBus()
if 'org.freedesktop.Geoclue.Master' not in bus.list_names():
self._on_geoclue_address_changed()
return
obj = bus.get_object('org.freedesktop.Geoclue.Master',
'/org/freedesktop/Geoclue/Master')
# get MasterClient path
path = obj.Create()
# get MasterClient
cli = bus.get_object('org.freedesktop.Geoclue.Master', path)
cli.AddressStart()
# Check that there is a provider
name, description, service, path = cli.GetAddressProvider()
if path:
timestamp, address, accuracy = cli.GetAddress()
self._on_geoclue_address_changed(timestamp, address, accuracy)
def _get_position(self):
bus = dbus.SessionBus()
if 'org.freedesktop.Geoclue.Master' not in bus.list_names():
self._on_geoclue_position_changed()
return
obj = bus.get_object('org.freedesktop.Geoclue.Master',
'/org/freedesktop/Geoclue/Master')
# get MasterClient path
path = obj.Create()
# get MasterClient
cli = bus.get_object('org.freedesktop.Geoclue.Master', path)
cli.PositionStart()
# Check that there is a provider
name, description, service, path = cli.GetPositionProvider()
if path:
fields, timestamp, lat, lon, alt, accuray = cli.GetPosition()
self._on_geoclue_position_changed(fields, timestamp, lat, lon, alt,
accuracy)
def start(self):
self.get_data()
bus = dbus.SessionBus()
# Geoclue
bus.add_signal_receiver(self._on_geoclue_address_changed,
'AddressChanged', 'org.freedesktop.Geoclue.Address')
bus.add_signal_receiver(self._on_geoclue_position_changed,
'PositionChanged', 'org.freedesktop.Geoclue.Position')
def shut_down(self):
pass
def _on_geoclue_address_changed(self, timestamp=None, address={},
accuracy=None):
# update data with info we just received
for field in ['country', 'countrycode', 'locality', 'postalcode',
'region', 'street']:
self._data[field] = address.get(field, None)
if timestamp:
self._data['timestamp'] = timestamp
if accuracy:
# in PEP it's horizontal accuracy
self._data['accuracy'] = accuracy[1]
self._send_location()
def _on_geoclue_position_changed(self, fields=[], timestamp=None, lat=None,
lon=None, alt=None, accuracy=None):
# update data with info we just received
_dict = {'lat': lat, 'lon': lon, 'alt': alt}
for field in _dict:
if _dict[field] is not None:
self._data[field] = _dict[field]
if timestamp:
self._data['timestamp'] = timestamp
if accuracy:
# in PEP it's horizontal accuracy
self._data['accuracy'] = accuracy[1]
self._send_location()
def _send_location(self):
accounts = gajim.connections.keys()
for acct in accounts:
if not gajim.account_is_connected(acct):
continue
if not gajim.config.get_per('accounts', acct, 'publish_location'):
continue
if gajim.connections[acct].location_info == self._data:
continue
gajim.connections[acct].send_location(self._data)
gajim.connections[acct].location_info = self._data
def enable():
listener = LocationListener.get()
listener.start()
def disable():
listener = LocationListener.get()
listener.shut_down()

View File

@ -212,8 +212,8 @@ class OptionsParser:
self.update_config_to_01257() self.update_config_to_01257()
if old < [0, 12, 5, 8] and new >= [0, 12, 5, 8]: if old < [0, 12, 5, 8] and new >= [0, 12, 5, 8]:
self.update_config_to_01258() self.update_config_to_01258()
if old < [0, 13, 0, 1] and new >= [0, 13, 0, 1]: if old < [0, 13, 10, 0] and new >= [0, 13, 10, 0]:
self.update_config_to_01301() self.update_config_to_013100()
gajim.logger.init_vars() gajim.logger.init_vars()
gajim.config.set('version', new_version) gajim.config.set('version', new_version)
@ -838,7 +838,7 @@ class OptionsParser:
'proxy.jabber.ru', 'proxy.jabbim.cz']) 'proxy.jabber.ru', 'proxy.jabbim.cz'])
gajim.config.set('version', '0.12.5.8') gajim.config.set('version', '0.12.5.8')
def update_config_to_01301(self): def update_config_to_013100(self):
back = os.getcwd() back = os.getcwd()
os.chdir(logger.LOG_DB_FOLDER) os.chdir(logger.LOG_DB_FOLDER)
con = sqlite.connect(logger.LOG_DB_FILE) con = sqlite.connect(logger.LOG_DB_FILE)
@ -855,6 +855,6 @@ class OptionsParser:
except sqlite.OperationalError: except sqlite.OperationalError:
pass pass
con.close() con.close()
gajim.config.set('version', '0.13.0.1') gajim.config.set('version', '0.13.10.0')
# vim: se ts=3: # vim: se ts=3:

View File

@ -191,6 +191,11 @@ ACTIVITIES = {
TUNE_DATA = ['artist', 'title', 'source', 'track', 'length'] TUNE_DATA = ['artist', 'title', 'source', 'track', 'length']
LOCATION_DATA = ['accuracy', 'alt', 'area', 'bearing', 'building', 'country',
'countrycode', 'datum', 'description', 'error', 'floor', 'lat',
'locality', 'lon', 'postalcode', 'region', 'room', 'speed', 'street',
'text', 'timestamp', 'uri']
import gobject import gobject
import gtk import gtk
@ -442,8 +447,52 @@ class UserNicknamePEP(AbstractPEP):
gajim.nicks[account] = self._pep_specific_data gajim.nicks[account] = self._pep_specific_data
class UserLocationPEP(AbstractPEP):
'''XEP-0080: User Location'''
type = 'location'
namespace = xmpp.NS_LOCATION
def _extract_info(self, items):
location_dict = {}
for item in items.getTags('item'):
location_tag = item.getTag('geoloc')
if location_tag:
for child in location_tag.getChildren():
name = child.getName().strip()
data = child.getData().strip()
if child.getName() in LOCATION_DATA:
location_dict[name] = data
retracted = items.getTag('retract') or not location_dict
return (location_dict, retracted)
def _update_account(self, account):
AbstractPEP._update_account(self, account)
con = gajim.connections[account].location_info = \
self._pep_specific_data
def asPixbufIcon(self):
path = gtkgui_helpers.get_icon_path('gajim-earth')
return gtk.gdk.pixbuf_new_from_file(path)
def asMarkupText(self):
assert not self._retracted
location = self._pep_specific_data
location_string = ''
for entry in location.keys():
text = location[entry]
text = gobject.markup_escape_text(text)
location_string += '\n<b>%(tag)s</b>: %(text)s' % \
{'tag': entry.capitalize(), 'text': text}
return location_string.strip()
SUPPORTED_PERSONAL_USER_EVENTS = [UserMoodPEP, UserTunePEP, UserActivityPEP, SUPPORTED_PERSONAL_USER_EVENTS = [UserMoodPEP, UserTunePEP, UserActivityPEP,
UserNicknamePEP] UserNicknamePEP, UserLocationPEP]
class ConnectionPEP(object): class ConnectionPEP(object):
@ -496,8 +545,8 @@ class ConnectionPEP(object):
def retract_activity(self): def retract_activity(self):
if not self.pep_supported: if not self.pep_supported:
return return
# not all server support retract, so send empty pep first
self.send_activity(None) self.send_activity(None)
# not all client support new XEP, so we still retract
self._pubsub_connection.send_pb_retract('', xmpp.NS_ACTIVITY, '0') self._pubsub_connection.send_pb_retract('', xmpp.NS_ACTIVITY, '0')
def send_mood(self, mood, message=None): def send_mood(self, mood, message=None):
@ -515,6 +564,7 @@ class ConnectionPEP(object):
if not self.pep_supported: if not self.pep_supported:
return return
self.send_mood(None) self.send_mood(None)
# not all client support new XEP, so we still retract
self._pubsub_connection.send_pb_retract('', xmpp.NS_MOOD, '0') self._pubsub_connection.send_pb_retract('', xmpp.NS_MOOD, '0')
def send_tune(self, artist='', title='', source='', track=0, length=0, def send_tune(self, artist='', title='', source='', track=0, length=0,
@ -544,8 +594,8 @@ class ConnectionPEP(object):
def retract_tune(self): def retract_tune(self):
if not self.pep_supported: if not self.pep_supported:
return return
# not all server support retract, so send empty pep first
self.send_tune(None) self.send_tune(None)
# not all client support new XEP, so we still retract
self._pubsub_connection.send_pb_retract('', xmpp.NS_TUNE, '0') self._pubsub_connection.send_pb_retract('', xmpp.NS_TUNE, '0')
def send_nickname(self, nick): def send_nickname(self, nick):
@ -558,8 +608,25 @@ class ConnectionPEP(object):
def retract_nickname(self): def retract_nickname(self):
if not self.pep_supported: if not self.pep_supported:
return return
# not all server support retract, so send empty pep first
self.send_nickname(None) self.send_nickname(None)
# not all client support new XEP, so we still retract
self._pubsub_connection.send_pb_retract('', xmpp.NS_NICK, '0') self._pubsub_connection.send_pb_retract('', xmpp.NS_NICK, '0')
def send_location(self, info):
if not self.pep_supported:
return
item = xmpp.Node('geoloc', {'xmlns': xmpp.NS_LOCATION})
for field in LOCATION_DATA:
if info.get(field, None):
i = item.addChild(field)
i.addData(info[field])
self._pubsub_connection.send_pb_publish('', xmpp.NS_LOCATION, item, '0')
def retract_location(self):
if not self.pep_supported:
return
self.send_location({})
# not all client support new XEP, so we still retract
self._pubsub_connection.send_pb_retract('', xmpp.NS_LOCATION, '0')
# vim: se ts=3: # vim: se ts=3:

View File

@ -72,6 +72,7 @@ NS_JINGLE_RTP_VIDEO='urn:xmpp:jingle:apps:rtp:video' # XEP-01
NS_JINGLE_RAW_UDP='urn:xmpp:jingle:transports:raw-udp:1' # XEP-0177 NS_JINGLE_RAW_UDP='urn:xmpp:jingle:transports:raw-udp:1' # XEP-0177
NS_JINGLE_ICE_UDP='urn:xmpp:jingle:transports:ice-udp:1' # XEP-0176 NS_JINGLE_ICE_UDP='urn:xmpp:jingle:transports:ice-udp:1' # XEP-0176
NS_LAST ='jabber:iq:last' NS_LAST ='jabber:iq:last'
NS_LOCATION ='http://jabber.org/protocol/geoloc' # XEP-0080
NS_MESSAGE ='message' # Jabberd2 NS_MESSAGE ='message' # Jabberd2
NS_MOOD ='http://jabber.org/protocol/mood' # XEP-0107 NS_MOOD ='http://jabber.org/protocol/mood' # XEP-0107
NS_MUC ='http://jabber.org/protocol/muc' NS_MUC ='http://jabber.org/protocol/muc'

View File

@ -137,6 +137,11 @@ class PreferencesWindow:
self.xml.get_widget('show_tunes_in_roster_checkbutton'). \ self.xml.get_widget('show_tunes_in_roster_checkbutton'). \
set_active(st) set_active(st)
# Display location in roster
st = gajim.config.get('show_location_in_roster')
self.xml.get_widget('show_location_in_roster_checkbutton'). \
set_active(st)
# Sort contacts by show # Sort contacts by show
st = gajim.config.get('sort_by_show_in_roster') st = gajim.config.get('sort_by_show_in_roster')
self.xml.get_widget('sort_by_show_in_roster_checkbutton').set_active(st) self.xml.get_widget('sort_by_show_in_roster_checkbutton').set_active(st)
@ -615,6 +620,10 @@ class PreferencesWindow:
self.on_checkbutton_toggled(widget, 'show_tunes_in_roster') self.on_checkbutton_toggled(widget, 'show_tunes_in_roster')
gajim.interface.roster.setup_and_draw_roster() gajim.interface.roster.setup_and_draw_roster()
def on_show_location_in_roster_checkbutton_toggled(self, widget):
self.on_checkbutton_toggled(widget, 'show_location_in_roster')
gajim.interface.roster.setup_and_draw_roster()
def on_emoticons_combobox_changed(self, widget): def on_emoticons_combobox_changed(self, widget):
active = widget.get_active() active = widget.get_active()
model = widget.get_model() model = widget.get_model()

View File

@ -50,6 +50,7 @@ from common import gajim
from common import dbus_support from common import dbus_support
if dbus_support.supported: if dbus_support.supported:
from music_track_listener import MusicTrackListener from music_track_listener import MusicTrackListener
from common import location_listener
import dbus import dbus
import gtkgui_helpers import gtkgui_helpers
@ -1547,6 +1548,10 @@ class Interface:
if gajim.connections[account].pep_supported and dbus_support.supported \ if gajim.connections[account].pep_supported and dbus_support.supported \
and gajim.config.get_per('accounts', account, 'publish_tune'): and gajim.config.get_per('accounts', account, 'publish_tune'):
self.enable_music_listener() self.enable_music_listener()
# enable location listener
if gajim.connections[account].pep_supported and dbus_support.supported \
and gajim.config.get_per('accounts', account, 'publish_location'):
location_listener.enable()
def handle_event_metacontacts(self, account, tags_list): def handle_event_metacontacts(self, account, tags_list):
gajim.contacts.define_metacontacts(account, tags_list) gajim.contacts.define_metacontacts(account, tags_list)

View File

@ -59,6 +59,7 @@ from common import helpers
from common.exceptions import GajimGeneralException from common.exceptions import GajimGeneralException
from common import i18n from common import i18n
from common import pep from common import pep
from common import location_listener
from message_window import MessageWindowMgr from message_window import MessageWindowMgr
@ -79,9 +80,10 @@ from common.pep import MOODS, ACTIVITIES
C_MOOD_PIXBUF, C_MOOD_PIXBUF,
C_ACTIVITY_PIXBUF, C_ACTIVITY_PIXBUF,
C_TUNE_PIXBUF, C_TUNE_PIXBUF,
C_LOCATION_PIXBUF,
C_AVATAR_PIXBUF, # avatar_pixbuf C_AVATAR_PIXBUF, # avatar_pixbuf
C_PADLOCK_PIXBUF, # use for account row only C_PADLOCK_PIXBUF, # use for account row only
) = range(10) ) = range(11)
class RosterWindow: class RosterWindow:
""" """
@ -278,7 +280,7 @@ class RosterWindow:
self.model.append(None, [ self.model.append(None, [
gajim.interface.jabber_state_images['16'][show], gajim.interface.jabber_state_images['16'][show],
_('Merged accounts'), 'account', '', 'all', _('Merged accounts'), 'account', '', 'all',
None, None, None, None, None]) None, None, None, None, None, None])
else: else:
show = gajim.SHOW_LIST[gajim.connections[account].connected] show = gajim.SHOW_LIST[gajim.connections[account].connected]
our_jid = gajim.get_jid_from_account(account) our_jid = gajim.get_jid_from_account(account)
@ -293,7 +295,7 @@ class RosterWindow:
self.model.append(None, [ self.model.append(None, [
gajim.interface.jabber_state_images['16'][show], gajim.interface.jabber_state_images['16'][show],
gobject.markup_escape_text(account), 'account', gobject.markup_escape_text(account), 'account',
our_jid, account, None, None, None, None, our_jid, account, None, None, None, None, None,
tls_pixbuf]) tls_pixbuf])
self.draw_account(account) self.draw_account(account)
@ -355,7 +357,8 @@ class RosterWindow:
for child_iter in parent_iters: for child_iter in parent_iters:
it = self.model.append(child_iter, (None, contact.get_shown_name(), it = self.model.append(child_iter, (None, contact.get_shown_name(),
'contact', contact.jid, account, None, None, None, None, None)) 'contact', contact.jid, account, None, None, None, None, None,
None))
added_iters.append(it) added_iters.append(it)
else: else:
# We are a normal contact. Add us to our groups. # We are a normal contact. Add us to our groups.
@ -370,7 +373,7 @@ class RosterWindow:
child_iterG = self.model.append(child_iterA, child_iterG = self.model.append(child_iterA,
[gajim.interface.jabber_state_images['16']['closed'], [gajim.interface.jabber_state_images['16']['closed'],
gobject.markup_escape_text(group), gobject.markup_escape_text(group),
'group', group, account, None, None, None, None, None]) 'group', group, account, None, None, None, None, None, None])
self.draw_group(group, account) self.draw_group(group, account)
if contact.is_transport(): if contact.is_transport():
@ -385,7 +388,7 @@ class RosterWindow:
i_ = self.model.append(child_iterG, (None, i_ = self.model.append(child_iterG, (None,
contact.get_shown_name(), typestr, contact.get_shown_name(), typestr,
contact.jid, account, None, None, None, contact.jid, account, None, None, None,
None, None)) None, None, None))
added_iters.append(i_) added_iters.append(i_)
# Restore the group expand state # Restore the group expand state
@ -627,7 +630,7 @@ class RosterWindow:
child_iterA = self._get_account_iter(account, self.model) child_iterA = self._get_account_iter(account, self.model)
self.model.append(child_iterA, (None, gajim.nicks[account], self.model.append(child_iterA, (None, gajim.nicks[account],
'self_contact', jid, account, None, None, None, None, 'self_contact', jid, account, None, None, None, None,
None)) None, None))
self.draw_completely(jid, account) self.draw_completely(jid, account)
self.draw_account(account) self.draw_account(account)
@ -1050,6 +1053,11 @@ class RosterWindow:
self.model[child_iter][C_TUNE_PIXBUF] = pep['tune'].asPixbufIcon() self.model[child_iter][C_TUNE_PIXBUF] = pep['tune'].asPixbufIcon()
else: else:
self.model[child_iter][C_TUNE_PIXBUF] = None self.model[child_iter][C_TUNE_PIXBUF] = None
if gajim.config.get('show_location_in_roster') and 'location' in pep:
self.model[child_iter][C_LOCATION_PIXBUF] = pep['location'].asPixbufIcon()
else:
self.model[child_iter][C_LOCATION_PIXBUF] = None
return False return False
def draw_group(self, group, account): def draw_group(self, group, account):
@ -1264,6 +1272,8 @@ class RosterWindow:
return gajim.config.get('show_activity_in_roster') return gajim.config.get('show_activity_in_roster')
elif pep_type == 'tune': elif pep_type == 'tune':
return gajim.config.get('show_tunes_in_roster') return gajim.config.get('show_tunes_in_roster')
elif pep_type == 'location':
return gajim.config.get('show_location_in_roster')
else: else:
return False return False
@ -1362,10 +1372,11 @@ class RosterWindow:
""" """
self.modelfilter = None self.modelfilter = None
# (icon, name, type, jid, account, editable, mood_pixbuf, # (icon, name, type, jid, account, editable, mood_pixbuf,
# activity_pixbuf, tune_pixbuf avatar_pixbuf, padlock_pixbuf) # activity_pixbuf, tune_pixbuf, location_pixbuf, avatar_pixbuf,
# padlock_pixbuf)
self.model = gtk.TreeStore(gtk.Image, str, str, str, str, self.model = gtk.TreeStore(gtk.Image, str, str, str, str,
gtk.gdk.Pixbuf, gtk.gdk.Pixbuf, gtk.gdk.Pixbuf, gtk.gdk.Pixbuf, gtk.gdk.Pixbuf, gtk.gdk.Pixbuf,
gtk.gdk.Pixbuf, gtk.gdk.Pixbuf) gtk.gdk.Pixbuf, gtk.gdk.Pixbuf, gtk.gdk.Pixbuf)
self.model.set_sort_func(1, self._compareIters) self.model.set_sort_func(1, self._compareIters)
self.model.set_sort_column_id(1, gtk.SORT_ASCENDING) self.model.set_sort_column_id(1, gtk.SORT_ASCENDING)
@ -3058,6 +3069,9 @@ class RosterWindow:
return return
type_ = model[list_of_paths[0]][C_TYPE] type_ = model[list_of_paths[0]][C_TYPE]
account = model[list_of_paths[0]][C_ACCOUNT].decode('utf-8') account = model[list_of_paths[0]][C_ACCOUNT].decode('utf-8')
if type_ in ('account', 'group', 'self_contact') or \
account == gajim.ZEROCONF_ACC_NAME:
return
list_ = [] list_ = []
for path in list_of_paths: for path in list_of_paths:
if model[path][C_TYPE] != type_: if model[path][C_TYPE] != type_:
@ -3067,9 +3081,6 @@ class RosterWindow:
contact = gajim.contacts.get_contact_with_highest_priority(account, contact = gajim.contacts.get_contact_with_highest_priority(account,
jid) jid)
list_.append((contact, account)) list_.append((contact, account))
if type_ in ('account', 'group', 'self_contact') or \
account == gajim.ZEROCONF_ACC_NAME:
return
if type_ == 'contact': if type_ == 'contact':
self.on_req_usub(widget, list_) self.on_req_usub(widget, list_)
elif type_ == 'agent': elif type_ == 'agent':
@ -3423,6 +3434,22 @@ class RosterWindow:
helpers.update_optional_features(account) helpers.update_optional_features(account)
def on_publish_location_toggled(self, widget, account):
active = widget.get_active()
gajim.config.set_per('accounts', account, 'publish_location', active)
if active:
location_listener.enable()
else:
gajim.connections[account].retract_location()
# disable music listener only if no other account uses it
for acc in gajim.connections:
if gajim.config.get_per('accounts', acc, 'publish_location'):
break
else:
location_listener.disable()
helpers.update_optional_features(account)
def on_pep_services_menuitem_activate(self, widget, account): def on_pep_services_menuitem_activate(self, widget, account):
if 'pep_services' in gajim.interface.instances[account]: if 'pep_services' in gajim.interface.instances[account]:
gajim.interface.instances[account]['pep_services'].window.present() gajim.interface.instances[account]['pep_services'].window.present()
@ -4981,17 +5008,22 @@ class RosterWindow:
pep_menuitem = xml.get_widget('pep_menuitem') pep_menuitem = xml.get_widget('pep_menuitem')
if gajim.connections[account].pep_supported: if gajim.connections[account].pep_supported:
have_tune = gajim.config.get_per('accounts', account,
'publish_tune')
pep_submenu = gtk.Menu() pep_submenu = gtk.Menu()
pep_menuitem.set_submenu(pep_submenu) pep_menuitem.set_submenu(pep_submenu)
item = gtk.CheckMenuItem(_('Publish Tune')) def add_item(label, opt_name, func):
item = gtk.CheckMenuItem(label)
pep_submenu.append(item) pep_submenu.append(item)
if not dbus_support.supported: if not dbus_support.supported:
item.set_sensitive(False) item.set_sensitive(False)
else: else:
item.set_active(have_tune) activ = gajim.config.get_per('accounts', account, opt_name)
item.connect('toggled', self.on_publish_tune_toggled, account) item.set_active(activ)
item.connect('toggled', func, account)
add_item(_('Publish Tune'), 'publish_tune',
self.on_publish_tune_toggled)
add_item(_('Publish Location'), 'publish_location',
self.on_publish_location_toggled)
pep_config = gtk.ImageMenuItem(_('Configure Services...')) pep_config = gtk.ImageMenuItem(_('Configure Services...'))
item = gtk.SeparatorMenuItem() item = gtk.SeparatorMenuItem()
@ -5892,9 +5924,16 @@ class RosterWindow:
col.set_cell_data_func(render_pixbuf, col.set_cell_data_func(render_pixbuf,
self._fill_pep_pixbuf_renderer, C_TUNE_PIXBUF) self._fill_pep_pixbuf_renderer, C_TUNE_PIXBUF)
render_pixbuf = gtk.CellRendererPixbuf()
col.pack_start(render_pixbuf, expand=False)
col.add_attribute(render_pixbuf, 'pixbuf', C_LOCATION_PIXBUF)
col.set_cell_data_func(render_pixbuf,
self._fill_pep_pixbuf_renderer, C_LOCATION_PIXBUF)
self._pep_type_to_model_column = {'mood': C_MOOD_PIXBUF, self._pep_type_to_model_column = {'mood': C_MOOD_PIXBUF,
'activity': C_ACTIVITY_PIXBUF, 'activity': C_ACTIVITY_PIXBUF,
'tune': C_TUNE_PIXBUF} 'tune': C_TUNE_PIXBUF,
'location': C_LOCATION_PIXBUF}
if gajim.config.get('avatar_position_in_roster') == 'right': if gajim.config.get('avatar_position_in_roster') == 'right':
add_avatar_renderer() add_avatar_renderer()

View File

@ -600,7 +600,7 @@ class RosterTooltip(NotificationAreaTooltip):
def _append_pep_info(self, contact, properties): def _append_pep_info(self, contact, properties):
""" """
Append Tune, Mood, Activity information of the specified contact Append Tune, Mood, Activity, Location information of the specified contact
to the given property list. to the given property list.
""" """
if 'mood' in contact.pep: if 'mood' in contact.pep:
@ -618,6 +618,11 @@ class RosterTooltip(NotificationAreaTooltip):
tune_string = _('Tune:') + ' %s' % tune tune_string = _('Tune:') + ' %s' % tune
properties.append((tune_string, None)) properties.append((tune_string, None))
if 'location' in contact.pep:
location = contact.pep['location'].asMarkupText()
location_string = _('Location:') + ' %s' % location
properties.append((location_string, None))
class FileTransfersTooltip(BaseTooltip): class FileTransfersTooltip(BaseTooltip):
""" """