Verified Commit 183a151d authored by mathieui's avatar mathieui

Merge branch 'master_rebased' of

parents 668c1eb6 9da530f8
......@@ -374,6 +374,9 @@ user_list_sort = desc
# If the MUC nicks should receive a fixed color based on their text or not
deterministic_nick_colors = true
# If _nick, nick_, _nick_, nick__ etc. should have the same color as nick
nick_color_aliases = true
# The nick of people who join, part, change their status, etc. in a MUC will
# be displayed using their nick color if true.
display_user_color_in_join_part = true
......@@ -509,3 +512,7 @@ M-i = ^I
# to save various data across restarts
folded_roster_groups =
info_win_height = 2
# Set color for a nick, under the form
# nick = color
......@@ -528,6 +528,15 @@ or the way messages are displayed.
The value of this option affects the behavior of :term:`/recolor`.
**Default value:** ``true``
Automatically search for color of nick aliases. For example, if nick is
set to red, _nick, nick_, _nick_, nick__ etc. will have the same color.
Aliases colors are checked first, so that it is still possible to have
different colors for nick_ and nick.
**Default value:** ``20``
......@@ -747,6 +756,14 @@ or the way messages are displayed.
If the message takes more than one line, the popup will stay visible
two more second per additional lines.
muc_colors (section)
**Default:** ``[empty]``
Fix a color for a nick. Whenever such a nick appears in a MUC, it will
be displayed in that color. This color won't be changed by the recolor
User Interaction
......@@ -43,6 +43,7 @@ DEFAULT_CONFIG = {
'custom_port': '',
'default_nick': '',
'deterministic_nick_colors': True,
'nick_color_aliases': True,
'display_activity_notifications': False,
'display_gaming_notifications': False,
'display_mood_notifications': False,
......@@ -135,6 +136,8 @@ DEFAULT_CONFIG = {
'var': {
'folded_roster_groups': '',
'info_win_height': 2
'muc_colors': {
......@@ -158,6 +158,12 @@ class MucTab(ChatTab):
' for a non-deterministic result.'),
shortdesc=_('Change the nicks colors.'),
self.register_command('color', self.command_color,
usage=_('<nick> <color>'),
desc=_('Fix a color for a nick. Use "unset" instead of a color'
' to remove the attribution'),
shortdesc=_('Fix a color for a nick.'),
self.register_command('cycle', self.command_cycle,
desc=_('Leave the current room and rejoin it immediately.'),
......@@ -261,6 +267,20 @@ class MucTab(ChatTab):
return the_input.new_completion(['random'], 1, '', quotify=False)
return True
def completion_color(self, the_input):
"""Completion for /color"""
n = the_input.get_argument_position(quoted=True)
if n == 1:
userlist = [user.nick for user in self.users]
if self.own_nick in userlist:
return the_input.new_completion(userlist, 1, '', quotify=True)
elif n == 2:
colors = [i for i in xhtml.colors if i]
return the_input.new_completion(colors, 2, '', quotify=False)
def completion_ignore(self, the_input):
"""Completion for /ignore"""
userlist = [user.nick for user in self.users]
......@@ -406,6 +426,9 @@ class MucTab(ChatTab):
for user in self.users:
if user.nick == self.own_nick:
color = self.search_for_color(user.nick)
if color != '':
if args[0] == 'random':
self.core.information(_('"random" was provided, but poezio is '
......@@ -417,11 +440,17 @@ class MucTab(ChatTab):
compare_users = lambda x: x.last_talked
users = list(self.users)
sorted_users = sorted(users, key=compare_users, reverse=True)
full_sorted_users = sorted_users[:]
# search our own user, to remove it from the list
for user in sorted_users:
# Also remove users whose color is fixed
for user in full_sorted_users:
color = self.search_for_color(user.nick)
if user.nick == self.own_nick:
user.color = get_theme().COLOR_OWN_NICK
elif color != '':
user.change_color(color, deterministic)
colors = list(get_theme().LIST_COLOR_NICKNAMES)
if args[0] == 'random':
......@@ -432,6 +461,44 @@ class MucTab(ChatTab):
@command_args_parser.quoted(2, 2, [''])
def command_color(self, args):
/color <nick> <color>
Fix a color for a nick.
Use "unset" instead of a color to remove the attribution
if args is None:
return self.core.command_help('color')
nick = args[0]
color = args[1].lower()
user = self.get_user_by_name(nick)
if not color in xhtml.colors and color != 'unset':
return self.core.information(_("Unknown color: %s") % color, 'Error')
if user and user.nick == self.own_nick:
return self.core.information(_("You cannot change the color of your"
" own nick.", 'Error'))
if color == 'unset':
if config.remove_and_save(nick, 'muc_colors'):
self.core.information(_('Color for nick %s unset') % (nick))
if user:
config.set_and_save(nick, color, 'muc_colors')
nick_color_aliases = config.get_by_tabname('nick_color_aliases',
if nick_color_aliases:
# if any user in the room has a nick which is an alias of the
# nick, update its color
for u in self.users:
nick_alias = re.sub('^_*', '', u.nick)
nick_alias = re.sub('_*$', '', nick_alias)
if nick_alias == nick:
def command_version(self, args):
......@@ -1009,12 +1076,13 @@ class MucTab(ChatTab):
jid = presence['muc']['jid']
typ = presence['type']
deterministic = config.get_by_tabname('deterministic_nick_colors',
color = self.search_for_color(from_nick)
if not self.joined: # user in the room BEFORE us.
# ignore redondant presence message, see bug #1509
if (from_nick not in [user.nick for user in self.users]
and typ != "unavailable"):
new_user = User(from_nick, affiliation, show,
status, role, jid, deterministic)
status, role, jid, deterministic, color)
self.users.append(new_user)'muc_join', presence, self)
if '110' in status_codes or self.own_nick == from_nick:
......@@ -1091,7 +1159,7 @@ class MucTab(ChatTab):
if not user:'muc_join', presence, self)
self.on_user_join(from_nick, affiliation, show, status, role,
jid, color)
# nick change
elif change_nick:'muc_nickchange', presence, self)
......@@ -1146,13 +1214,13 @@ class MucTab(ChatTab):
def on_user_join(self, from_nick, affiliation, show, status, role, jid):
def on_user_join(self, from_nick, affiliation, show, status, role, jid, color):
When a new user joins the groupchat
deterministic = config.get_by_tabname('deterministic_nick_colors',
user = User(from_nick, affiliation,
show, status, role, jid, deterministic)
show, status, role, jid, deterministic, color)
hide_exit_join = config.get_by_tabname('hide_exit_join',
......@@ -1193,6 +1261,12 @@ class MucTab(ChatTab):
self.own_nick = new_nick
# also change our nick in all private discussions of this room
color = config.get_by_tabname(new_nick, 'muc_colors')
if color != '':
deterministic = config.get_by_tabname('deterministic_nick_colors',
user.change_color(color, deterministic)
if config.get_by_tabname('display_user_color_in_join_part',
......@@ -1604,3 +1678,19 @@ class MucTab(ChatTab):
else: # Re-send a self-ping in a few seconds
def search_for_color(self, nick):
Search for the color of a nick in the config file.
Also, look at the colors of its possible aliases if nick_color_aliases
is set.
color = config.get_by_tabname(nick, 'muc_colors')
if color != '':
return color
nick_color_aliases = config.get_by_tabname('nick_color_aliases',
if nick_color_aliases:
nick_alias = re.sub('^_*', '', nick)
nick_alias = re.sub('_*$', '', nick_alias)
color = config.get_by_tabname(nick_alias, 'muc_colors')
return color
......@@ -13,9 +13,13 @@ An user is a MUC participant, not a roster contact (see
from random import choice
from datetime import timedelta, datetime
from hashlib import md5
import xhtml
from theming import get_theme
import logging
log = logging.getLogger(__name__)
......@@ -28,14 +32,17 @@ class User(object):
keep trace of an user in a Room
def __init__(self, nick, affiliation, show, status, role, jid, deterministic=True):
def __init__(self, nick, affiliation, show, status, role, jid, deterministic=True, color=''):
self.last_talked = datetime(1, 1, 1) # The oldest possible time
self.update(affiliation, show, status, role)
if deterministic:
if color != '':
self.change_color(color, deterministic)
self.color = choice(get_theme().LIST_COLOR_NICKNAMES)
if deterministic:
self.color = choice(get_theme().LIST_COLOR_NICKNAMES)
self.jid = jid
self.chatstate = None
......@@ -56,6 +63,17 @@ class User(object):
def change_nick(self, nick):
self.nick = nick
def change_color(self, color_name, deterministic=False):
color = xhtml.colors.get(color_name)
if color == None:
log.error('Unknown color "%s"' % color_name)
if deterministic:
self.color = choice(get_theme().LIST_COLOR_NICKNAMES)
self.color = (color, -1)
def set_last_talked(self, time):
time: datetime object
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment