Refactor UserNickname and UserMood

- Use IconTheme for mood icons
- Simplify modules because nbxmpp handles more stuff
This commit is contained in:
Philipp Hörist 2019-01-30 20:23:16 +01:00
parent 8e336311cc
commit be95b04007
101 changed files with 243 additions and 167 deletions

View file

@ -47,6 +47,7 @@ from gajim.common.contacts import GC_Contact
from gajim.common.const import AvatarSize from gajim.common.const import AvatarSize
from gajim.common.const import KindConstant from gajim.common.const import KindConstant
from gajim.common.const import Chatstate from gajim.common.const import Chatstate
from gajim.common.const import PEPEventType
from gajim import gtkgui_helpers from gajim import gtkgui_helpers
from gajim import gui_menu_builder from gajim import gui_menu_builder
@ -57,6 +58,8 @@ from gajim.gtk.dialogs import ConfirmationDialog
from gajim.gtk.add_contact import AddNewContactWindow from gajim.gtk.add_contact import AddNewContactWindow
from gajim.gtk.util import get_icon_name from gajim.gtk.util import get_icon_name
from gajim.gtk.util import get_cursor from gajim.gtk.util import get_cursor
from gajim.gtk.util import ensure_proper_control
from gajim.gtk.util import format_mood
from gajim.command_system.implementation.hosts import ChatCommands from gajim.command_system.implementation.hosts import ChatCommands
from gajim.command_system.framework import CommandHost # pylint: disable=unused-import from gajim.command_system.framework import CommandHost # pylint: disable=unused-import
@ -128,7 +131,6 @@ class ChatControl(ChatControlBase):
self.update_toolbar() self.update_toolbar()
self._pep_images = {} self._pep_images = {}
self._pep_images['mood'] = self.xml.get_object('mood_image')
self._pep_images['activity'] = self.xml.get_object('activity_image') self._pep_images['activity'] = self.xml.get_object('activity_image')
self._pep_images['tune'] = self.xml.get_object('tune_image') self._pep_images['tune'] = self.xml.get_object('tune_image')
self._pep_images['geoloc'] = self.xml.get_object('location_image') self._pep_images['geoloc'] = self.xml.get_object('location_image')
@ -227,6 +229,10 @@ class ChatControl(ChatControlBase):
app.ged.register_event_handler('pep-received', ged.GUI1, app.ged.register_event_handler('pep-received', ged.GUI1,
self._nec_pep_received) 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,
self._on_mood_received)
if self.TYPE_ID == message_control.TYPE_CHAT: if self.TYPE_ID == message_control.TYPE_CHAT:
# Dont connect this when PrivateChatControl is used # Dont connect this when PrivateChatControl is used
app.ged.register_event_handler('update-roster-avatar', ged.GUI1, app.ged.register_event_handler('update-roster-avatar', ged.GUI1,
@ -409,6 +415,7 @@ class ChatControl(ChatControlBase):
def update_all_pep_types(self): def update_all_pep_types(self):
for pep_type in self._pep_images: for pep_type in self._pep_images:
self.update_pep(pep_type) self.update_pep(pep_type)
self._update_pep(PEPEventType.MOOD)
def update_pep(self, pep_type): def update_pep(self, pep_type):
if isinstance(self.contact, GC_Contact): if isinstance(self.contact, GC_Contact):
@ -434,12 +441,36 @@ class ChatControl(ChatControlBase):
if obj.jid != self.contact.jid: if obj.jid != self.contact.jid:
return return
if obj.pep_type == 'nick': self.update_pep(obj.pep_type)
self.update_ui()
self.parent_win.redraw_tab(self) def _update_pep(self, type_):
self.parent_win.show_title() image = self._get_pep_widget(type_)
else: data = self.contact.pep.get(type_)
self.update_pep(obj.pep_type) if data is None:
image.hide()
return
if type_ == PEPEventType.MOOD:
icon = 'mood-%s' % data.mood
formated_text = format_mood(*data)
image.set_from_icon_name(icon, Gtk.IconSize.MENU)
image.set_tooltip_markup(formated_text)
image.show()
def _get_pep_widget(self, type_):
if type_ == PEPEventType.MOOD:
return self.xml.get_object('mood_image')
@ensure_proper_control
def _on_mood_received(self, _event):
self._update_pep(PEPEventType.MOOD)
@ensure_proper_control
def _on_nickname_received(self, _event):
self.update_ui()
self.parent_win.redraw_tab(self)
self.parent_win.show_title()
def _update_jingle(self, jingle_type): def _update_jingle(self, jingle_type):
if jingle_type not in ('audio', 'video'): if jingle_type not in ('audio', 'video'):
@ -1051,6 +1082,10 @@ class ChatControl(ChatControlBase):
app.ged.remove_event_handler('pep-received', ged.GUI1, app.ged.remove_event_handler('pep-received', ged.GUI1,
self._nec_pep_received) 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,
self._on_mood_received)
if self.TYPE_ID == message_control.TYPE_CHAT: if self.TYPE_ID == message_control.TYPE_CHAT:
app.ged.remove_event_handler('update-roster-avatar', ged.GUI1, app.ged.remove_event_handler('update-roster-avatar', ged.GUI1,
self._nec_update_avatar) self._nec_update_avatar)

View file

@ -221,8 +221,6 @@ class ConfigPaths:
'emoticons', PathLocation.DATA, PathType.FOLDER_OPTIONAL), 'emoticons', PathLocation.DATA, PathType.FOLDER_OPTIONAL),
('MY_ICONSETS', ('MY_ICONSETS',
'iconsets', PathLocation.DATA, PathType.FOLDER_OPTIONAL), 'iconsets', PathLocation.DATA, PathType.FOLDER_OPTIONAL),
('MY_MOOD_ICONSETS',
'moods', PathLocation.DATA, PathType.FOLDER_OPTIONAL),
('MY_ACTIVITY_ICONSETS', ('MY_ACTIVITY_ICONSETS',
'activities', PathLocation.DATA, PathType.FOLDER_OPTIONAL), 'activities', PathLocation.DATA, PathType.FOLDER_OPTIONAL),

View file

@ -1631,6 +1631,7 @@ class Connection(CommonConnection, ConnectionHandlers):
# Inform GUI we just signed in # Inform GUI we just signed in
app.nec.push_incoming_event(NetworkEvent('signed-in', conn=self)) app.nec.push_incoming_event(NetworkEvent('signed-in', conn=self))
modules.send_stored_publish(self.name)
self.get_module('PEP').send_stored_publish() self.get_module('PEP').send_stored_publish()
self.continue_connect_info = None self.continue_connect_info = None

View file

@ -1098,13 +1098,6 @@ def get_current_show(account):
status = app.connections[account].connected status = app.connections[account].connected
return app.SHOW_LIST[status] return app.SHOW_LIST[status]
def get_mood_iconset_path(iconset):
if os.path.isdir(os.path.join(configpaths.get('DATA'), 'moods', iconset)):
return os.path.join(configpaths.get('DATA'), 'moods', iconset)
if os.path.isdir(
os.path.join(configpaths.get('MY_MOOD_ICONSETS'), iconset)):
return os.path.join(configpaths.get('MY_MOOD_ICONSETS'), iconset)
def get_activity_iconset_path(iconset): def get_activity_iconset_path(iconset):
if os.path.isdir(os.path.join(configpaths.get('DATA'), 'activities', iconset)): if os.path.isdir(os.path.join(configpaths.get('DATA'), 'activities', iconset)):
return os.path.join(configpaths.get('DATA'), 'activities', iconset) return os.path.join(configpaths.get('DATA'), 'activities', iconset)

View file

@ -34,6 +34,8 @@ ZEROCONF_MODULES = ['iq',
_imported_modules = [] # type: List[tuple] _imported_modules = [] # type: List[tuple]
_modules = {} # type: Dict[str, Dict[str, Any]] _modules = {} # type: Dict[str, Dict[str, Any]]
_store_publish_modules = [
'UserMood'] # type: List[str]
for file in Path(__file__).parent.iterdir(): for file in Path(__file__).parent.iterdir():
if file.stem == '__init__': if file.stem == '__init__':
@ -112,6 +114,11 @@ def unregister_single(con: ConnectionT, name: str) -> None:
del _modules[con.name][name] del _modules[con.name][name]
def send_stored_publish(account: str) -> None:
for name in _store_publish_modules:
_modules[account][name].send_stored_publish()
def get(account: str, name: str) -> Any: def get(account: str, name: str) -> Any:
try: try:
return _modules[account][name] return _modules[account][name]

View file

@ -20,6 +20,9 @@ import logging
from functools import partial from functools import partial
from unittest.mock import Mock from unittest.mock import Mock
import nbxmpp
from nbxmpp.structs import StanzaHandler
from gajim.common import app from gajim.common import app
log = logging.getLogger('gajim.c.m.base') log = logging.getLogger('gajim.c.m.base')
@ -34,6 +37,7 @@ class BaseModule:
self._con = con self._con = con
self._account = con.name self._account = con.name
self._nbxmpp_callbacks = {} # type: Dict[str, Any] self._nbxmpp_callbacks = {} # type: Dict[str, Any]
self._stored_publish = None # type: Callable
self.handlers = [] # type: List[str] self.handlers = [] # type: List[str]
def __getattr__(self, key): def __getattr__(self, key):
@ -46,8 +50,10 @@ class BaseModule:
module = self._con.connection.get_module(self._nbxmpp_extends) module = self._con.connection.get_module(self._nbxmpp_extends)
return partial(getattr(module, key), callback = self._nbxmpp_callbacks.get(key)
callback=self._nbxmpp_callbacks.get(key)) if callback is None:
return getattr(module, key)
return partial(getattr(module, key), callback=callback)
def _nbxmpp(self, module_name=None): def _nbxmpp(self, module_name=None):
if not app.account_is_connected(self._account): if not app.account_is_connected(self._account):
@ -61,3 +67,16 @@ class BaseModule:
def _register_callback(self, method, callback): def _register_callback(self, method, callback):
self._nbxmpp_callbacks[method] = callback self._nbxmpp_callbacks[method] = callback
def _register_pubsub_handler(self, callback):
handler = StanzaHandler(name='message',
callback=callback,
ns=nbxmpp.NS_PUBSUB_EVENT,
priority=49)
self.handlers.append(handler)
def send_stored_publish(self):
if self._stored_publish is None:
return
log.info('Send stored publish')
self._stored_publish()

View file

@ -55,12 +55,11 @@ class Message:
] ]
# XEPs for which this message module should not be executed # XEPs for which this message module should not be executed
self._message_namespaces = set([nbxmpp.NS_PUBSUB_EVENT, self._message_namespaces = set([nbxmpp.NS_ROSTERX,
nbxmpp.NS_ROSTERX,
nbxmpp.NS_IBB]) nbxmpp.NS_IBB])
def _message_received(self, _con, stanza, properties): def _message_received(self, _con, stanza, properties):
if properties.is_mam_message: if properties.is_mam_message or properties.is_pubsub_event:
return return
# Check if a child of the message contains any # Check if a child of the message contains any
# namespaces that we handle in other modules. # namespaces that we handle in other modules.

View file

@ -6,94 +6,69 @@
# #
# Gajim is distributed in the hope that it will be useful, # Gajim is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>. # along with Gajim. If not, see <http://www.gnu.org/licenses/>.
# XEP-0107: User Mood # XEP-0107: User Mood
from typing import Any from typing import Any
from typing import Dict
from typing import List # pylint: disable=unused-import
from typing import Optional
from typing import Tuple from typing import Tuple
import logging import logging
import nbxmpp import nbxmpp
from gi.repository import GLib
from gajim.common.const import PEPEventType, MOODS from gajim.common import app
from gajim.common.exceptions import StanzaMalformed from gajim.common.nec import NetworkEvent
from gajim.common.modules.pep import AbstractPEPModule, AbstractPEPData 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_mood') log = logging.getLogger('gajim.c.m.user_mood')
class UserMoodData(AbstractPEPData): class UserMood(BaseModule):
type_ = PEPEventType.MOOD _nbxmpp_extends = 'Mood'
_nbxmpp_methods = [
'set_mood',
]
def as_markup_text(self) -> str: def __init__(self, con):
if self.data is None: BaseModule.__init__(self, con)
return '' self._register_pubsub_handler(self._mood_received)
mood = self._translate_mood(self.data['mood'])
markuptext = '<b>%s</b>' % GLib.markup_escape_text(mood)
if 'text' in self.data:
text = self.data['text']
markuptext += ' (%s)' % GLib.markup_escape_text(text)
return markuptext
@staticmethod @event_node(nbxmpp.NS_MOOD)
def _translate_mood(mood: str) -> str: def _mood_received(self, _con, _stanza, properties):
if mood in MOODS: data = properties.pubsub_event.data
return MOODS[mood] for contact in app.contacts.get_contacts(self._account,
return mood str(properties.jid)):
if data.mood is not None:
contact.pep[PEPEventType.MOOD] = data
class UserMood(AbstractPEPModule):
name = 'mood'
namespace = nbxmpp.NS_MOOD
pep_class = UserMoodData
store_publish = True
_log = log
def _extract_info(self, item: nbxmpp.Node) -> Optional[Dict[str, str]]:
mood_dict = {}
mood_tag = item.getTag('mood', namespace=nbxmpp.NS_MOOD)
if mood_tag is None:
raise StanzaMalformed('No mood node')
if not mood_tag.getChildren():
return None
for child in mood_tag.getChildren():
name = child.getName().strip()
if name == 'text':
mood_dict['text'] = child.getData()
else: else:
mood_dict['mood'] = name contact.pep.pop(PEPEventType.MOOD, None)
if 'mood' not in mood_dict: if properties.is_self_message:
raise StanzaMalformed('No mood value found') if data.mood is not None:
return mood_dict self._con.pep[PEPEventType.MOOD] = data
else:
self._con.pep.pop(PEPEventType.MOOD, None)
def _build_node(self, data: Optional[Tuple[str, str]]) -> nbxmpp.Node: app.nec.push_incoming_event(
item = nbxmpp.Node('mood', {'xmlns': nbxmpp.NS_MOOD}) NetworkEvent('mood-received',
if data is None: account=self._account,
return item jid=properties.jid.getBare(),
mood=data,
is_self_message=properties.is_self_message))
mood, text = data @store_publish
if not mood: def set_mood(self, mood):
return item log.info('Send %s', mood)
item.addChild(mood) self._nbxmpp('Mood').set_mood(mood)
if text:
item.addChild('text', payload=text)
return item
def get_instance(*args: Any, **kwargs: Any) -> Tuple[UserMood, str]: def get_instance(*args: Any, **kwargs: Any) -> Tuple[UserMood, str]:

View file

@ -6,17 +6,15 @@
# #
# Gajim is distributed in the hope that it will be useful, # Gajim is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>. # along with Gajim. If not, see <http://www.gnu.org/licenses/>.
# XEP-0172: User Nickname # XEP-0172: User Nickname
from typing import Any from typing import Any
from typing import List # pylint: disable=unused-import
from typing import Optional
from typing import Tuple from typing import Tuple
import logging import logging
@ -24,56 +22,41 @@ import logging
import nbxmpp import nbxmpp
from gajim.common import app from gajim.common import app
from gajim.common.const import PEPEventType from gajim.common.nec import NetworkEvent
from gajim.common.exceptions import StanzaMalformed from gajim.common.modules.base import BaseModule
from gajim.common.modules.pep import AbstractPEPModule, AbstractPEPData from gajim.common.modules.util import event_node
log = logging.getLogger('gajim.c.m.user_nickname') log = logging.getLogger('gajim.c.m.user_nickname')
class UserNicknameData(AbstractPEPData): class UserNickname(BaseModule):
type_ = PEPEventType.NICKNAME _nbxmpp_extends = 'Nickname'
_nbxmpp_methods = [
'set_nickname',
]
def get_nick(self) -> str: def __init__(self, con):
return self.data or '' BaseModule.__init__(self, con)
self._register_pubsub_handler(self._nickname_received)
@event_node(nbxmpp.NS_NICK)
def _nickname_received(self, _con, _stanza, properties):
nick = properties.pubsub_event.data
if properties.self_message:
if nick is None:
nick = app.config.get_per('accounts', self._account, 'name')
app.nicks[self._account] = nick
class UserNickname(AbstractPEPModule): for contact in app.contacts.get_contacts(self._account,
str(properties.jid)):
contact.contact_name = nick
name = 'nick' app.nec.push_incoming_event(
namespace = nbxmpp.NS_NICK NetworkEvent('nickname-received',
pep_class = UserNicknameData account=self._account,
store_publish = True jid=properties.jid.getBare(),
_log = log nickname=nick))
def _extract_info(self, item: nbxmpp.Node) -> Optional[str]:
nick = ''
child = item.getTag('nick', namespace=nbxmpp.NS_NICK)
if child is None:
raise StanzaMalformed('No nick node')
nick = child.getData()
return nick or None
def _build_node(self, data: Optional[str]) -> Optional[nbxmpp.Node]:
item = nbxmpp.Node('nick', {'xmlns': nbxmpp.NS_NICK})
if data is not None:
item.addData(data)
return item
def _notification_received(self,
jid: nbxmpp.JID,
user_pep: UserNicknameData) -> None:
for contact in app.contacts.get_contacts(self._account, str(jid)):
contact.contact_name = user_pep.get_nick()
if jid == self._con.get_own_jid().getStripped():
if user_pep:
app.nicks[self._account] = user_pep.get_nick()
else:
app.nicks[self._account] = app.config.get_per(
'accounts', self._account, 'name')
def parse_nickname(stanza: nbxmpp.Node) -> str: def parse_nickname(stanza: nbxmpp.Node) -> str:

View file

@ -16,6 +16,11 @@
from typing import Union from typing import Union
from functools import wraps
from functools import partial
from gajim.common import app
def from_xs_boolean(value: Union[str, bool]) -> bool: def from_xs_boolean(value: Union[str, bool]) -> bool:
if isinstance(value, bool): if isinstance(value, bool):
@ -44,3 +49,25 @@ def to_xs_boolean(value: Union[bool, None]) -> str:
raise ValueError( raise ValueError(
'Cant convert %s to xs:boolean' % value) 'Cant convert %s to xs:boolean' % value)
def event_node(node):
def event_node_decorator(func):
@wraps(func)
def func_wrapper(self, _con, _stanza, properties):
if properties.pubsub_event.node != node:
return
func(self, _con, _stanza, properties)
return func_wrapper
return event_node_decorator
def store_publish(func):
@wraps(func)
def func_wrapper(self, *args, **kwargs):
if not app.account_is_connected(self._account):
self._stored_publish = partial(func, self, *args, **kwargs)
return
return func(self, *args, **kwargs)
return func_wrapper

View file

Before

Width:  |  Height:  |  Size: 984 B

After

Width:  |  Height:  |  Size: 984 B

View file

Before

Width:  |  Height:  |  Size: 966 B

After

Width:  |  Height:  |  Size: 966 B

View file

Before

Width:  |  Height:  |  Size: 989 B

After

Width:  |  Height:  |  Size: 989 B

View file

Before

Width:  |  Height:  |  Size: 943 B

After

Width:  |  Height:  |  Size: 943 B

View file

Before

Width:  |  Height:  |  Size: 924 B

After

Width:  |  Height:  |  Size: 924 B

View file

Before

Width:  |  Height:  |  Size: 949 B

After

Width:  |  Height:  |  Size: 949 B

View file

Before

Width:  |  Height:  |  Size: 956 B

After

Width:  |  Height:  |  Size: 956 B

View file

Before

Width:  |  Height:  |  Size: 942 B

After

Width:  |  Height:  |  Size: 942 B

View file

Before

Width:  |  Height:  |  Size: 934 B

After

Width:  |  Height:  |  Size: 934 B

View file

Before

Width:  |  Height:  |  Size: 931 B

After

Width:  |  Height:  |  Size: 931 B

View file

Before

Width:  |  Height:  |  Size: 918 B

After

Width:  |  Height:  |  Size: 918 B

View file

Before

Width:  |  Height:  |  Size: 922 B

After

Width:  |  Height:  |  Size: 922 B

View file

Before

Width:  |  Height:  |  Size: 996 B

After

Width:  |  Height:  |  Size: 996 B

View file

Before

Width:  |  Height:  |  Size: 913 B

After

Width:  |  Height:  |  Size: 913 B

View file

Before

Width:  |  Height:  |  Size: 951 B

After

Width:  |  Height:  |  Size: 951 B

View file

Before

Width:  |  Height:  |  Size: 907 B

After

Width:  |  Height:  |  Size: 907 B

View file

Before

Width:  |  Height:  |  Size: 886 B

After

Width:  |  Height:  |  Size: 886 B

View file

Before

Width:  |  Height:  |  Size: 939 B

After

Width:  |  Height:  |  Size: 939 B

View file

Before

Width:  |  Height:  |  Size: 981 B

After

Width:  |  Height:  |  Size: 981 B

View file

Before

Width:  |  Height:  |  Size: 916 B

After

Width:  |  Height:  |  Size: 916 B

View file

Before

Width:  |  Height:  |  Size: 944 B

After

Width:  |  Height:  |  Size: 944 B

View file

Before

Width:  |  Height:  |  Size: 886 B

After

Width:  |  Height:  |  Size: 886 B

View file

Before

Width:  |  Height:  |  Size: 1,001 B

After

Width:  |  Height:  |  Size: 1,001 B

View file

Before

Width:  |  Height:  |  Size: 918 B

After

Width:  |  Height:  |  Size: 918 B

View file

Before

Width:  |  Height:  |  Size: 956 B

After

Width:  |  Height:  |  Size: 956 B

View file

Before

Width:  |  Height:  |  Size: 964 B

After

Width:  |  Height:  |  Size: 964 B

View file

Before

Width:  |  Height:  |  Size: 871 B

After

Width:  |  Height:  |  Size: 871 B

View file

Before

Width:  |  Height:  |  Size: 902 B

After

Width:  |  Height:  |  Size: 902 B

View file

Before

Width:  |  Height:  |  Size: 960 B

After

Width:  |  Height:  |  Size: 960 B

View file

Before

Width:  |  Height:  |  Size: 949 B

After

Width:  |  Height:  |  Size: 949 B

View file

Before

Width:  |  Height:  |  Size: 906 B

After

Width:  |  Height:  |  Size: 906 B

View file

Before

Width:  |  Height:  |  Size: 975 B

After

Width:  |  Height:  |  Size: 975 B

View file

Before

Width:  |  Height:  |  Size: 923 B

After

Width:  |  Height:  |  Size: 923 B

View file

Before

Width:  |  Height:  |  Size: 928 B

After

Width:  |  Height:  |  Size: 928 B

View file

Before

Width:  |  Height:  |  Size: 897 B

After

Width:  |  Height:  |  Size: 897 B

View file

Before

Width:  |  Height:  |  Size: 923 B

After

Width:  |  Height:  |  Size: 923 B

View file

Before

Width:  |  Height:  |  Size: 880 B

After

Width:  |  Height:  |  Size: 880 B

View file

Before

Width:  |  Height:  |  Size: 883 B

After

Width:  |  Height:  |  Size: 883 B

View file

Before

Width:  |  Height:  |  Size: 982 B

After

Width:  |  Height:  |  Size: 982 B

View file

Before

Width:  |  Height:  |  Size: 925 B

After

Width:  |  Height:  |  Size: 925 B

View file

Before

Width:  |  Height:  |  Size: 924 B

After

Width:  |  Height:  |  Size: 924 B

View file

Before

Width:  |  Height:  |  Size: 855 B

After

Width:  |  Height:  |  Size: 855 B

View file

Before

Width:  |  Height:  |  Size: 954 B

After

Width:  |  Height:  |  Size: 954 B

View file

Before

Width:  |  Height:  |  Size: 972 B

After

Width:  |  Height:  |  Size: 972 B

View file

Before

Width:  |  Height:  |  Size: 979 B

After

Width:  |  Height:  |  Size: 979 B

View file

Before

Width:  |  Height:  |  Size: 979 B

After

Width:  |  Height:  |  Size: 979 B

View file

Before

Width:  |  Height:  |  Size: 922 B

After

Width:  |  Height:  |  Size: 922 B

View file

Before

Width:  |  Height:  |  Size: 968 B

After

Width:  |  Height:  |  Size: 968 B

View file

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 1 KiB

View file

Before

Width:  |  Height:  |  Size: 986 B

After

Width:  |  Height:  |  Size: 986 B

View file

Before

Width:  |  Height:  |  Size: 923 B

After

Width:  |  Height:  |  Size: 923 B

View file

Before

Width:  |  Height:  |  Size: 914 B

After

Width:  |  Height:  |  Size: 914 B

View file

Before

Width:  |  Height:  |  Size: 940 B

After

Width:  |  Height:  |  Size: 940 B

View file

Before

Width:  |  Height:  |  Size: 888 B

After

Width:  |  Height:  |  Size: 888 B

View file

Before

Width:  |  Height:  |  Size: 889 B

After

Width:  |  Height:  |  Size: 889 B

View file

Before

Width:  |  Height:  |  Size: 892 B

After

Width:  |  Height:  |  Size: 892 B

View file

Before

Width:  |  Height:  |  Size: 963 B

After

Width:  |  Height:  |  Size: 963 B

View file

Before

Width:  |  Height:  |  Size: 903 B

After

Width:  |  Height:  |  Size: 903 B

View file

Before

Width:  |  Height:  |  Size: 914 B

After

Width:  |  Height:  |  Size: 914 B

View file

Before

Width:  |  Height:  |  Size: 987 B

After

Width:  |  Height:  |  Size: 987 B

View file

Before

Width:  |  Height:  |  Size: 947 B

After

Width:  |  Height:  |  Size: 947 B

View file

Before

Width:  |  Height:  |  Size: 914 B

After

Width:  |  Height:  |  Size: 914 B

View file

Before

Width:  |  Height:  |  Size: 949 B

After

Width:  |  Height:  |  Size: 949 B

View file

Before

Width:  |  Height:  |  Size: 969 B

After

Width:  |  Height:  |  Size: 969 B

View file

Before

Width:  |  Height:  |  Size: 935 B

After

Width:  |  Height:  |  Size: 935 B

View file

Before

Width:  |  Height:  |  Size: 966 B

After

Width:  |  Height:  |  Size: 966 B

View file

Before

Width:  |  Height:  |  Size: 978 B

After

Width:  |  Height:  |  Size: 978 B

View file

Before

Width:  |  Height:  |  Size: 963 B

After

Width:  |  Height:  |  Size: 963 B

View file

Before

Width:  |  Height:  |  Size: 931 B

After

Width:  |  Height:  |  Size: 931 B

View file

Before

Width:  |  Height:  |  Size: 937 B

After

Width:  |  Height:  |  Size: 937 B

View file

Before

Width:  |  Height:  |  Size: 1,002 B

After

Width:  |  Height:  |  Size: 1,002 B

View file

Before

Width:  |  Height:  |  Size: 966 B

After

Width:  |  Height:  |  Size: 966 B

View file

Before

Width:  |  Height:  |  Size: 1,023 B

After

Width:  |  Height:  |  Size: 1,023 B

View file

Before

Width:  |  Height:  |  Size: 910 B

After

Width:  |  Height:  |  Size: 910 B

View file

Before

Width:  |  Height:  |  Size: 947 B

After

Width:  |  Height:  |  Size: 947 B

View file

Before

Width:  |  Height:  |  Size: 998 B

After

Width:  |  Height:  |  Size: 998 B

View file

Before

Width:  |  Height:  |  Size: 961 B

After

Width:  |  Height:  |  Size: 961 B

View file

Before

Width:  |  Height:  |  Size: 975 B

After

Width:  |  Height:  |  Size: 975 B

View file

Before

Width:  |  Height:  |  Size: 892 B

After

Width:  |  Height:  |  Size: 892 B

View file

Before

Width:  |  Height:  |  Size: 967 B

After

Width:  |  Height:  |  Size: 967 B

View file

Before

Width:  |  Height:  |  Size: 959 B

After

Width:  |  Height:  |  Size: 959 B

View file

Before

Width:  |  Height:  |  Size: 899 B

After

Width:  |  Height:  |  Size: 899 B

View file

Before

Width:  |  Height:  |  Size: 720 B

After

Width:  |  Height:  |  Size: 720 B

View file

Before

Width:  |  Height:  |  Size: 851 B

After

Width:  |  Height:  |  Size: 851 B

View file

Before

Width:  |  Height:  |  Size: 992 B

After

Width:  |  Height:  |  Size: 992 B

View file

@ -504,10 +504,12 @@ class ChangeMoodDialog:
self.MOODS.sort() self.MOODS.sort()
for mood in self.MOODS: for mood in self.MOODS:
image = Gtk.Image.new_from_icon_name(
'mood-%s' % mood, Gtk.IconSize.MENU)
self.mood_buttons[mood] = Gtk.RadioButton() self.mood_buttons[mood] = Gtk.RadioButton()
self.mood_buttons[mood].join_group(no_mood_button) self.mood_buttons[mood].join_group(no_mood_button)
self.mood_buttons[mood].set_mode(False) self.mood_buttons[mood].set_mode(False)
self.mood_buttons[mood].add(gtkgui_helpers.load_mood_icon(mood)) self.mood_buttons[mood].add(image)
self.mood_buttons[mood].set_relief(Gtk.ReliefStyle.NONE) self.mood_buttons[mood].set_relief(Gtk.ReliefStyle.NONE)
self.mood_buttons[mood].set_tooltip_text(MOODS[mood]) self.mood_buttons[mood].set_tooltip_text(MOODS[mood])
self.mood_buttons[mood].connect('clicked', self.mood_buttons[mood].connect('clicked',
@ -700,8 +702,8 @@ class ChangeStatusMessageDialog(TimeoutDialog):
img = self.xml.get_object('mood_image') img = self.xml.get_object('mood_image')
label = self.xml.get_object('mood_button_label') label = self.xml.get_object('mood_button_label')
if 'mood' in self.pep_dict and self.pep_dict['mood'] in MOODS: if 'mood' in self.pep_dict and self.pep_dict['mood'] in MOODS:
img.set_from_pixbuf(gtkgui_helpers.load_mood_icon( img.set_from_icon_name('mood-%s' % self.pep_dict['mood'],
self.pep_dict['mood']).get_pixbuf()) Gtk.IconSize.MENU)
if self.pep_dict['mood_text']: if self.pep_dict['mood_text']:
label.set_text(self.pep_dict['mood_text']) label.set_text(self.pep_dict['mood_text'])
else: else:

View file

@ -325,7 +325,7 @@ class ProfileWindow(Gtk.ApplicationWindow):
return return
vcard_, sha = self.make_vcard() vcard_, sha = self.make_vcard()
nick = vcard_.get('NICKNAME') or None nick = vcard_.get('NICKNAME') or None
app.connections[self.account].get_module('UserNickname').send(nick) app.connections[self.account].get_module('UserNickname').set_nickname(nick)
if not nick: if not nick:
nick = app.config.get_per('accounts', self.account, 'name') nick = app.config.get_per('accounts', self.account, 'name')
app.nicks[self.account] = nick app.nicks[self.account] = nick

View file

@ -36,11 +36,13 @@ from gi.repository import Pango
from gajim.common import app from gajim.common import app
from gajim.common import helpers from gajim.common import helpers
from gajim.common.const import AvatarSize from gajim.common.const import AvatarSize
from gajim.common.const import PEPEventType
from gajim.common.i18n import Q_ from gajim.common.i18n import Q_
from gajim.common.i18n import _ from gajim.common.i18n import _
from gajim.gtk.util import get_builder from gajim.gtk.util import get_builder
from gajim.gtk.util import get_icon_name from gajim.gtk.util import get_icon_name
from gajim.gtk.util import format_mood
log = logging.getLogger('gajim.gtk.tooltips') log = logging.getLogger('gajim.gtk.tooltips')
@ -471,8 +473,8 @@ class RosterTooltip(StatusTable):
Append Tune, Mood, Activity, Location 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 PEPEventType.MOOD in contact.pep:
mood = contact.pep['mood'].as_markup_text() mood = format_mood(*contact.pep[PEPEventType.MOOD])
self._ui.mood.set_markup(mood) self._ui.mood.set_markup(mood)
self._ui.mood.show() self._ui.mood.show()
self._ui.mood_label.show() self._ui.mood_label.show()

View file

@ -36,6 +36,7 @@ from gajim.common import app
from gajim.common import configpaths from gajim.common import configpaths
from gajim.common import i18n from gajim.common import i18n
from gajim.common.i18n import _ from gajim.common.i18n import _
from gajim.common.const import MOODS
from gajim.gtk.const import GajimIconSet from gajim.gtk.const import GajimIconSet
@ -499,3 +500,24 @@ def ensure_not_destroyed(func):
return return
return func(self, *args, **kwargs) return func(self, *args, **kwargs)
return func_wrapper return func_wrapper
def ensure_proper_control(func):
@wraps(func)
def func_wrapper(self, event):
if event.account != self.account:
return
if event.jid != self.contact.jid:
return
return func(self, event)
return func_wrapper
def format_mood(mood, text):
if mood is None:
return ''
mood = MOODS[mood]
markuptext = '<b>%s</b>' % GLib.markup_escape_text(mood)
if text is not None:
markuptext += ' (%s)' % GLib.markup_escape_text(text)
return markuptext

View file

@ -267,15 +267,6 @@ def create_list_multi(value_list, selected_values=None):
treeview.show_all() treeview.show_all()
return treeview return treeview
def load_mood_icon(icon_name):
"""
Load an icon from the mood iconset in 16x16
"""
iconset = app.config.get('mood_iconset')
path = os.path.join(helpers.get_mood_iconset_path(iconset), '')
icon_list = _load_icon_list([icon_name], path)
return icon_list[icon_name]
def load_activity_icon(category, activity=None): def load_activity_icon(category, activity=None):
""" """
Load an icon from the activity iconset in 16x16 Load an icon from the activity iconset in 16x16
@ -289,12 +280,6 @@ def load_activity_icon(category, activity=None):
return icon_list[activity] return icon_list[activity]
def get_pep_icon(pep_class): def get_pep_icon(pep_class):
if pep_class == PEPEventType.MOOD:
received_mood = pep_class.data['mood']
mood = received_mood if received_mood in MOODS else 'unknown'
pixbuf = load_mood_icon(mood).get_pixbuf()
return pixbuf
if pep_class == PEPEventType.TUNE: if pep_class == PEPEventType.TUNE:
return 'audio-x-generic' return 'audio-x-generic'

Some files were not shown because too many files have changed in this diff Show more