gajim-plural/src/roster_window.py

5841 lines
208 KiB
Python
Raw Normal View History

2006-11-18 21:52:28 +01:00
# -*- coding: utf-8 -*-
## src/roster_window.py
##
## Copyright (C) 2003-2008 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2005 Alex Mauer <hawke AT hawkesnest.net>
## Stéphan Kochen <stephan AT kochen.nl>
## Copyright (C) 2005-2006 Dimitur Kirov <dkirov AT gmail.com>
## Copyright (C) 2005-2007 Travis Shirk <travis AT pobox.com>
## Nikos Kouremenos <kourem AT gmail.com>
## Copyright (C) 2006 Stefan Bethge <stefan AT lanpartei.de>
## Copyright (C) 2006-2008 Jean-Marie Traissard <jim AT lapin.org>
## Copyright (C) 2007 Lukas Petrovicky <lukas AT petrovicky.net>
## James Newton <redshodan AT gmail.com>
## Tomasz Melcer <liori AT exroot.org>
## Julien Pivotto <roidelapluie AT gmail.com>
## Copyright (C) 2007-2008 Stephan Erb <steve-e AT h3c.de>
## Copyright (C) 2008 Brendan Taylor <whateley AT gmail.com>
## Jonathan Schleifer <js-gajim AT webkeks.org>
##
2007-12-12 09:44:46 +01:00
## 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
2007-12-12 09:44:46 +01:00
## by the Free Software Foundation; version 3 only.
##
2007-12-12 09:44:46 +01:00
## 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.
##
2007-12-12 09:44:46 +01:00
## You should have received a copy of the GNU General Public License
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
2007-12-12 09:44:46 +01:00
##
import gtk
2007-08-09 17:39:18 +02:00
import pango
import gobject
import os
2007-12-12 09:44:46 +01:00
import sys
import time
import locale
import common.sleepy
import history_window
import dialogs
2005-11-13 21:25:04 +01:00
import vcard
import config
import disco
2005-07-30 12:20:46 +02:00
import gtkgui_helpers
import gui_menu_builder
import cell_renderer_image
import tooltips
2006-01-06 02:48:59 +01:00
import message_control
import adhoc_commands
2007-08-09 17:39:18 +02:00
import features_window
from common import gajim
from common import helpers
2006-11-18 21:52:28 +01:00
from common.exceptions import GajimGeneralException
from common import i18n
from common import pep
2006-11-18 21:52:28 +01:00
from message_window import MessageWindowMgr
2006-11-18 21:52:28 +01:00
from common import dbus_support
if dbus_support.supported:
2007-06-03 12:04:20 +02:00
import dbus
2007-12-12 09:44:46 +01:00
from common.xmpp.protocol import NS_FILE
2008-07-29 04:32:57 +02:00
from common.pep import MOODS, ACTIVITIES
#(icon, name, type, jid, account, editable, second pixbuf)
(
C_IMG, # image to show state (online, new message etc)
C_NAME, # cellrenderer text that holds contact nickame
C_TYPE, # account, group or contact?
2005-09-09 22:28:25 +02:00
C_JID, # the jid of the row
C_ACCOUNT, # cellrenderer text that holds account name
C_MOOD_PIXBUF,
2008-07-29 04:32:57 +02:00
C_ACTIVITY_PIXBUF,
2008-07-25 16:11:14 +02:00
C_TUNE_PIXBUF,
C_AVATAR_PIXBUF, # avatar_pixbuf
C_PADLOCK_PIXBUF, # use for account row only
2008-07-29 04:32:57 +02:00
) = range(10)
class RosterWindow:
2006-11-18 21:52:28 +01:00
'''Class for main window of the GTK+ interface'''
2008-09-02 22:31:05 +02:00
def _get_account_iter(self, name, model=None):
2008-07-25 01:53:56 +02:00
'''
Return the gtk.TreeIter of the given account or None
if not found.
2008-05-13 16:03:30 +02:00
Keyword arguments:
name -- the account name
model -- the data model (default TreeFilterModel)
'''
if not model:
model = self.modelfilter
2005-07-25 20:48:15 +02:00
if model is None:
return
account_iter = model.get_iter_root()
if self.regroup:
return account_iter
while account_iter:
account_name = model[account_iter][C_ACCOUNT]
if account_name and name == account_name.decode('utf-8'):
break
account_iter = model.iter_next(account_iter)
return account_iter
2008-09-02 22:31:05 +02:00
def _get_group_iter(self, name, account, account_iter=None, model=None):
2008-07-25 01:53:56 +02:00
'''
Return the gtk.TreeIter of the given group or None if not found.
2008-05-13 16:03:30 +02:00
Keyword arguments:
name -- the group name
account -- the account name
account_iter -- the iter of the account the model (default None)
2008-05-13 16:03:30 +02:00
model -- the data model (default TreeFilterModel)
2008-06-02 12:04:27 +02:00
'''
if not model:
model = self.modelfilter
if not account_iter:
2008-05-01 10:40:20 +02:00
account_iter = self._get_account_iter(account, model)
group_iter = model.iter_children(account_iter)
# C_NAME column contacts the pango escaped group name
while group_iter:
2006-11-18 21:52:28 +01:00
group_name = model[group_iter][C_JID].decode('utf-8')
if name == group_name:
break
group_iter = model.iter_next(group_iter)
return group_iter
2008-06-02 12:04:27 +02:00
def _get_self_contact_iter(self, account, model=None):
''' Return the gtk.TreeIter of SelfContact or None if not found.
2008-05-13 16:03:30 +02:00
Keyword arguments:
account -- the account of SelfContact
model -- the data model (default TreeFilterModel)
2008-06-02 12:04:27 +02:00
'''
2008-06-02 12:04:27 +02:00
if not model:
model = self.modelfilter
iterAcct = self._get_account_iter(account, model)
iterC = model.iter_children(iterAcct)
2008-06-02 12:04:27 +02:00
# There might be several SelfContacts in merged account view
while iterC:
if model[iterC][C_TYPE] != 'self_contact':
break
iter_account = model[iterC][C_ACCOUNT]
if account == iter_account.decode('utf-8'):
return iterC
iterC = model.iter_next(iterC)
return None
2008-08-06 22:19:16 +02:00
def _get_contact_iter(self, jid, account, contact=None, model=None):
''' Return a list of gtk.TreeIter of the given contact.
Keyword arguments:
jid -- the jid without resource
account -- the account
contact -- the contact (default None)
model -- the data model (default TreeFilterModel)
2008-06-02 12:04:27 +02:00
'''
if not model:
model = self.modelfilter
2008-07-25 01:53:56 +02:00
# when closing Gajim model can be none (async pbs?)
if model is None:
return []
if jid == gajim.get_jid_from_account(account):
contact_iter = self._get_self_contact_iter(account, model)
if contact_iter:
return [contact_iter]
else:
return []
if not contact:
2008-08-06 22:19:16 +02:00
contact = gajim.contacts.get_first_contact_from_jid(account, jid)
if not contact:
# We don't know this contact
2008-08-06 22:19:16 +02:00
return []
acct = self._get_account_iter(account, model)
found = [] # the contact iters. One per group
for group in contact.get_shown_groups():
2008-08-06 22:19:16 +02:00
group_iter = self._get_group_iter(group, account, acct, model)
contact_iter = model.iter_children(group_iter)
while contact_iter:
# Loop over all contacts in this group
iter_jid = model[contact_iter][C_JID]
2008-08-06 22:19:16 +02:00
if iter_jid and jid == iter_jid.decode('utf-8') and \
account == model[contact_iter][C_ACCOUNT].decode('utf-8'):
# only one iter per group
found.append(contact_iter)
contact_iter = None
elif model.iter_has_child(contact_iter):
# it's a big brother and has children
2008-08-06 22:19:16 +02:00
contact_iter = model.iter_children(contact_iter)
2008-06-02 12:04:27 +02:00
else:
# try to find next contact:
2008-07-25 01:53:56 +02:00
# other contact in this group or
# brother contact
2008-08-06 22:19:16 +02:00
next_contact_iter = model.iter_next(contact_iter)
if next_contact_iter:
contact_iter = next_contact_iter
else:
2008-07-25 01:53:56 +02:00
# It's the last one.
# Go up if we are big brother
2008-08-06 22:19:16 +02:00
parent_iter = model.iter_parent(contact_iter)
if parent_iter and model[parent_iter][C_TYPE] == 'contact':
contact_iter = model.iter_next(parent_iter)
else:
2008-07-25 03:10:14 +02:00
# we tested all
2008-07-25 01:53:56 +02:00
# contacts in this group
contact_iter = None
return found
2008-06-02 12:04:27 +02:00
def _iter_is_separator(self, model, titer):
''' Return True if the given iter is a separator.
2008-06-02 12:04:27 +02:00
Keyword arguments:
model -- the data model
2008-06-02 12:04:27 +02:00
iter -- the gtk.TreeIter to test
'''
if model[titer][0] == 'SEPARATOR':
return True
return False
2006-11-18 21:52:28 +01:00
2008-09-02 22:31:05 +02:00
def _iter_contact_rows(self, model=None):
'''Iterate over all contact rows in given model.
2008-06-02 12:04:27 +02:00
Keyword argument
model -- the data model (default TreeFilterModel)
'''
if not model:
model = self.modelfilter
account_iter = model.get_iter_root()
while account_iter:
group_iter = model.iter_children(account_iter)
while group_iter:
contact_iter = model.iter_children(group_iter)
while contact_iter:
yield model[contact_iter]
2008-07-25 01:53:56 +02:00
contact_iter = model.iter_next(
contact_iter)
group_iter = model.iter_next(group_iter)
account_iter = model.iter_next(account_iter)
2008-06-02 12:04:27 +02:00
#############################################################################
### Methods for adding and removing roster window items
2008-05-08 23:18:39 +02:00
#############################################################################
2008-06-02 12:04:27 +02:00
def add_account(self, account):
2008-07-25 01:53:56 +02:00
'''
Add account to roster and draw it. Do nothing if it is
already in.
'''
if self._get_account_iter(account):
2008-06-02 12:04:27 +02:00
# Will happen on reconnect or for merged accounts
return
2008-06-02 12:04:27 +02:00
if self.regroup:
# Merged accounts view
show = helpers.get_global_show()
2008-07-25 01:53:56 +02:00
self.model.append(None, [
gajim.interface.jabber_state_images['16'][show],
_('Merged accounts'), 'account', '', 'all',
2008-07-29 04:32:57 +02:00
None, None, None, None, None])
else:
2008-08-06 22:19:16 +02:00
show = gajim.SHOW_LIST[gajim.connections[account].connected]
our_jid = gajim.get_jid_from_account(account)
tls_pixbuf = None
if gajim.account_is_securely_connected(account):
2008-06-02 12:04:27 +02:00
# the only way to create a pixbuf from stock
tls_pixbuf = self.window.render_icon(
2008-07-25 01:53:56 +02:00
gtk.STOCK_DIALOG_AUTHENTICATION,
gtk.ICON_SIZE_MENU)
2008-07-25 01:53:56 +02:00
self.model.append(None, [
gajim.interface.jabber_state_images['16'][show],
gobject.markup_escape_text(account), 'account',
2008-07-29 04:32:57 +02:00
our_jid, account, None, None, None, None,
tls_pixbuf])
self.draw_account(account)
def add_account_contacts(self, account):
'''Add all contacts and groups of the given account to roster,
draw them and account.
'''
self.starting = True
jids = gajim.contacts.get_jid_list(account)
2008-06-02 12:04:27 +02:00
self.tree.freeze_child_notify()
for jid in jids:
self.add_contact(jid, account)
self.tree.thaw_child_notify()
2008-04-24 00:34:10 +02:00
# Do not freeze the GUI when drawing the contacts
if jids:
# Overhead is big, only invoke when needed
self._idle_draw_jids_of_account(jids, account)
# Draw all known groups
2008-08-06 22:19:16 +02:00
for group in gajim.groups[account]:
self.draw_group(group, account)
self.draw_account(account)
self.starting = False
2008-06-02 12:04:27 +02:00
2008-09-02 09:13:24 +02:00
def _add_entity(self, contact, account, groups=None,
big_brother_contact=None, big_brother_account=None):
'''Add the given contact to roster data model.
2008-06-02 12:04:27 +02:00
Contact is added regardless if he is already in roster or not.
Return list of newly added iters.
2008-06-02 12:04:27 +02:00
Keyword arguments:
contact -- the contact to add
account -- the contacts account
2008-07-25 01:53:56 +02:00
groups -- list of groups to add the contact to.
(default groups in contact.get_shown_groups()).
Parameter ignored when big_brother_contact is specified.
2008-07-25 01:53:56 +02:00
big_brother_contact -- if specified contact is added as child
big_brother_contact. (default None)
'''
added_iters = []
if big_brother_contact:
# Add contact under big brother
2008-07-25 01:53:56 +02:00
parent_iters = self._get_contact_iter(
big_brother_contact.jid, big_brother_account,
big_brother_contact, self.model)
2008-09-02 09:13:24 +02:00
assert len(parent_iters) > 0, 'Big brother is not yet in roster!'
2008-08-06 22:19:16 +02:00
# Do not confuse get_contact_iter: Sync groups of family members
contact.groups = big_brother_contact.get_shown_groups()[:]
for child_iter in parent_iters:
2008-12-03 22:56:12 +01:00
it = self.model.append(child_iter, (None, contact.get_shown_name(),
2008-08-06 22:19:16 +02:00
'contact', contact.jid, account, None, None, None, None, None))
added_iters.append(it)
else:
# We are a normal contact. Add us to our groups.
if not groups:
groups = contact.get_shown_groups()
for group in groups:
2008-12-03 22:56:12 +01:00
child_iterG = self._get_group_iter(group, account,
2008-08-06 22:19:16 +02:00
model = self.model)
if not child_iterG:
# Group is not yet in roster, add it!
2008-08-06 22:19:16 +02:00
child_iterA = self._get_account_iter(account, self.model)
2008-12-03 22:56:12 +01:00
child_iterG = self.model.append(child_iterA,
[gajim.interface.jabber_state_images['16']['closed'],
2008-08-06 22:19:16 +02:00
gobject.markup_escape_text(group),
'group', group, account, None, None, None, None, None])
self.draw_group(group, account)
if contact.is_transport():
typestr = 'agent'
elif contact.is_groupchat():
typestr = 'groupchat'
else:
typestr = 'contact'
2008-06-02 12:04:27 +02:00
2008-07-25 01:53:56 +02:00
# we add some values here. see draw_contact
# for more
i_ = self.model.append(child_iterG, (None,
contact.get_shown_name(), typestr,
2008-07-25 16:11:14 +02:00
contact.jid, account, None, None, None,
2008-07-29 04:32:57 +02:00
None, None))
added_iters.append(i_)
# Restore the group expand state
if account + group in self.collapsed_rows:
is_expanded = False
else:
is_expanded = True
if group not in gajim.groups[account]:
2008-08-06 22:19:16 +02:00
gajim.groups[account][group] = {'expand': is_expanded}
assert len(added_iters), '%s has not been added to roster!' % contact.jid
2008-06-02 12:04:27 +02:00
return added_iters
2008-09-02 22:31:05 +02:00
def _remove_entity(self, contact, account, groups=None):
'''Remove the given contact from roster data model.
2008-06-02 12:04:27 +02:00
Empty groups after contact removal are removed too.
2008-07-25 01:53:56 +02:00
Return False if contact still has children and deletion was
not performed.
Return True on success.
2008-06-02 12:04:27 +02:00
Keyword arguments:
contact -- the contact to add
account -- the contacts account
groups -- list of groups to remove the contact from.
'''
2008-08-06 22:19:16 +02:00
iters = self._get_contact_iter(contact.jid, account, contact, self.model)
assert iters, '%s shall be removed but is not in roster' % contact.jid
parent_iter = self.model.iter_parent(iters[0])
parent_type = self.model[parent_iter][C_TYPE]
if groups:
# Only remove from specified groups
all_iters = iters[:]
2008-12-03 22:56:12 +01:00
group_iters = [self._get_group_iter(group, account)
2008-07-25 01:53:56 +02:00
for group in groups]
2008-06-02 12:04:27 +02:00
iters = [titer for titer in all_iters
if self.model.iter_parent(titer) in group_iters]
iter_children = self.model.iter_children(iters[0])
if iter_children:
# We have children. We cannot be removed!
return False
else:
# Remove us and empty groups from the model
for i in iters:
assert self.model[i][C_JID] == contact.jid and \
self.model[i][C_ACCOUNT] == account, \
"Invalidated iters of %s" % contact.jid
2008-08-06 22:19:16 +02:00
parent_i = self.model.iter_parent(i)
2008-08-06 22:19:16 +02:00
if parent_type == 'group' and \
2008-06-02 12:04:27 +02:00
self.model.iter_n_children(parent_i) == 1:
2008-08-06 22:19:16 +02:00
group = self.model[parent_i][C_JID].decode('utf-8')
if group in gajim.groups[account]:
del gajim.groups[account][group]
self.model.remove(parent_i)
else:
self.model.remove(i)
return True
def _add_metacontact_family(self, family, account):
2008-07-25 01:53:56 +02:00
'''
Add the give Metacontact family to roster data model.
2008-06-02 12:04:27 +02:00
Add Big Brother to his groups and all others under him.
2008-07-25 01:53:56 +02:00
Return list of all added (contact, account) tuples with
Big Brother as first element.
2008-06-02 12:04:27 +02:00
Keyword arguments:
family -- the family, see Contacts.get_metacontacts_family()
'''
nearby_family, big_brother_jid, big_brother_account = \
self._get_nearby_family_and_big_brother(family, account)
2008-05-08 23:18:39 +02:00
big_brother_contact = gajim.contacts.get_first_contact_from_jid(
big_brother_account, big_brother_jid)
2008-07-25 01:53:56 +02:00
assert len(self._get_contact_iter(big_brother_jid,
2008-08-06 22:19:16 +02:00
big_brother_account, big_brother_contact, self.model)) == 0, \
'Big brother %s already in roster\n Family: %s' \
2008-07-25 01:53:56 +02:00
% (big_brother_jid, family)
self._add_entity(big_brother_contact, big_brother_account)
2008-06-02 12:04:27 +02:00
brothers = []
# Filter family members
for data in nearby_family:
_account = data['account']
_jid = data['jid']
2008-07-25 01:53:56 +02:00
_contact = gajim.contacts.get_first_contact_from_jid(
_account, _jid)
if not _contact or _contact == big_brother_contact:
# Corresponding account is not connected
# or brother already added
continue
2008-06-02 12:04:27 +02:00
2008-07-25 01:53:56 +02:00
assert len(self._get_contact_iter(_jid, _account,
2008-08-06 22:19:16 +02:00
_contact, self.model)) == 0, \
"%s already in roster.\n Family: %s" % (_jid, nearby_family)
2008-07-25 01:53:56 +02:00
self._add_entity(_contact, _account,
big_brother_contact = big_brother_contact,
big_brother_account = big_brother_account)
brothers.append((_contact, _account))
brothers.insert(0, (big_brother_contact, big_brother_account))
return brothers
def _remove_metacontact_family(self, family, account):
2008-07-25 01:53:56 +02:00
'''
Remove the given Metacontact family from roster data model.
2008-06-02 12:04:27 +02:00
2008-07-25 01:53:56 +02:00
See Contacts.get_metacontacts_family() and
RosterWindow._remove_entity()
'''
nearby_family = self._get_nearby_family_and_big_brother(
family, account)[0]
2008-06-02 12:04:27 +02:00
# Family might has changed (actual big brother not on top).
# Remove childs first then big brother
family_in_roster = False
for data in nearby_family:
_account = data['account']
_jid = data['jid']
_contact = gajim.contacts.get_first_contact_from_jid(_account, _jid)
2008-06-02 12:04:27 +02:00
iters = self._get_contact_iter(_jid, _account, _contact, self.model)
if not iters or not _contact:
# Family might not be up to date.
# Only try to remove what is actually in the roster
continue
2008-06-02 12:04:27 +02:00
assert iters, '%s shall be removed but is not in roster \
\n Family: %s' % (_jid, family)
family_in_roster = True
parent_iter = self.model.iter_parent(iters[0])
parent_type = self.model[parent_iter][C_TYPE]
2008-06-02 12:04:27 +02:00
if parent_type != 'contact':
# The contact on top
old_big_account = _account
old_big_contact = _contact
old_big_jid = _jid
continue
ok = self._remove_entity(_contact, _account)
2008-06-02 12:04:27 +02:00
assert ok, '%s was not removed' % _jid
assert len(self._get_contact_iter(_jid, _account, _contact,
self.model)) == 0, '%s is removed but still in roster' % _jid
if not family_in_roster:
return False
2008-12-03 22:56:12 +01:00
assert old_big_jid, 'No Big Brother in nearby family % (Family: %)' % \
(nearby_family, family)
2008-06-02 12:04:27 +02:00
iters = self._get_contact_iter(old_big_jid, old_big_account,
old_big_contact, self.model)
assert len(iters) > 0, 'Old Big Brother %s is not in roster anymore' % \
old_big_jid
2008-06-02 12:23:27 +02:00
assert not self.model.iter_children(iters[0]),\
2008-06-02 12:04:27 +02:00
'Old Big Brother %s still has children' % old_big_jid
ok = self._remove_entity(old_big_contact, old_big_account)
assert ok, "Old Big Brother %s not removed" % old_big_jid
2008-06-02 12:04:27 +02:00
assert len(self._get_contact_iter(old_big_jid, old_big_account,
2008-06-02 12:23:27 +02:00
old_big_contact, self.model)) == 0,\
2008-06-02 12:04:27 +02:00
'Old Big Brother %s is removed but still in roster' % old_big_jid
return True
2008-06-02 12:04:27 +02:00
def _recalibrate_metacontact_family(self, family, account):
'''Regroup metacontact family if necessary.'''
brothers = []
nearby_family, big_brother_jid, big_brother_account = \
self._get_nearby_family_and_big_brother(family, account)
big_brother_contact = gajim.contacts.get_contact(big_brother_account,
big_brother_jid)
child_iters = self._get_contact_iter(big_brother_jid, big_brother_account,
model=self.model)
if child_iters:
parent_iter = self.model.iter_parent(child_iters[0])
parent_type = self.model[parent_iter][C_TYPE]
# Check if the current BigBrother has even been before.
if parent_type == 'contact':
for data in nearby_family:
# recalibrate after remove to keep highlight
if data['jid'] in gajim.to_be_removed[data['account']]:
return
self._remove_metacontact_family(family, account)
brothers = self._add_metacontact_family(family, account)
2008-12-03 22:56:12 +01:00
for c, acc in brothers:
self.draw_completely(c.jid, acc)
# Check is small brothers are under the big brother
for child in nearby_family:
_jid = child['jid']
_account = child['account']
if _account == big_brother_account and _jid == big_brother_jid:
continue
child_iters = self._get_contact_iter(_jid, _account, model=self.model)
if not child_iters:
continue
parent_iter = self.model.iter_parent(child_iters[0])
parent_type = self.model[parent_iter][C_TYPE]
if parent_type != 'contact':
_contact = gajim.contacts.get_contact(_account, _jid)
self._remove_entity(_contact, _account)
self._add_entity(_contact, _account, groups=None,
big_brother_contact=big_brother_contact,
big_brother_account=big_brother_account)
def _get_nearby_family_and_big_brother(self, family, account):
return gajim.contacts.get_nearby_family_and_big_brother(family, account)
def _add_self_contact(self, account):
'''Add account's SelfContact to roster and draw it and the account.
2008-06-02 12:04:27 +02:00
Return the SelfContact contact instance
'''
jid = gajim.get_jid_from_account(account)
contact = gajim.contacts.get_first_contact_from_jid(account, jid)
2008-06-02 12:04:27 +02:00
assert len(self._get_contact_iter(jid, account, contact, self.model)) == \
0, 'Self contact %s already in roster' % jid
child_iterA = self._get_account_iter(account, self.model)
self.model.append(child_iterA, (None, gajim.nicks[account],
2008-07-29 04:32:57 +02:00
'self_contact', jid, account, None, None, None, None,
None))
2008-06-02 12:04:27 +02:00
self.draw_completely(jid, account)
self.draw_account(account)
return contact
2008-06-02 12:04:27 +02:00
def redraw_metacontacts(self, account):
for family in gajim.contacts.iter_metacontacts_families(account):
self._recalibrate_metacontact_family(family, account)
2008-06-02 12:04:27 +02:00
def add_contact(self, jid, account):
'''Add contact to roster and draw him.
2008-06-02 12:04:27 +02:00
Add contact to all its group and redraw the groups, the contact and the
account. If it's a Metacontact, add and draw the whole family.
2008-06-02 12:04:27 +02:00
Do nothing if the contact is already in roster.
Return the added contact instance. If it is a Metacontact return
Big Brother.
2008-06-02 12:04:27 +02:00
Keyword arguments:
jid -- the contact's jid or SelfJid to add SelfContact
account -- the corresponding account.
2008-06-02 12:04:27 +02:00
'''
contact = gajim.contacts.get_contact_with_highest_priority(account, jid)
if len(self._get_contact_iter(jid, account, contact, self.model)):
# If contact already in roster, do nothing
return
if jid == gajim.get_jid_from_account(account):
show_self_contact = gajim.config.get('show_self_contact')
if show_self_contact == 'never':
return
if (contact.resource != gajim.connections[account].server_resource and\
show_self_contact == 'when_other_resource') or show_self_contact == \
'always':
return self._add_self_contact(account)
2006-11-18 21:52:28 +01:00
return
2008-06-02 12:04:27 +02:00
2008-04-24 00:34:10 +02:00
is_observer = contact.is_observer()
if is_observer:
# if he has a tag, remove it
gajim.contacts.remove_metacontact(account, jid)
2008-06-02 12:04:27 +02:00
# Add contact to roster
family = gajim.contacts.get_metacontacts_family(account, jid)
contacts = []
if family:
# We have a family. So we are a metacontact.
# Add all family members that we shall be grouped with
if self.regroup:
# remove existing family members to regroup them
self._remove_metacontact_family(family, account)
contacts = self._add_metacontact_family(family, account)
else:
# We are a normal contact
contacts = [(contact, account),]
self._add_entity(contact, account)
# Draw the contact and its groups contact
if not self.starting:
for c, acc in contacts:
self.draw_completely(c.jid, acc)
for group in contact.get_shown_groups():
self.draw_group(group, account)
self._adjust_group_expand_collapse_state(group, account)
self.draw_account(account)
return contacts[0][0] # it's contact/big brother with highest priority
def remove_contact(self, jid, account, force=False, backend=False):
'''Remove contact from roster.
2008-06-02 12:04:27 +02:00
Remove contact from all its group. Remove empty groups or redraw
otherwise.
Draw the account.
If it's a Metacontact, remove the whole family.
2008-06-02 12:04:27 +02:00
Do nothing if the contact is not in roster.
Keyword arguments:
jid -- the contact's jid or SelfJid to remove SelfContact
account -- the corresponding account.
force -- remove contact even it has pending evens (Default False)
backend -- also remove contact instance (Default False)
2008-06-02 12:04:27 +02:00
'''
contact = gajim.contacts.get_contact_with_highest_priority(account, jid)
if not contact:
return
if not force and (self.contact_has_pending_roster_events(contact,
account) or gajim.interface.msg_win_mgr.get_control(jid, account)):
# Contact has pending events or window
#TODO: or single message windows? Bur they are not listed for the
# moment
key = (jid, account)
if not key in self.contacts_to_be_removed:
self.contacts_to_be_removed[key] = {'backend': backend}
# if more pending event, don't remove from roster
if self.contact_has_pending_roster_events(contact, account):
return False
iters = self._get_contact_iter(jid, account, contact, self.model)
if iters:
# no more pending events
# Remove contact from roster directly
family = gajim.contacts.get_metacontacts_family(account, jid)
if family:
# We have a family. So we are a metacontact.
self._remove_metacontact_family(family, account)
2008-06-02 12:04:27 +02:00
else:
self._remove_entity(contact, account)
2006-11-18 21:52:28 +01:00
if backend and (not gajim.interface.msg_win_mgr.get_control(jid, account)\
or force):
# If a window is still opened: don't remove contact instance
# Remove contact before redrawing, otherwise the old
# numbers will still be show
gajim.contacts.remove_jid(account, jid, remove_meta=True)
2009-07-24 16:17:49 +02:00
if iters:
rest_of_family = [data for data in family
if account != data['account'] or jid != data['jid']]
if rest_of_family:
# reshow the rest of the family
brothers = self._add_metacontact_family(rest_of_family, account)
for c, acc in brothers:
self.draw_completely(c.jid, acc)
if iters:
# Draw all groups of the contact
for group in contact.get_shown_groups():
self.draw_group(group, account)
self.draw_account(account)
return True
def rename_self_contact(self, old_jid, new_jid, account):
'''Rename the self_contact jid
Keyword arguments:
old_jid -- our old jid
new_jid -- our new jid
account -- the corresponding account.
'''
gajim.contacts.change_contact_jid(old_jid, new_jid, account)
self_iter = self._get_self_contact_iter(account, model=self.model)
if not self_iter:
return
self.model[self_iter][C_JID] = new_jid
self.draw_contact(new_jid, account)
2008-09-02 22:31:05 +02:00
def add_groupchat(self, jid, account, status=''):
'''Add groupchat to roster and draw it.
Return the added contact instance.
'''
2007-06-03 12:04:20 +02:00
contact = gajim.contacts.get_contact_with_highest_priority(account, jid)
# Do not show gc if we are disconnected and minimize it
if gajim.account_is_connected(account):
show = 'online'
2008-07-25 03:10:14 +02:00
else:
show = 'offline'
status = ''
if contact is None:
gc_control = gajim.interface.msg_win_mgr.get_gc_control(jid, account)
if gc_control:
# there is a window that we can minimize
gajim.interface.minimized_controls[account][jid] = gc_control
name = gc_control.name
elif jid in gajim.interface.minimized_controls[account]:
name = gajim.interface.minimized_controls[account][jid].name
else:
name = jid.split('@')[0]
# New groupchat
#GCMIN
contact = gajim.contacts.create_contact(jid=jid, account=account, name=name,
groups=[_('Groupchats')], show=show, status=status, sub='none')
gajim.contacts.add_contact(account, contact)
2008-04-24 00:34:10 +02:00
self.add_contact(jid, account)
2007-08-09 17:39:18 +02:00
else:
if jid not in gajim.interface.minimized_controls[account]:
# there is a window that we can minimize
gc_control = gajim.interface.msg_win_mgr.get_gc_control(jid,
account)
gajim.interface.minimized_controls[account][jid] = gc_control
contact.show = show
contact.status = status
self.adjust_and_draw_contact_context(jid, account)
2007-06-03 12:04:20 +02:00
return contact
2008-06-02 12:04:27 +02:00
2007-06-03 12:04:20 +02:00
def remove_groupchat(self, jid, account):
'''Remove groupchat from roster and redraw account and group.'''
contact = gajim.contacts.get_contact_with_highest_priority(account, jid)
if contact.is_groupchat():
if jid in gajim.interface.minimized_controls[account]:
del gajim.interface.minimized_controls[account][jid]
self.remove_contact(jid, account, force=True, backend=True)
return True
else:
return False
2008-06-02 12:04:27 +02:00
# FIXME: This function is yet unused! Port to new API
2008-04-24 00:34:10 +02:00
def add_transport(self, jid, account):
'''Add transport to roster and draw it.
Return the added contact instance.'''
contact = gajim.contacts.get_contact_with_highest_priority(account, jid)
2008-06-02 12:04:27 +02:00
if contact is None:
#TRANSP
contact = gajim.contacts.create_contact(jid=jid, account=account, name=jid,
groups=[_('Transports')], show='offline', status='offline',
sub='from')
gajim.contacts.add_contact(account, contact)
self.add_contact(jid, account)
return contact
2008-04-24 00:34:10 +02:00
def remove_transport(self, jid, account):
'''Remove transport from roster and redraw account and group.'''
self.remove_contact(jid, account, force=True, backend=True)
2008-04-24 00:34:10 +02:00
return True
def rename_group(self, old_name, new_name, account):
"""
rename a roster group
"""
if old_name == new_name:
return
# Groups may not change name from or to a special groups
for g in helpers.special_groups:
if g in (new_name, old_name):
return
# update all contacts in the given group
if self.regroup:
accounts = gajim.connections.keys()
else:
accounts = [account,]
for acc in accounts:
changed_contacts = []
for jid in gajim.contacts.get_jid_list(acc):
contact = gajim.contacts.get_first_contact_from_jid(acc, jid)
if old_name not in contact.groups:
continue
self.remove_contact(jid, acc, force=True)
contact.groups.remove(old_name)
if new_name not in contact.groups:
contact.groups.append(new_name)
changed_contacts.append({'jid':jid, 'name':contact.name,
'groups':contact.groups})
gajim.connections[acc].update_contacts(changed_contacts)
for c in changed_contacts:
self.add_contact(c['jid'], acc)
self._adjust_group_expand_collapse_state(new_name, acc)
self.draw_group(old_name, acc)
self.draw_group(new_name, acc)
2008-04-24 00:34:10 +02:00
2008-09-02 22:31:05 +02:00
def add_contact_to_groups(self, jid, account, groups, update=True):
2008-06-02 12:04:27 +02:00
'''Add contact to given groups and redraw them.
Contact on server is updated too. When the contact has a family,
the action will be performed for all members.
2008-06-02 12:04:27 +02:00
Keyword Arguments:
jid -- the jid
account -- the corresponding account
groups -- list of Groups to add the contact to.
update -- update contact on the server
2008-06-02 12:04:27 +02:00
'''
self.remove_contact(jid, account, force=True)
for contact in gajim.contacts.get_contacts(account, jid):
for group in groups:
if group not in contact.groups:
# we might be dropped from meta to group
contact.groups.append(group)
if update:
gajim.connections[account].update_contact(jid, contact.name,
contact.groups)
self.add_contact(jid, account)
for group in groups:
self._adjust_group_expand_collapse_state(group, account)
def remove_contact_from_groups(self, jid, account, groups, update=True):
2008-06-02 12:04:27 +02:00
'''Remove contact from given groups and redraw them.
Contact on server is updated too. When the contact has a family,
the action will be performed for all members.
2008-06-02 12:04:27 +02:00
Keyword Arguments:
jid -- the jid
account -- the corresponding account
groups -- list of Groups to remove the contact from
update -- update contact on the server
2008-06-02 12:04:27 +02:00
'''
self.remove_contact(jid, account, force=True)
for contact in gajim.contacts.get_contacts(account, jid):
for group in groups:
if group in contact.groups:
# Needed when we remove from "General" or "Observers"
contact.groups.remove(group)
if update:
gajim.connections[account].update_contact(jid, contact.name,
contact.groups)
self.add_contact(jid, account)
2008-12-03 22:56:12 +01:00
# Also redraw old groups
for group in groups:
self.draw_group(group, account)
2008-06-02 12:04:27 +02:00
# FIXME: maybe move to gajim.py
def remove_newly_added(self, jid, account):
if jid in gajim.newly_added[account]:
gajim.newly_added[account].remove(jid)
self.draw_contact(jid, account)
# FIXME: maybe move to gajim.py
def remove_to_be_removed(self, jid, account):
2008-07-31 20:23:14 +02:00
if account not in gajim.interface.instances:
2006-07-17 21:30:53 +02:00
# Account has been deleted during the timeout that called us
return
if jid in gajim.newly_added[account]:
return
if jid in gajim.to_be_removed[account]:
gajim.to_be_removed[account].remove(jid)
family = gajim.contacts.get_metacontacts_family(account, jid)
if family:
# Peform delayed recalibration
self._recalibrate_metacontact_family(family, account)
self.draw_contact(jid, account)
2008-06-02 12:04:27 +02:00
#FIXME: integrate into add_contact()
2008-09-02 22:31:05 +02:00
def add_to_not_in_the_roster(self, account, jid, nick='', resource=''):
keyID = ''
attached_keys = gajim.config.get_per('accounts', account,
'attached_gpg_keys').split()
if jid in attached_keys:
keyID = attached_keys[attached_keys.index(jid) + 1]
contact = gajim.contacts.create_not_in_roster_contact(jid=jid,
account=account, resource=resource, name=nick, keyID=keyID)
gajim.contacts.add_contact(account, contact)
self.add_contact(contact.jid, account)
return contact
2008-06-02 12:04:27 +02:00
################################################################################
### Methods for adding and removing roster window items
2008-06-02 12:04:27 +02:00
################################################################################
2007-08-09 17:39:18 +02:00
def draw_account(self, account):
child_iter = self._get_account_iter(account, self.model)
if not child_iter:
assert False, 'Account iter of %s could not be found.' % account
return
2006-11-18 21:52:28 +01:00
num_of_accounts = gajim.get_number_of_connected_accounts()
num_of_secured = gajim.get_number_of_securely_connected_accounts()
2008-06-02 12:04:27 +02:00
if gajim.account_is_securely_connected(account) and not self.regroup or \
self.regroup and num_of_secured and num_of_secured == num_of_accounts:
tls_pixbuf = self.window.render_icon(gtk.STOCK_DIALOG_AUTHENTICATION,
gtk.ICON_SIZE_MENU) # the only way to create a pixbuf from stock
self.model[child_iter][C_PADLOCK_PIXBUF] = tls_pixbuf
else:
self.model[child_iter][C_PADLOCK_PIXBUF] = None
if self.regroup:
account_name = _('Merged accounts')
accounts = []
else:
account_name = account
accounts = [account]
if account in self.collapsed_rows and \
self.model.iter_has_child(child_iter):
account_name = '[%s]' % account_name
if (gajim.account_is_connected(account) or (self.regroup and \
gajim.get_number_of_connected_accounts())) and gajim.config.get(
'show_contacts_number'):
nbr_on, nbr_total = gajim.contacts.get_nb_online_total_contacts(
accounts = accounts)
account_name += ' (%s/%s)' % (repr(nbr_on), repr(nbr_total))
self.model[child_iter][C_NAME] = account_name
2008-07-25 03:10:14 +02:00
pep = gajim.connections[account].pep
if gajim.config.get('show_mood_in_roster') and 'mood' in pep:
self.model[child_iter][C_MOOD_PIXBUF] = pep['mood'].asPixbufIcon()
2008-07-25 03:10:14 +02:00
else:
self.model[child_iter][C_MOOD_PIXBUF] = None
if gajim.config.get('show_activity_in_roster') and 'activity' in pep:
self.model[child_iter][C_ACTIVITY_PIXBUF] = pep['activity'].asPixbufIcon()
2008-07-29 04:32:57 +02:00
else:
self.model[child_iter][C_ACTIVITY_PIXBUF] = None
if gajim.config.get('show_tunes_in_roster') and 'tune' in pep:
self.model[child_iter][C_TUNE_PIXBUF] = pep['tune'].asPixbufIcon()
2008-07-25 16:11:14 +02:00
else:
self.model[child_iter][C_TUNE_PIXBUF] = None
return False
2008-06-02 12:04:27 +02:00
def draw_group(self, group, account):
2008-09-02 22:34:11 +02:00
child_iter = self._get_group_iter(group, account, model=self.model)
if not child_iter:
# Eg. We redraw groups after we removed a entitiy
# and its empty groups
return
if self.regroup:
accounts = []
else:
accounts = [account]
text = gobject.markup_escape_text(group)
if helpers.group_is_blocked(account, group):
text = '<span strikethrough="true">%s</span>' % text
if gajim.config.get('show_contacts_number'):
nbr_on, nbr_total = gajim.contacts.get_nb_online_total_contacts(
accounts = accounts, groups = [group])
text += ' (%s/%s)' % (repr(nbr_on), repr(nbr_total))
2008-06-02 12:04:27 +02:00
self.model[child_iter][C_NAME] = text
return False
2008-06-02 12:04:27 +02:00
def draw_parent_contact(self, jid, account):
2008-09-02 22:34:11 +02:00
child_iters = self._get_contact_iter(jid, account, model=self.model)
if not child_iters:
return False
parent_iter = self.model.iter_parent(child_iters[0])
if self.model[parent_iter][C_TYPE] != 'contact':
# parent is not a contact
return
parent_jid = self.model[parent_iter][C_JID].decode('utf-8')
parent_account = self.model[parent_iter][C_ACCOUNT].decode('utf-8')
self.draw_contact(parent_jid, parent_account)
2008-04-24 00:34:10 +02:00
return False
2008-06-02 12:04:27 +02:00
2008-09-02 22:31:05 +02:00
def draw_contact(self, jid, account, selected=False, focus=False):
'''draw the correct state image, name BUT not avatar'''
2005-11-15 20:56:49 +01:00
# focus is about if the roster window has toplevel-focus or not
# FIXME: We really need a custom cell_renderer
2007-08-09 17:39:18 +02:00
contact_instances = gajim.contacts.get_contacts(account, jid)
contact = gajim.contacts.get_highest_prio_contact_from_contacts(
contact_instances)
2008-07-31 20:23:14 +02:00
child_iters = self._get_contact_iter(jid, account, contact, self.model)
if not child_iters:
2008-06-02 12:04:27 +02:00
return False
name = gobject.markup_escape_text(contact.get_shown_name())
2007-06-03 12:04:20 +02:00
# gets number of unread gc marked messages
if jid in gajim.interface.minimized_controls[account] and \
gajim.interface.minimized_controls[account][jid]:
2007-06-03 12:04:20 +02:00
nb_unread = len(gajim.events.get_events(account, jid,
['printed_marked_gc_msg']))
2008-07-25 01:53:56 +02:00
nb_unread += gajim.interface.minimized_controls \
[account][jid].get_nb_unread_pm()
2007-06-03 12:04:20 +02:00
if nb_unread == 1:
name = '%s *' % name
elif nb_unread > 1:
name = '%s [%s]' % (name, str(nb_unread))
2008-06-02 12:04:27 +02:00
# Strike name if blocked
2007-06-03 12:04:20 +02:00
strike = False
if helpers.jid_is_blocked(account, jid):
2007-06-03 12:04:20 +02:00
strike = True
else:
for group in contact.get_shown_groups():
if helpers.group_is_blocked(account, group):
2007-06-03 12:04:20 +02:00
strike = True
break
if strike:
name = '<span strikethrough="true">%s</span>' % name
# Show resource counter
2006-11-18 21:52:28 +01:00
nb_connected_contact = 0
for c in contact_instances:
if c.show not in ('error', 'offline'):
nb_connected_contact += 1
if nb_connected_contact > 1:
# switch back to default writing direction
name += i18n.paragraph_direction_mark(unicode(name))
name += u' (%d)' % nb_connected_contact
2008-07-25 01:53:56 +02:00
# show (account_name) if there are 2 contact with same jid
# in merged mode
if self.regroup:
add_acct = False
# look through all contacts of all accounts
for account_ in gajim.connections:
2008-07-25 01:53:56 +02:00
# useless to add account name
if account_ == account:
2006-11-18 21:52:28 +01:00
continue
2008-07-31 20:23:14 +02:00
for jid_ in gajim.contacts.get_jid_list(account_):
contact_ = gajim.contacts.get_first_contact_from_jid(
2008-07-25 01:53:56 +02:00
account_, jid_)
2008-07-31 20:23:14 +02:00
if contact_.get_shown_name() == contact.get_shown_name() and \
(jid_, account_) != (jid, account):
add_acct = True
break
if add_acct:
2008-07-25 01:53:56 +02:00
# No need to continue in other account
# if we already found one
break
if add_acct:
name += ' (' + account + ')'
2008-07-25 01:53:56 +02:00
# add status msg, if not empty, under contact name in
# the treeview
2008-07-31 20:23:14 +02:00
if contact.status and gajim.config.get('show_status_msgs_in_roster'):
status = contact.status.strip()
if status != '':
2008-07-25 01:53:56 +02:00
status = helpers.reduce_chars_newlines(status,
max_lines = 1)
# escape markup entities and make them small
# italic and fg color color is calcuted to be
# always readable
2008-07-31 20:23:14 +02:00
color = gtkgui_helpers._get_fade_color(self.tree, selected, focus)
colorstring = '#%04x%04x%04x' % (color.red, color.green, color.blue)
2008-07-25 01:53:56 +02:00
name += '\n<span size="small" style="italic" ' \
'foreground="%s">%s</span>' % (
colorstring,
gobject.markup_escape_text(status))
2008-06-02 12:04:27 +02:00
icon_name = helpers.get_icon_name_to_show(contact, account)
2006-09-13 18:47:58 +02:00
# look if another resource has awaiting events
for c in contact_instances:
c_icon_name = helpers.get_icon_name_to_show(c, account)
2008-07-31 20:23:14 +02:00
if c_icon_name in ('event', 'muc_active', 'muc_inactive'):
icon_name = c_icon_name
break
# Check for events of collapsed (hidden) brothers
family = gajim.contacts.get_metacontacts_family(account, jid)
is_big_brother = False
have_visible_children = False
if family:
2008-12-02 16:53:23 +01:00
bb_jid, bb_account = \
self._get_nearby_family_and_big_brother(family, account)[1:]
is_big_brother = (jid, account) == (bb_jid, bb_account)
2008-12-03 22:56:12 +01:00
iters = self._get_contact_iter(jid, account)
2008-07-25 01:53:56 +02:00
have_visible_children = iters \
and self.modelfilter.iter_has_child(iters[0])
if have_visible_children:
# We are the big brother and have a visible family
for child_iter in child_iters:
child_path = self.model.get_path(child_iter)
2008-07-31 20:23:14 +02:00
path = self.modelfilter.convert_child_path_to_path(child_path)
2009-11-04 20:37:22 +01:00
if not path:
continue
2008-07-31 20:23:14 +02:00
if not self.tree.row_expanded(path) and icon_name != 'event':
iterC = self.model.iter_children(child_iter)
while iterC:
# a child has awaiting messages?
2008-07-31 20:23:14 +02:00
jidC = self.model[iterC][C_JID].decode('utf-8')
accountC = self.model[iterC][C_ACCOUNT].decode('utf-8')
if len(gajim.events.get_events(accountC, jidC)):
icon_name = 'event'
break
2008-07-31 20:23:14 +02:00
iterC = self.model.iter_next(iterC)
if self.tree.row_expanded(path):
2008-07-31 20:23:14 +02:00
state_images = self.get_appropriate_state_images(
2008-07-25 01:53:56 +02:00
jid, size = 'opened',
icon_name = icon_name)
else:
2008-07-31 20:23:14 +02:00
state_images = self.get_appropriate_state_images(
2008-07-25 01:53:56 +02:00
jid, size = 'closed',
icon_name = icon_name)
2008-12-03 22:56:12 +01:00
2008-07-25 01:53:56 +02:00
# Expand/collapse icon might differ per iter
# (group)
img = state_images[icon_name]
self.model[child_iter][C_IMG] = img
self.model[child_iter][C_NAME] = name
else:
# A normal contact or little brother
state_images = self.get_appropriate_state_images(jid,
icon_name = icon_name)
2007-06-03 12:04:20 +02:00
# All iters have the same icon (no expand/collapse)
img = state_images[icon_name]
for child_iter in child_iters:
self.model[child_iter][C_IMG] = img
self.model[child_iter][C_NAME] = name
# We are a little brother
if family and not is_big_brother and not self.starting:
self.draw_parent_contact(jid, account)
for group in contact.get_shown_groups():
# We need to make sure that _visible_func is called for
# our groups otherwise we might not be shown
2008-09-02 22:34:11 +02:00
iterG = self._get_group_iter(group, account, model=self.model)
if iterG:
# it's not self contact
2008-07-31 20:23:14 +02:00
self.model[iterG][C_JID] = self.model[iterG][C_JID]
return False
def _is_pep_shown_in_roster(self, pep_type):
if pep_type == 'mood':
return gajim.config.get('show_mood_in_roster')
elif pep_type == 'activity':
return gajim.config.get('show_activity_in_roster')
elif pep_type == 'tune':
return gajim.config.get('show_tunes_in_roster')
else:
return False
def draw_all_pep_types(self, jid, account):
for pep_type in self._pep_type_to_model_column:
self.draw_pep(jid, account, pep_type)
def draw_pep(self, jid, account, pep_type):
if pep_type not in self._pep_type_to_model_column:
2008-07-29 04:32:57 +02:00
return
if not self._is_pep_shown_in_roster(pep_type):
return
model_column = self._pep_type_to_model_column[pep_type]
2008-09-02 22:34:11 +02:00
iters = self._get_contact_iter(jid, account, model=self.model)
if not iters:
2008-07-25 16:11:14 +02:00
return
jid = self.model[iters[0]][C_JID]
jid = jid.decode('utf-8')
contact = gajim.contacts.get_contact(account, jid)
if pep_type in contact.pep:
pixbuf = contact.pep[pep_type].asPixbufIcon()
2008-07-25 16:11:14 +02:00
else:
pixbuf = None
for child_iter in iters:
self.model[child_iter][model_column] = pixbuf
2008-07-25 16:11:14 +02:00
def draw_avatar(self, jid, account):
2008-09-02 22:34:11 +02:00
iters = self._get_contact_iter(jid, account, model=self.model)
if not iters or not gajim.config.get('show_avatars_in_roster'):
return
jid = self.model[iters[0]][C_JID]
jid = jid.decode('utf-8')
pixbuf = gtkgui_helpers.get_avatar_pixbuf_from_cache(jid)
if pixbuf is None or pixbuf == 'ask':
scaled_pixbuf = None
else:
scaled_pixbuf = gtkgui_helpers.get_scaled_pixbuf(pixbuf, 'roster')
for child_iter in iters:
self.model[child_iter][C_AVATAR_PIXBUF] = scaled_pixbuf
return False
2008-12-03 22:56:12 +01:00
def draw_completely(self, jid, account):
self.draw_contact(jid, account)
self.draw_all_pep_types(jid, account)
self.draw_avatar(jid, account)
2007-08-09 17:39:18 +02:00
def adjust_and_draw_contact_context(self, jid, account):
'''Draw contact, account and groups of given jid
Show contact if it has pending events
'''
contact = gajim.contacts.get_first_contact_from_jid(account, jid)
if not contact:
# idle draw or just removed SelfContact
return
family = gajim.contacts.get_metacontacts_family(account, jid)
if family:
# There might be a new big brother
self._recalibrate_metacontact_family(family, account)
self.draw_contact(jid, account)
self.draw_account(account)
for group in contact.get_shown_groups():
self.draw_group(group, account)
self._adjust_group_expand_collapse_state(group, account)
def _idle_draw_jids_of_account(self, jids, account):
'''Draw given contacts and their avatars in a lazy fashion.
2008-06-02 12:04:27 +02:00
Keyword arguments:
jids -- a list of jids to draw
account -- the corresponding account
'''
def _draw_all_contacts(jids, account):
for jid in jids:
family = gajim.contacts.get_metacontacts_family(account, jid)
if family:
# For metacontacts over several accounts:
# When we connect a new account existing brothers
# must be redrawn (got removed and readded)
for data in family:
self.draw_completely(data['jid'], data['account'])
else:
self.draw_completely(jid, account)
yield True
yield False
2008-06-02 12:04:27 +02:00
task = _draw_all_contacts(jids, account)
gobject.idle_add(task.next)
2008-06-02 12:04:27 +02:00
def setup_and_draw_roster(self):
'''create new empty model and draw roster'''
self.modelfilter = None
2008-07-25 03:10:14 +02:00
# (icon, name, type, jid, account, editable, mood_pixbuf,
2008-07-29 04:32:57 +02:00
# activity_pixbuf, tune_pixbuf avatar_pixbuf, padlock_pixbuf)
2008-07-25 01:53:56 +02:00
self.model = gtk.TreeStore(gtk.Image, str, str, str, str,
2008-07-25 16:11:14 +02:00
gtk.gdk.Pixbuf, gtk.gdk.Pixbuf, gtk.gdk.Pixbuf,
2008-07-29 04:32:57 +02:00
gtk.gdk.Pixbuf, gtk.gdk.Pixbuf)
self.model.set_sort_func(1, self._compareIters)
self.model.set_sort_column_id(1, gtk.SORT_ASCENDING)
self.modelfilter = self.model.filter_new()
self.modelfilter.set_visible_func(self._visible_func)
self.modelfilter.connect('row-has-child-toggled',
self.on_modelfilter_row_has_child_toggled)
self.tree.set_model(self.modelfilter)
for acct in gajim.connections:
self.add_account(acct)
self.add_account_contacts(acct)
# Recalculate column width for ellipsizing
self.tree.columns_autosize()
2008-06-02 12:04:27 +02:00
def select_contact(self, jid, account):
'''Select contact in roster. If contact is hidden but has events,
show him.'''
# Refiltering SHOULD NOT be needed:
# When a contact gets a new event he will be redrawn and his
# icon changes, so _visible_func WILL be called on him anyway
iters = self._get_contact_iter(jid, account)
if not iters:
# Not visible in roster
return
path = self.modelfilter.get_path(iters[0])
if self.dragging or not gajim.config.get('scroll_roster_to_last_message'):
# do not change selection while DND'ing
return
# Expand his parent, so this path is visible, don't expand it.
self.tree.expand_to_path(path[:-1])
self.tree.scroll_to_cell(path)
self.tree.set_cursor(path)
def _adjust_account_expand_collapse_state(self, account):
'''Expand/collapse account row based on self.collapsed_rows'''
iterA = self._get_account_iter(account)
if not iterA:
# thank you modelfilter
return
path = self.modelfilter.get_path(iterA)
if account in self.collapsed_rows:
self.tree.collapse_row(path)
else:
self.tree.expand_row(path, False)
return False
def _adjust_group_expand_collapse_state(self, group, account):
'''Expand/collapse group row based on self.collapsed_rows'''
iterG = self._get_group_iter(group, account)
if not iterG:
# Group not visible
return
path = self.modelfilter.get_path(iterG)
if account + group in self.collapsed_rows:
self.tree.collapse_row(path)
else:
self.tree.expand_row(path, False)
return False
2008-05-08 23:18:39 +02:00
##############################################################################
### Roster and Modelfilter handling
2008-06-02 12:04:27 +02:00
##############################################################################
def _search_roster_func(self, model, column, key, titer):
key = key.decode('utf-8').lower()
name = model[titer][C_NAME].decode('utf-8').lower()
return not (key in name)
2008-06-02 12:04:27 +02:00
def refilter_shown_roster_items(self):
self.filtering = True
self.modelfilter.refilter()
2008-06-02 12:04:27 +02:00
self.filtering = False
def contact_has_pending_roster_events(self, contact, account):
2008-06-02 12:04:27 +02:00
'''Return True if the contact or one if it resources has pending events'''
# jid has pending events
if gajim.events.get_nb_roster_events(account, contact.jid) > 0:
return True
# check events of all resources
for contact_ in gajim.contacts.get_contacts(account, contact.jid):
if contact_.resource and gajim.events.get_nb_roster_events(account,
contact_.get_full_jid()) > 0:
return True
return False
def contact_is_visible(self, contact, account):
if self.contact_has_pending_roster_events(contact, account):
return True
if contact.show in ('offline', 'error'):
if contact.jid in gajim.to_be_removed[account]:
return True
return False
if gajim.config.get('show_only_chat_and_online') and contact.show in (
'away', 'xa', 'busy'):
return False
2008-06-02 12:04:27 +02:00
return True
def _visible_func(self, model, titer):
2008-06-02 12:04:27 +02:00
'''Determine whether iter should be visible in the treeview'''
type_ = model[titer][C_TYPE]
if not type_:
return False
if type_ == 'account':
# Always show account
return True
account = model[titer][C_ACCOUNT]
if not account:
return False
account = account.decode('utf-8')
jid = model[titer][C_JID]
if not jid:
return False
jid = jid.decode('utf-8')
if type_ == 'group':
group = jid
if group == _('Transports'):
return gajim.config.get('show_transports_group') and \
(gajim.account_is_connected(account) or \
gajim.config.get('showoffline'))
if gajim.config.get('showoffline'):
return True
if self.regroup:
# C_ACCOUNT for groups depends on the order
# accounts were connected
# Check all accounts for online group contacts
accounts = gajim.contacts.get_accounts()
else:
accounts = [account]
for _acc in accounts:
for contact in gajim.contacts.iter_contacts(_acc):
2008-07-25 03:10:14 +02:00
# Is this contact in this group ? (last part of if check if it's
# self contact)
if group in contact.get_shown_groups():
if self.contact_is_visible(contact, _acc):
return True
return False
if type_ == 'contact':
if gajim.config.get('showoffline'):
return True
bb_jid = None
bb_account = None
family = gajim.contacts.get_metacontacts_family(account, jid)
if family:
nearby_family, bb_jid, bb_account = \
self._get_nearby_family_and_big_brother(family, account)
if (bb_jid, bb_account) == (jid, account):
# Show the big brother if a child has pending events
for data in nearby_family:
jid = data['jid']
account = data['account']
contact = gajim.contacts.get_contact_with_highest_priority(
account, jid)
2008-06-16 11:51:03 +02:00
if contact and self.contact_is_visible(contact, account):
return True
2008-07-25 03:10:14 +02:00
return False
else:
contact = gajim.contacts.get_contact_with_highest_priority(account,
jid)
return self.contact_is_visible(contact, account)
if type_ == 'agent':
return gajim.config.get('show_transports_group') and \
(gajim.account_is_connected(account) or \
gajim.config.get('showoffline'))
return True
2005-08-06 21:14:21 +02:00
2008-09-02 22:31:05 +02:00
def _compareIters(self, model, iter1, iter2, data=None):
'''Compare two iters to sort them'''
name1 = model[iter1][C_NAME]
name2 = model[iter2][C_NAME]
if not name1 or not name2:
return 0
name1 = name1.decode('utf-8')
name2 = name2.decode('utf-8')
type1 = model[iter1][C_TYPE]
type2 = model[iter2][C_TYPE]
if type1 == 'self_contact':
return -1
if type2 == 'self_contact':
return 1
if type1 == 'group':
name1 = model[iter1][C_JID]
name2 = model[iter2][C_JID]
if name1 == _('Transports'):
return 1
if name2 == _('Transports'):
return -1
if name1 == _('Not in Roster'):
return 1
if name2 == _('Not in Roster'):
return -1
if name1 == _('Groupchats'):
return 1
if name2 == _('Groupchats'):
return -1
account1 = model[iter1][C_ACCOUNT]
account2 = model[iter2][C_ACCOUNT]
if not account1 or not account2:
return 0
account1 = account1.decode('utf-8')
account2 = account2.decode('utf-8')
if type1 == 'account':
return locale.strcoll(account1, account2)
jid1 = model[iter1][C_JID].decode('utf-8')
jid2 = model[iter2][C_JID].decode('utf-8')
if type1 == 'contact':
lcontact1 = gajim.contacts.get_contacts(account1, jid1)
contact1 = gajim.contacts.get_first_contact_from_jid(account1, jid1)
if not contact1:
return 0
name1 = contact1.get_shown_name()
if type2 == 'contact':
lcontact2 = gajim.contacts.get_contacts(account2, jid2)
contact2 = gajim.contacts.get_first_contact_from_jid(account2, jid2)
if not contact2:
return 0
name2 = contact2.get_shown_name()
# We first compare by show if sort_by_show_in_roster is True or if it's a
# child contact
if type1 == 'contact' and type2 == 'contact' and \
gajim.config.get('sort_by_show_in_roster'):
cshow = {'chat':0, 'online': 1, 'away': 2, 'xa': 3, 'dnd': 4,
'invisible': 5, 'offline': 6, 'not in roster': 7, 'error': 8}
s = self.get_show(lcontact1)
show1 = cshow.get(s, 9)
s = self.get_show(lcontact2)
show2 = cshow.get(s, 9)
removing1 = False
removing2 = False
if show1 == 6 and jid1 in gajim.to_be_removed[account1]:
removing1 = True
if show2 == 6 and jid2 in gajim.to_be_removed[account2]:
removing2 = True
if removing1 and not removing2:
return 1
if removing2 and not removing1:
return -1
sub1 = contact1.sub
sub2 = contact2.sub
# none and from goes after
if sub1 not in ['none', 'from'] and sub2 in ['none', 'from']:
return -1
if sub1 in ['none', 'from'] and sub2 not in ['none', 'from']:
return 1
if show1 < show2:
return -1
elif show1 > show2:
return 1
# We compare names
cmp_result = locale.strcoll(name1.lower(), name2.lower())
if cmp_result < 0:
return -1
if cmp_result > 0:
return 1
if type1 == 'contact' and type2 == 'contact':
# We compare account names
cmp_result = locale.strcoll(account1.lower(), account2.lower())
if cmp_result < 0:
return -1
if cmp_result > 0:
return 1
# We compare jids
cmp_result = locale.strcoll(jid1.lower(), jid2.lower())
if cmp_result < 0:
return -1
if cmp_result > 0:
return 1
return 0
################################################################################
2008-06-02 12:04:27 +02:00
### FIXME: Methods that don't belong to roster window...
2008-05-13 16:03:30 +02:00
### ... atleast not in there current form
################################################################################
def fire_up_unread_messages_events(self, account):
'''reads from db the unread messages, and fire them up, and
if we find very old unread messages, delete them from unread table'''
results = gajim.logger.get_unread_msgs()
for result in results:
jid = result[4]
shown = result[5]
if gajim.contacts.get_first_contact_from_jid(account, jid) and not \
shown:
# We have this jid in our contacts list
# XXX unread messages should probably have their session saved with
# them
session = gajim.connections[account].make_new_session(jid)
2005-08-06 21:14:21 +02:00
tim = time.localtime(float(result[2]))
session.roster_message(jid, result[1], tim, msg_type='chat',
msg_id=result[0])
gajim.logger.set_shown_unread_msgs(result[0])
2005-08-06 21:14:21 +02:00
elif (time.time() - result[2]) > 2592000:
# ok, here we see that we have a message in unread messages table
2008-06-02 12:04:27 +02:00
# that is older than a month. It is probably from someone not in our
# roster for accounts we usually launch, so we will delete this id
# from unread message tables.
gajim.logger.set_read_messages([result[0]])
2006-11-18 21:52:28 +01:00
def fill_contacts_and_groups_dicts(self, array, account):
'''fill gajim.contacts and gajim.groups'''
# FIXME: This function needs to be splitted
# Most of the logic SHOULD NOT be done at GUI level
if account not in gajim.contacts.get_accounts():
gajim.contacts.add_account(account)
2008-07-31 20:23:14 +02:00
if account not in gajim.groups:
gajim.groups[account] = {}
if gajim.config.get('show_self_contact') == 'always':
self_jid = gajim.get_jid_from_account(account)
if gajim.connections[account].server_resource:
self_jid += '/' + gajim.connections[account].server_resource
array[self_jid] = {'name': gajim.nicks[account],
'groups': ['self_contact'], 'subscription': 'both', 'ask': 'none'}
2008-08-07 13:46:07 +02:00
# .keys() is needed
for jid in array.keys():
# Remove the contact in roster. It might has changed
self.remove_contact(jid, account, force=True)
# Remove old Contact instances
gajim.contacts.remove_jid(account, jid, remove_meta=False)
jids = jid.split('/')
# get jid
ji = jids[0]
# get resource
resource = ''
if len(jids) > 1:
resource = '/'.join(jids[1:])
# get name
name = array[jid]['name'] or ''
show = 'offline' # show is offline by default
status = '' # no status message by default
2005-08-06 21:14:21 +02:00
keyID = ''
attached_keys = gajim.config.get_per('accounts', account,
'attached_gpg_keys').split()
if jid in attached_keys:
keyID = attached_keys[attached_keys.index(jid) + 1]
if gajim.jid_is_transport(jid):
array[jid]['groups'] = [_('Transports')]
#TRANSP - potential
contact1 = gajim.contacts.create_contact(jid=ji, account=account, name=name,
groups=array[jid]['groups'], show=show, status=status,
sub=array[jid]['subscription'], ask=array[jid]['ask'],
resource=resource, keyID=keyID)
gajim.contacts.add_contact(account, contact1)
2005-08-06 21:14:21 +02:00
if gajim.config.get('ask_avatars_on_startup'):
pixbuf = gtkgui_helpers.get_avatar_pixbuf_from_cache(ji)
if pixbuf == 'ask':
transport = gajim.get_transport_name_from_jid(contact1.jid)
if not transport or gajim.jid_is_transport(contact1.jid):
jid_with_resource = contact1.jid
if contact1.resource:
jid_with_resource += '/' + contact1.resource
gajim.connections[account].request_vcard(jid_with_resource)
else:
host = gajim.get_server_from_jid(contact1.jid)
2008-07-31 20:23:14 +02:00
if host not in gajim.transport_avatar[account]:
gajim.transport_avatar[account][host] = [contact1.jid]
else:
gajim.transport_avatar[account][host].append(contact1.jid)
# If we already have chat windows opened, update them with new contact
# instance
chat_control = gajim.interface.msg_win_mgr.get_control(ji, account)
if chat_control:
chat_control.contact = contact1
2007-12-12 09:44:46 +01:00
def connected_rooms(self, account):
if account in gajim.gc_connected[account].values():
return True
2008-06-02 12:04:27 +02:00
return False
def on_event_removed(self, event_list):
2008-06-02 12:04:27 +02:00
'''Remove contacts on last events removed.
Only performed if removal was requested before but the contact
still had pending events
'''
2008-06-02 12:04:27 +02:00
contact_list = ((event.jid.split('/')[0], event.account) for event in \
event_list)
for jid, account in contact_list:
self.draw_contact(jid, account)
# Remove contacts in roster if removal was requested
key = (jid, account)
if key in self.contacts_to_be_removed.keys():
backend = self.contacts_to_be_removed[key]['backend']
del self.contacts_to_be_removed[key]
# Remove contact will delay removal if there are more events pending
self.remove_contact(jid, account, backend=backend)
self.show_title()
2008-06-02 12:04:27 +02:00
def open_event(self, account, jid, event):
'''If an event was handled, return True, else return False'''
data = event.parameters
ft = gajim.interface.instances['file_transfers']
event = gajim.events.get_first_event(account, jid, event.type_)
if event.type_ == 'normal':
dialogs.SingleMessageWindow(account, jid,
action='receive', from_whom=jid, subject=data[1], message=data[0],
resource=data[5], session=data[8], form_node=data[9])
gajim.events.remove_events(account, jid, event)
return True
elif event.type_ == 'file-request':
contact = gajim.contacts.get_contact_with_highest_priority(account,
jid)
ft.show_file_request(account, contact, data)
gajim.events.remove_events(account, jid, event)
return True
elif event.type_ in ('file-request-error', 'file-send-error'):
ft.show_send_error(data)
gajim.events.remove_events(account, jid, event)
return True
elif event.type_ in ('file-error', 'file-stopped'):
2009-08-28 13:44:03 +02:00
msg_err = ''
if data['error'] == -1:
msg_err = _('Remote contact stopped transfer')
elif data['error'] == -6:
msg_err = _('Error opening file')
ft.show_stopped(jid, data, error_msg=msg_err)
gajim.events.remove_events(account, jid, event)
return True
elif event.type_ == 'file-completed':
ft.show_completed(jid, data)
gajim.events.remove_events(account, jid, event)
return True
elif event.type_ == 'gc-invitation':
dialogs.InvitationReceivedDialog(account, data[0], jid, data[2],
data[1])
gajim.events.remove_events(account, jid, event)
2008-06-02 12:04:27 +02:00
return True
elif event.type_ == 'subscription_request':
dialogs.SubscriptionRequestWindow(jid, data[0], account, data[1])
gajim.events.remove_events(account, jid, event)
return True
elif event.type_ == 'unsubscribed':
gajim.interface.show_unsubscribed_dialog(account, data)
gajim.events.remove_events(account, jid, event)
return True
return False
################################################################################
### This and that... random.
################################################################################
def show_roster_vbox(self, active):
if active:
self.xml.get_widget('roster_vbox2').show()
else:
self.xml.get_widget('roster_vbox2').hide()
2007-12-12 09:44:46 +01:00
2008-06-02 12:04:27 +02:00
def show_tooltip(self, contact):
pointer = self.tree.get_pointer()
props = self.tree.get_path_at_pos(pointer[0], pointer[1])
# check if the current pointer is at the same path
# as it was before setting the timeout
if props and self.tooltip.id == props[0]:
# bounding rectangle of coordinates for the cell within the treeview
rect = self.tree.get_cell_area(props[0], props[1])
# position of the treeview on the screen
position = self.tree.window.get_origin()
self.tooltip.show_tooltip(contact, rect.height, position[1] + rect.y)
else:
self.tooltip.hide_tooltip()
def authorize(self, widget, jid, account):
'''Authorize a contact (by re-sending auth menuitem)'''
gajim.connections[account].send_authorization(jid)
dialogs.InformationDialog(_('Authorization has been sent'),
_('Now "%s" will know your status.') %jid)
2007-08-09 17:39:18 +02:00
2008-09-02 22:31:05 +02:00
def req_sub(self, widget, jid, txt, account, groups=[], nickname=None,
auto_auth=False):
'''Request subscription to a contact'''
gajim.connections[account].request_subscription(jid, txt, nickname,
groups, auto_auth, gajim.nicks[account])
contact = gajim.contacts.get_contact_with_highest_priority(account, jid)
if not contact:
keyID = ''
attached_keys = gajim.config.get_per('accounts', account,
'attached_gpg_keys').split()
if jid in attached_keys:
keyID = attached_keys[attached_keys.index(jid) + 1]
contact = gajim.contacts.create_contact(jid=jid, account=account, name=nickname,
groups=groups, show='requested', status='', ask='none',
sub='subscribe', keyID=keyID)
gajim.contacts.add_contact(account, contact)
else:
if not _('Not in Roster') in contact.get_shown_groups():
dialogs.InformationDialog(_('Subscription request has been sent'),
_('If "%s" accepts this request you will know his or her status.'
) % jid)
return
self.remove_contact(contact.jid, account, force=True)
contact.groups = groups
if nickname:
contact.name = nickname
self.add_contact(jid, account)
2007-12-12 09:44:46 +01:00
def revoke_auth(self, widget, jid, account):
'''Revoke a contact's authorization'''
gajim.connections[account].refuse_authorization(jid)
dialogs.InformationDialog(_('Authorization has been removed'),
_('Now "%s" will always see you as offline.') %jid)
2007-12-12 09:44:46 +01:00
def set_state(self, account, state):
child_iterA = self._get_account_iter(account, self.model)
if child_iterA:
self.model[child_iterA][0] = \
gajim.interface.jabber_state_images['16'][state]
if gajim.interface.systray_enabled:
gajim.interface.systray.change_status(state)
def set_connecting_state(self, account):
self.set_state(account, 'connecting')
2006-09-13 18:47:58 +02:00
def send_status(self, account, status, txt, auto=False, to=None):
child_iterA = self._get_account_iter(account, self.model)
if status != 'offline':
2008-07-16 17:50:51 +02:00
if to is None:
if status == gajim.connections[account].get_status() and \
txt == gajim.connections[account].status:
return
gajim.config.set_per('accounts', account, 'last_status', status)
gajim.config.set_per('accounts', account, 'last_status_msg',
helpers.to_one_line(txt))
if gajim.connections[account].connected < 2:
self.set_connecting_state(account)
2006-11-18 21:52:28 +01:00
keyid = gajim.config.get_per('accounts', account, 'keyid')
if keyid and not gajim.connections[account].gpg:
2008-12-02 16:53:23 +01:00
dialogs.WarningDialog(_('GPG is not usable'),
_('You will be connected to %s without OpenPGP.') % account)
Merge one_window branch Merged revisions 9143,9145-9155,9157-9162,9164-9169,9171-9177 via svnmerge from svn://88.191.11.156/gajim/branches/one_window ........ r9145 | nicfit | 2007-12-13 21:49:09 -0700 (Thu, 13 Dec 2007) | 2 lines Implemented the original Nikos patch with an HPaned instead of a HBox and only do this mode when one_message_window == 'always' ........ r9152 | nicfit | 2007-12-15 13:33:56 -0700 (Sat, 15 Dec 2007) | 2 lines Added config and GUI for one_message_window_with_roster ........ r9153 | nicfit | 2007-12-15 13:41:46 -0700 (Sat, 15 Dec 2007) | 2 lines Use one_message_window_with_roster and some whitespace cleanup ........ r9154 | nicfit | 2007-12-15 14:04:49 -0700 (Sat, 15 Dec 2007) | 2 lines Scratch the chckbox for with roster mode, use one_message_window opt and combo ........ r9155 | nicfit | 2007-12-15 17:01:13 -0700 (Sat, 15 Dec 2007) | 2 lines MessageWindowMgr knows about ONE_MESSAGE_WINDOW_ALWAYS_WITH_ROSTER and MessageWindow can reparent itself rather then the roster having to do so. ........ r9157 | nicfit | 2007-12-15 17:47:20 -0700 (Sat, 15 Dec 2007) | 2 lines Resizing fixes and make the roster window shrink when last tab is removed ........ r9158 | nicfit | 2007-12-15 19:15:11 -0700 (Sat, 15 Dec 2007) | 2 lines Added "Show roster" (CTRL+R) to view menu when using always_with_roster to quickly hide/show the roster. ........ r9159 | nicfit | 2007-12-15 19:49:30 -0700 (Sat, 15 Dec 2007) | 2 lines Handle window title setting in always_with_roster mode. ........ r9160 | nicfit | 2007-12-15 20:13:57 -0700 (Sat, 15 Dec 2007) | 2 lines Removed FIXME ........ r9167 | nicfit | 2007-12-17 18:40:59 -0700 (Mon, 17 Dec 2007) | 2 lines When roster is hidden, show it when the number of MessageWindow controls == 0 ........ r9168 | nicfit | 2007-12-17 19:07:49 -0700 (Mon, 17 Dec 2007) | 2 lines Disable hiding roster when there are no message controls open ........ r9169 | nicfit | 2007-12-17 20:41:11 -0700 (Mon, 17 Dec 2007) | 2 lines Bunch of saved size bugs fixed ........
2007-12-19 00:42:22 +01:00
self.send_status_continue(account, status, txt, auto, to)
def send_pep(self, account, pep_dict):
connection = gajim.connections[account]
if 'activity' in pep_dict:
activity = pep_dict['activity']
subactivity = pep_dict.get('subactivity', None)
activity_text = pep_dict.get('activity_text', None)
connection.send_activity(activity, subactivity, activity_text)
else:
connection.retract_activity()
if 'mood' in pep_dict:
mood = pep_dict['mood']
mood_text = pep_dict.get('mood_text', None)
connection.send_mood(mood, mood_text)
else:
connection.retract_mood()
def delete_pep(self, jid, account):
if jid == gajim.get_jid_from_account(account):
gajim.connections[account].pep = {}
self.draw_account(account)
for contact in gajim.contacts.get_contacts(account, jid):
contact.pep = {}
self.draw_all_pep_types(jid, account)
ctrl = gajim.interface.msg_win_mgr.get_control(jid, account)
if ctrl:
ctrl.update_all_pep_types()
def send_status_continue(self, account, status, txt, auto, to):
if gajim.account_is_connected(account) and not to:
if status == 'online' and gajim.interface.sleeper.getState() != \
common.sleepy.STATE_UNKNOWN:
gajim.sleeper_state[account] = 'online'
elif gajim.sleeper_state[account] not in ('autoaway', 'autoxa') or \
status == 'offline':
gajim.sleeper_state[account] = 'off'
if to:
gajim.connections[account].send_custom_status(status, txt, to)
else:
if status in ('invisible', 'offline'):
self.delete_pep(gajim.get_jid_from_account(account), account)
was_invisible = gajim.connections[account].connected == \
gajim.SHOW_LIST.index('invisible')
gajim.connections[account].change_status(status, txt, auto)
2006-11-18 21:52:28 +01:00
if account in gajim.interface.status_sent_to_users:
gajim.interface.status_sent_to_users[account] = {}
if account in gajim.interface.status_sent_to_groups:
gajim.interface.status_sent_to_groups[account] = {}
for gc_control in gajim.interface.msg_win_mgr.get_controls(
message_control.TYPE_GC) + \
gajim.interface.minimized_controls[account].values():
if gc_control.account == account:
if gajim.gc_connected[account][gc_control.room_jid]:
gajim.connections[account].send_gc_status(gc_control.nick,
gc_control.room_jid, status, txt)
else:
# for some reason, we are not connected to the room even if
# tab is opened, send initial join_gc()
gajim.connections[account].join_gc(gc_control.nick,
gc_control.room_jid, None)
if was_invisible and status != 'offline':
# We come back from invisible, join bookmarks
gajim.interface.auto_join_bookmarks(account)
def chg_contact_status(self, contact, show, status, account):
'''When a contact changes his or her status'''
contact_instances = gajim.contacts.get_contacts(account, contact.jid)
contact.show = show
contact.status = status
# name is to show in conversation window
name = contact.get_shown_name()
fjid = contact.get_full_jid()
# The contact has several resources
if len(contact_instances) > 1:
if contact.resource != '':
name += '/' + contact.resource
# Remove resource when going offline
if show in ('offline', 'error') and \
not self.contact_has_pending_roster_events(contact, account):
ctrl = gajim.interface.msg_win_mgr.get_control(fjid, account)
if ctrl:
ctrl.update_ui()
ctrl.parent_win.redraw_tab(ctrl)
# keep the contact around, since it's
# already attached to the control
else:
gajim.contacts.remove_contact(account, contact)
2008-06-02 12:04:27 +02:00
elif contact.jid == gajim.get_jid_from_account(account) and \
show in ('offline', 'error'):
if gajim.config.get('show_self_contact') != 'never':
# SelfContact went offline. Remove him when last pending
# message was read
self.remove_contact(contact.jid, account, backend=True)
uf_show = helpers.get_uf_show(show)
# print status in chat window and update status/GPG image
ctrl = gajim.interface.msg_win_mgr.get_control(contact.jid, account)
if ctrl and ctrl.type_id != message_control.TYPE_GC:
ctrl.contact = gajim.contacts.get_contact_with_highest_priority(
account, contact.jid)
ctrl.update_status_display(name, uf_show, status)
if contact.resource:
ctrl = gajim.interface.msg_win_mgr.get_control(fjid, account)
if ctrl:
ctrl.update_status_display(name, uf_show, status)
# Delete pep if needed
2008-12-03 22:23:04 +01:00
keep_pep = any(c.show not in ('error', 'offline') for c in
contact_instances)
if not keep_pep and contact.jid != gajim.get_jid_from_account(account) \
and not contact.is_groupchat():
self.delete_pep(contact.jid, account)
# Redraw everything and select the sender
self.adjust_and_draw_contact_context(contact.jid, account)
2007-12-12 09:44:46 +01:00
2007-08-09 17:39:18 +02:00
def on_status_changed(self, account, show):
'''the core tells us that our status has changed'''
if account not in gajim.contacts.get_accounts():
return
child_iterA = self._get_account_iter(account, self.model)
if gajim.config.get('show_self_contact') == 'always':
self_resource = gajim.connections[account].server_resource
self_contact = gajim.contacts.get_contact(account,
gajim.get_jid_from_account(account), resource=self_resource)
if self_contact:
status = gajim.connections[account].status
self.chg_contact_status(self_contact, show, status, account)
self.set_account_status_icon(account)
if show == 'offline':
if self.quit_on_next_offline > -1:
# we want to quit, we are waiting for all accounts to be offline
self.quit_on_next_offline -= 1
if self.quit_on_next_offline < 1:
# all accounts offline, quit
self.quit_gtkgui_interface()
else:
# No need to redraw contacts if we're quitting
if child_iterA:
self.model[child_iterA][C_AVATAR_PIXBUF] = None
if account in gajim.con_types:
gajim.con_types[account] = None
for jid in gajim.contacts.get_jid_list(account):
lcontact = gajim.contacts.get_contacts(account, jid)
ctrl = gajim.interface.msg_win_mgr.get_gc_control(jid, account)
for contact in [c for c in lcontact if ((c.show != 'offline' or \
c.is_transport()) and not ctrl)]:
self.chg_contact_status(contact, 'offline', '', account)
self.actions_menu_needs_rebuild = True
self.update_status_combobox()
2008-06-02 12:04:27 +02:00
def get_status_message(self, show, on_response, show_pep=True,
always_ask=False):
''' get the status message by:
1/ looking in default status message
2/ asking to user if needed depending on ask_on(ff)line_status and
always_ask
show_pep can be False to hide pep things from status message or True
'''
empty_pep = {'activity': '', 'subactivity': '', 'activity_text': '',
'mood': '', 'mood_text': ''}
if show in gajim.config.get_per('defaultstatusmsg'):
if gajim.config.get_per('defaultstatusmsg', show, 'enabled'):
on_response(gajim.config.get_per('defaultstatusmsg', show,
'message'), empty_pep)
return
if not always_ask and ((show == 'online' and not gajim.config.get(
'ask_online_status')) or (show in ('offline', 'invisible') and not \
gajim.config.get('ask_offline_status'))):
on_response('', empty_pep)
return
dlg = dialogs.ChangeStatusMessageDialog(on_response, show, show_pep)
dlg.dialog.present() # show it on current workspace
2008-06-02 12:04:27 +02:00
def change_status(self, widget, account, status):
def change(account, status):
def on_response(message, pep_dict):
if message is None:
# user pressed Cancel to change status message dialog
return
self.send_status(account, status, message)
self.send_pep(account, pep_dict)
self.get_status_message(status, on_response)
if status == 'invisible' and self.connected_rooms(account):
dialogs.ConfirmationDialog(
_('You are participating in one or more group chats'),
_('Changing your status to invisible will result in disconnection '
'from those group chats. Are you sure you want to go invisible?'),
on_response_ok = (change, account, status))
else:
change(account, status)
2008-06-02 12:04:27 +02:00
def update_status_combobox(self):
# table to change index in connection.connected to index in combobox
table = {'offline':9, 'connecting':9, 'online':0, 'chat':1, 'away':2,
'xa':3, 'dnd':4, 'invisible':5}
2007-12-12 09:44:46 +01:00
# we check if there are more options in the combobox that it should
# if yes, we remove the first ones
while len(self.status_combobox.get_model()) > len(table)+2:
self.status_combobox.remove_text(0)
2006-09-13 18:47:58 +02:00
show = helpers.get_global_show()
# temporarily block signal in order not to send status that we show
# in the combobox
self.combobox_callback_active = False
if helpers.statuses_unified():
self.status_combobox.set_active(table[show])
2006-09-13 18:47:58 +02:00
else:
uf_show = helpers.get_uf_show(show)
liststore = self.status_combobox.get_model()
liststore.prepend(['SEPARATOR', None, '', True])
2008-04-20 22:06:16 +02:00
status_combobox_text = uf_show + ' (' + _("desync'ed") +')'
liststore.prepend([status_combobox_text,
gajim.interface.jabber_state_images['16'][show], show, False])
self.status_combobox.set_active(0)
gajim.interface._change_awn_icon_status(show)
self.combobox_callback_active = True
if gajim.interface.systray_enabled:
gajim.interface.systray.change_status(show)
2007-08-09 17:39:18 +02:00
def get_show(self, lcontact):
prio = lcontact[0].priority
show = lcontact[0].show
for u in lcontact:
if u.priority > prio:
prio = u.priority
show = u.show
return show
2008-06-02 12:04:27 +02:00
def on_message_window_delete(self, win_mgr, msg_win):
if gajim.config.get('one_message_window') == 'always_with_roster':
self.show_roster_vbox(True)
gtkgui_helpers.resize_window(self.window,
gajim.config.get('roster_width'),
2008-06-02 12:04:27 +02:00
gajim.config.get('roster_height'))
2005-11-14 11:08:50 +01:00
def close_all_from_dict(self, dic):
'''close all the windows in the given dictionary'''
for w in dic.values():
if isinstance(w, dict):
self.close_all_from_dict(w)
else:
w.window.destroy()
2008-09-02 22:31:05 +02:00
def close_all(self, account, force=False):
'''close all the windows from an account
if force is True, do not ask confirmation before closing chat/gc windows
'''
if account in gajim.interface.instances:
self.close_all_from_dict(gajim.interface.instances[account])
2008-09-02 22:34:11 +02:00
for ctrl in gajim.interface.msg_win_mgr.get_controls(acct=account):
ctrl.parent_win.remove_tab(ctrl, ctrl.parent_win.CLOSE_CLOSE_BUTTON,
force = force)
def on_roster_window_delete_event(self, widget, event):
'''Main window X button was clicked'''
if gajim.interface.systray_enabled and not gajim.config.get(
'quit_on_roster_x_button') and gajim.config.get('trayicon') != 'on_event':
self.tooltip.hide_tooltip()
self.window.hide()
elif gajim.config.get('quit_on_roster_x_button'):
self.on_quit_request()
else:
def on_ok(checked):
if checked:
gajim.config.set('quit_on_roster_x_button', True)
self.on_quit_request()
2009-06-23 22:08:06 +02:00
dialogs.ConfirmationDialogCheck(_('Really quit Gajim?'),
_('Are you sure you want to quit Gajim?'),
2009-06-23 22:24:11 +02:00
_('Always close Gajim'), on_response_ok=on_ok)
return True # do NOT destroy the window
def prepare_quit(self):
msgwin_width_adjust = 0
# in case show_roster_on_start is False and roster is never shown
# window.window is None
if self.window.window is not None:
x, y = self.window.window.get_root_origin()
gajim.config.set('roster_x-position', x)
gajim.config.set('roster_y-position', y)
width, height = self.window.get_size()
# For the width use the size of the vbox containing the tree and
# status combo, this will cancel out any hpaned width
width = self.xml.get_widget('roster_vbox2').allocation.width
gajim.config.set('roster_width', width)
gajim.config.set('roster_height', height)
if not self.xml.get_widget('roster_vbox2').get_property('visible'):
# The roster vbox is hidden, so the message window is larger
# then we want to save (i.e. the window will grow every startup)
# so adjust.
msgwin_width_adjust = -1 * width
gajim.config.set('show_roster_on_startup',
self.window.get_property('visible'))
gajim.interface.msg_win_mgr.shutdown(msgwin_width_adjust)
gajim.config.set('collapsed_rows', '\t'.join(self.collapsed_rows))
gajim.interface.save_config()
for account in gajim.connections:
gajim.connections[account].quit(True)
self.close_all(account)
if gajim.interface.systray_enabled:
gajim.interface.hide_systray()
def quit_gtkgui_interface(self):
'''When we quit the gtk interface : exit gtk'''
self.prepare_quit()
gtk.main_quit()
def on_quit_request(self, widget=None):
''' user want to quit. Check if he should be warned about messages
pending. Terminate all sessions and send offline to all connected
account. We do NOT really quit gajim here '''
accounts = gajim.connections.keys()
get_msg = False
for acct in accounts:
if gajim.connections[acct].connected:
get_msg = True
break
def on_continue2(message, pep_dict):
2008-08-07 15:25:25 +02:00
self.quit_on_next_offline = 0
accounts_to_disconnect = []
2008-08-07 15:25:25 +02:00
for acct in accounts:
if gajim.connections[acct].connected:
self.quit_on_next_offline += 1
accounts_to_disconnect.append(acct)
for acct in accounts_to_disconnect:
self.send_status(acct, 'offline', message)
self.send_pep(acct, pep_dict)
2008-08-07 15:25:25 +02:00
if not self.quit_on_next_offline:
self.quit_gtkgui_interface()
def on_continue(message, pep_dict):
if message is None:
# user pressed Cancel to change status message dialog
2006-11-18 21:52:28 +01:00
return
# check if we have unread messages
unread = gajim.events.get_nb_events()
if not gajim.config.get('notify_on_all_muc_messages'):
unread_not_to_notify = gajim.events.get_nb_events(
['printed_gc_msg'])
unread -= unread_not_to_notify
# check if we have recent messages
recent = False
for win in gajim.interface.msg_win_mgr.windows():
for ctrl in win.controls():
fjid = ctrl.get_full_jid()
if fjid in gajim.last_message_time[ctrl.account]:
2008-08-07 15:25:25 +02:00
if time.time() - gajim.last_message_time[ctrl.account][fjid] \
< 2:
recent = True
break
if recent:
break
2006-11-18 21:52:28 +01:00
if unread or recent:
2008-12-02 16:53:23 +01:00
dialogs.ConfirmationDialog(_('You have unread messages'),
_('Messages will only be available for reading them later if you'
2008-08-07 15:25:25 +02:00
' have history enabled and contact is in your roster.'),
on_response_ok=(on_continue2, message, pep_dict))
2008-08-07 15:25:25 +02:00
return
on_continue2(message, pep_dict)
if get_msg:
self.get_status_message('offline', on_continue, show_pep=False)
else:
2009-04-13 17:15:45 +02:00
on_continue('', None)
2005-11-14 11:08:50 +01:00
################################################################################
### Menu and GUI callbacks
### FIXME: order callbacks in itself...
################################################################################
def on_actions_menuitem_activate(self, widget):
self.make_menu()
def on_edit_menuitem_activate(self, widget):
'''need to call make_menu to build profile, avatar item'''
self.make_menu()
def on_bookmark_menuitem_activate(self, widget, account, bookmark):
gajim.interface.join_gc_room(account, bookmark['jid'], bookmark['nick'],
bookmark['password'])
def on_send_server_message_menuitem_activate(self, widget, account):
server = gajim.config.get_per('accounts', account, 'hostname')
server += '/announce/online'
dialogs.SingleMessageWindow(account, server, 'send')
def on_xml_console_menuitem_activate(self, widget, account):
if 'xml_console' in gajim.interface.instances[account]:
gajim.interface.instances[account]['xml_console'].window.present()
2005-07-09 00:26:46 +02:00
else:
gajim.interface.instances[account]['xml_console'] = \
dialogs.XMLConsoleWindow(account)
def on_archiving_preferences_menuitem_activate(self, widget, account):
if 'archiving_preferences' in gajim.interface.instances[account]:
gajim.interface.instances[account]['archiving_preferences'].window.\
present()
else:
gajim.interface.instances[account]['archiving_preferences'] = \
dialogs.ArchivingPreferencesWindow(account)
def on_privacy_lists_menuitem_activate(self, widget, account):
if 'privacy_lists' in gajim.interface.instances[account]:
gajim.interface.instances[account]['privacy_lists'].window.present()
else:
gajim.interface.instances[account]['privacy_lists'] = \
dialogs.PrivacyListsWindow(account)
def on_set_motd_menuitem_activate(self, widget, account):
server = gajim.config.get_per('accounts', account, 'hostname')
server += '/announce/motd'
dialogs.SingleMessageWindow(account, server, 'send')
def on_update_motd_menuitem_activate(self, widget, account):
server = gajim.config.get_per('accounts', account, 'hostname')
server += '/announce/motd/update'
dialogs.SingleMessageWindow(account, server, 'send')
def on_delete_motd_menuitem_activate(self, widget, account):
server = gajim.config.get_per('accounts', account, 'hostname')
server += '/announce/motd/delete'
gajim.connections[account].send_motd(server)
def on_history_manager_menuitem_activate(self, widget):
if os.name == 'nt':
if os.path.exists('history_manager.exe'): # user is running stable
helpers.exec_command('history_manager.exe')
else: # user is running svn
helpers.exec_command('%s history_manager.py' % sys.executable)
else: # Unix user
2009-10-08 17:51:49 +02:00
helpers.exec_command('%s history_manager.py' % sys.executable)
2008-06-02 12:04:27 +02:00
def on_info(self, widget, contact, account):
'''Call vcard_information_window class to display contact's information'''
if gajim.connections[account].is_zeroconf:
self.on_info_zeroconf(widget, contact, account)
return
info = gajim.interface.instances[account]['infos']
if contact.jid in info:
info[contact.jid].window.present()
else:
info[contact.jid] = vcard.VcardWindow(contact, account)
def on_info_zeroconf(self, widget, contact, account):
info = gajim.interface.instances[account]['infos']
if contact.jid in info:
info[contact.jid].window.present()
else:
contact = gajim.contacts.get_first_contact_from_jid(account,
contact.jid)
if contact.show in ('offline', 'error'):
# don't show info on offline contacts
return
info[contact.jid] = vcard.ZeroconfVcardWindow(contact, account)
def on_roster_treeview_leave_notify_event(self, widget, event):
props = widget.get_path_at_pos(int(event.x), int(event.y))
if self.tooltip.timeout > 0:
if not props or self.tooltip.id == props[0]:
self.tooltip.hide_tooltip()
def on_roster_treeview_motion_notify_event(self, widget, event):
model = widget.get_model()
props = widget.get_path_at_pos(int(event.x), int(event.y))
if self.tooltip.timeout > 0:
if not props or self.tooltip.id != props[0]:
self.tooltip.hide_tooltip()
if props:
2008-12-02 16:53:23 +01:00
row = props[0]
titer = None
2005-08-03 16:14:11 +02:00
try:
titer = model.get_iter(row)
except Exception:
2005-08-03 16:14:11 +02:00
self.tooltip.hide_tooltip()
return
if model[titer][C_TYPE] in ('contact', 'self_contact'):
# we're on a contact entry in the roster
account = model[titer][C_ACCOUNT].decode('utf-8')
jid = model[titer][C_JID].decode('utf-8')
if self.tooltip.timeout == 0 or self.tooltip.id != props[0]:
self.tooltip.id = row
2007-08-09 17:39:18 +02:00
contacts = gajim.contacts.get_contacts(account, jid)
2006-11-18 21:52:28 +01:00
connected_contacts = []
for c in contacts:
if c.show not in ('offline', 'error'):
connected_contacts.append(c)
if not connected_contacts:
# no connected contacts, show the ofline one
connected_contacts = contacts
2007-06-03 12:04:20 +02:00
self.tooltip.account = account
self.tooltip.timeout = gobject.timeout_add(500,
2006-11-18 21:52:28 +01:00
self.show_tooltip, connected_contacts)
elif model[titer][C_TYPE] == 'groupchat':
account = model[titer][C_ACCOUNT].decode('utf-8')
jid = model[titer][C_JID].decode('utf-8')
2007-06-03 12:04:20 +02:00
if self.tooltip.timeout == 0 or self.tooltip.id != props[0]:
self.tooltip.id = row
2007-08-09 17:39:18 +02:00
contact = gajim.contacts.get_contacts(account, jid)
2007-06-03 12:04:20 +02:00
self.tooltip.account = account
self.tooltip.timeout = gobject.timeout_add(500,
self.show_tooltip, contact)
elif model[titer][C_TYPE] == 'account':
# we're on an account entry in the roster
account = model[titer][C_ACCOUNT].decode('utf-8')
if account == 'all':
2005-11-09 22:05:55 +01:00
if self.tooltip.timeout == 0 or self.tooltip.id != props[0]:
self.tooltip.id = row
2007-06-03 12:04:20 +02:00
self.tooltip.account = None
2005-11-09 22:05:55 +01:00
self.tooltip.timeout = gobject.timeout_add(500,
self.show_tooltip, [])
return
2005-09-13 20:46:21 +02:00
jid = gajim.get_jid_from_account(account)
contacts = []
connection = gajim.connections[account]
# get our current contact info
2006-11-18 21:52:28 +01:00
nbr_on, nbr_total = gajim.contacts.get_nb_online_total_contacts(
accounts = [account])
account_name = account
if gajim.account_is_connected(account):
account_name += ' (%s/%s)' % (repr(nbr_on), repr(nbr_total))
contact = gajim.contacts.create_self_contact(jid=jid, account=account,
name=account_name, show=connection.get_status(),
status=connection.status, resource=connection.server_resource,
priority=connection.priority)
2007-12-12 09:44:46 +01:00
if gajim.connections[account].gpg:
contact.keyID = gajim.config.get_per('accounts', connection.name,
'keyid')
contacts.append(contact)
# if we're online ...
if connection.connection:
roster = connection.connection.getRoster()
2006-11-20 08:53:58 +01:00
# in threadless connection when no roster stanza is sent,
# 'roster' is None
if roster and roster.getItem(jid):
resources = roster.getResources(jid)
# ...get the contact info for our other online resources
for resource in resources:
2007-12-12 09:44:46 +01:00
# Check if we already have this resource
found = False
for contact_ in contacts:
if contact_.resource == resource:
found = True
break
if found:
continue
show = roster.getShow(jid+'/'+resource)
if not show:
show = 'online'
contact = gajim.contacts.create_self_contact(jid=jid,
account=account, show=show, status=roster.getStatus(jid + '/' + resource),
priority=roster.getPriority(jid + '/' + resource),
resource=resource)
contacts.append(contact)
2005-09-13 20:46:21 +02:00
if self.tooltip.timeout == 0 or self.tooltip.id != props[0]:
self.tooltip.id = row
2007-06-03 12:04:20 +02:00
self.tooltip.account = None
2005-09-13 20:46:21 +02:00
self.tooltip.timeout = gobject.timeout_add(500,
self.show_tooltip, contacts)
def on_agent_logging(self, widget, jid, state, account):
'''When an agent is requested to log in or off'''
gajim.connections[account].send_agent_status(jid, state)
def on_edit_agent(self, widget, contact, account):
'''When we want to modify the agent registration'''
gajim.connections[account].request_register_agent_info(contact.jid)
2006-09-13 18:47:58 +02:00
def on_remove_agent(self, widget, list_):
2006-11-18 21:52:28 +01:00
'''When an agent is requested to be removed. list_ is a list of
2006-09-13 18:47:58 +02:00
(contact, account) tuple'''
for (contact, account) in list_:
if gajim.config.get_per('accounts', account, 'hostname') == \
contact.jid:
# We remove the server contact
# remove it from treeview
gajim.connections[account].unsubscribe(contact.jid)
self.remove_contact(contact.jid, account, backend=True)
2006-09-13 18:47:58 +02:00
return
2007-12-12 09:44:46 +01:00
def remove(list_):
2006-09-13 18:47:58 +02:00
for (contact, account) in list_:
full_jid = contact.get_full_jid()
gajim.connections[account].unsubscribe_agent(full_jid)
# remove transport from treeview
self.remove_contact(contact.jid, account, backend=True)
2006-11-18 21:52:28 +01:00
# Check if there are unread events from some contacts
has_unread_events = False
for (contact, account) in list_:
for jid in gajim.events.get_events(account):
if jid.endswith(contact.jid):
has_unread_events = True
break
if has_unread_events:
dialogs.ErrorDialog(_('You have unread messages'),
_('You must read them before removing this transport.'))
return
2006-09-13 18:47:58 +02:00
if len(list_) == 1:
pritext = _('Transport "%s" will be removed') % list_[0][0].jid
2006-11-20 08:53:58 +01:00
sectext = _('You will no longer be able to send and receive messages '
2007-01-02 14:36:54 +01:00
'from contacts using this transport.')
2006-09-13 18:47:58 +02:00
else:
pritext = _('Transports will be removed')
jids = ''
for (contact, account) in list_:
jids += '\n ' + contact.get_shown_name() + ','
jids = jids[:-1] + '.'
2006-11-20 08:53:58 +01:00
sectext = _('You will no longer be able to send and receive messages '
2008-03-10 22:41:21 +01:00
'to contacts from these transports: %s') % jids
2007-12-12 09:44:46 +01:00
dialogs.ConfirmationDialog(pritext, sectext,
2006-09-13 18:47:58 +02:00
on_response_ok = (remove, list_))
def on_block(self, widget, list_, group=None):
''' When clicked on the 'block' button in context menu.
list_ is a list of (contact, account)'''
def on_continue(msg, pep_dict):
if msg is None:
# user pressed Cancel to change status message dialog
return
accounts = []
if group is None:
for (contact, account) in list_:
if account not in accounts:
if not gajim.connections[account].privacy_rules_supported:
continue
accounts.append(account)
self.send_status(account, 'offline', msg, to=contact.jid)
new_rule = {'order': u'1', 'type': u'jid', 'action': u'deny',
'value' : contact.jid, 'child': [u'message', u'iq',
u'presence-out']}
gajim.connections[account].blocked_list.append(new_rule)
# needed for draw_contact:
gajim.connections[account].blocked_contacts.append(
contact.jid)
self.draw_contact(contact.jid, account)
else:
for (contact, account) in list_:
if account not in accounts:
if not gajim.connections[account].privacy_rules_supported:
continue
accounts.append(account)
# needed for draw_group:
gajim.connections[account].blocked_groups.append(group)
self.draw_group(group, account)
self.send_status(account, 'offline', msg, to=contact.jid)
self.draw_contact(contact.jid, account)
new_rule = {'order': u'1', 'type': u'group', 'action': u'deny',
'value' : group, 'child': [u'message', u'iq', u'presence-out']}
gajim.connections[account].blocked_list.append(new_rule)
for account in accounts:
connection = gajim.connections[account]
connection.set_privacy_list('block', connection.blocked_list)
if len(connection.blocked_list) == 1:
connection.set_active_list('block')
connection.set_default_list('block')
connection.get_privacy_list('block')
def _block_it(is_checked=None):
if is_checked is not None: # dialog has been shown
if is_checked: # user does not want to be asked again
gajim.config.set('confirm_block', 'no')
else:
gajim.config.set('confirm_block', 'yes')
self.get_status_message('offline', on_continue, show_pep=False)
confirm_block = gajim.config.get('confirm_block')
if confirm_block == 'no':
_block_it()
return
pritext = _('You are about to block a contact. Are you sure you want'
' to continue?')
sectext = _('This contact will see you offline and you will not receive '
'messages he will send you.')
dlg = dialogs.ConfirmationDialogCheck(pritext, sectext,
_('Do _not ask me again'), on_response_ok=_block_it)
2007-06-03 12:04:20 +02:00
def on_unblock(self, widget, list_, group=None):
2007-06-03 12:04:20 +02:00
''' When clicked on the 'unblock' button in context menu. '''
accounts = []
if group is None:
for (contact, account) in list_:
if account not in accounts:
if gajim.connections[account].privacy_rules_supported:
accounts.append(account)
gajim.connections[account].new_blocked_list = []
gajim.connections[account].to_unblock = []
2007-06-03 12:04:20 +02:00
gajim.connections[account].to_unblock.append(contact.jid)
else:
gajim.connections[account].to_unblock.append(contact.jid)
# needed for draw_contact:
if contact.jid in gajim.connections[account].blocked_contacts:
gajim.connections[account].blocked_contacts.remove(contact.jid)
self.draw_contact(contact.jid, account)
for account in accounts:
for rule in gajim.connections[account].blocked_list:
if rule['action'] != 'deny' or rule['type'] != 'jid' \
or rule['value'] not in gajim.connections[account].to_unblock:
gajim.connections[account].new_blocked_list.append(rule)
else:
for (contact, account) in list_:
if account not in accounts:
if gajim.connections[account].privacy_rules_supported:
accounts.append(account)
# needed for draw_group:
if group in gajim.connections[account].blocked_groups:
gajim.connections[account].blocked_groups.remove(group)
self.draw_group(group, account)
gajim.connections[account].new_blocked_list = []
for rule in gajim.connections[account].blocked_list:
if rule['action'] != 'deny' or rule['type'] != 'group' \
or rule['value'] != group:
gajim.connections[account].new_blocked_list.append(rule)
self.draw_contact(contact.jid, account)
2007-06-03 12:04:20 +02:00
for account in accounts:
gajim.connections[account].set_privacy_list('block',
gajim.connections[account].new_blocked_list)
2007-06-03 12:04:20 +02:00
gajim.connections[account].get_privacy_list('block')
if len(gajim.connections[account].new_blocked_list) == 0:
gajim.connections[account].blocked_list = []
gajim.connections[account].blocked_contacts = []
gajim.connections[account].blocked_groups = []
gajim.connections[account].set_default_list('')
gajim.connections[account].set_active_list('')
gajim.connections[account].del_privacy_list('block')
if 'blocked_contacts' in gajim.interface.instances[account]:
2007-06-03 12:04:20 +02:00
gajim.interface.instances[account]['blocked_contacts'].\
privacy_list_received([])
for (contact, account) in list_:
2007-06-03 12:04:20 +02:00
if not self.regroup:
show = gajim.SHOW_LIST[gajim.connections[account].connected]
2007-06-03 12:04:20 +02:00
else: # accounts merged
show = helpers.get_global_show()
if show == 'invisible':
# Don't send our presence if we're invisible
continue
if account not in accounts:
accounts.append(account)
if gajim.connections[account].privacy_rules_supported:
2007-06-03 12:04:20 +02:00
self.send_status(account, show,
2007-08-09 17:39:18 +02:00
gajim.connections[account].status, to=contact.jid)
else:
self.send_status(account, show,
gajim.connections[account].status, to=contact.jid)
2007-06-03 12:04:20 +02:00
def on_rename(self, widget, row_type, jid, account):
2005-11-08 20:19:09 +01:00
# this function is called either by F2 or by Rename menuitem
if 'rename' in gajim.interface.instances:
2007-08-09 17:39:18 +02:00
gajim.interface.instances['rename'].dialog.present()
return
# account is offline, don't allow to rename
if gajim.connections[account].connected < 2:
return
if row_type in ('contact', 'agent'):
2005-07-21 15:16:31 +02:00
# it's jid
title = _('Rename Contact')
message = _('Enter a new nickname for contact %s') % jid
old_text = gajim.contacts.get_contact_with_highest_priority(account,
jid).name
elif row_type == 'group':
if jid in helpers.special_groups + (_('General'),):
return
old_text = jid
title = _('Rename Group')
message = _('Enter a new name for group %s') % \
gobject.markup_escape_text(jid)
def on_renamed(new_text, account, row_type, jid, old_text):
if 'rename' in gajim.interface.instances:
del gajim.interface.instances['rename']
if row_type in ('contact', 'agent'):
if old_text == new_text:
return
for contact in gajim.contacts.get_contacts(account, jid):
contact.name = new_text
gajim.connections[account].update_contact(jid, new_text, \
contact.groups)
self.draw_contact(jid, account)
2008-05-02 04:32:28 +02:00
# Update opened chats
for ctrl in gajim.interface.msg_win_mgr.get_controls(jid, account):
ctrl.update_ui()
win = gajim.interface.msg_win_mgr.get_window(jid, account)
win.redraw_tab(ctrl)
win.show_title()
elif row_type == 'group':
# in C_JID column, we hold the group name (which is not escaped)
self.rename_group(old_text, new_text, account)
def on_canceled():
if 'rename' in gajim.interface.instances:
del gajim.interface.instances['rename']
2007-08-09 17:39:18 +02:00
gajim.interface.instances['rename'] = dialogs.InputDialog(title, message,
old_text, False, (on_renamed, account, row_type, jid, old_text),
on_canceled)
2006-11-18 21:52:28 +01:00
def on_remove_group_item_activated(self, widget, group, account):
def on_ok(checked):
2006-11-18 21:52:28 +01:00
for contact in gajim.contacts.get_contacts_from_group(account, group):
if not checked:
self.remove_contact_from_groups(contact.jid,account, [group])
2006-11-18 21:52:28 +01:00
else:
2007-08-09 17:39:18 +02:00
gajim.connections[account].unsubscribe(contact.jid)
self.remove_contact(contact.jid, account, backend=True)
2008-09-01 01:03:10 +02:00
dialogs.ConfirmationDialogCheck(_('Remove Group'),
2008-09-03 16:16:13 +02:00
_('Do you want to remove group %s from the roster?') % group,
2008-09-01 01:03:10 +02:00
_('Also remove all contacts in this group from your roster'),
on_response_ok=on_ok)
def on_assign_pgp_key(self, widget, contact, account):
attached_keys = gajim.config.get_per('accounts', account,
'attached_gpg_keys').split()
keys = {}
keyID = _('None')
for i in xrange(len(attached_keys)/2):
keys[attached_keys[2*i]] = attached_keys[2*i+1]
if attached_keys[2*i] == contact.jid:
keyID = attached_keys[2*i+1]
public_keys = gajim.connections[account].ask_gpg_keys()
public_keys[_('None')] = _('None')
2008-08-08 12:26:11 +02:00
def on_key_selected(keyID):
if keyID is None:
return
if keyID[0] == _('None'):
if contact.jid in keys:
del keys[contact.jid]
keyID = ''
else:
keyID = keyID[0]
keys[contact.jid] = keyID
ctrl = gajim.interface.msg_win_mgr.get_control(contact.jid, account)
if ctrl:
ctrl.update_ui()
keys_str = ''
for jid in keys:
keys_str += jid + ' ' + keys[jid] + ' '
gajim.config.set_per('accounts', account, 'attached_gpg_keys',
keys_str)
for u in gajim.contacts.get_contacts(account, contact.jid):
u.keyID = helpers.prepare_and_validate_gpg_keyID(account,
contact.jid, keyID)
2008-12-02 16:53:23 +01:00
dialogs.ChooseGPGKeyDialog(_('Assign OpenPGP Key'),
2008-08-08 12:26:11 +02:00
_('Select a key to apply to the contact'), public_keys,
on_key_selected, selected=keyID)
2007-08-09 17:39:18 +02:00
def on_set_custom_avatar_activate(self, widget, contact, account):
def on_ok(widget, path_to_file):
filesize = os.path.getsize(path_to_file) # in bytes
invalid_file = False
msg = ''
if os.path.isfile(path_to_file):
stat = os.stat(path_to_file)
if stat[6] == 0:
invalid_file = True
2007-08-09 17:39:18 +02:00
msg = _('File is empty')
else:
invalid_file = True
msg = _('File does not exist')
if invalid_file:
dialogs.ErrorDialog(_('Could not load image'), msg)
return
try:
pixbuf = gtk.gdk.pixbuf_new_from_file(path_to_file)
if filesize > 16384: # 16 kb
2007-12-12 09:44:46 +01:00
# get the image at 'tooltip size'
2007-08-09 17:39:18 +02:00
# and hope that user did not specify in ACE crazy size
pixbuf = gtkgui_helpers.get_scaled_pixbuf(pixbuf, 'tooltip')
except gobject.GError, msg: # unknown format
# msg should be string, not object instance
msg = str(msg)
dialogs.ErrorDialog(_('Could not load image'), msg)
return
2008-09-02 22:34:11 +02:00
gajim.interface.save_avatar_files(contact.jid, pixbuf, local=True)
2007-08-09 17:39:18 +02:00
dlg.destroy()
self.update_avatar_in_gui(contact.jid, account)
def on_clear(widget):
dlg.destroy()
# Delete file:
gajim.interface.remove_avatar_files(contact.jid, local=True)
2007-08-09 17:39:18 +02:00
self.update_avatar_in_gui(contact.jid, account)
2008-09-02 22:34:11 +02:00
dlg = dialogs.AvatarChooserDialog(on_response_ok=on_ok,
on_response_clear=on_clear)
2007-08-09 17:39:18 +02:00
2006-09-13 18:47:58 +02:00
def on_edit_groups(self, widget, list_):
dialogs.EditGroupsDialog(list_)
def on_history(self, widget, contact, account):
'''When history menuitem is activated: call log window'''
if 'logs' in gajim.interface.instances:
2007-12-12 09:44:46 +01:00
gajim.interface.instances['logs'].window.present()
gajim.interface.instances['logs'].open_history(contact.jid, account)
else:
2007-12-12 09:44:46 +01:00
gajim.interface.instances['logs'] = history_window.\
HistoryWindow(contact.jid, account)
2007-08-09 17:39:18 +02:00
def on_disconnect(self, widget, jid, account):
'''When disconnect menuitem is activated: disconect from room'''
if jid in gajim.interface.minimized_controls[account]:
ctrl = gajim.interface.minimized_controls[account][jid]
ctrl.shutdown()
ctrl.got_disconnected()
self.remove_groupchat(jid, account)
2007-08-09 17:39:18 +02:00
def on_reconnect(self, widget, jid, account):
'''When disconnect menuitem is activated: disconect from room'''
if jid in gajim.interface.minimized_controls[account]:
ctrl = gajim.interface.minimized_controls[account][jid]
gajim.interface.join_gc_room(account, jid, ctrl.nick,
gajim.gc_passwords.get(jid, ''))
def on_send_single_message_menuitem_activate(self, widget, account,
contact=None):
2005-08-06 21:14:21 +02:00
if contact is None:
2008-09-02 22:34:11 +02:00
dialogs.SingleMessageWindow(account, action='send')
elif isinstance(contact, list):
2006-11-18 21:52:28 +01:00
dialogs.SingleMessageWindow(account, contact, 'send')
2005-08-06 21:14:21 +02:00
else:
jid = contact.jid
if contact.jid == gajim.get_jid_from_account(account):
jid += '/' + contact.resource
dialogs.SingleMessageWindow(account, jid, 'send')
2007-12-12 09:44:46 +01:00
def on_send_file_menuitem_activate(self, widget, contact, account,
resource=None):
gajim.interface.instances['file_transfers'].show_file_send_request(
2005-08-03 16:14:11 +02:00
account, contact)
2006-11-20 08:53:58 +01:00
def on_add_special_notification_menuitem_activate(self, widget, jid):
dialogs.AddSpecialNotificationDialog(jid)
2008-09-02 22:31:05 +02:00
def on_invite_to_new_room(self, widget, list_, resource=None):
''' resource parameter MUST NOT be used if more than one contact in
list '''
account_list = []
jid_list = []
for (contact, account) in list_:
if contact.jid not in jid_list:
if resource: # we MUST have one contact only in list_
fjid = contact.jid + '/' + resource
jid_list.append(fjid)
else:
jid_list.append(contact.jid)
if account not in account_list:
account_list.append(account)
# transform None in 'jabber'
type_ = gajim.get_transport_name_from_jid(jid_list[0]) or 'jabber'
for account in account_list:
if gajim.connections[account].muc_jid[type_]:
# create the room on this muc server
if 'join_gc' in gajim.interface.instances[account]:
gajim.interface.instances[account]['join_gc'].window.destroy()
try:
gajim.interface.instances[account]['join_gc'] = \
dialogs.JoinGroupchatWindow(account,
gajim.connections[account].muc_jid[type_],
automatic = {'invities': jid_list})
except GajimGeneralException:
continue
break
def on_invite_to_room(self, widget, list_, room_jid, room_account,
resource=None):
''' resource parameter MUST NOT be used if more than one contact in
list '''
2008-12-02 16:53:23 +01:00
for e in list_:
contact = e[0]
contact_jid = contact.jid
if resource: # we MUST have one contact only in list_
contact_jid += '/' + resource
gajim.connections[room_account].send_invite(room_jid, contact_jid)
2008-06-02 12:04:27 +02:00
def on_all_groupchat_maximized(self, widget, group_list):
for (contact, account) in group_list:
self.on_groupchat_maximized(widget, contact.jid, account)
def on_groupchat_maximized(self, widget, jid, account):
'''When a groupchat is maximised'''
if not jid in gajim.interface.minimized_controls[account]:
# Already opened?
gc_control = gajim.interface.msg_win_mgr.get_gc_control(jid, account)
if gc_control:
mw = gajim.interface.msg_win_mgr.get_window(jid, account)
mw.set_active_tab(gc_control)
mw.window.window.focus(gtk.get_current_event_time())
return
ctrl = gajim.interface.minimized_controls[account][jid]
mw = gajim.interface.msg_win_mgr.get_window(jid, account)
if not mw:
mw = gajim.interface.msg_win_mgr.create_window(ctrl.contact,
ctrl.account, ctrl.type_id)
ctrl.parent_win = mw
mw.new_tab(ctrl)
mw.set_active_tab(ctrl)
mw.window.window.focus(gtk.get_current_event_time())
self.remove_groupchat(jid, account)
2006-11-20 08:53:58 +01:00
def on_edit_account(self, widget, account):
if 'accounts' in gajim.interface.instances:
gajim.interface.instances['accounts'].window.present()
else:
gajim.interface.instances['accounts'] = config.AccountsWindow()
gajim.interface.instances['accounts'].select_account(account)
2006-11-18 21:52:28 +01:00
def on_zeroconf_properties(self, widget, account):
if 'accounts' in gajim.interface.instances:
gajim.interface.instances['accounts'].window.present()
else:
gajim.interface.instances['accounts'] = config.AccountsWindow()
gajim.interface.instances['accounts'].select_account(account)
2006-11-18 21:52:28 +01:00
def on_open_gmail_inbox(self, widget, account):
url = gajim.connections[account].gmail_url
if url:
helpers.launch_browser_mailer('url', url)
2006-11-18 21:52:28 +01:00
def on_change_status_message_activate(self, widget, account):
show = gajim.SHOW_LIST[gajim.connections[account].connected]
def on_response(message, pep_dict):
if message is None: # None is if user pressed Cancel
return
self.send_status(account, show, message)
self.send_pep(account, pep_dict)
dialogs.ChangeStatusMessageDialog(on_response, show)
2006-11-18 21:52:28 +01:00
def on_add_to_roster(self, widget, contact, account):
dialogs.AddNewContactWindow(account, contact.jid, contact.name)
2006-11-18 21:52:28 +01:00
def on_roster_treeview_scroll_event(self, widget, event):
self.tooltip.hide_tooltip()
2006-11-18 21:52:28 +01:00
def on_roster_treeview_key_press_event(self, widget, event):
'''when a key is pressed in the treeviews'''
self.tooltip.hide_tooltip()
if event.keyval == gtk.keysyms.Escape:
self.tree.get_selection().unselect_all()
elif event.keyval == gtk.keysyms.F2:
treeselection = self.tree.get_selection()
model, list_of_paths = treeselection.get_selected_rows()
if len(list_of_paths) != 1:
return
path = list_of_paths[0]
type_ = model[path][C_TYPE]
if type_ in ('contact', 'group', 'agent'):
jid = model[path][C_JID].decode('utf-8')
account = model[path][C_ACCOUNT].decode('utf-8')
self.on_rename(widget, type_, jid, account)
2006-11-18 21:52:28 +01:00
elif event.keyval == gtk.keysyms.Delete:
treeselection = self.tree.get_selection()
model, list_of_paths = treeselection.get_selected_rows()
if not len(list_of_paths):
return
type_ = model[list_of_paths[0]][C_TYPE]
account = model[list_of_paths[0]][C_ACCOUNT].decode('utf-8')
list_ = []
for path in list_of_paths:
if model[path][C_TYPE] != type_:
return
jid = model[path][C_JID].decode('utf-8')
account = model[path][C_ACCOUNT].decode('utf-8')
contact = gajim.contacts.get_contact_with_highest_priority(account,
jid)
list_.append((contact, account))
if type_ in ('account', 'group', 'self_contact') or \
account == gajim.ZEROCONF_ACC_NAME:
return
if type_ == 'contact':
self.on_req_usub(widget, list_)
elif type_ == 'agent':
self.on_remove_agent(widget, list_)
2006-11-18 21:52:28 +01:00
def on_roster_treeview_button_release_event(self, widget, event):
try:
2008-12-02 16:53:23 +01:00
path = self.tree.get_path_at_pos(int(event.x), int(event.y))[0]
except TypeError:
return False
2006-11-18 21:52:28 +01:00
if event.button == 1: # Left click
if gajim.single_click and not event.state & gtk.gdk.SHIFT_MASK and \
not event.state & gtk.gdk.CONTROL_MASK:
# Check if button has been pressed on the same row
if self.clicked_path == path:
self.on_row_activated(widget, path)
self.clicked_path = None
2006-11-18 21:52:28 +01:00
def on_roster_treeview_button_press_event(self, widget, event):
# hide tooltip, no matter the button is pressed
self.tooltip.hide_tooltip()
try:
2008-12-02 16:53:23 +01:00
pos = self.tree.get_path_at_pos(int(event.x), int(event.y))
path, x = pos[0], pos[2]
except TypeError:
self.tree.get_selection().unselect_all()
return False
2006-11-18 21:52:28 +01:00
if event.button == 3: # Right click
try:
model, list_of_paths = self.tree.get_selection().get_selected_rows()
except TypeError:
list_of_paths = []
if path not in list_of_paths:
self.tree.get_selection().unselect_all()
self.tree.get_selection().select_path(path)
return self.show_treeview_menu(event)
elif event.button == 2: # Middle click
try:
model, list_of_paths = self.tree.get_selection().get_selected_rows()
except TypeError:
list_of_paths = []
if list_of_paths != [path]:
self.tree.get_selection().unselect_all()
self.tree.get_selection().select_path(path)
type_ = model[path][C_TYPE]
if type_ in ('agent', 'contact', 'self_contact', 'groupchat'):
self.on_row_activated(widget, path)
elif type_ == 'account':
account = model[path][C_ACCOUNT].decode('utf-8')
if account != 'all':
show = gajim.connections[account].connected
if show > 1: # We are connected
self.on_change_status_message_activate(widget, account)
return True
show = helpers.get_global_show()
if show == 'offline':
return True
def on_response(message, pep_dict):
if message is None:
return True
for acct in gajim.connections:
if not gajim.config.get_per('accounts', acct,
'sync_with_global_status'):
continue
current_show = gajim.SHOW_LIST[gajim.connections[acct].\
connected]
self.send_status(acct, current_show, message)
self.send_pep(acct, pep_dict)
dialogs.ChangeStatusMessageDialog(on_response, show)
return True
2006-11-20 08:53:58 +01:00
elif event.button == 1: # Left click
model = self.modelfilter
type_ = model[path][C_TYPE]
# x_min is the x start position of status icon column
if gajim.config.get('avatar_position_in_roster') == 'left':
x_min = gajim.config.get('roster_avatar_width')
else:
x_min = 0
if gajim.single_click and not event.state & gtk.gdk.SHIFT_MASK and \
not event.state & gtk.gdk.CONTROL_MASK:
# Don't handle double click if we press icon of a metacontact
titer = model.get_iter(path)
if x > x_min and x < x_min + 27 and type_ == 'contact' and \
model.iter_has_child(titer):
if (self.tree.row_expanded(path)):
self.tree.collapse_row(path)
else:
self.tree.expand_row(path, False)
return
# We just save on which row we press button, and open chat window on
# button release to be able to do DND without opening chat window
self.clicked_path = path
return
else:
if type_ == 'group' and x < 27:
# first cell in 1st column (the arrow SINGLE clicked)
if (self.tree.row_expanded(path)):
self.tree.collapse_row(path)
else:
self.tree.expand_row(path, False)
elif type_ == 'contact' and x > x_min and x < x_min + 27:
if (self.tree.row_expanded(path)):
self.tree.collapse_row(path)
else:
self.tree.expand_row(path, False)
def on_req_usub(self, widget, list_):
'''Remove a contact. list_ is a list of (contact, account) tuples'''
def on_ok(is_checked, list_):
remove_auth = True
if len(list_) == 1:
contact = list_[0][0]
if contact.sub != 'to' and is_checked:
remove_auth = False
for (contact, account) in list_:
if _('Not in Roster') not in contact.get_shown_groups():
gajim.connections[account].unsubscribe(contact.jid, remove_auth)
self.remove_contact(contact.jid, account, backend=True)
if not remove_auth and contact.sub == 'both':
contact.name = ''
contact.groups = []
contact.sub = 'from'
# we can't see him, but have to set it manually in contact
2008-07-25 03:10:14 +02:00
contact.show = 'offline'
gajim.contacts.add_contact(account, contact)
self.add_contact(contact.jid, account)
def on_ok2(list_):
on_ok(False, list_)
if len(list_) == 1:
contact = list_[0][0]
pritext = _('Contact "%s" will be removed from your roster') % \
contact.get_shown_name()
sectext = _('You are about to remove "%(name)s" (%(jid)s) from your '
'roster.\n') % {'name': contact.get_shown_name(),
'jid': contact.jid}
if contact.sub == 'to':
dialogs.ConfirmationDialog(pritext, sectext + \
_('By removing this contact you also remove authorization '
'resulting in him or her always seeing you as offline.'),
on_response_ok = (on_ok2, list_))
elif _('Not in Roster') in contact.get_shown_groups():
# Contact is not in roster
dialogs.ConfirmationDialog(pritext, sectext + \
_('Do you want to continue?'), on_response_ok = (on_ok2, list_))
else:
dialogs.ConfirmationDialogCheck(pritext, sectext + \
_('By removing this contact you also by default remove '
'authorization resulting in him or her always seeing you as '
'offline.'),
_('I want this contact to know my status after removal'),
on_response_ok = (on_ok, list_))
else:
# several contact to remove at the same time
pritext = _('Contacts will be removed from your roster')
jids = ''
for (contact, account) in list_:
jids += '\n ' + contact.get_shown_name() + ' (%s)' % contact.jid +\
','
sectext = _('By removing these contacts:%s\nyou also remove '
'authorization resulting in them always seeing you as offline.') % \
jids
dialogs.ConfirmationDialog(pritext, sectext,
on_response_ok = (on_ok2, list_))
2008-06-02 12:04:27 +02:00
def on_send_custom_status(self, widget, contact_list, show, group=None):
'''send custom status'''
# contact_list has only one element except if group != None
def on_response(message, pep_dict):
if message is None: # None if user pressed Cancel
return
account_list = []
for (contact, account) in contact_list:
if account not in account_list:
account_list.append(account)
# 1. update status_sent_to_[groups|users] list
if group:
for account in account_list:
if account not in gajim.interface.status_sent_to_groups:
gajim.interface.status_sent_to_groups[account] = {}
gajim.interface.status_sent_to_groups[account][group] = show
else:
for (contact, account) in contact_list:
if account not in gajim.interface.status_sent_to_users:
gajim.interface.status_sent_to_users[account] = {}
gajim.interface.status_sent_to_users[account][contact.jid] = show
# 2. update privacy lists if main status is invisible
for account in account_list:
if gajim.SHOW_LIST[gajim.connections[account].connected] == \
'invisible':
gajim.connections[account].set_invisible_rule()
# 3. send directed presence
for (contact, account) in contact_list:
our_jid = gajim.get_jid_from_account(account)
jid = contact.jid
if jid == our_jid:
jid += '/' + contact.resource
self.send_status(account, show, message, to=jid)
def send_it(is_checked=None):
if is_checked is not None: # dialog has been shown
if is_checked: # user does not want to be asked again
gajim.config.set('confirm_custom_status', 'no')
else:
gajim.config.set('confirm_custom_status', 'yes')
self.get_status_message(show, on_response, show_pep=False,
always_ask=True)
confirm_custom_status = gajim.config.get('confirm_custom_status')
if confirm_custom_status == 'no':
send_it()
return
pritext = _('You are about to send a custom status. Are you sure you want'
' to continue?')
sectext = _('This contact will temporarily see you as %(status)s, '
'but only until you change your status. Then he will see your global '
'status.') % {'status': show}
dlg = dialogs.ConfirmationDialogCheck(pritext, sectext,
_('Do _not ask me again'), on_response_ok=send_it)
def on_status_combobox_changed(self, widget):
'''When we change our status via the combobox'''
model = self.status_combobox.get_model()
active = self.status_combobox.get_active()
if active == -1: # no active item
return
if not self.combobox_callback_active:
self.previous_status_combobox_active = active
return
accounts = gajim.connections.keys()
if len(accounts) == 0:
dialogs.ErrorDialog(_('No account available'),
_('You must create an account before you can chat with other contacts.'))
self.update_status_combobox()
return
status = model[active][2].decode('utf-8')
statuses_unified = helpers.statuses_unified() # status "desync'ed" or not
2008-06-02 12:04:27 +02:00
if (active == 7 and statuses_unified) or (active == 9 and \
not statuses_unified):
# 'Change status message' selected:
# do not change show, just show change status dialog
status = model[self.previous_status_combobox_active][2].decode('utf-8')
def on_response(message, pep_dict):
if message is not None: # None if user pressed Cancel
for account in accounts:
if not gajim.config.get_per('accounts', account,
'sync_with_global_status'):
continue
current_show = gajim.SHOW_LIST[
gajim.connections[account].connected]
self.send_status(account, current_show, message)
self.send_pep(account, pep_dict)
self.combobox_callback_active = False
self.status_combobox.set_active(
self.previous_status_combobox_active)
self.combobox_callback_active = True
dialogs.ChangeStatusMessageDialog(on_response, status)
return
# we are about to change show, so save this new show so in case
# after user chooses "Change status message" menuitem
# we can return to this show
self.previous_status_combobox_active = active
connected_accounts = gajim.get_number_of_connected_accounts()
def on_continue(message, pep_dict):
if message is None:
# user pressed Cancel to change status message dialog
self.update_status_combobox()
return
global_sync_accounts = []
for acct in accounts:
if gajim.config.get_per('accounts', acct,
'sync_with_global_status'):
global_sync_accounts.append(acct)
global_sync_connected_accounts = \
gajim.get_number_of_connected_accounts(global_sync_accounts)
for account in accounts:
if not gajim.config.get_per('accounts', account,
'sync_with_global_status'):
continue
# we are connected (so we wanna change show and status)
# or no account is connected and we want to connect with new show
# and status
if not global_sync_connected_accounts > 0 or \
gajim.connections[account].connected > 0:
self.send_status(account, status, message)
self.send_pep(account, pep_dict)
self.update_status_combobox()
2008-08-07 15:25:25 +02:00
if status == 'invisible':
bug_user = False
for account in accounts:
if connected_accounts < 1 or gajim.account_is_connected(account):
if not gajim.config.get_per('accounts', account,
'sync_with_global_status'):
continue
# We're going to change our status to invisible
if self.connected_rooms(account):
bug_user = True
break
if bug_user:
def on_ok():
self.get_status_message(status, on_continue, show_pep=False)
2008-08-07 15:25:25 +02:00
def on_cancel():
self.update_status_combobox()
2008-12-02 16:53:23 +01:00
dialogs.ConfirmationDialog(
2008-08-07 15:25:25 +02:00
_('You are participating in one or more group chats'),
_('Changing your status to invisible will result in '
'disconnection from those group chats. Are you sure you want to '
'go invisible?'), on_reponse_ok=on_ok,
on_response_cancel=on_cancel)
return
self.get_status_message(status, on_continue)
2006-03-14 14:10:09 +01:00
def on_preferences_menuitem_activate(self, widget):
if 'preferences' in gajim.interface.instances:
gajim.interface.instances['preferences'].window.present()
else:
gajim.interface.instances['preferences'] = config.PreferencesWindow()
def on_publish_tune_toggled(self, widget, account):
active = widget.get_active()
gajim.config.set_per('accounts', account, 'publish_tune', active)
if active:
gajim.interface.enable_music_listener()
else:
gajim.connections[account].retract_tune()
# disable music listener only if no other account uses it
for acc in gajim.connections:
if gajim.config.get_per('accounts', acc, 'publish_tune'):
break
else:
gajim.interface.disable_music_listener()
helpers.update_optional_features(account)
def on_pep_services_menuitem_activate(self, widget, account):
if 'pep_services' in gajim.interface.instances[account]:
gajim.interface.instances[account]['pep_services'].window.present()
else:
gajim.interface.instances[account]['pep_services'] = \
config.ManagePEPServicesWindow(account)
2007-08-09 17:39:18 +02:00
def on_add_new_contact(self, widget, account):
dialogs.AddNewContactWindow(account)
def on_join_gc_activate(self, widget, account):
'''when the join gc menuitem is clicked, show the join gc window'''
invisible_show = gajim.SHOW_LIST.index('invisible')
if gajim.connections[account].connected == invisible_show:
dialogs.ErrorDialog(_('You cannot join a group chat while you are '
'invisible'))
return
if 'join_gc' in gajim.interface.instances[account]:
gajim.interface.instances[account]['join_gc'].window.present()
else:
# c http://nkour.blogspot.com/2005/05/pythons-init-return-none-doesnt-return.html
try:
gajim.interface.instances[account]['join_gc'] = \
dialogs.JoinGroupchatWindow(account)
except GajimGeneralException:
pass
2006-09-13 18:47:58 +02:00
def on_new_chat_menuitem_activate(self, widget, account):
dialogs.NewChatDialog(account)
def on_contents_menuitem_activate(self, widget):
helpers.launch_browser_mailer('url', 'http://trac.gajim.org/wiki')
def on_faq_menuitem_activate(self, widget):
helpers.launch_browser_mailer('url',
'http://trac.gajim.org/wiki/GajimFaq')
def on_features_menuitem_activate(self, widget):
features_window.FeaturesWindow()
def on_about_menuitem_activate(self, widget):
dialogs.AboutDialog()
def on_accounts_menuitem_activate(self, widget):
if 'accounts' in gajim.interface.instances:
gajim.interface.instances['accounts'].window.present()
2007-06-03 12:04:20 +02:00
else:
gajim.interface.instances['accounts'] = config.AccountsWindow()
def on_file_transfers_menuitem_activate(self, widget):
if gajim.interface.instances['file_transfers'].window.get_property(
'visible'):
gajim.interface.instances['file_transfers'].window.present()
else:
gajim.interface.instances['file_transfers'].window.show_all()
def on_history_menuitem_activate(self, widget):
if 'logs' in gajim.interface.instances:
gajim.interface.instances['logs'].window.present()
else:
gajim.interface.instances['logs'] = history_window.\
HistoryWindow()
2006-09-13 18:47:58 +02:00
def on_show_transports_menuitem_activate(self, widget):
gajim.config.set('show_transports_group', widget.get_active())
self.refilter_shown_roster_items()
2007-08-09 17:39:18 +02:00
def on_manage_bookmarks_menuitem_activate(self, widget):
config.ManageBookmarksWindow()
2006-09-13 18:47:58 +02:00
def on_profile_avatar_menuitem_activate(self, widget, account):
gajim.interface.edit_own_details(account)
2006-09-13 18:47:58 +02:00
def on_execute_command(self, widget, contact, account, resource=None):
'''Execute command. Full JID needed; if it is other contact,
resource is necessary. Widget is unnecessary, only to be
able to make this a callback.'''
jid = contact.jid
if resource is not None:
jid = jid + u'/' + resource
adhoc_commands.CommandWindow(account, jid)
2006-09-13 18:47:58 +02:00
def on_roster_window_focus_in_event(self, widget, event):
# roster received focus, so if we had urgency REMOVE IT
# NOTE: we do not have to read the message to remove urgency
# so this functions does that
gtkgui_helpers.set_unset_urgency_hint(widget, False)
# if a contact row is selected, update colors (eg. for status msg)
# because gtk engines may differ in bg when window is selected
# or not
if len(self._last_selected_contact):
for (jid, account) in self._last_selected_contact:
2008-09-02 22:34:11 +02:00
self.draw_contact(jid, account, selected=True, focus=True)
2007-08-09 17:39:18 +02:00
def on_roster_window_focus_out_event(self, widget, event):
# if a contact row is selected, update colors (eg. for status msg)
# because gtk engines may differ in bg when window is selected
# or not
if len(self._last_selected_contact):
for (jid, account) in self._last_selected_contact:
2008-09-02 22:34:11 +02:00
self.draw_contact(jid, account, selected=True, focus=False)
2006-09-13 18:47:58 +02:00
def on_roster_window_key_press_event(self, widget, event):
if event.keyval == gtk.keysyms.Escape:
if gajim.interface.msg_win_mgr.mode == \
MessageWindowMgr.ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER and \
gajim.interface.msg_win_mgr.one_window_opened():
# let message window close the tab
return
2008-12-02 16:53:23 +01:00
list_of_paths = self.tree.get_selection().get_selected_rows()[1]
if not len(list_of_paths) and gajim.interface.systray_enabled and \
not gajim.config.get('quit_on_roster_x_button'):
self.tooltip.hide_tooltip()
self.window.hide()
elif event.state & gtk.gdk.CONTROL_MASK and event.keyval == gtk.keysyms.i:
treeselection = self.tree.get_selection()
model, list_of_paths = treeselection.get_selected_rows()
for path in list_of_paths:
type_ = model[path][C_TYPE]
if type_ in ('contact', 'agent'):
jid = model[path][C_JID].decode('utf-8')
account = model[path][C_ACCOUNT].decode('utf-8')
contact = gajim.contacts.get_first_contact_from_jid(account, jid)
self.on_info(widget, contact, account)
elif event.state & gtk.gdk.CONTROL_MASK and event.keyval == gtk.keysyms.h:
treeselection = self.tree.get_selection()
model, list_of_paths = treeselection.get_selected_rows()
if len(list_of_paths) != 1:
return
path = list_of_paths[0]
type_ = model[path][C_TYPE]
if type_ in ('contact', 'agent'):
jid = model[path][C_JID].decode('utf-8')
account = model[path][C_ACCOUNT].decode('utf-8')
contact = gajim.contacts.get_first_contact_from_jid(account, jid)
self.on_history(widget, contact, account)
2007-08-09 17:39:18 +02:00
def on_roster_window_popup_menu(self, widget):
event = gtk.gdk.Event(gtk.gdk.KEY_PRESS)
self.show_treeview_menu(event)
def on_row_activated(self, widget, path):
'''When an iter is activated (double-click or single click if gnome is
set this way)'''
model = self.modelfilter
account = model[path][C_ACCOUNT].decode('utf-8')
type_ = model[path][C_TYPE]
if type_ in ('group', 'account'):
if self.tree.row_expanded(path):
self.tree.collapse_row(path)
else:
self.tree.expand_row(path, False)
return
jid = model[path][C_JID].decode('utf-8')
resource = None
contact = gajim.contacts.get_contact_with_highest_priority(account, jid)
titer = model.get_iter(path)
if contact.is_groupchat():
first_ev = gajim.events.get_first_event(account, jid)
if first_ev and self.open_event(account, jid, first_ev):
# We are invited to a GC
# open event cares about connecting to it
self.remove_groupchat(jid, account)
else:
self.on_groupchat_maximized(None, jid, account)
return
# else
first_ev = gajim.events.get_first_event(account, jid)
if not first_ev:
# look in other resources
for c in gajim.contacts.get_contacts(account, jid):
fjid = c.get_full_jid()
first_ev = gajim.events.get_first_event(account, fjid)
if first_ev:
resource = c.resource
break
if not first_ev and model.iter_has_child(titer):
child_iter = model.iter_children(titer)
while not first_ev and child_iter:
child_jid = model[child_iter][C_JID].decode('utf-8')
first_ev = gajim.events.get_first_event(account, child_jid)
if first_ev:
jid = child_jid
else:
child_iter = model.iter_next(child_iter)
session = None
if first_ev:
if first_ev.type_ in ('chat', 'normal'):
session = first_ev.parameters[8]
fjid = jid
if resource:
fjid += '/' + resource
if self.open_event(account, fjid, first_ev):
return
# else
contact = gajim.contacts.get_contact(account, jid, resource)
if not contact or isinstance(contact, list):
contact = gajim.contacts.get_contact_with_highest_priority(account,
jid)
if jid == gajim.get_jid_from_account(account):
resource = contact.resource
gajim.interface.on_open_chat_window(None, contact, account, \
resource=resource, session=session)
2006-09-13 18:47:58 +02:00
2008-09-02 22:31:05 +02:00
def on_roster_treeview_row_activated(self, widget, path, col=0):
'''When an iter is double clicked: open the first event window'''
if not gajim.single_click:
self.on_row_activated(widget, path)
2007-08-09 17:39:18 +02:00
def on_roster_treeview_row_expanded(self, widget, titer, path):
'''When a row is expanded change the icon of the arrow'''
self._toggeling_row = True
model = widget.get_model()
child_model = model.get_model()
child_iter = model.convert_iter_to_child_iter(titer)
if self.regroup: # merged accounts
accounts = gajim.connections.keys()
2007-06-03 12:04:20 +02:00
else:
accounts = [model[titer][C_ACCOUNT].decode('utf-8')]
type_ = model[titer][C_TYPE]
if type_ == 'group':
2009-08-27 19:56:11 +02:00
group = model[titer][C_JID].decode('utf-8')
child_model[child_iter][C_IMG] = gajim.interface.jabber_state_images[
'16']['opened']
for account in accounts:
if group in gajim.groups[account]: # This account has this group
gajim.groups[account][group]['expand'] = True
if account + group in self.collapsed_rows:
self.collapsed_rows.remove(account + group)
for contact in gajim.contacts.iter_contacts(account):
jid = contact.jid
if group in contact.groups and gajim.contacts.is_big_brother(
account, jid, accounts) and account + group + jid \
not in self.collapsed_rows:
titers = self._get_contact_iter(jid, account)
for titer in titers:
path = model.get_path(titer)
self.tree.expand_row(path, False)
elif type_ == 'account':
account = accounts[0] # There is only one cause we don't use merge
if account in self.collapsed_rows:
self.collapsed_rows.remove(account)
self.draw_account(account)
# When we expand, groups are collapsed. Restore expand state
for group in gajim.groups[account]:
if gajim.groups[account][group]['expand']:
titer = self._get_group_iter(group, account)
2008-06-02 12:04:27 +02:00
if titer:
path = model.get_path(titer)
self.tree.expand_row(path, False)
elif type_ == 'contact':
# Metacontact got toggled, update icon
jid = model[titer][C_JID].decode('utf-8')
account = model[titer][C_ACCOUNT].decode('utf-8')
contact = gajim.contacts.get_contact(account, jid)
for group in contact.groups:
if account + group + jid in self.collapsed_rows:
2009-01-16 17:51:20 +01:00
self.collapsed_rows.remove(account + group + jid)
family = gajim.contacts.get_metacontacts_family(account, jid)
2008-12-02 16:53:23 +01:00
nearby_family = \
self._get_nearby_family_and_big_brother(family, account)[0]
# Redraw all brothers to show pending events
for data in nearby_family:
self.draw_contact(data['jid'], data['account'])
2007-08-09 17:39:18 +02:00
self._toggeling_row = False
2008-06-02 12:04:27 +02:00
def on_roster_treeview_row_collapsed(self, widget, titer, path):
'''When a row is collapsed change the icon of the arrow'''
self._toggeling_row = True
model = widget.get_model()
child_model = model.get_model()
child_iter = model.convert_iter_to_child_iter(titer)
if self.regroup: # merged accounts
accounts = gajim.connections.keys()
else:
accounts = [model[titer][C_ACCOUNT].decode('utf-8')]
2008-06-02 12:04:27 +02:00
type_ = model[titer][C_TYPE]
if type_ == 'group':
child_model[child_iter][C_IMG] = gajim.interface.jabber_state_images[
'16']['closed']
group = model[titer][C_JID].decode('utf-8')
for account in accounts:
if group in gajim.groups[account]: # This account has this group
gajim.groups[account][group]['expand'] = False
if account + group not in self.collapsed_rows:
self.collapsed_rows.append(account + group)
elif type_ == 'account':
account = accounts[0] # There is only one cause we don't use merge
if account not in self.collapsed_rows:
self.collapsed_rows.append(account)
self.draw_account(account)
elif type_ == 'contact':
# Metacontact got toggled, update icon
jid = model[titer][C_JID].decode('utf-8')
account = model[titer][C_ACCOUNT].decode('utf-8')
contact = gajim.contacts.get_contact(account, jid)
for group in contact.groups:
if account + group + jid not in self.collapsed_rows:
self.collapsed_rows.append(account + group + jid)
family = gajim.contacts.get_metacontacts_family(account, jid)
2008-12-02 16:53:23 +01:00
nearby_family = \
self._get_nearby_family_and_big_brother(family, account)[0]
# Redraw all brothers to show pending events
for data in nearby_family:
self.draw_contact(data['jid'], data['account'])
2008-06-02 12:04:27 +02:00
self._toggeling_row = False
2007-08-09 17:39:18 +02:00
def on_modelfilter_row_has_child_toggled(self, model, path, titer):
2008-05-08 23:18:39 +02:00
'''Called when a row has gotten the first or lost its last child row.
Expand Parent if necessary.
'''
if self._toggeling_row:
# Signal is emitted when we write to our model
return
2008-06-02 12:04:27 +02:00
type_ = model[titer][C_TYPE]
account = model[titer][C_ACCOUNT]
if not account:
return
2006-09-13 18:47:58 +02:00
account = account.decode('utf-8')
2008-06-02 12:04:27 +02:00
if type_ == 'contact':
child_iter = model.convert_iter_to_child_iter(titer)
2008-05-01 10:40:20 +02:00
if self.model.iter_has_child(child_iter):
# we are a bigbrother metacontact
# redraw us to show/hide expand icon
if self.filtering:
# Prevent endless loops
jid = model[titer][C_JID].decode('utf-8')
gobject.idle_add(self.draw_contact, jid, account)
elif type_ == 'group':
group = model[titer][C_JID].decode('utf-8')
self._adjust_group_expand_collapse_state(group, account)
elif type_ == 'account':
self._adjust_account_expand_collapse_state(account)
# Selection can change when the model is filtered
# Only write to the model when filtering is finished!
#
# FIXME: When we are filtering our custom colors are somehow lost
#
# def on_treeview_selection_changed(self, selection):
# '''Called when selection in TreeView has changed.
#
# Redraw unselected rows to make status message readable
# on all possible backgrounds.
# '''
# model, list_of_paths = selection.get_selected_rows()
# if len(self._last_selected_contact):
# # update unselected rows
# for (jid, account) in self._last_selected_contact:
# gobject.idle_add(self.draw_contact, jid, account)
# self._last_selected_contact = []
# if len(list_of_paths) == 0:
# return
# for path in list_of_paths:
# row = model[path]
# if row[C_TYPE] != 'contact':
# self._last_selected_contact = []
# return
# jid = row[C_JID].decode('utf-8')
# account = row[C_ACCOUNT].decode('utf-8')
# self._last_selected_contact.append((jid, account))
# gobject.idle_add(self.draw_contact, jid, account, True)
2007-06-03 12:04:20 +02:00
def on_service_disco_menuitem_activate(self, widget, account):
server_jid = gajim.config.get_per('accounts', account, 'hostname')
if server_jid in gajim.interface.instances[account]['disco']:
gajim.interface.instances[account]['disco'][server_jid].\
window.present()
else:
try:
# Object will add itself to the window dict
2008-09-02 22:34:11 +02:00
disco.ServiceDiscoveryWindow(account, address_entry=True)
except GajimGeneralException:
pass
2007-06-03 12:04:20 +02:00
def on_show_offline_contacts_menuitem_activate(self, widget):
'''when show offline option is changed:
redraw the treeview'''
gajim.config.set('showoffline', not gajim.config.get('showoffline'))
self.refilter_shown_roster_items()
w = self.xml.get_widget('show_only_active_contacts_menuitem')
if gajim.config.get('showoffline'):
# We need to filter twice to show groups with no contacts inside
# in the correct expand state
2008-06-02 12:04:27 +02:00
self.refilter_shown_roster_items()
w.set_sensitive(False)
else:
w.set_sensitive(True)
2008-06-02 12:04:27 +02:00
def on_show_only_active_contacts_menuitem_activate(self, widget):
'''when show only active contact option is changed:
redraw the treeview'''
gajim.config.set('show_only_chat_and_online', not gajim.config.get(
'show_only_chat_and_online'))
self.refilter_shown_roster_items()
w = self.xml.get_widget('show_offline_contacts_menuitem')
if gajim.config.get('show_only_chat_and_online'):
# We need to filter twice to show groups with no contacts inside
# in the correct expand state
self.refilter_shown_roster_items()
w.set_sensitive(False)
else:
w.set_sensitive(True)
def on_view_menu_activate(self, widget):
# Hide the show roster menu if we are not in the right windowing mode.
if self.hpaned.get_child2() is not None:
self.xml.get_widget('show_roster_menuitem').show()
else:
self.xml.get_widget('show_roster_menuitem').hide()
def on_show_roster_menuitem_toggled(self, widget):
# when num controls is 0 this menuitem is hidden, but still need to
# disable keybinding
if self.hpaned.get_child2() is not None:
2008-06-02 12:04:27 +02:00
self.show_roster_vbox(widget.get_active())
################################################################################
### Drag and Drop handling
################################################################################
def drag_data_get_data(self, treeview, context, selection, target_id, etime):
model, list_of_paths = self.tree.get_selection().get_selected_rows()
if len(list_of_paths) != 1:
return
path = list_of_paths[0]
data = ''
if len(path) >= 3:
data = model[path][C_JID]
selection.set(selection.target, 8, data)
2007-08-09 17:39:18 +02:00
def drag_begin(self, treeview, context):
self.dragging = True
2007-08-09 17:39:18 +02:00
def drag_end(self, treeview, context):
self.dragging = False
2007-06-03 12:04:20 +02:00
def on_drop_rosterx(self, widget, account_source, c_source, account_dest,
c_dest, was_big_brother, context, etime):
gajim.connections[account_dest].send_contacts([c_source], c_dest.jid)
def on_drop_in_contact(self, widget, account_source, c_source, account_dest,
c_dest, was_big_brother, context, etime):
2007-08-09 17:39:18 +02:00
if not gajim.connections[account_source].private_storage_supported or not\
gajim.connections[account_dest].private_storage_supported:
dialogs.WarningDialog(_('Metacontacts storage not supported by your '
'server'),
_('Your server does not support storing metacontacts information. '
'So those information will not be saved on next reconnection.'))
2007-08-09 17:39:18 +02:00
def merge_contacts(is_checked=None):
contacts = 0
if is_checked is not None: # dialog has been shown
if is_checked: # user does not want to be asked again
gajim.config.set('confirm_metacontacts', 'no')
else:
gajim.config.set('confirm_metacontacts', 'yes')
2008-06-02 12:04:27 +02:00
# We might have dropped on a metacontact.
# Remove it and readd later with updated family info
dest_family = gajim.contacts.get_metacontacts_family(account_dest,
c_dest.jid)
if dest_family:
self._remove_metacontact_family(dest_family, account_dest)
source_family = gajim.contacts.get_metacontacts_family(account_source, c_source.jid)
if dest_family == source_family:
n = contacts = len(dest_family)
for tag in source_family:
if tag['jid'] == c_source.jid:
tag['order'] = contacts
continue
if 'order' in tag:
n -= 1
tag['order'] = n
else:
self._remove_entity(c_dest, account_dest)
2007-08-09 17:39:18 +02:00
old_family = gajim.contacts.get_metacontacts_family(account_source,
c_source.jid)
old_groups = c_source.groups
2007-08-09 17:39:18 +02:00
2008-06-02 12:04:27 +02:00
# Remove old source contact(s)
if was_big_brother:
# We have got little brothers. Readd them all
self._remove_metacontact_family(old_family, account_source)
2008-06-02 12:04:27 +02:00
else:
# We are only a litle brother. Simply remove us from our big brother
if self._get_contact_iter(c_source.jid, account_source):
# When we have been in the group before.
# Do not try to remove us again
self._remove_entity(c_source, account_source)
own_data = {}
own_data['jid'] = c_source.jid
own_data['account'] = account_source
# Don't touch the rest of the family
old_family = [own_data]
2008-06-02 12:04:27 +02:00
# Apply new tag and update contact
for data in old_family:
if account_source != data['account'] and not self.regroup:
continue
_account = data['account']
_jid = data['jid']
_contact = gajim.contacts.get_first_contact_from_jid(_account, _jid)
2007-06-03 12:04:20 +02:00
_contact.groups = c_dest.groups[:]
gajim.contacts.add_metacontact(account_dest, c_dest.jid,
_account, _contact.jid, contacts)
gajim.connections[account_source].update_contact(_contact.jid,
_contact.name, _contact.groups)
2007-06-03 12:04:20 +02:00
# Re-add all and update GUI
new_family = gajim.contacts.get_metacontacts_family(account_source,
c_source.jid)
brothers = self._add_metacontact_family(new_family, account_source)
2008-06-02 12:04:27 +02:00
for c, acc in brothers:
self.draw_completely(c.jid, acc)
old_groups.extend(c_dest.groups)
for g in old_groups:
self.draw_group(g, account_source)
2008-06-02 12:04:27 +02:00
self.draw_account(account_source)
context.finish(True, True, etime)
2006-11-18 21:52:28 +01:00
confirm_metacontacts = gajim.config.get('confirm_metacontacts')
if confirm_metacontacts == 'no':
merge_contacts()
return
pritext = _('You are about to create a metacontact. Are you sure you want'
' to continue?')
sectext = _('Metacontacts are a way to regroup several contacts in one '
'line. Generally it is used when the same person has several Jabber '
'accounts or transport accounts.')
dlg = dialogs.ConfirmationDialogCheck(pritext, sectext,
_('Do _not ask me again'), on_response_ok=merge_contacts)
if not confirm_metacontacts: # First time we see this window
dlg.checkbutton.set_active(True)
2006-11-18 21:52:28 +01:00
2008-06-02 12:04:27 +02:00
def on_drop_in_group(self, widget, account, c_source, grp_dest,
is_big_brother, context, etime, grp_source = None):
if is_big_brother:
# add whole metacontact to new group
self.add_contact_to_groups(c_source.jid, account, [grp_dest,])
2008-06-02 12:04:27 +02:00
# remove afterwards so the contact is not moved to General in the
# meantime
if grp_dest != grp_source:
2008-06-02 12:04:27 +02:00
self.remove_contact_from_groups(c_source.jid, account, [grp_source])
2007-06-03 12:04:20 +02:00
else:
# Normal contact or little brother
family = gajim.contacts.get_metacontacts_family(account,
c_source.jid)
if family:
# Little brother
# Remove whole family. Remove us from the family.
# Then re-add other family members.
self._remove_metacontact_family(family, account)
gajim.contacts.remove_metacontact(account, c_source.jid)
for data in family:
if account != data['account'] and not self.regroup:
continue
if data['jid'] == c_source.jid and\
data['account'] == account:
continue
self.add_contact(data['jid'], data['account'])
break
self.add_contact_to_groups(c_source.jid, account, [grp_dest,])
2007-08-09 17:39:18 +02:00
else:
# Normal contact
self.add_contact_to_groups(c_source.jid, account, [grp_dest,])
2008-06-02 12:04:27 +02:00
# remove afterwards so the contact is not moved to General in the
# meantime
if grp_dest != grp_source:
2008-06-02 12:04:27 +02:00
self.remove_contact_from_groups(c_source.jid, account,
[grp_source])
2007-08-09 17:39:18 +02:00
if context.action in (gtk.gdk.ACTION_MOVE, gtk.gdk.ACTION_COPY):
context.finish(True, True, etime)
2008-06-02 12:04:27 +02:00
2007-08-09 17:39:18 +02:00
def drag_drop(self, treeview, context, x, y, timestamp):
target_list = treeview.drag_dest_get_target_list()
target = treeview.drag_dest_find_target(context, target_list)
2008-12-02 16:53:23 +01:00
treeview.drag_get_data(context, target)
context.finish(False, True)
return True
def drag_data_received_data(self, treeview, context, x, y, selection, info,
etime):
treeview.stop_emission('drag_data_received')
drop_info = treeview.get_dest_row_at_pos(x, y)
if not drop_info:
return
if not selection.data:
return # prevents tb when several entrys are dragged
model = treeview.get_model()
data = selection.data
path_dest, position = drop_info
if position == gtk.TREE_VIEW_DROP_BEFORE and len(path_dest) == 2 \
and path_dest[1] == 0: # dropped before the first group
return
if position == gtk.TREE_VIEW_DROP_BEFORE and len(path_dest) == 2:
# dropped before a group: we drop it in the previous group every time
path_dest = (path_dest[0], path_dest[1]-1)
# destination: the row something got dropped on
iter_dest = model.get_iter(path_dest)
type_dest = model[iter_dest][C_TYPE].decode('utf-8')
jid_dest = model[iter_dest][C_JID].decode('utf-8')
account_dest = model[iter_dest][C_ACCOUNT].decode('utf-8')
# drop on account row in merged mode, we cannot know the desired account
if account_dest == 'all':
return
# nothing can be done, if destination account is offline
if gajim.connections[account_dest].connected < 2:
return
2007-08-09 17:39:18 +02:00
# A file got dropped on the roster
if info == self.TARGET_TYPE_URI_LIST:
if len(path_dest) < 3:
return
if type_dest != 'contact':
return
c_dest = gajim.contacts.get_contact_with_highest_priority(account_dest,
jid_dest)
if not c_dest.supports(NS_FILE):
return
uri = data.strip()
uri_splitted = uri.split() # we may have more than one file dropped
try:
2008-06-02 12:04:27 +02:00
# This is always the last element in windows
uri_splitted.remove('\0')
except ValueError:
pass
nb_uri = len(uri_splitted)
# Check the URIs
bad_uris = []
for a_uri in uri_splitted:
path = helpers.get_file_path_from_dnd_dropped_uri(a_uri)
if not os.path.isfile(path):
bad_uris.append(a_uri)
if len(bad_uris):
dialogs.ErrorDialog(_('Invalid file URI:'), '\n'.join(bad_uris))
return
def _on_send_files(account, jid, uris):
c = gajim.contacts.get_contact_with_highest_priority(account, jid)
for uri in uris:
path = helpers.get_file_path_from_dnd_dropped_uri(uri)
if os.path.isfile(path): # is it file?
gajim.interface.instances['file_transfers'].send_file(
account, c, path)
# Popup dialog to confirm sending
prim_text = 'Send file?'
sec_text = i18n.ngettext('Do you want to send this file to %s:',
2008-08-25 12:06:22 +02:00
'Do you want to send these files to %s:', nb_uri) %\
c_dest.get_shown_name()
for uri in uri_splitted:
path = helpers.get_file_path_from_dnd_dropped_uri(uri)
sec_text += '\n' + os.path.basename(path)
dialog = dialogs.NonModalConfirmationDialog(prim_text, sec_text,
on_response_ok = (_on_send_files, account_dest, jid_dest,
uri_splitted))
dialog.popup()
return
2007-08-09 17:39:18 +02:00
# a roster entry was dragged and dropped somewhere in the roster
2007-08-09 17:39:18 +02:00
# source: the row that was dragged
path_source = treeview.get_selection().get_selected_rows()[1][0]
iter_source = model.get_iter(path_source)
type_source = model[iter_source][C_TYPE]
account_source = model[iter_source][C_ACCOUNT].decode('utf-8')
2007-08-09 17:39:18 +02:00
# Only normal contacts can be dragged
if type_source != 'contact':
return
if gajim.config.get_per('accounts', account_source, 'is_zeroconf'):
return
2007-08-09 17:39:18 +02:00
# A contact was dropped
if gajim.config.get_per('accounts', account_dest, 'is_zeroconf'):
# drop on zeroconf account, adding not possible
return
if type_dest == 'self_contact':
# drop on self contact row
return
if type_dest == 'account' and account_source == account_dest:
# drop on the account it was dragged from
return
if type_dest == 'groupchat':
# drop on a minimized groupchat
# TODO: Invite to groupchat
return
# Get valid source group, jid and contact
it = iter_source
while model[it][C_TYPE] == 'contact':
it = model.iter_parent(it)
grp_source = model[it][C_JID].decode('utf-8')
if grp_source in helpers.special_groups and \
grp_source not in ('Not in Roster', 'Observers'):
# a transport or a minimized groupchat was dragged
2008-06-02 12:04:27 +02:00
# we can add it to other accounts but not move it to another group,
# see below
return
jid_source = data.decode('utf-8')
c_source = gajim.contacts.get_contact_with_highest_priority(
account_source, jid_source)
# Get destination group
grp_dest = None
if type_dest == 'group':
grp_dest = model[iter_dest][C_JID].decode('utf-8')
elif type_dest in ('contact', 'agent'):
it = iter_dest
while model[it][C_TYPE] != 'group':
it = model.iter_parent(it)
grp_dest = model[it][C_JID].decode('utf-8')
if grp_dest in helpers.special_groups:
return
2007-06-03 12:04:20 +02:00
if jid_source == jid_dest:
if grp_source == grp_dest and account_source == account_dest:
# Drop on self
return
# contact drop somewhere in or on a foreign account
if (type_dest == 'account' or not self.regroup) and \
account_source != account_dest:
# add to account in specified group
2008-09-02 22:34:11 +02:00
dialogs.AddNewContactWindow(account=account_dest, jid=jid_source,
user_nick=c_source.name, group=grp_dest)
return
# we may not add contacts from special_groups
if grp_source in helpers.special_groups :
return
# Is the contact we drag a meta contact?
accounts = (self.regroup and gajim.contacts.get_accounts()) or \
account_source
is_big_brother = gajim.contacts.is_big_brother(account_source, jid_source,
accounts)
drop_in_middle_of_meta = False
if type_dest == 'contact':
if position == gtk.TREE_VIEW_DROP_BEFORE and len(path_dest) == 4:
drop_in_middle_of_meta = True
if position == gtk.TREE_VIEW_DROP_AFTER and (len(path_dest) == 4 or \
self.modelfilter.iter_has_child(iter_dest)):
drop_in_middle_of_meta = True
# Contact drop on group row or between two contacts that are
# not metacontacts
if (type_dest == 'group' or position in (gtk.TREE_VIEW_DROP_BEFORE,
gtk.TREE_VIEW_DROP_AFTER)) and not drop_in_middle_of_meta:
self.on_drop_in_group(None, account_source, c_source, grp_dest,
is_big_brother, context, etime, grp_source)
return
# Contact drop on another contact, make meta contacts
if position == gtk.TREE_VIEW_DROP_INTO_OR_AFTER or \
position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE or drop_in_middle_of_meta:
c_dest = gajim.contacts.get_contact_with_highest_priority(account_dest,
jid_dest)
if not c_dest:
# c_dest is None if jid_dest doesn't belong to account
return
menu = gtk.Menu()
item = gtk.MenuItem(_('Send %s to %s') % (c_source.get_shown_name(),
c_dest.get_shown_name()))
item.connect('activate', self.on_drop_rosterx, account_source,
c_source, account_dest, c_dest, is_big_brother, context, etime)
menu.append(item)
item = gtk.MenuItem(_('Make %s and %s metacontacts') % (
c_source.get_shown_name(), c_dest.get_shown_name()))
item.connect('activate', self.on_drop_in_contact, account_source,
c_source, account_dest, c_dest, is_big_brother, context, etime)
menu.append(item)
menu.attach_to_widget(self.tree, None)
menu.connect('selection-done', gtkgui_helpers.destroy_widget)
menu.show_all()
menu.popup(None, None, None, 1, etime)
2008-06-02 12:04:27 +02:00
################################################################################
### Everything about images and icons....
### Cleanup assigned to Jim++ :-)
################################################################################
2008-06-02 12:04:27 +02:00
2008-09-02 22:31:05 +02:00
def get_appropriate_state_images(self, jid, size='16', icon_name='online'):
'''check jid and return the appropriate state images dict for
the demanded size. icon_name is taken into account when jid is from
transport: transport iconset doesn't contain all icons, so we fall back
to jabber one'''
transport = gajim.get_transport_name_from_jid(jid)
if transport and size in self.transports_state_images:
if transport not in self.transports_state_images[size]:
# we don't have iconset for this transport loaded yet. Let's do it
self.make_transport_state_images(transport)
if transport in self.transports_state_images[size] and \
icon_name in self.transports_state_images[size][transport]:
return self.transports_state_images[size][transport]
return gajim.interface.jabber_state_images[size]
def make_transport_state_images(self, transport):
'''initialise opened and closed 'transport' iconset dict'''
if gajim.config.get('use_transports_iconsets'):
folder = os.path.join(helpers.get_transport_path(transport),
'16x16')
pixo, pixc = gtkgui_helpers.load_icons_meta()
self.transports_state_images['opened'][transport] = \
2008-06-02 12:04:27 +02:00
gtkgui_helpers.load_iconset(folder, pixo, transport=True)
self.transports_state_images['closed'][transport] = \
2008-06-02 12:04:27 +02:00
gtkgui_helpers.load_iconset(folder, pixc, transport=True)
folder = os.path.join(helpers.get_transport_path(transport), '32x32')
2008-06-02 12:04:27 +02:00
self.transports_state_images['32'][transport] = \
gtkgui_helpers.load_iconset(folder, transport=True)
folder = os.path.join(helpers.get_transport_path(transport), '16x16')
2008-06-02 12:04:27 +02:00
self.transports_state_images['16'][transport] = \
gtkgui_helpers.load_iconset(folder, transport=True)
def update_jabber_state_images(self):
# Update the roster
self.setup_and_draw_roster()
# Update the status combobox
model = self.status_combobox.get_model()
titer = model.get_iter_root()
while titer:
if model[titer][2] != '':
# If it's not change status message iter
# eg. if it has show parameter not ''
2008-06-02 12:04:27 +02:00
model[titer][1] = gajim.interface.jabber_state_images['16'][model[
titer][2]]
titer = model.iter_next(titer)
# Update the systray
if gajim.interface.systray_enabled:
gajim.interface.systray.set_img()
for win in gajim.interface.msg_win_mgr.windows():
for ctrl in win.controls():
ctrl.update_ui()
win.redraw_tab(ctrl)
self.update_status_combobox()
2008-06-02 12:04:27 +02:00
def set_account_status_icon(self, account):
status = gajim.connections[account].connected
child_iterA = self._get_account_iter(account, self.model)
if not child_iterA:
return
if not self.regroup:
show = gajim.SHOW_LIST[status]
else: # accounts merged
show = helpers.get_global_show()
2008-06-02 12:04:27 +02:00
self.model[child_iterA][C_IMG] = gajim.interface.jabber_state_images[
'16'][show]
################################################################################
### Style and theme related methods
################################################################################
def show_title(self):
change_title_allowed = gajim.config.get('change_roster_title')
if not change_title_allowed:
return
2007-08-09 17:39:18 +02:00
if gajim.config.get('one_message_window') == 'always_with_roster':
# always_with_roster mode defers to the MessageWindow
if not gajim.interface.msg_win_mgr.one_window_opened():
# No MessageWindow to defer to
self.window.set_title('Gajim')
return
2007-08-09 17:39:18 +02:00
nb_unread = 0
start = ''
for account in gajim.connections:
# Count events in roster title only if we don't auto open them
if not helpers.allow_popup_window(account):
nb_unread += gajim.events.get_nb_events(['chat', 'normal',
'file-request', 'file-error', 'file-completed',
'file-request-error', 'file-send-error', 'file-stopped',
'printed_chat'], account)
if nb_unread > 1:
start = '[' + str(nb_unread) + '] '
elif nb_unread == 1:
start = '* '
2006-11-18 21:52:28 +01:00
self.window.set_title(start + 'Gajim')
gtkgui_helpers.set_unset_urgency_hint(self.window, nb_unread)
def _change_style(self, model, path, titer, option):
if option is None or model[titer][C_TYPE] == option:
# We changed style for this type of row
model[titer][C_NAME] = model[titer][C_NAME]
def change_roster_style(self, option):
self.model.foreach(self._change_style, option)
for win in gajim.interface.msg_win_mgr.windows():
win.repaint_themed_widgets()
def repaint_themed_widgets(self):
'''Notify windows that contain themed widgets to repaint them'''
for win in gajim.interface.msg_win_mgr.windows():
win.repaint_themed_widgets()
for account in gajim.connections:
for addr in gajim.interface.instances[account]['disco']:
gajim.interface.instances[account]['disco'][addr].paint_banner()
for ctrl in gajim.interface.minimized_controls[account].values():
ctrl.repaint_themed_widgets()
def update_avatar_in_gui(self, jid, account):
# Update roster
self.draw_avatar(jid, account)
# Update chat window
ctrl = gajim.interface.msg_win_mgr.get_control(jid, account)
if ctrl:
ctrl.show_avatar()
def on_roster_treeview_style_set(self, treeview, style):
'''When style (theme) changes, redraw all contacts'''
for contact in self._iter_contact_rows():
self.draw_contact(contact[C_JID].decode('utf-8'),
contact[C_ACCOUNT].decode('utf-8'))
2008-06-02 12:04:27 +02:00
2008-09-02 22:31:05 +02:00
def set_renderer_color(self, renderer, style, set_background=True):
'''set style for treeview cell, using PRELIGHT system color'''
if set_background:
bgcolor = self.tree.style.bg[style]
renderer.set_property('cell-background-gdk', bgcolor)
2006-09-13 18:47:58 +02:00
else:
fgcolor = self.tree.style.fg[style]
renderer.set_property('foreground-gdk', fgcolor)
2008-06-02 12:04:27 +02:00
2008-09-02 22:31:05 +02:00
def _iconCellDataFunc(self, column, renderer, model, titer, data=None):
'''When a row is added, set properties for icon renderer'''
theme = gajim.config.get('roster_theme')
type_ = model[titer][C_TYPE]
if type_ == 'account':
color = gajim.config.get_per('themes', theme, 'accountbgcolor')
if color:
renderer.set_property('cell-background', color)
else:
self.set_renderer_color(renderer, gtk.STATE_ACTIVE)
renderer.set_property('xalign', 0)
elif type_ == 'group':
color = gajim.config.get_per('themes', theme, 'groupbgcolor')
if color:
renderer.set_property('cell-background', color)
else:
self.set_renderer_color(renderer, gtk.STATE_PRELIGHT)
renderer.set_property('xalign', 0.2)
elif type_: # prevent type_ = None, see http://trac.gajim.org/ticket/2534
if not model[titer][C_JID] or not model[titer][C_ACCOUNT]:
# This can append when at the moment we add the row
return
jid = model[titer][C_JID].decode('utf-8')
account = model[titer][C_ACCOUNT].decode('utf-8')
if jid in gajim.newly_added[account]:
renderer.set_property('cell-background', gajim.config.get(
'just_connected_bg_color'))
elif jid in gajim.to_be_removed[account]:
renderer.set_property('cell-background', gajim.config.get(
'just_disconnected_bg_color'))
else:
color = gajim.config.get_per('themes', theme, 'contactbgcolor')
if color:
renderer.set_property('cell-background', color)
else:
renderer.set_property('cell-background', None)
parent_iter = model.iter_parent(titer)
if model[parent_iter][C_TYPE] == 'contact':
renderer.set_property('xalign', 1)
else:
renderer.set_property('xalign', 0.4)
renderer.set_property('width', 26)
2008-06-02 12:04:27 +02:00
2008-09-02 22:31:05 +02:00
def _nameCellDataFunc(self, column, renderer, model, titer, data=None):
'''When a row is added, set properties for name renderer'''
theme = gajim.config.get('roster_theme')
type_ = model[titer][C_TYPE]
if type_ == 'account':
color = gajim.config.get_per('themes', theme, 'accounttextcolor')
if color:
renderer.set_property('foreground', color)
else:
self.set_renderer_color(renderer, gtk.STATE_ACTIVE, False)
color = gajim.config.get_per('themes', theme, 'accountbgcolor')
if color:
renderer.set_property('cell-background', color)
else:
self.set_renderer_color(renderer, gtk.STATE_ACTIVE)
renderer.set_property('font',
gtkgui_helpers.get_theme_font_for_option(theme, 'accountfont'))
renderer.set_property('xpad', 0)
renderer.set_property('width', 3)
elif type_ == 'group':
color = gajim.config.get_per('themes', theme, 'grouptextcolor')
if color:
renderer.set_property('foreground', color)
else:
self.set_renderer_color(renderer, gtk.STATE_PRELIGHT, False)
color = gajim.config.get_per('themes', theme, 'groupbgcolor')
if color:
renderer.set_property('cell-background', color)
else:
self.set_renderer_color(renderer, gtk.STATE_PRELIGHT)
renderer.set_property('font',
gtkgui_helpers.get_theme_font_for_option(theme, 'groupfont'))
renderer.set_property('xpad', 4)
elif type_: # prevent type_ = None, see http://trac.gajim.org/ticket/2534
if not model[titer][C_JID] or not model[titer][C_ACCOUNT]:
# This can append when at the moment we add the row
return
jid = model[titer][C_JID].decode('utf-8')
account = model[titer][C_ACCOUNT].decode('utf-8')
color = None
if type_ == 'groupchat':
ctrl = gajim.interface.minimized_controls[account].get(jid, None)
if ctrl and ctrl.attention_flag:
color = gajim.config.get_per('themes', theme,
'state_muc_directed_msg_color')
renderer.set_property('foreground', 'red')
if not color:
color = gajim.config.get_per('themes', theme, 'contacttextcolor')
if color:
renderer.set_property('foreground', color)
else:
renderer.set_property('foreground', None)
if jid in gajim.newly_added[account]:
renderer.set_property('cell-background', gajim.config.get(
'just_connected_bg_color'))
elif jid in gajim.to_be_removed[account]:
renderer.set_property('cell-background', gajim.config.get(
'just_disconnected_bg_color'))
else:
color = gajim.config.get_per('themes', theme, 'contactbgcolor')
if color:
renderer.set_property('cell-background', color)
else:
renderer.set_property('cell-background', None)
renderer.set_property('font',
gtkgui_helpers.get_theme_font_for_option(theme, 'contactfont'))
parent_iter = model.iter_parent(titer)
if model[parent_iter][C_TYPE] == 'contact':
renderer.set_property('xpad', 16)
else:
renderer.set_property('xpad', 8)
2009-11-15 17:11:06 +01:00
def _fill_pep_pixbuf_renderer(self, column, renderer, model, titer,
data=None):
'''When a row is added, draw the respective pep icon'''
theme = gajim.config.get('roster_theme')
type_ = model[titer][C_TYPE]
2008-07-25 03:10:14 +02:00
if type_ == 'group':
renderer.set_property('visible', False)
return
# allocate space for the icon only if needed
2009-11-15 17:11:06 +01:00
if model[titer][data]:
renderer.set_property('visible', True)
else:
renderer.set_property('visible', False)
2008-07-25 03:10:14 +02:00
if type_ == 'account':
2009-11-15 17:11:06 +01:00
color = gajim.config.get_per('themes', theme, 'accountbgcolor')
2008-07-25 16:11:14 +02:00
if color:
renderer.set_property('cell-background', color)
else:
2009-11-15 17:11:06 +01:00
self.set_renderer_color(renderer, gtk.STATE_ACTIVE)
2008-07-25 16:11:14 +02:00
# align pixbuf to the right)
renderer.set_property('xalign', 1)
# prevent type_ = None, see http://trac.gajim.org/ticket/2534
elif type_:
2009-11-15 17:11:06 +01:00
if not model[titer][C_JID] or not model[titer][C_ACCOUNT]:
2008-07-25 16:11:14 +02:00
# This can append at the moment we add the row
return
jid = model[titer][C_JID].decode('utf-8')
account = model[titer][C_ACCOUNT].decode('utf-8')
if jid in gajim.newly_added[account]:
2009-11-15 17:11:06 +01:00
renderer.set_property('cell-background', gajim.config.get(
2008-07-25 16:11:14 +02:00
'just_connected_bg_color'))
elif jid in gajim.to_be_removed[account]:
2009-11-15 17:11:06 +01:00
renderer.set_property('cell-background', gajim.config.get(
2008-07-25 16:11:14 +02:00
'just_disconnected_bg_color'))
else:
2009-11-15 17:11:06 +01:00
color = gajim.config.get_per('themes', theme, 'contactbgcolor')
renderer.set_property('cell-background', color if color else None)
2008-07-25 16:11:14 +02:00
# align pixbuf to the right
renderer.set_property('xalign', 1)
2008-12-03 22:58:08 +01:00
def _fill_avatar_pixbuf_renderer(self, column, renderer, model, titer,
data = None):
'''When a row is added, set properties for avatar renderer'''
theme = gajim.config.get('roster_theme')
type_ = model[titer][C_TYPE]
if type_ in ('group', 'account'):
renderer.set_property('visible', False)
return
2006-11-18 21:52:28 +01:00
# allocate space for the icon only if needed
if model[titer][C_AVATAR_PIXBUF] or \
gajim.config.get('avatar_position_in_roster') == 'left':
renderer.set_property('visible', True)
else:
renderer.set_property('visible', False)
if type_: # prevent type_ = None, see http://trac.gajim.org/ticket/2534
if not model[titer][C_JID] or not model[titer][C_ACCOUNT]:
# This can append at the moment we add the row
return
jid = model[titer][C_JID].decode('utf-8')
account = model[titer][C_ACCOUNT].decode('utf-8')
if jid in gajim.newly_added[account]:
renderer.set_property('cell-background', gajim.config.get(
'just_connected_bg_color'))
elif jid in gajim.to_be_removed[account]:
renderer.set_property('cell-background', gajim.config.get(
'just_disconnected_bg_color'))
else:
color = gajim.config.get_per('themes', theme, 'contactbgcolor')
if color:
renderer.set_property('cell-background', color)
else:
renderer.set_property('cell-background', None)
if gajim.config.get('avatar_position_in_roster') == 'left':
renderer.set_property('width', gajim.config.get('roster_avatar_width'))
renderer.set_property('xalign', 0.5)
else:
renderer.set_property('xalign', 1) # align pixbuf to the right
2006-09-13 18:47:58 +02:00
2008-12-03 22:58:08 +01:00
def _fill_padlock_pixbuf_renderer(self, column, renderer, model, titer,
data = None):
'''When a row is added, set properties for padlock renderer'''
theme = gajim.config.get('roster_theme')
type_ = model[titer][C_TYPE]
# allocate space for the icon only if needed
if type_ == 'account' and model[titer][C_PADLOCK_PIXBUF]:
renderer.set_property('visible', True)
color = gajim.config.get_per('themes', theme, 'accountbgcolor')
if color:
renderer.set_property('cell-background', color)
else:
self.set_renderer_color(renderer, gtk.STATE_ACTIVE)
renderer.set_property('xalign', 1) # align pixbuf to the right
else:
renderer.set_property('visible', False)
2008-06-02 12:04:27 +02:00
################################################################################
### Everything about building menus
### FIXME: We really need to make it simpler! 1465 lines are a few to much....
2008-06-02 12:04:27 +02:00
################################################################################
2008-09-02 22:31:05 +02:00
def make_menu(self, force=False):
'''create the main window\'s menus'''
if not force and not self.actions_menu_needs_rebuild:
return
new_chat_menuitem = self.xml.get_widget('new_chat_menuitem')
2008-06-02 12:04:27 +02:00
single_message_menuitem = self.xml.get_widget(
'send_single_message_menuitem')
join_gc_menuitem = self.xml.get_widget('join_gc_menuitem')
muc_icon = gtkgui_helpers.load_icon('muc_active')
if muc_icon:
join_gc_menuitem.set_image(muc_icon)
add_new_contact_menuitem = self.xml.get_widget('add_new_contact_menuitem')
service_disco_menuitem = self.xml.get_widget('service_disco_menuitem')
advanced_menuitem = self.xml.get_widget('advanced_menuitem')
profile_avatar_menuitem = self.xml.get_widget('profile_avatar_menuitem')
2006-11-18 21:52:28 +01:00
# destroy old advanced menus
for m in self.advanced_menus:
m.destroy()
2006-11-18 21:52:28 +01:00
# make it sensitive. it is insensitive only if no accounts are *available*
advanced_menuitem.set_sensitive(True)
2007-08-09 17:39:18 +02:00
if self.add_new_contact_handler_id:
add_new_contact_menuitem.handler_disconnect(
self.add_new_contact_handler_id)
self.add_new_contact_handler_id = None
if self.service_disco_handler_id:
service_disco_menuitem.handler_disconnect(
self.service_disco_handler_id)
self.service_disco_handler_id = None
if self.new_chat_menuitem_handler_id:
new_chat_menuitem.handler_disconnect(
self.new_chat_menuitem_handler_id)
self.new_chat_menuitem_handler_id = None
if self.single_message_menuitem_handler_id:
single_message_menuitem.handler_disconnect(
self.single_message_menuitem_handler_id)
self.single_message_menuitem_handler_id = None
2007-03-31 00:52:11 +02:00
if self.profile_avatar_menuitem_handler_id:
profile_avatar_menuitem.handler_disconnect(
self.profile_avatar_menuitem_handler_id)
self.profile_avatar_menuitem_handler_id = None
# remove the existing submenus
add_new_contact_menuitem.remove_submenu()
service_disco_menuitem.remove_submenu()
join_gc_menuitem.remove_submenu()
single_message_menuitem.remove_submenu()
new_chat_menuitem.remove_submenu()
advanced_menuitem.remove_submenu()
profile_avatar_menuitem.remove_submenu()
Merge one_window branch Merged revisions 9143,9145-9155,9157-9162,9164-9169,9171-9177 via svnmerge from svn://88.191.11.156/gajim/branches/one_window ........ r9145 | nicfit | 2007-12-13 21:49:09 -0700 (Thu, 13 Dec 2007) | 2 lines Implemented the original Nikos patch with an HPaned instead of a HBox and only do this mode when one_message_window == 'always' ........ r9152 | nicfit | 2007-12-15 13:33:56 -0700 (Sat, 15 Dec 2007) | 2 lines Added config and GUI for one_message_window_with_roster ........ r9153 | nicfit | 2007-12-15 13:41:46 -0700 (Sat, 15 Dec 2007) | 2 lines Use one_message_window_with_roster and some whitespace cleanup ........ r9154 | nicfit | 2007-12-15 14:04:49 -0700 (Sat, 15 Dec 2007) | 2 lines Scratch the chckbox for with roster mode, use one_message_window opt and combo ........ r9155 | nicfit | 2007-12-15 17:01:13 -0700 (Sat, 15 Dec 2007) | 2 lines MessageWindowMgr knows about ONE_MESSAGE_WINDOW_ALWAYS_WITH_ROSTER and MessageWindow can reparent itself rather then the roster having to do so. ........ r9157 | nicfit | 2007-12-15 17:47:20 -0700 (Sat, 15 Dec 2007) | 2 lines Resizing fixes and make the roster window shrink when last tab is removed ........ r9158 | nicfit | 2007-12-15 19:15:11 -0700 (Sat, 15 Dec 2007) | 2 lines Added "Show roster" (CTRL+R) to view menu when using always_with_roster to quickly hide/show the roster. ........ r9159 | nicfit | 2007-12-15 19:49:30 -0700 (Sat, 15 Dec 2007) | 2 lines Handle window title setting in always_with_roster mode. ........ r9160 | nicfit | 2007-12-15 20:13:57 -0700 (Sat, 15 Dec 2007) | 2 lines Removed FIXME ........ r9167 | nicfit | 2007-12-17 18:40:59 -0700 (Mon, 17 Dec 2007) | 2 lines When roster is hidden, show it when the number of MessageWindow controls == 0 ........ r9168 | nicfit | 2007-12-17 19:07:49 -0700 (Mon, 17 Dec 2007) | 2 lines Disable hiding roster when there are no message controls open ........ r9169 | nicfit | 2007-12-17 20:41:11 -0700 (Mon, 17 Dec 2007) | 2 lines Bunch of saved size bugs fixed ........
2007-12-19 00:42:22 +01:00
# remove the existing accelerator
if self.have_new_chat_accel:
ag = gtk.accel_groups_from_object(self.window)[0]
new_chat_menuitem.remove_accelerator(ag, gtk.keysyms.n,
gtk.gdk.CONTROL_MASK)
self.have_new_chat_accel = False
2007-08-09 17:39:18 +02:00
gc_sub_menu = gtk.Menu() # gc is always a submenu
join_gc_menuitem.set_submenu(gc_sub_menu)
connected_accounts = gajim.get_number_of_connected_accounts()
2006-09-13 18:47:58 +02:00
connected_accounts_with_private_storage = 0
# items that get shown whether an account is zeroconf or not
accounts_list = sorted(gajim.contacts.get_accounts())
if connected_accounts > 1: # 2 or more accounts? make submenus
new_chat_sub_menu = gtk.Menu()
for account in accounts_list:
if gajim.connections[account].connected <= 1:
# if offline or connecting
continue
2006-11-18 21:52:28 +01:00
# new chat
new_chat_item = gtk.MenuItem(_('using account %s') % account,
False)
new_chat_sub_menu.append(new_chat_item)
new_chat_item.connect('activate',
self.on_new_chat_menuitem_activate, account)
2006-11-18 21:52:28 +01:00
new_chat_menuitem.set_submenu(new_chat_sub_menu)
new_chat_sub_menu.show_all()
elif connected_accounts == 1: # user has only one account
for account in gajim.connections:
if gajim.account_is_connected(account): # THE connected account
# new chat
if not self.new_chat_menuitem_handler_id:
self.new_chat_menuitem_handler_id = new_chat_menuitem.\
connect('activate', self.on_new_chat_menuitem_activate,
account)
break
# menu items that don't apply to zeroconf connections
if connected_accounts == 1 or (connected_accounts == 2 and \
gajim.zeroconf_is_connected()):
# only one 'real' (non-zeroconf) account is connected, don't need submenus
for account in accounts_list:
if gajim.account_is_connected(account) and \
not gajim.config.get_per('accounts', account, 'is_zeroconf'):
# gc
if gajim.connections[account].private_storage_supported:
connected_accounts_with_private_storage += 1
self.add_bookmarks_list(gc_sub_menu, account)
gc_sub_menu.show_all()
# add
if not self.add_new_contact_handler_id:
self.add_new_contact_handler_id =\
add_new_contact_menuitem.connect(
'activate', self.on_add_new_contact, account)
# disco
if not self.service_disco_handler_id:
self.service_disco_handler_id = service_disco_menuitem.\
connect('activate',
self.on_service_disco_menuitem_activate, account)
# single message
if not self.single_message_menuitem_handler_id:
self.single_message_menuitem_handler_id = \
single_message_menuitem.connect('activate', \
self.on_send_single_message_menuitem_activate, account)
# new chat accel
if not self.have_new_chat_accel:
ag = gtk.accel_groups_from_object(self.window)[0]
new_chat_menuitem.add_accelerator('activate', ag,
gtk.keysyms.n, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)
self.have_new_chat_accel = True
break # No other account connected
else:
# 2 or more 'real' accounts are connected, make submenus
single_message_sub_menu = gtk.Menu()
add_sub_menu = gtk.Menu()
disco_sub_menu = gtk.Menu()
for account in accounts_list:
if gajim.connections[account].connected <= 1 or \
gajim.config.get_per('accounts', account, 'is_zeroconf'):
# skip account if it's offline or connecting or is zeroconf
continue
# single message
single_message_item = gtk.MenuItem(_('using account %s') % account,
False)
single_message_sub_menu.append(single_message_item)
single_message_item.connect('activate',
self.on_send_single_message_menuitem_activate, account)
# join gc
if gajim.connections[account].private_storage_supported:
connected_accounts_with_private_storage += 1
gc_item = gtk.MenuItem(_('using account %s') % account, False)
gc_sub_menu.append(gc_item)
gc_menuitem_menu = gtk.Menu()
self.add_bookmarks_list(gc_menuitem_menu, account)
gc_item.set_submenu(gc_menuitem_menu)
# add
add_item = gtk.MenuItem(_('to %s account') % account, False)
add_sub_menu.append(add_item)
add_item.connect('activate', self.on_add_new_contact, account)
# disco
disco_item = gtk.MenuItem(_('using %s account') % account, False)
disco_sub_menu.append(disco_item)
disco_item.connect('activate',
self.on_service_disco_menuitem_activate, account)
single_message_menuitem.set_submenu(single_message_sub_menu)
single_message_sub_menu.show_all()
gc_sub_menu.show_all()
add_new_contact_menuitem.set_submenu(add_sub_menu)
add_sub_menu.show_all()
service_disco_menuitem.set_submenu(disco_sub_menu)
disco_sub_menu.show_all()
if connected_accounts == 0:
# no connected accounts, make the menuitems insensitive
for item in (new_chat_menuitem, join_gc_menuitem,\
add_new_contact_menuitem, service_disco_menuitem,\
single_message_menuitem):
item.set_sensitive(False)
else: # we have one or more connected accounts
for item in (new_chat_menuitem, join_gc_menuitem,
add_new_contact_menuitem, service_disco_menuitem,
single_message_menuitem):
item.set_sensitive(True)
# disable some fields if only local account is there
if connected_accounts == 1:
for account in gajim.connections:
if gajim.account_is_connected(account) and \
gajim.connections[account].is_zeroconf:
2008-12-03 22:56:12 +01:00
for item in (join_gc_menuitem, add_new_contact_menuitem,
service_disco_menuitem, single_message_menuitem):
item.set_sensitive(False)
# Manage GC bookmarks
newitem = gtk.SeparatorMenuItem() # separator
gc_sub_menu.append(newitem)
newitem = gtk.ImageMenuItem(_('_Manage Bookmarks...'))
img = gtk.image_new_from_stock(gtk.STOCK_PREFERENCES,
gtk.ICON_SIZE_MENU)
newitem.set_image(img)
newitem.connect('activate', self.on_manage_bookmarks_menuitem_activate)
gc_sub_menu.append(newitem)
gc_sub_menu.show_all()
if connected_accounts_with_private_storage == 0:
newitem.set_sensitive(False)
2005-07-09 00:26:46 +02:00
connected_accounts_with_vcard = []
for account in gajim.connections:
if gajim.account_is_connected(account) and \
gajim.connections[account].vcard_supported:
connected_accounts_with_vcard.append(account)
if len(connected_accounts_with_vcard) > 1:
# 2 or more accounts? make submenus
profile_avatar_sub_menu = gtk.Menu()
for account in connected_accounts_with_vcard:
# profile, avatar
profile_avatar_item = gtk.MenuItem(_('of account %s') % account,
False)
profile_avatar_sub_menu.append(profile_avatar_item)
profile_avatar_item.connect('activate',
self.on_profile_avatar_menuitem_activate, account)
profile_avatar_menuitem.set_submenu(profile_avatar_sub_menu)
profile_avatar_sub_menu.show_all()
elif len(connected_accounts_with_vcard) == 1: # user has only one account
account = connected_accounts_with_vcard[0]
# profile, avatar
if not self.profile_avatar_menuitem_handler_id:
self.profile_avatar_menuitem_handler_id = \
profile_avatar_menuitem.connect('activate',
self.on_profile_avatar_menuitem_activate, account)
if len(connected_accounts_with_vcard) == 0:
profile_avatar_menuitem.set_sensitive(False)
else:
profile_avatar_menuitem.set_sensitive(True)
# Advanced Actions
if len(gajim.connections) == 0: # user has no accounts
advanced_menuitem.set_sensitive(False)
elif len(gajim.connections) == 1: # we have one acccount
account = gajim.connections.keys()[0]
advanced_menuitem_menu = self.get_and_connect_advanced_menuitem_menu(
account)
self.advanced_menus.append(advanced_menuitem_menu)
self.add_history_manager_menuitem(advanced_menuitem_menu)
advanced_menuitem.set_submenu(advanced_menuitem_menu)
advanced_menuitem_menu.show_all()
else: # user has *more* than one account : build advanced submenus
advanced_sub_menu = gtk.Menu()
accounts = [] # Put accounts in a list to sort them
for account in gajim.connections:
accounts.append(account)
accounts.sort()
for account in accounts:
advanced_item = gtk.MenuItem(_('for account %s') % account, False)
advanced_sub_menu.append(advanced_item)
advanced_menuitem_menu = \
self.get_and_connect_advanced_menuitem_menu(account)
self.advanced_menus.append(advanced_menuitem_menu)
advanced_item.set_submenu(advanced_menuitem_menu)
self.add_history_manager_menuitem(advanced_sub_menu)
2007-12-12 09:44:46 +01:00
advanced_menuitem.set_submenu(advanced_sub_menu)
advanced_sub_menu.show_all()
2007-12-12 09:44:46 +01:00
2008-06-02 12:04:27 +02:00
self.actions_menu_needs_rebuild = False
def build_account_menu(self, account):
# we have to create our own set of icons for the menu
# using self.jabber_status_images is poopoo
iconset = gajim.config.get('iconset')
path = os.path.join(helpers.get_iconset_path(iconset), '16x16')
state_images = gtkgui_helpers.load_iconset(path)
if not gajim.config.get_per('accounts', account, 'is_zeroconf'):
xml = gtkgui_helpers.get_glade('account_context_menu.glade')
account_context_menu = xml.get_widget('account_context_menu')
status_menuitem = xml.get_widget('status_menuitem')
start_chat_menuitem = xml.get_widget('start_chat_menuitem')
join_group_chat_menuitem = xml.get_widget('join_group_chat_menuitem')
muc_icon = gtkgui_helpers.load_icon('muc_active')
if muc_icon:
join_group_chat_menuitem.set_image(muc_icon)
open_gmail_inbox_menuitem = xml.get_widget('open_gmail_inbox_menuitem')
add_contact_menuitem = xml.get_widget('add_contact_menuitem')
service_discovery_menuitem = xml.get_widget(
'service_discovery_menuitem')
execute_command_menuitem = xml.get_widget('execute_command_menuitem')
edit_account_menuitem = xml.get_widget('edit_account_menuitem')
sub_menu = gtk.Menu()
status_menuitem.set_submenu(sub_menu)
2007-08-09 17:39:18 +02:00
for show in ('online', 'chat', 'away', 'xa', 'dnd', 'invisible'):
2008-09-02 22:34:11 +02:00
uf_show = helpers.get_uf_show(show, use_mnemonic=True)
item = gtk.ImageMenuItem(uf_show)
icon = state_images[show]
item.set_image(icon)
sub_menu.append(item)
con = gajim.connections[account]
if show == 'invisible' and con.connected > 1 and \
not con.privacy_rules_supported:
item.set_sensitive(False)
else:
item.connect('activate', self.change_status, account, show)
item = gtk.SeparatorMenuItem()
sub_menu.append(item)
item = gtk.ImageMenuItem(_('_Change Status Message'))
path = os.path.join(gajim.DATA_DIR, 'pixmaps', 'kbd_input.png')
img = gtk.Image()
img.set_from_file(path)
item.set_image(img)
sub_menu.append(item)
item.connect('activate', self.on_change_status_message_activate,
account)
if gajim.connections[account].connected < 2:
item.set_sensitive(False)
item = gtk.SeparatorMenuItem()
sub_menu.append(item)
2008-09-02 22:34:11 +02:00
uf_show = helpers.get_uf_show('offline', use_mnemonic=True)
item = gtk.ImageMenuItem(uf_show)
icon = state_images['offline']
item.set_image(icon)
sub_menu.append(item)
item.connect('activate', self.change_status, account, 'offline')
pep_menuitem = xml.get_widget('pep_menuitem')
if gajim.connections[account].pep_supported:
have_tune = gajim.config.get_per('accounts', account,
'publish_tune')
2008-11-12 21:04:25 +01:00
pep_submenu = gtk.Menu()
pep_menuitem.set_submenu(pep_submenu)
item = gtk.CheckMenuItem(_('Publish Tune'))
pep_submenu.append(item)
if not dbus_support.supported:
item.set_sensitive(False)
else:
item.set_active(have_tune)
item.connect('toggled', self.on_publish_tune_toggled, account)
pep_config = gtk.ImageMenuItem(_('Configure Services...'))
item = gtk.SeparatorMenuItem()
pep_submenu.append(item)
pep_config.set_sensitive(True)
pep_submenu.append(pep_config)
2008-06-02 12:04:27 +02:00
pep_config.connect('activate',
self.on_pep_services_menuitem_activate, account)
img = gtk.image_new_from_stock(gtk.STOCK_PREFERENCES,
gtk.ICON_SIZE_MENU)
pep_config.set_image(img)
2007-12-12 09:44:46 +01:00
2008-11-12 21:04:25 +01:00
else:
pep_menuitem.set_sensitive(False)
if not gajim.connections[account].gmail_url:
open_gmail_inbox_menuitem.set_no_show_all(True)
open_gmail_inbox_menuitem.hide()
2006-09-13 18:47:58 +02:00
else:
open_gmail_inbox_menuitem.connect('activate',
self.on_open_gmail_inbox, account)
edit_account_menuitem.connect('activate', self.on_edit_account,
account)
add_contact_menuitem.connect('activate', self.on_add_new_contact,
account)
service_discovery_menuitem.connect('activate',
self.on_service_disco_menuitem_activate, account)
hostname = gajim.config.get_per('accounts', account, 'hostname')
contact = gajim.contacts.create_contact(jid=hostname, account=account) # Fake contact
execute_command_menuitem.connect('activate',
self.on_execute_command, contact, account)
start_chat_menuitem.connect('activate',
self.on_new_chat_menuitem_activate, account)
gc_sub_menu = gtk.Menu() # gc is always a submenu
join_group_chat_menuitem.set_submenu(gc_sub_menu)
self.add_bookmarks_list(gc_sub_menu, account)
2005-09-05 15:28:09 +02:00
# make some items insensitive if account is offline
if gajim.connections[account].connected < 2:
for widget in (add_contact_menuitem, service_discovery_menuitem,
join_group_chat_menuitem, execute_command_menuitem, pep_menuitem,
start_chat_menuitem):
widget.set_sensitive(False)
else:
xml = gtkgui_helpers.get_glade('zeroconf_context_menu.glade')
account_context_menu = xml.get_widget('zeroconf_context_menu')
status_menuitem = xml.get_widget('status_menuitem')
zeroconf_properties_menuitem = xml.get_widget(
'zeroconf_properties_menuitem')
sub_menu = gtk.Menu()
status_menuitem.set_submenu(sub_menu)
for show in ('online', 'away', 'dnd', 'invisible'):
2008-09-02 22:34:11 +02:00
uf_show = helpers.get_uf_show(show, use_mnemonic=True)
item = gtk.ImageMenuItem(uf_show)
icon = state_images[show]
item.set_image(icon)
sub_menu.append(item)
item.connect('activate', self.change_status, account, show)
item = gtk.SeparatorMenuItem()
sub_menu.append(item)
2007-06-03 12:04:20 +02:00
item = gtk.ImageMenuItem(_('_Change Status Message'))
path = os.path.join(gajim.DATA_DIR, 'pixmaps', 'kbd_input.png')
img = gtk.Image()
img.set_from_file(path)
item.set_image(img)
sub_menu.append(item)
item.connect('activate', self.on_change_status_message_activate,
account)
if gajim.connections[account].connected < 2:
item.set_sensitive(False)
2008-09-02 22:34:11 +02:00
uf_show = helpers.get_uf_show('offline', use_mnemonic=True)
item = gtk.ImageMenuItem(uf_show)
icon = state_images['offline']
item.set_image(icon)
sub_menu.append(item)
item.connect('activate', self.change_status, account, 'offline')
zeroconf_properties_menuitem.connect('activate',
self.on_zeroconf_properties, account)
return account_context_menu
def make_account_menu(self, event, titer):
'''Make account's popup menu'''
model = self.modelfilter
account = model[titer][C_ACCOUNT].decode('utf-8')
2007-06-03 12:04:20 +02:00
if account != 'all': # not in merged mode
menu = self.build_account_menu(account)
else:
menu = gtk.Menu()
iconset = gajim.config.get('iconset')
path = os.path.join(helpers.get_iconset_path(iconset), '16x16')
accounts = [] # Put accounts in a list to sort them
for account in gajim.connections:
accounts.append(account)
accounts.sort()
2006-11-18 21:52:28 +01:00
for account in accounts:
state_images = gtkgui_helpers.load_iconset(path)
item = gtk.ImageMenuItem(account)
show = gajim.SHOW_LIST[gajim.connections[account].connected]
icon = state_images[show]
item.set_image(icon)
account_menu = self.build_account_menu(account)
item.set_submenu(account_menu)
menu.append(item)
event_button = gtkgui_helpers.get_possible_button_event(event)
menu.attach_to_widget(self.tree, None)
menu.connect('selection-done', gtkgui_helpers.destroy_widget)
menu.show_all()
menu.popup(None, None, None, event_button, event.time)
2008-06-02 12:04:27 +02:00
def make_group_menu(self, event, titer):
'''Make group's popup menu'''
model = self.modelfilter
path = model.get_path(titer)
group = model[titer][C_JID].decode('utf-8')
account = model[titer][C_ACCOUNT].decode('utf-8')
2007-08-09 17:39:18 +02:00
list_ = [] # list of (jid, account) tuples
list_online = [] # list of (jid, account) tuples
2007-12-12 09:44:46 +01:00
group = model[titer][C_JID]
for jid in gajim.contacts.get_jid_list(account):
contact = gajim.contacts.get_contact_with_highest_priority(account,
jid)
if group in contact.get_shown_groups():
if contact.show not in ('offline', 'error'):
list_online.append((contact, account))
list_.append((contact, account))
menu = gtk.Menu()
2007-06-03 12:04:20 +02:00
# Make special context menu if group is Groupchats
if group == _('Groupchats'):
maximize_menuitem = gtk.ImageMenuItem(_('_Maximize All'))
icon = gtk.image_new_from_stock(gtk.STOCK_GOTO_TOP, gtk.ICON_SIZE_MENU)
maximize_menuitem.set_image(icon)
maximize_menuitem.connect('activate', self.on_all_groupchat_maximized,\
list_)
menu.append(maximize_menuitem)
2007-08-10 22:18:32 +02:00
else:
# Send Group Message
send_group_message_item = gtk.ImageMenuItem(_('Send Group M_essage'))
icon = gtk.image_new_from_stock(gtk.STOCK_NEW, gtk.ICON_SIZE_MENU)
send_group_message_item.set_image(icon)
2006-11-18 21:52:28 +01:00
send_group_message_submenu = gtk.Menu()
send_group_message_item.set_submenu(send_group_message_submenu)
menu.append(send_group_message_item)
2007-12-12 09:44:46 +01:00
group_message_to_all_item = gtk.MenuItem(_('To all users'))
send_group_message_submenu.append(group_message_to_all_item)
2007-12-12 09:44:46 +01:00
2008-06-02 12:04:27 +02:00
group_message_to_all_online_item = gtk.MenuItem(
_('To all online users'))
send_group_message_submenu.append(group_message_to_all_online_item)
group_message_to_all_online_item.connect('activate',
self.on_send_single_message_menuitem_activate, account, list_online)
group_message_to_all_item.connect('activate',
self.on_send_single_message_menuitem_activate, account, list_)
2006-11-18 21:52:28 +01:00
# Invite to
invite_menuitem = gtk.ImageMenuItem(_('In_vite to'))
muc_icon = gtkgui_helpers.load_icon('muc_active')
if muc_icon:
invite_menuitem.set_image(muc_icon)
gui_menu_builder.build_invite_submenu(invite_menuitem, list_online)
menu.append(invite_menuitem)
# Send Custom Status
2008-06-02 12:04:27 +02:00
send_custom_status_menuitem = gtk.ImageMenuItem(
_('Send Cus_tom Status'))
# add a special img for this menuitem
if helpers.group_is_blocked(account, group):
2008-06-02 12:04:27 +02:00
send_custom_status_menuitem.set_image(gtkgui_helpers.load_icon(
'offline'))
send_custom_status_menuitem.set_sensitive(False)
2007-12-12 09:44:46 +01:00
else:
icon = gtk.image_new_from_stock(gtk.STOCK_NETWORK,
gtk.ICON_SIZE_MENU)
send_custom_status_menuitem.set_image(icon)
status_menuitems = gtk.Menu()
send_custom_status_menuitem.set_submenu(status_menuitems)
iconset = gajim.config.get('iconset')
path = os.path.join(helpers.get_iconset_path(iconset), '16x16')
for s in ('online', 'chat', 'away', 'xa', 'dnd', 'offline'):
# icon MUST be different instance for every item
state_images = gtkgui_helpers.load_iconset(path)
status_menuitem = gtk.ImageMenuItem(helpers.get_uf_show(s))
2008-06-02 12:04:27 +02:00
status_menuitem.connect('activate', self.on_send_custom_status,
list_, s, group)
icon = state_images[s]
status_menuitem.set_image(icon)
status_menuitems.append(status_menuitem)
menu.append(send_custom_status_menuitem)
# there is no singlemessage and custom status for zeroconf
if gajim.config.get_per('accounts', account, 'is_zeroconf'):
send_custom_status_menuitem.set_sensitive(False)
send_group_message_item.set_sensitive(False)
2007-06-03 12:04:20 +02:00
if not group in helpers.special_groups:
item = gtk.SeparatorMenuItem() # separator
menu.append(item)
2007-06-03 12:04:20 +02:00
# Rename
rename_item = gtk.ImageMenuItem(_('Re_name'))
# add a special img for rename menuitem
path_to_kbd_input_img = os.path.join(gajim.DATA_DIR, 'pixmaps',
'kbd_input.png')
img = gtk.Image()
img.set_from_file(path_to_kbd_input_img)
rename_item.set_image(img)
menu.append(rename_item)
rename_item.connect('activate', self.on_rename, 'group', group,
account)
2006-01-06 07:59:55 +01:00
# Block group
is_blocked = False
if self.regroup:
for g_account in gajim.connections:
if helpers.group_is_blocked(g_account, group):
is_blocked = True
else:
if helpers.group_is_blocked(account, group):
is_blocked = True
2007-12-12 09:44:46 +01:00
if is_blocked and gajim.connections[account].privacy_rules_supported:
unblock_menuitem = gtk.ImageMenuItem(_('_Unblock'))
icon = gtk.image_new_from_stock(gtk.STOCK_STOP, gtk.ICON_SIZE_MENU)
unblock_menuitem.set_image(icon)
unblock_menuitem.connect('activate', self.on_unblock, list_, group)
menu.append(unblock_menuitem)
else:
block_menuitem = gtk.ImageMenuItem(_('_Block'))
icon = gtk.image_new_from_stock(gtk.STOCK_STOP, gtk.ICON_SIZE_MENU)
block_menuitem.set_image(icon)
block_menuitem.connect('activate', self.on_block, list_, group)
menu.append(block_menuitem)
if not gajim.connections[account].privacy_rules_supported:
block_menuitem.set_sensitive(False)
2006-01-06 07:59:55 +01:00
# Remove group
remove_item = gtk.ImageMenuItem(_('_Remove'))
icon = gtk.image_new_from_stock(gtk.STOCK_REMOVE, gtk.ICON_SIZE_MENU)
remove_item.set_image(icon)
menu.append(remove_item)
remove_item.connect('activate', self.on_remove_group_item_activated,
group, account)
2006-01-06 07:59:55 +01:00
# unsensitive if account is not connected
if gajim.connections[account].connected < 2:
rename_item.set_sensitive(False)
2006-01-06 07:59:55 +01:00
# General group cannot be changed
if group == _('General'):
rename_item.set_sensitive(False)
block_menuitem.set_sensitive(False)
remove_item.set_sensitive(False)
event_button = gtkgui_helpers.get_possible_button_event(event)
menu.attach_to_widget(self.tree, None)
menu.connect('selection-done', gtkgui_helpers.destroy_widget)
menu.show_all()
2008-06-02 12:04:27 +02:00
menu.popup(None, None, None, event_button, event.time)
def make_contact_menu(self, event, titer):
'''Make contact\'s popup menu'''
model = self.modelfilter
jid = model[titer][C_JID].decode('utf-8')
tree_path = model.get_path(titer)
account = model[titer][C_ACCOUNT].decode('utf-8')
contact = gajim.contacts.get_contact_with_highest_priority(account, jid)
menu = gui_menu_builder.get_contact_menu(contact, account)
event_button = gtkgui_helpers.get_possible_button_event(event)
menu.attach_to_widget(self.tree, None)
menu.popup(None, None, None, event_button, event.time)
2008-06-02 12:04:27 +02:00
def make_multiple_contact_menu(self, event, iters):
'''Make group's popup menu'''
model = self.modelfilter
list_ = [] # list of (jid, account) tuples
one_account_offline = False
is_blocked = True
privacy_rules_supported = True
for titer in iters:
jid = model[titer][C_JID].decode('utf-8')
account = model[titer][C_ACCOUNT].decode('utf-8')
if gajim.connections[account].connected < 2:
one_account_offline = True
if not gajim.connections[account].privacy_rules_supported:
privacy_rules_supported = False
contact = gajim.contacts.get_contact_with_highest_priority(account,
jid)
if helpers.jid_is_blocked(account, jid):
is_blocked = False
list_.append((contact, account))
menu = gtk.Menu()
account = None
for (contact, current_account) in list_:
# check that we use the same account for every sender
if account is not None and account != current_account:
account = None
break
account = current_account
if account is not None:
send_group_message_item = gtk.ImageMenuItem(_('Send Group M_essage'))
icon = gtk.image_new_from_stock(gtk.STOCK_NEW, gtk.ICON_SIZE_MENU)
send_group_message_item.set_image(icon)
menu.append(send_group_message_item)
send_group_message_item.connect('activate',
self.on_send_single_message_menuitem_activate, account, list_)
# Invite to Groupchat
invite_item = gtk.ImageMenuItem(_('In_vite to'))
muc_icon = gtkgui_helpers.load_icon('muc_active')
if muc_icon:
invite_item.set_image(muc_icon)
gui_menu_builder.build_invite_submenu(invite_item, list_)
menu.append(invite_item)
item = gtk.SeparatorMenuItem() # separator
menu.append(item)
# Manage Transport submenu
item = gtk.ImageMenuItem(_('_Manage Contacts'))
icon = gtk.image_new_from_stock(gtk.STOCK_PROPERTIES, gtk.ICON_SIZE_MENU)
item.set_image(icon)
manage_contacts_submenu = gtk.Menu()
item.set_submenu(manage_contacts_submenu)
menu.append(item)
# Edit Groups
edit_groups_item = gtk.ImageMenuItem(_('Edit _Groups'))
icon = gtk.image_new_from_stock(gtk.STOCK_EDIT, gtk.ICON_SIZE_MENU)
edit_groups_item.set_image(icon)
manage_contacts_submenu.append(edit_groups_item)
edit_groups_item.connect('activate', self.on_edit_groups, list_)
item = gtk.SeparatorMenuItem() # separator
manage_contacts_submenu.append(item)
2007-08-09 17:39:18 +02:00
# Block
if is_blocked and privacy_rules_supported:
unblock_menuitem = gtk.ImageMenuItem(_('_Unblock'))
icon = gtk.image_new_from_stock(gtk.STOCK_STOP, gtk.ICON_SIZE_MENU)
unblock_menuitem.set_image(icon)
unblock_menuitem.connect('activate', self.on_unblock, list_)
manage_contacts_submenu.append(unblock_menuitem)
Merge one_window branch Merged revisions 9143,9145-9155,9157-9162,9164-9169,9171-9177 via svnmerge from svn://88.191.11.156/gajim/branches/one_window ........ r9145 | nicfit | 2007-12-13 21:49:09 -0700 (Thu, 13 Dec 2007) | 2 lines Implemented the original Nikos patch with an HPaned instead of a HBox and only do this mode when one_message_window == 'always' ........ r9152 | nicfit | 2007-12-15 13:33:56 -0700 (Sat, 15 Dec 2007) | 2 lines Added config and GUI for one_message_window_with_roster ........ r9153 | nicfit | 2007-12-15 13:41:46 -0700 (Sat, 15 Dec 2007) | 2 lines Use one_message_window_with_roster and some whitespace cleanup ........ r9154 | nicfit | 2007-12-15 14:04:49 -0700 (Sat, 15 Dec 2007) | 2 lines Scratch the chckbox for with roster mode, use one_message_window opt and combo ........ r9155 | nicfit | 2007-12-15 17:01:13 -0700 (Sat, 15 Dec 2007) | 2 lines MessageWindowMgr knows about ONE_MESSAGE_WINDOW_ALWAYS_WITH_ROSTER and MessageWindow can reparent itself rather then the roster having to do so. ........ r9157 | nicfit | 2007-12-15 17:47:20 -0700 (Sat, 15 Dec 2007) | 2 lines Resizing fixes and make the roster window shrink when last tab is removed ........ r9158 | nicfit | 2007-12-15 19:15:11 -0700 (Sat, 15 Dec 2007) | 2 lines Added "Show roster" (CTRL+R) to view menu when using always_with_roster to quickly hide/show the roster. ........ r9159 | nicfit | 2007-12-15 19:49:30 -0700 (Sat, 15 Dec 2007) | 2 lines Handle window title setting in always_with_roster mode. ........ r9160 | nicfit | 2007-12-15 20:13:57 -0700 (Sat, 15 Dec 2007) | 2 lines Removed FIXME ........ r9167 | nicfit | 2007-12-17 18:40:59 -0700 (Mon, 17 Dec 2007) | 2 lines When roster is hidden, show it when the number of MessageWindow controls == 0 ........ r9168 | nicfit | 2007-12-17 19:07:49 -0700 (Mon, 17 Dec 2007) | 2 lines Disable hiding roster when there are no message controls open ........ r9169 | nicfit | 2007-12-17 20:41:11 -0700 (Mon, 17 Dec 2007) | 2 lines Bunch of saved size bugs fixed ........
2007-12-19 00:42:22 +01:00
else:
block_menuitem = gtk.ImageMenuItem(_('_Block'))
icon = gtk.image_new_from_stock(gtk.STOCK_STOP, gtk.ICON_SIZE_MENU)
block_menuitem.set_image(icon)
block_menuitem.connect('activate', self.on_block, list_)
manage_contacts_submenu.append(block_menuitem)
Merge one_window branch Merged revisions 9143,9145-9155,9157-9162,9164-9169,9171-9177 via svnmerge from svn://88.191.11.156/gajim/branches/one_window ........ r9145 | nicfit | 2007-12-13 21:49:09 -0700 (Thu, 13 Dec 2007) | 2 lines Implemented the original Nikos patch with an HPaned instead of a HBox and only do this mode when one_message_window == 'always' ........ r9152 | nicfit | 2007-12-15 13:33:56 -0700 (Sat, 15 Dec 2007) | 2 lines Added config and GUI for one_message_window_with_roster ........ r9153 | nicfit | 2007-12-15 13:41:46 -0700 (Sat, 15 Dec 2007) | 2 lines Use one_message_window_with_roster and some whitespace cleanup ........ r9154 | nicfit | 2007-12-15 14:04:49 -0700 (Sat, 15 Dec 2007) | 2 lines Scratch the chckbox for with roster mode, use one_message_window opt and combo ........ r9155 | nicfit | 2007-12-15 17:01:13 -0700 (Sat, 15 Dec 2007) | 2 lines MessageWindowMgr knows about ONE_MESSAGE_WINDOW_ALWAYS_WITH_ROSTER and MessageWindow can reparent itself rather then the roster having to do so. ........ r9157 | nicfit | 2007-12-15 17:47:20 -0700 (Sat, 15 Dec 2007) | 2 lines Resizing fixes and make the roster window shrink when last tab is removed ........ r9158 | nicfit | 2007-12-15 19:15:11 -0700 (Sat, 15 Dec 2007) | 2 lines Added "Show roster" (CTRL+R) to view menu when using always_with_roster to quickly hide/show the roster. ........ r9159 | nicfit | 2007-12-15 19:49:30 -0700 (Sat, 15 Dec 2007) | 2 lines Handle window title setting in always_with_roster mode. ........ r9160 | nicfit | 2007-12-15 20:13:57 -0700 (Sat, 15 Dec 2007) | 2 lines Removed FIXME ........ r9167 | nicfit | 2007-12-17 18:40:59 -0700 (Mon, 17 Dec 2007) | 2 lines When roster is hidden, show it when the number of MessageWindow controls == 0 ........ r9168 | nicfit | 2007-12-17 19:07:49 -0700 (Mon, 17 Dec 2007) | 2 lines Disable hiding roster when there are no message controls open ........ r9169 | nicfit | 2007-12-17 20:41:11 -0700 (Mon, 17 Dec 2007) | 2 lines Bunch of saved size bugs fixed ........
2007-12-19 00:42:22 +01:00
if not privacy_rules_supported:
block_menuitem.set_sensitive(False)
Merge one_window branch Merged revisions 9143,9145-9155,9157-9162,9164-9169,9171-9177 via svnmerge from svn://88.191.11.156/gajim/branches/one_window ........ r9145 | nicfit | 2007-12-13 21:49:09 -0700 (Thu, 13 Dec 2007) | 2 lines Implemented the original Nikos patch with an HPaned instead of a HBox and only do this mode when one_message_window == 'always' ........ r9152 | nicfit | 2007-12-15 13:33:56 -0700 (Sat, 15 Dec 2007) | 2 lines Added config and GUI for one_message_window_with_roster ........ r9153 | nicfit | 2007-12-15 13:41:46 -0700 (Sat, 15 Dec 2007) | 2 lines Use one_message_window_with_roster and some whitespace cleanup ........ r9154 | nicfit | 2007-12-15 14:04:49 -0700 (Sat, 15 Dec 2007) | 2 lines Scratch the chckbox for with roster mode, use one_message_window opt and combo ........ r9155 | nicfit | 2007-12-15 17:01:13 -0700 (Sat, 15 Dec 2007) | 2 lines MessageWindowMgr knows about ONE_MESSAGE_WINDOW_ALWAYS_WITH_ROSTER and MessageWindow can reparent itself rather then the roster having to do so. ........ r9157 | nicfit | 2007-12-15 17:47:20 -0700 (Sat, 15 Dec 2007) | 2 lines Resizing fixes and make the roster window shrink when last tab is removed ........ r9158 | nicfit | 2007-12-15 19:15:11 -0700 (Sat, 15 Dec 2007) | 2 lines Added "Show roster" (CTRL+R) to view menu when using always_with_roster to quickly hide/show the roster. ........ r9159 | nicfit | 2007-12-15 19:49:30 -0700 (Sat, 15 Dec 2007) | 2 lines Handle window title setting in always_with_roster mode. ........ r9160 | nicfit | 2007-12-15 20:13:57 -0700 (Sat, 15 Dec 2007) | 2 lines Removed FIXME ........ r9167 | nicfit | 2007-12-17 18:40:59 -0700 (Mon, 17 Dec 2007) | 2 lines When roster is hidden, show it when the number of MessageWindow controls == 0 ........ r9168 | nicfit | 2007-12-17 19:07:49 -0700 (Mon, 17 Dec 2007) | 2 lines Disable hiding roster when there are no message controls open ........ r9169 | nicfit | 2007-12-17 20:41:11 -0700 (Mon, 17 Dec 2007) | 2 lines Bunch of saved size bugs fixed ........
2007-12-19 00:42:22 +01:00
# Remove
remove_item = gtk.ImageMenuItem(_('_Remove'))
icon = gtk.image_new_from_stock(gtk.STOCK_REMOVE, gtk.ICON_SIZE_MENU)
remove_item.set_image(icon)
manage_contacts_submenu.append(remove_item)
remove_item.connect('activate', self.on_req_usub, list_)
# unsensitive remove if one account is not connected
if one_account_offline:
remove_item.set_sensitive(False)
Merge one_window branch Merged revisions 9143,9145-9155,9157-9162,9164-9169,9171-9177 via svnmerge from svn://88.191.11.156/gajim/branches/one_window ........ r9145 | nicfit | 2007-12-13 21:49:09 -0700 (Thu, 13 Dec 2007) | 2 lines Implemented the original Nikos patch with an HPaned instead of a HBox and only do this mode when one_message_window == 'always' ........ r9152 | nicfit | 2007-12-15 13:33:56 -0700 (Sat, 15 Dec 2007) | 2 lines Added config and GUI for one_message_window_with_roster ........ r9153 | nicfit | 2007-12-15 13:41:46 -0700 (Sat, 15 Dec 2007) | 2 lines Use one_message_window_with_roster and some whitespace cleanup ........ r9154 | nicfit | 2007-12-15 14:04:49 -0700 (Sat, 15 Dec 2007) | 2 lines Scratch the chckbox for with roster mode, use one_message_window opt and combo ........ r9155 | nicfit | 2007-12-15 17:01:13 -0700 (Sat, 15 Dec 2007) | 2 lines MessageWindowMgr knows about ONE_MESSAGE_WINDOW_ALWAYS_WITH_ROSTER and MessageWindow can reparent itself rather then the roster having to do so. ........ r9157 | nicfit | 2007-12-15 17:47:20 -0700 (Sat, 15 Dec 2007) | 2 lines Resizing fixes and make the roster window shrink when last tab is removed ........ r9158 | nicfit | 2007-12-15 19:15:11 -0700 (Sat, 15 Dec 2007) | 2 lines Added "Show roster" (CTRL+R) to view menu when using always_with_roster to quickly hide/show the roster. ........ r9159 | nicfit | 2007-12-15 19:49:30 -0700 (Sat, 15 Dec 2007) | 2 lines Handle window title setting in always_with_roster mode. ........ r9160 | nicfit | 2007-12-15 20:13:57 -0700 (Sat, 15 Dec 2007) | 2 lines Removed FIXME ........ r9167 | nicfit | 2007-12-17 18:40:59 -0700 (Mon, 17 Dec 2007) | 2 lines When roster is hidden, show it when the number of MessageWindow controls == 0 ........ r9168 | nicfit | 2007-12-17 19:07:49 -0700 (Mon, 17 Dec 2007) | 2 lines Disable hiding roster when there are no message controls open ........ r9169 | nicfit | 2007-12-17 20:41:11 -0700 (Mon, 17 Dec 2007) | 2 lines Bunch of saved size bugs fixed ........
2007-12-19 00:42:22 +01:00
event_button = gtkgui_helpers.get_possible_button_event(event)
2007-08-09 17:39:18 +02:00
menu.attach_to_widget(self.tree, None)
menu.connect('selection-done', gtkgui_helpers.destroy_widget)
menu.show_all()
menu.popup(None, None, None, event_button, event.time)
2008-06-02 12:04:27 +02:00
def make_transport_menu(self, event, titer):
'''Make transport\'s popup menu'''
model = self.modelfilter
jid = model[titer][C_JID].decode('utf-8')
path = model.get_path(titer)
account = model[titer][C_ACCOUNT].decode('utf-8')
contact = gajim.contacts.get_contact_with_highest_priority(account, jid)
menu = gtk.Menu()
# Send single message
item = gtk.ImageMenuItem(_('Send Single Message'))
icon = gtk.image_new_from_stock(gtk.STOCK_NEW, gtk.ICON_SIZE_MENU)
item.set_image(icon)
item.connect('activate',
self.on_send_single_message_menuitem_activate, account, contact)
menu.append(item)
blocked = False
if helpers.jid_is_blocked(account, jid):
blocked = True
# Send Custom Status
send_custom_status_menuitem = gtk.ImageMenuItem(_('Send Cus_tom Status'))
# add a special img for this menuitem
if blocked:
2008-06-02 12:04:27 +02:00
send_custom_status_menuitem.set_image(gtkgui_helpers.load_icon(
'offline'))
send_custom_status_menuitem.set_sensitive(False)
else:
if account in gajim.interface.status_sent_to_users and \
jid in gajim.interface.status_sent_to_users[account]:
send_custom_status_menuitem.set_image(gtkgui_helpers.load_icon(
gajim.interface.status_sent_to_users[account][jid]))
else:
icon = gtk.image_new_from_stock(gtk.STOCK_NETWORK,
gtk.ICON_SIZE_MENU)
send_custom_status_menuitem.set_image(icon)
status_menuitems = gtk.Menu()
send_custom_status_menuitem.set_submenu(status_menuitems)
iconset = gajim.config.get('iconset')
path = os.path.join(helpers.get_iconset_path(iconset), '16x16')
for s in ('online', 'chat', 'away', 'xa', 'dnd', 'offline'):
# icon MUST be different instance for every item
state_images = gtkgui_helpers.load_iconset(path)
status_menuitem = gtk.ImageMenuItem(helpers.get_uf_show(s))
status_menuitem.connect('activate', self.on_send_custom_status,
[(contact, account)], s)
icon = state_images[s]
status_menuitem.set_image(icon)
status_menuitems.append(status_menuitem)
menu.append(send_custom_status_menuitem)
item = gtk.SeparatorMenuItem() # separator
menu.append(item)
# Execute Command
item = gtk.ImageMenuItem(_('Execute Command...'))
icon = gtk.image_new_from_stock(gtk.STOCK_EXECUTE, gtk.ICON_SIZE_MENU)
item.set_image(icon)
menu.append(item)
item.connect('activate', self.on_execute_command, contact, account,
contact.resource)
if gajim.account_is_disconnected(account):
item.set_sensitive(False)
# Manage Transport submenu
item = gtk.ImageMenuItem(_('_Manage Transport'))
icon = gtk.image_new_from_stock(gtk.STOCK_PROPERTIES, gtk.ICON_SIZE_MENU)
item.set_image(icon)
manage_transport_submenu = gtk.Menu()
item.set_submenu(manage_transport_submenu)
menu.append(item)
# Modify Transport
item = gtk.ImageMenuItem(_('_Modify Transport'))
icon = gtk.image_new_from_stock(gtk.STOCK_PREFERENCES, gtk.ICON_SIZE_MENU)
item.set_image(icon)
manage_transport_submenu.append(item)
item.connect('activate', self.on_edit_agent, contact, account)
if gajim.account_is_disconnected(account):
item.set_sensitive(False)
# Rename
item = gtk.ImageMenuItem(_('_Rename'))
# add a special img for rename menuitem
path_to_kbd_input_img = os.path.join(gajim.DATA_DIR, 'pixmaps',
'kbd_input.png')
img = gtk.Image()
img.set_from_file(path_to_kbd_input_img)
item.set_image(img)
manage_transport_submenu.append(item)
item.connect('activate', self.on_rename, 'agent', jid, account)
if gajim.account_is_disconnected(account):
item.set_sensitive(False)
item = gtk.SeparatorMenuItem() # separator
manage_transport_submenu.append(item)
# Block
if blocked:
item = gtk.ImageMenuItem(_('_Unblock'))
item.connect('activate', self.on_unblock, [(contact, account)])
else:
item = gtk.ImageMenuItem(_('_Block'))
item.connect('activate', self.on_block, [(contact, account)])
icon = gtk.image_new_from_stock(gtk.STOCK_STOP, gtk.ICON_SIZE_MENU)
item.set_image(icon)
manage_transport_submenu.append(item)
if gajim.account_is_disconnected(account):
item.set_sensitive(False)
# Remove
item = gtk.ImageMenuItem(_('_Remove'))
icon = gtk.image_new_from_stock(gtk.STOCK_REMOVE, gtk.ICON_SIZE_MENU)
item.set_image(icon)
manage_transport_submenu.append(item)
item.connect('activate', self.on_remove_agent, [(contact, account)])
if gajim.account_is_disconnected(account):
item.set_sensitive(False)
item = gtk.SeparatorMenuItem() # separator
menu.append(item)
# Information
information_menuitem = gtk.ImageMenuItem(_('_Information'))
icon = gtk.image_new_from_stock(gtk.STOCK_INFO, gtk.ICON_SIZE_MENU)
information_menuitem.set_image(icon)
menu.append(information_menuitem)
information_menuitem.connect('activate', self.on_info, contact, account)
2006-11-18 21:52:28 +01:00
event_button = gtkgui_helpers.get_possible_button_event(event)
menu.attach_to_widget(self.tree, None)
menu.connect('selection-done', gtkgui_helpers.destroy_widget)
menu.show_all()
menu.popup(None, None, None, event_button, event.time)
def make_groupchat_menu(self, event, titer):
model = self.modelfilter
2007-08-09 17:39:18 +02:00
jid = model[titer][C_JID].decode('utf-8')
account = model[titer][C_ACCOUNT].decode('utf-8')
contact = gajim.contacts.get_contact_with_highest_priority(account, jid)
menu = gtk.Menu()
if jid in gajim.interface.minimized_controls[account]:
maximize_menuitem = gtk.ImageMenuItem(_('_Maximize'))
icon = gtk.image_new_from_stock(gtk.STOCK_GOTO_TOP, gtk.ICON_SIZE_MENU)
maximize_menuitem.set_image(icon)
maximize_menuitem.connect('activate', self.on_groupchat_maximized, \
jid, account)
menu.append(maximize_menuitem)
Merged revisions 5017-5020,5022-5029 via svnmerge from svn://svn.gajim.org/gajim/trunk ........ r5017 | asterix | 2006-01-06 01:55:51 -0700 (Fri, 06 Jan 2006) | 2 lines use escape for pango markup ........ r5018 | asterix | 2006-01-06 02:21:39 -0700 (Fri, 06 Jan 2006) | 2 lines missing new contacts function ........ r5019 | asterix | 2006-01-06 11:03:07 -0700 (Fri, 06 Jan 2006) | 2 lines handle the click on toggle_gpg_encryption menuitem ........ r5020 | asterix | 2006-01-06 11:14:14 -0700 (Fri, 06 Jan 2006) | 2 lines use the saved size even if a chat window is already opened ........ r5022 | asterix | 2006-01-07 03:43:47 -0700 (Sat, 07 Jan 2006) | 2 lines we can now resume filetransfert ........ r5023 | asterix | 2006-01-07 03:56:31 -0700 (Sat, 07 Jan 2006) | 2 lines [Knuckles] Google E-Mail Notification ........ r5024 | asterix | 2006-01-07 04:02:16 -0700 (Sat, 07 Jan 2006) | 2 lines better string ........ r5025 | asterix | 2006-01-07 04:14:32 -0700 (Sat, 07 Jan 2006) | 2 lines fix a TB ........ r5026 | asterix | 2006-01-07 05:36:55 -0700 (Sat, 07 Jan 2006) | 2 lines we can now drag a file on a contact in the roster to send him a file ........ r5027 | asterix | 2006-01-07 06:26:28 -0700 (Sat, 07 Jan 2006) | 2 lines contact.groups is always a list, even if emtpy ........ r5028 | asterix | 2006-01-07 06:54:30 -0700 (Sat, 07 Jan 2006) | 2 lines make all buttons insensitive on a category row in disco ........ r5029 | asterix | 2006-01-07 07:19:25 -0700 (Sat, 07 Jan 2006) | 2 lines auto open groupchat configuration window when we create a new room ........
2006-01-07 18:25:35 +01:00
if not gajim.gc_connected[account].get(jid, False):
connect_menuitem = gtk.ImageMenuItem(_('_Reconnect'))
connect_icon = gtk.image_new_from_stock(gtk.STOCK_CONNECT, \
gtk.ICON_SIZE_MENU)
connect_menuitem.set_image(connect_icon)
connect_menuitem.connect('activate', self.on_reconnect, jid, account)
menu.append(connect_menuitem)
disconnect_menuitem = gtk.ImageMenuItem(_('_Disconnect'))
disconnect_icon = gtk.image_new_from_stock(gtk.STOCK_DISCONNECT, \
gtk.ICON_SIZE_MENU)
disconnect_menuitem.set_image(disconnect_icon)
disconnect_menuitem.connect('activate', self.on_disconnect, jid, account)
menu.append(disconnect_menuitem)
Merge one_window branch Merged revisions 9143,9145-9155,9157-9162,9164-9169,9171-9177 via svnmerge from svn://88.191.11.156/gajim/branches/one_window ........ r9145 | nicfit | 2007-12-13 21:49:09 -0700 (Thu, 13 Dec 2007) | 2 lines Implemented the original Nikos patch with an HPaned instead of a HBox and only do this mode when one_message_window == 'always' ........ r9152 | nicfit | 2007-12-15 13:33:56 -0700 (Sat, 15 Dec 2007) | 2 lines Added config and GUI for one_message_window_with_roster ........ r9153 | nicfit | 2007-12-15 13:41:46 -0700 (Sat, 15 Dec 2007) | 2 lines Use one_message_window_with_roster and some whitespace cleanup ........ r9154 | nicfit | 2007-12-15 14:04:49 -0700 (Sat, 15 Dec 2007) | 2 lines Scratch the chckbox for with roster mode, use one_message_window opt and combo ........ r9155 | nicfit | 2007-12-15 17:01:13 -0700 (Sat, 15 Dec 2007) | 2 lines MessageWindowMgr knows about ONE_MESSAGE_WINDOW_ALWAYS_WITH_ROSTER and MessageWindow can reparent itself rather then the roster having to do so. ........ r9157 | nicfit | 2007-12-15 17:47:20 -0700 (Sat, 15 Dec 2007) | 2 lines Resizing fixes and make the roster window shrink when last tab is removed ........ r9158 | nicfit | 2007-12-15 19:15:11 -0700 (Sat, 15 Dec 2007) | 2 lines Added "Show roster" (CTRL+R) to view menu when using always_with_roster to quickly hide/show the roster. ........ r9159 | nicfit | 2007-12-15 19:49:30 -0700 (Sat, 15 Dec 2007) | 2 lines Handle window title setting in always_with_roster mode. ........ r9160 | nicfit | 2007-12-15 20:13:57 -0700 (Sat, 15 Dec 2007) | 2 lines Removed FIXME ........ r9167 | nicfit | 2007-12-17 18:40:59 -0700 (Mon, 17 Dec 2007) | 2 lines When roster is hidden, show it when the number of MessageWindow controls == 0 ........ r9168 | nicfit | 2007-12-17 19:07:49 -0700 (Mon, 17 Dec 2007) | 2 lines Disable hiding roster when there are no message controls open ........ r9169 | nicfit | 2007-12-17 20:41:11 -0700 (Mon, 17 Dec 2007) | 2 lines Bunch of saved size bugs fixed ........
2007-12-19 00:42:22 +01:00
item = gtk.SeparatorMenuItem() # separator
menu.append(item)
history_menuitem = gtk.ImageMenuItem(_('_History'))
history_icon = gtk.image_new_from_stock(gtk.STOCK_JUSTIFY_FILL, \
gtk.ICON_SIZE_MENU)
history_menuitem.set_image(history_icon)
history_menuitem .connect('activate', self.on_history, \
contact, account)
menu.append(history_menuitem)
Merge one_window branch Merged revisions 9143,9145-9155,9157-9162,9164-9169,9171-9177 via svnmerge from svn://88.191.11.156/gajim/branches/one_window ........ r9145 | nicfit | 2007-12-13 21:49:09 -0700 (Thu, 13 Dec 2007) | 2 lines Implemented the original Nikos patch with an HPaned instead of a HBox and only do this mode when one_message_window == 'always' ........ r9152 | nicfit | 2007-12-15 13:33:56 -0700 (Sat, 15 Dec 2007) | 2 lines Added config and GUI for one_message_window_with_roster ........ r9153 | nicfit | 2007-12-15 13:41:46 -0700 (Sat, 15 Dec 2007) | 2 lines Use one_message_window_with_roster and some whitespace cleanup ........ r9154 | nicfit | 2007-12-15 14:04:49 -0700 (Sat, 15 Dec 2007) | 2 lines Scratch the chckbox for with roster mode, use one_message_window opt and combo ........ r9155 | nicfit | 2007-12-15 17:01:13 -0700 (Sat, 15 Dec 2007) | 2 lines MessageWindowMgr knows about ONE_MESSAGE_WINDOW_ALWAYS_WITH_ROSTER and MessageWindow can reparent itself rather then the roster having to do so. ........ r9157 | nicfit | 2007-12-15 17:47:20 -0700 (Sat, 15 Dec 2007) | 2 lines Resizing fixes and make the roster window shrink when last tab is removed ........ r9158 | nicfit | 2007-12-15 19:15:11 -0700 (Sat, 15 Dec 2007) | 2 lines Added "Show roster" (CTRL+R) to view menu when using always_with_roster to quickly hide/show the roster. ........ r9159 | nicfit | 2007-12-15 19:49:30 -0700 (Sat, 15 Dec 2007) | 2 lines Handle window title setting in always_with_roster mode. ........ r9160 | nicfit | 2007-12-15 20:13:57 -0700 (Sat, 15 Dec 2007) | 2 lines Removed FIXME ........ r9167 | nicfit | 2007-12-17 18:40:59 -0700 (Mon, 17 Dec 2007) | 2 lines When roster is hidden, show it when the number of MessageWindow controls == 0 ........ r9168 | nicfit | 2007-12-17 19:07:49 -0700 (Mon, 17 Dec 2007) | 2 lines Disable hiding roster when there are no message controls open ........ r9169 | nicfit | 2007-12-17 20:41:11 -0700 (Mon, 17 Dec 2007) | 2 lines Bunch of saved size bugs fixed ........
2007-12-19 00:42:22 +01:00
event_button = gtkgui_helpers.get_possible_button_event(event)
2007-08-09 17:39:18 +02:00
menu.attach_to_widget(self.tree, None)
menu.connect('selection-done', gtkgui_helpers.destroy_widget)
menu.show_all()
menu.popup(None, None, None, event_button, event.time)
2008-06-02 12:04:27 +02:00
def get_and_connect_advanced_menuitem_menu(self, account):
'''adds FOR ACCOUNT options'''
xml = gtkgui_helpers.get_glade('advanced_menuitem_menu.glade')
advanced_menuitem_menu = xml.get_widget('advanced_menuitem_menu')
2006-07-17 21:30:53 +02:00
xml_console_menuitem = xml.get_widget('xml_console_menuitem')
archiving_preferences_menuitem = \
xml.get_widget('archiving_preferences_menuitem')
privacy_lists_menuitem = xml.get_widget('privacy_lists_menuitem')
administrator_menuitem = xml.get_widget('administrator_menuitem')
send_server_message_menuitem = xml.get_widget(
'send_server_message_menuitem')
set_motd_menuitem = xml.get_widget('set_motd_menuitem')
update_motd_menuitem = xml.get_widget('update_motd_menuitem')
delete_motd_menuitem = xml.get_widget('delete_motd_menuitem')
Merge one_window branch Merged revisions 9143,9145-9155,9157-9162,9164-9169,9171-9177 via svnmerge from svn://88.191.11.156/gajim/branches/one_window ........ r9145 | nicfit | 2007-12-13 21:49:09 -0700 (Thu, 13 Dec 2007) | 2 lines Implemented the original Nikos patch with an HPaned instead of a HBox and only do this mode when one_message_window == 'always' ........ r9152 | nicfit | 2007-12-15 13:33:56 -0700 (Sat, 15 Dec 2007) | 2 lines Added config and GUI for one_message_window_with_roster ........ r9153 | nicfit | 2007-12-15 13:41:46 -0700 (Sat, 15 Dec 2007) | 2 lines Use one_message_window_with_roster and some whitespace cleanup ........ r9154 | nicfit | 2007-12-15 14:04:49 -0700 (Sat, 15 Dec 2007) | 2 lines Scratch the chckbox for with roster mode, use one_message_window opt and combo ........ r9155 | nicfit | 2007-12-15 17:01:13 -0700 (Sat, 15 Dec 2007) | 2 lines MessageWindowMgr knows about ONE_MESSAGE_WINDOW_ALWAYS_WITH_ROSTER and MessageWindow can reparent itself rather then the roster having to do so. ........ r9157 | nicfit | 2007-12-15 17:47:20 -0700 (Sat, 15 Dec 2007) | 2 lines Resizing fixes and make the roster window shrink when last tab is removed ........ r9158 | nicfit | 2007-12-15 19:15:11 -0700 (Sat, 15 Dec 2007) | 2 lines Added "Show roster" (CTRL+R) to view menu when using always_with_roster to quickly hide/show the roster. ........ r9159 | nicfit | 2007-12-15 19:49:30 -0700 (Sat, 15 Dec 2007) | 2 lines Handle window title setting in always_with_roster mode. ........ r9160 | nicfit | 2007-12-15 20:13:57 -0700 (Sat, 15 Dec 2007) | 2 lines Removed FIXME ........ r9167 | nicfit | 2007-12-17 18:40:59 -0700 (Mon, 17 Dec 2007) | 2 lines When roster is hidden, show it when the number of MessageWindow controls == 0 ........ r9168 | nicfit | 2007-12-17 19:07:49 -0700 (Mon, 17 Dec 2007) | 2 lines Disable hiding roster when there are no message controls open ........ r9169 | nicfit | 2007-12-17 20:41:11 -0700 (Mon, 17 Dec 2007) | 2 lines Bunch of saved size bugs fixed ........
2007-12-19 00:42:22 +01:00
xml_console_menuitem.connect('activate',
self.on_xml_console_menuitem_activate, account)
Merge one_window branch Merged revisions 9143,9145-9155,9157-9162,9164-9169,9171-9177 via svnmerge from svn://88.191.11.156/gajim/branches/one_window ........ r9145 | nicfit | 2007-12-13 21:49:09 -0700 (Thu, 13 Dec 2007) | 2 lines Implemented the original Nikos patch with an HPaned instead of a HBox and only do this mode when one_message_window == 'always' ........ r9152 | nicfit | 2007-12-15 13:33:56 -0700 (Sat, 15 Dec 2007) | 2 lines Added config and GUI for one_message_window_with_roster ........ r9153 | nicfit | 2007-12-15 13:41:46 -0700 (Sat, 15 Dec 2007) | 2 lines Use one_message_window_with_roster and some whitespace cleanup ........ r9154 | nicfit | 2007-12-15 14:04:49 -0700 (Sat, 15 Dec 2007) | 2 lines Scratch the chckbox for with roster mode, use one_message_window opt and combo ........ r9155 | nicfit | 2007-12-15 17:01:13 -0700 (Sat, 15 Dec 2007) | 2 lines MessageWindowMgr knows about ONE_MESSAGE_WINDOW_ALWAYS_WITH_ROSTER and MessageWindow can reparent itself rather then the roster having to do so. ........ r9157 | nicfit | 2007-12-15 17:47:20 -0700 (Sat, 15 Dec 2007) | 2 lines Resizing fixes and make the roster window shrink when last tab is removed ........ r9158 | nicfit | 2007-12-15 19:15:11 -0700 (Sat, 15 Dec 2007) | 2 lines Added "Show roster" (CTRL+R) to view menu when using always_with_roster to quickly hide/show the roster. ........ r9159 | nicfit | 2007-12-15 19:49:30 -0700 (Sat, 15 Dec 2007) | 2 lines Handle window title setting in always_with_roster mode. ........ r9160 | nicfit | 2007-12-15 20:13:57 -0700 (Sat, 15 Dec 2007) | 2 lines Removed FIXME ........ r9167 | nicfit | 2007-12-17 18:40:59 -0700 (Mon, 17 Dec 2007) | 2 lines When roster is hidden, show it when the number of MessageWindow controls == 0 ........ r9168 | nicfit | 2007-12-17 19:07:49 -0700 (Mon, 17 Dec 2007) | 2 lines Disable hiding roster when there are no message controls open ........ r9169 | nicfit | 2007-12-17 20:41:11 -0700 (Mon, 17 Dec 2007) | 2 lines Bunch of saved size bugs fixed ........
2007-12-19 00:42:22 +01:00
if gajim.connections[account]:
if gajim.connections[account].privacy_rules_supported:
privacy_lists_menuitem.connect('activate',
self.on_privacy_lists_menuitem_activate, account)
else:
privacy_lists_menuitem.set_sensitive(False)
if gajim.connections[account].archive_pref_supported:
archiving_preferences_menuitem.connect('activate',
self.on_archiving_preferences_menuitem_activate, account)
else:
archiving_preferences_menuitem.set_sensitive(False)
2006-07-17 21:30:53 +02:00
if gajim.connections[account].is_zeroconf:
administrator_menuitem.set_sensitive(False)
send_server_message_menuitem.set_sensitive(False)
set_motd_menuitem.set_sensitive(False)
update_motd_menuitem.set_sensitive(False)
delete_motd_menuitem.set_sensitive(False)
else:
send_server_message_menuitem.connect('activate',
self.on_send_server_message_menuitem_activate, account)
2007-08-09 17:39:18 +02:00
set_motd_menuitem.connect('activate',
self.on_set_motd_menuitem_activate, account)
Merge one_window branch Merged revisions 9143,9145-9155,9157-9162,9164-9169,9171-9177 via svnmerge from svn://88.191.11.156/gajim/branches/one_window ........ r9145 | nicfit | 2007-12-13 21:49:09 -0700 (Thu, 13 Dec 2007) | 2 lines Implemented the original Nikos patch with an HPaned instead of a HBox and only do this mode when one_message_window == 'always' ........ r9152 | nicfit | 2007-12-15 13:33:56 -0700 (Sat, 15 Dec 2007) | 2 lines Added config and GUI for one_message_window_with_roster ........ r9153 | nicfit | 2007-12-15 13:41:46 -0700 (Sat, 15 Dec 2007) | 2 lines Use one_message_window_with_roster and some whitespace cleanup ........ r9154 | nicfit | 2007-12-15 14:04:49 -0700 (Sat, 15 Dec 2007) | 2 lines Scratch the chckbox for with roster mode, use one_message_window opt and combo ........ r9155 | nicfit | 2007-12-15 17:01:13 -0700 (Sat, 15 Dec 2007) | 2 lines MessageWindowMgr knows about ONE_MESSAGE_WINDOW_ALWAYS_WITH_ROSTER and MessageWindow can reparent itself rather then the roster having to do so. ........ r9157 | nicfit | 2007-12-15 17:47:20 -0700 (Sat, 15 Dec 2007) | 2 lines Resizing fixes and make the roster window shrink when last tab is removed ........ r9158 | nicfit | 2007-12-15 19:15:11 -0700 (Sat, 15 Dec 2007) | 2 lines Added "Show roster" (CTRL+R) to view menu when using always_with_roster to quickly hide/show the roster. ........ r9159 | nicfit | 2007-12-15 19:49:30 -0700 (Sat, 15 Dec 2007) | 2 lines Handle window title setting in always_with_roster mode. ........ r9160 | nicfit | 2007-12-15 20:13:57 -0700 (Sat, 15 Dec 2007) | 2 lines Removed FIXME ........ r9167 | nicfit | 2007-12-17 18:40:59 -0700 (Mon, 17 Dec 2007) | 2 lines When roster is hidden, show it when the number of MessageWindow controls == 0 ........ r9168 | nicfit | 2007-12-17 19:07:49 -0700 (Mon, 17 Dec 2007) | 2 lines Disable hiding roster when there are no message controls open ........ r9169 | nicfit | 2007-12-17 20:41:11 -0700 (Mon, 17 Dec 2007) | 2 lines Bunch of saved size bugs fixed ........
2007-12-19 00:42:22 +01:00
update_motd_menuitem.connect('activate',
self.on_update_motd_menuitem_activate, account)
delete_motd_menuitem.connect('activate',
self.on_delete_motd_menuitem_activate, account)
Merge one_window branch Merged revisions 9143,9145-9155,9157-9162,9164-9169,9171-9177 via svnmerge from svn://88.191.11.156/gajim/branches/one_window ........ r9145 | nicfit | 2007-12-13 21:49:09 -0700 (Thu, 13 Dec 2007) | 2 lines Implemented the original Nikos patch with an HPaned instead of a HBox and only do this mode when one_message_window == 'always' ........ r9152 | nicfit | 2007-12-15 13:33:56 -0700 (Sat, 15 Dec 2007) | 2 lines Added config and GUI for one_message_window_with_roster ........ r9153 | nicfit | 2007-12-15 13:41:46 -0700 (Sat, 15 Dec 2007) | 2 lines Use one_message_window_with_roster and some whitespace cleanup ........ r9154 | nicfit | 2007-12-15 14:04:49 -0700 (Sat, 15 Dec 2007) | 2 lines Scratch the chckbox for with roster mode, use one_message_window opt and combo ........ r9155 | nicfit | 2007-12-15 17:01:13 -0700 (Sat, 15 Dec 2007) | 2 lines MessageWindowMgr knows about ONE_MESSAGE_WINDOW_ALWAYS_WITH_ROSTER and MessageWindow can reparent itself rather then the roster having to do so. ........ r9157 | nicfit | 2007-12-15 17:47:20 -0700 (Sat, 15 Dec 2007) | 2 lines Resizing fixes and make the roster window shrink when last tab is removed ........ r9158 | nicfit | 2007-12-15 19:15:11 -0700 (Sat, 15 Dec 2007) | 2 lines Added "Show roster" (CTRL+R) to view menu when using always_with_roster to quickly hide/show the roster. ........ r9159 | nicfit | 2007-12-15 19:49:30 -0700 (Sat, 15 Dec 2007) | 2 lines Handle window title setting in always_with_roster mode. ........ r9160 | nicfit | 2007-12-15 20:13:57 -0700 (Sat, 15 Dec 2007) | 2 lines Removed FIXME ........ r9167 | nicfit | 2007-12-17 18:40:59 -0700 (Mon, 17 Dec 2007) | 2 lines When roster is hidden, show it when the number of MessageWindow controls == 0 ........ r9168 | nicfit | 2007-12-17 19:07:49 -0700 (Mon, 17 Dec 2007) | 2 lines Disable hiding roster when there are no message controls open ........ r9169 | nicfit | 2007-12-17 20:41:11 -0700 (Mon, 17 Dec 2007) | 2 lines Bunch of saved size bugs fixed ........
2007-12-19 00:42:22 +01:00
advanced_menuitem_menu.show_all()
Merge one_window branch Merged revisions 9143,9145-9155,9157-9162,9164-9169,9171-9177 via svnmerge from svn://88.191.11.156/gajim/branches/one_window ........ r9145 | nicfit | 2007-12-13 21:49:09 -0700 (Thu, 13 Dec 2007) | 2 lines Implemented the original Nikos patch with an HPaned instead of a HBox and only do this mode when one_message_window == 'always' ........ r9152 | nicfit | 2007-12-15 13:33:56 -0700 (Sat, 15 Dec 2007) | 2 lines Added config and GUI for one_message_window_with_roster ........ r9153 | nicfit | 2007-12-15 13:41:46 -0700 (Sat, 15 Dec 2007) | 2 lines Use one_message_window_with_roster and some whitespace cleanup ........ r9154 | nicfit | 2007-12-15 14:04:49 -0700 (Sat, 15 Dec 2007) | 2 lines Scratch the chckbox for with roster mode, use one_message_window opt and combo ........ r9155 | nicfit | 2007-12-15 17:01:13 -0700 (Sat, 15 Dec 2007) | 2 lines MessageWindowMgr knows about ONE_MESSAGE_WINDOW_ALWAYS_WITH_ROSTER and MessageWindow can reparent itself rather then the roster having to do so. ........ r9157 | nicfit | 2007-12-15 17:47:20 -0700 (Sat, 15 Dec 2007) | 2 lines Resizing fixes and make the roster window shrink when last tab is removed ........ r9158 | nicfit | 2007-12-15 19:15:11 -0700 (Sat, 15 Dec 2007) | 2 lines Added "Show roster" (CTRL+R) to view menu when using always_with_roster to quickly hide/show the roster. ........ r9159 | nicfit | 2007-12-15 19:49:30 -0700 (Sat, 15 Dec 2007) | 2 lines Handle window title setting in always_with_roster mode. ........ r9160 | nicfit | 2007-12-15 20:13:57 -0700 (Sat, 15 Dec 2007) | 2 lines Removed FIXME ........ r9167 | nicfit | 2007-12-17 18:40:59 -0700 (Mon, 17 Dec 2007) | 2 lines When roster is hidden, show it when the number of MessageWindow controls == 0 ........ r9168 | nicfit | 2007-12-17 19:07:49 -0700 (Mon, 17 Dec 2007) | 2 lines Disable hiding roster when there are no message controls open ........ r9169 | nicfit | 2007-12-17 20:41:11 -0700 (Mon, 17 Dec 2007) | 2 lines Bunch of saved size bugs fixed ........
2007-12-19 00:42:22 +01:00
return advanced_menuitem_menu
2008-06-02 12:04:27 +02:00
def add_history_manager_menuitem(self, menu):
'''adds a seperator and History Manager menuitem BELOW for account
menuitems'''
item = gtk.SeparatorMenuItem() # separator
menu.append(item)
# History manager
item = gtk.ImageMenuItem(_('History Manager'))
icon = gtk.image_new_from_stock(gtk.STOCK_JUSTIFY_FILL,
gtk.ICON_SIZE_MENU)
item.set_image(icon)
menu.append(item)
item.connect('activate', self.on_history_manager_menuitem_activate)
2008-06-02 12:04:27 +02:00
def add_bookmarks_list(self, gc_sub_menu, account):
'''Show join new group chat item and bookmarks list for an account'''
item = gtk.ImageMenuItem(_('_Join New Group Chat'))
icon = gtk.image_new_from_stock(gtk.STOCK_NEW, gtk.ICON_SIZE_MENU)
item.set_image(icon)
item.connect('activate', self.on_join_gc_activate, account)
gc_sub_menu.append(item)
# user has at least one bookmark
if len(gajim.connections[account].bookmarks) > 0:
item = gtk.SeparatorMenuItem() # separator
gc_sub_menu.append(item)
for bookmark in gajim.connections[account].bookmarks:
item = gtk.MenuItem(bookmark['name'], False) # Do not use underline
item.connect('activate', self.on_bookmark_menuitem_activate,
account, bookmark)
gc_sub_menu.append(item)
2008-06-02 12:04:27 +02:00
2009-06-16 15:14:09 +02:00
def set_actions_menu_needs_rebuild(self):
self.actions_menu_needs_rebuild = True
def show_appropriate_context_menu(self, event, iters):
# iters must be all of the same type
model = self.modelfilter
type_ = model[iters[0]][C_TYPE]
for titer in iters[1:]:
if model[titer][C_TYPE] != type_:
return
if type_ == 'group' and len(iters) == 1:
self.make_group_menu(event, iters[0])
if type_ == 'groupchat' and len(iters) == 1:
self.make_groupchat_menu(event, iters[0])
elif type_ == 'agent' and len(iters) == 1:
self.make_transport_menu(event, iters[0])
elif type_ in ('contact', 'self_contact') and len(iters) == 1:
self.make_contact_menu(event, iters[0])
elif type_ == 'contact':
self.make_multiple_contact_menu(event, iters)
elif type_ == 'account' and len(iters) == 1:
self.make_account_menu(event, iters[0])
def show_treeview_menu(self, event):
try:
model, list_of_paths = self.tree.get_selection().get_selected_rows()
except TypeError:
self.tree.get_selection().unselect_all()
return
if not len(list_of_paths):
# no row is selected
return
if len(list_of_paths) > 1:
iters = []
for path in list_of_paths:
iters.append(model.get_iter(path))
else:
path = list_of_paths[0]
iters = [model.get_iter(path)]
self.show_appropriate_context_menu(event, iters)
return True
2008-06-02 12:04:27 +02:00
################################################################################
2008-06-02 12:04:27 +02:00
###
################################################################################
2008-06-02 12:04:27 +02:00
def __init__(self):
self.filtering = False
self.xml = gtkgui_helpers.get_glade('roster_window.glade')
self.window = self.xml.get_widget('roster_window')
Merge one_window branch Merged revisions 9143,9145-9155,9157-9162,9164-9169,9171-9177 via svnmerge from svn://88.191.11.156/gajim/branches/one_window ........ r9145 | nicfit | 2007-12-13 21:49:09 -0700 (Thu, 13 Dec 2007) | 2 lines Implemented the original Nikos patch with an HPaned instead of a HBox and only do this mode when one_message_window == 'always' ........ r9152 | nicfit | 2007-12-15 13:33:56 -0700 (Sat, 15 Dec 2007) | 2 lines Added config and GUI for one_message_window_with_roster ........ r9153 | nicfit | 2007-12-15 13:41:46 -0700 (Sat, 15 Dec 2007) | 2 lines Use one_message_window_with_roster and some whitespace cleanup ........ r9154 | nicfit | 2007-12-15 14:04:49 -0700 (Sat, 15 Dec 2007) | 2 lines Scratch the chckbox for with roster mode, use one_message_window opt and combo ........ r9155 | nicfit | 2007-12-15 17:01:13 -0700 (Sat, 15 Dec 2007) | 2 lines MessageWindowMgr knows about ONE_MESSAGE_WINDOW_ALWAYS_WITH_ROSTER and MessageWindow can reparent itself rather then the roster having to do so. ........ r9157 | nicfit | 2007-12-15 17:47:20 -0700 (Sat, 15 Dec 2007) | 2 lines Resizing fixes and make the roster window shrink when last tab is removed ........ r9158 | nicfit | 2007-12-15 19:15:11 -0700 (Sat, 15 Dec 2007) | 2 lines Added "Show roster" (CTRL+R) to view menu when using always_with_roster to quickly hide/show the roster. ........ r9159 | nicfit | 2007-12-15 19:49:30 -0700 (Sat, 15 Dec 2007) | 2 lines Handle window title setting in always_with_roster mode. ........ r9160 | nicfit | 2007-12-15 20:13:57 -0700 (Sat, 15 Dec 2007) | 2 lines Removed FIXME ........ r9167 | nicfit | 2007-12-17 18:40:59 -0700 (Mon, 17 Dec 2007) | 2 lines When roster is hidden, show it when the number of MessageWindow controls == 0 ........ r9168 | nicfit | 2007-12-17 19:07:49 -0700 (Mon, 17 Dec 2007) | 2 lines Disable hiding roster when there are no message controls open ........ r9169 | nicfit | 2007-12-17 20:41:11 -0700 (Mon, 17 Dec 2007) | 2 lines Bunch of saved size bugs fixed ........
2007-12-19 00:42:22 +01:00
self.hpaned = self.xml.get_widget('roster_hpaned')
gajim.interface.msg_win_mgr = MessageWindowMgr(self.window, self.hpaned)
2008-05-08 23:18:39 +02:00
gajim.interface.msg_win_mgr.connect('window-delete',
self.on_message_window_delete)
self.advanced_menus = [] # We keep them to destroy them
2005-12-27 21:27:02 +01:00
if gajim.config.get('roster_window_skip_taskbar'):
self.window.set_property('skip-taskbar-hint', True)
self.tree = self.xml.get_widget('roster_treeview')
2006-09-13 18:47:58 +02:00
sel = self.tree.get_selection()
sel.set_mode(gtk.SELECTION_MULTIPLE)
#sel.connect('changed',
# self.on_treeview_selection_changed)
2006-09-13 18:47:58 +02:00
self._last_selected_contact = [] # holds a list of (jid, account) tupples
2006-01-31 14:52:54 +01:00
self.transports_state_images = {'16': {}, '32': {}, 'opened': {},
'closed': {}}
2005-07-30 16:40:58 +02:00
self.last_save_dir = None
2007-12-12 09:44:46 +01:00
self.editing_path = None # path of row with cell in edit mode
self.add_new_contact_handler_id = False
self.service_disco_handler_id = False
self.new_chat_menuitem_handler_id = False
2007-12-12 09:44:46 +01:00
self.single_message_menuitem_handler_id = False
self.profile_avatar_menuitem_handler_id = False
2006-02-19 22:28:41 +01:00
self.actions_menu_needs_rebuild = True
self.regroup = gajim.config.get('mergeaccounts')
2007-12-12 09:44:46 +01:00
self.clicked_path = None # Used remember on wich row we clicked
if len(gajim.connections) < 2: # Do not merge accounts if only one exists
self.regroup = False
#FIXME: When list_accel_closures will be wrapped in pygtk
# no need of this variable
self.have_new_chat_accel = False # Is the "Ctrl+N" shown ?
gtkgui_helpers.resize_window(self.window,
gajim.config.get('roster_width'),
gajim.config.get('roster_height'))
gtkgui_helpers.move_window(self.window,
gajim.config.get('roster_x-position'),
gajim.config.get('roster_y-position'))
self.popups_notification_height = 0
self.popup_notification_windows = []
# Remove contact from roster when last event opened
# { (contact, account): { backend: boolean }
self.contacts_to_be_removed = {}
gajim.events.event_removed_subscribe(self.on_event_removed)
# when this value become 0 we quit main application. If it's more than 0
# it means we are waiting for this number of accounts to disconnect before
# quitting
self.quit_on_next_offline = -1
# uf_show, img, show, sensitive
liststore = gtk.ListStore(str, gtk.Image, str, bool)
self.status_combobox = self.xml.get_widget('status_combobox')
cell = cell_renderer_image.CellRendererImage(0, 1)
self.status_combobox.pack_start(cell, False)
# img to show is in in 2nd column of liststore
self.status_combobox.add_attribute(cell, 'image', 1)
# if it will be sensitive or not it is in the fourth column
# all items in the 'row' must have sensitive to False
# if we want False (so we add it for img_cell too)
self.status_combobox.add_attribute(cell, 'sensitive', 3)
cell = gtk.CellRendererText()
cell.set_property('xpad', 5) # padding for status text
self.status_combobox.pack_start(cell, True)
# text to show is in in first column of liststore
self.status_combobox.add_attribute(cell, 'text', 0)
# if it will be sensitive or not it is in the fourth column
self.status_combobox.add_attribute(cell, 'sensitive', 3)
self.status_combobox.set_row_separator_func(self._iter_is_separator)
for show in ('online', 'chat', 'away', 'xa', 'dnd', 'invisible'):
uf_show = helpers.get_uf_show(show)
2008-06-02 12:04:27 +02:00
liststore.append([uf_show, gajim.interface.jabber_state_images['16'][
show], show, True])
# Add a Separator (self._iter_is_separator() checks on string SEPARATOR)
liststore.append(['SEPARATOR', None, '', True])
path = os.path.join(gajim.DATA_DIR, 'pixmaps', 'kbd_input.png')
img = gtk.Image()
img.set_from_file(path)
# sensitivity to False because by default we're offline
self.status_message_menuitem_iter = liststore.append(
[_('Change Status Message...'), img, '', False])
# Add a Separator (self._iter_is_separator() checks on string SEPARATOR)
liststore.append(['SEPARATOR', None, '', True])
uf_show = helpers.get_uf_show('offline')
2008-06-02 12:04:27 +02:00
liststore.append([uf_show, gajim.interface.jabber_state_images['16'][
'offline'], 'offline', True])
2006-11-20 08:53:58 +01:00
status_combobox_items = ['online', 'chat', 'away', 'xa', 'dnd',
'invisible', 'separator1', 'change_status_msg', 'separator2',
'offline']
self.status_combobox.set_model(liststore)
# default to offline
number_of_menuitem = status_combobox_items.index('offline')
self.status_combobox.set_active(number_of_menuitem)
# holds index to previously selected item so if "change status message..."
# is selected we can fallback to previously selected item and not stay
# with that item selected
self.previous_status_combobox_active = number_of_menuitem
showOffline = gajim.config.get('showoffline')
showOnlyChatAndOnline = gajim.config.get('show_only_chat_and_online')
w = self.xml.get_widget('show_offline_contacts_menuitem')
w.set_active(showOffline)
if showOnlyChatAndOnline:
w.set_sensitive(False)
w = self.xml.get_widget('show_only_active_contacts_menuitem')
w.set_active(showOnlyChatAndOnline)
if showOffline:
w.set_sensitive(False)
2006-11-18 21:52:28 +01:00
show_transports_group = gajim.config.get('show_transports_group')
self.xml.get_widget('show_transports_menuitem').set_active(
show_transports_group)
Merge one_window branch Merged revisions 9143,9145-9155,9157-9162,9164-9169,9171-9177 via svnmerge from svn://88.191.11.156/gajim/branches/one_window ........ r9145 | nicfit | 2007-12-13 21:49:09 -0700 (Thu, 13 Dec 2007) | 2 lines Implemented the original Nikos patch with an HPaned instead of a HBox and only do this mode when one_message_window == 'always' ........ r9152 | nicfit | 2007-12-15 13:33:56 -0700 (Sat, 15 Dec 2007) | 2 lines Added config and GUI for one_message_window_with_roster ........ r9153 | nicfit | 2007-12-15 13:41:46 -0700 (Sat, 15 Dec 2007) | 2 lines Use one_message_window_with_roster and some whitespace cleanup ........ r9154 | nicfit | 2007-12-15 14:04:49 -0700 (Sat, 15 Dec 2007) | 2 lines Scratch the chckbox for with roster mode, use one_message_window opt and combo ........ r9155 | nicfit | 2007-12-15 17:01:13 -0700 (Sat, 15 Dec 2007) | 2 lines MessageWindowMgr knows about ONE_MESSAGE_WINDOW_ALWAYS_WITH_ROSTER and MessageWindow can reparent itself rather then the roster having to do so. ........ r9157 | nicfit | 2007-12-15 17:47:20 -0700 (Sat, 15 Dec 2007) | 2 lines Resizing fixes and make the roster window shrink when last tab is removed ........ r9158 | nicfit | 2007-12-15 19:15:11 -0700 (Sat, 15 Dec 2007) | 2 lines Added "Show roster" (CTRL+R) to view menu when using always_with_roster to quickly hide/show the roster. ........ r9159 | nicfit | 2007-12-15 19:49:30 -0700 (Sat, 15 Dec 2007) | 2 lines Handle window title setting in always_with_roster mode. ........ r9160 | nicfit | 2007-12-15 20:13:57 -0700 (Sat, 15 Dec 2007) | 2 lines Removed FIXME ........ r9167 | nicfit | 2007-12-17 18:40:59 -0700 (Mon, 17 Dec 2007) | 2 lines When roster is hidden, show it when the number of MessageWindow controls == 0 ........ r9168 | nicfit | 2007-12-17 19:07:49 -0700 (Mon, 17 Dec 2007) | 2 lines Disable hiding roster when there are no message controls open ........ r9169 | nicfit | 2007-12-17 20:41:11 -0700 (Mon, 17 Dec 2007) | 2 lines Bunch of saved size bugs fixed ........
2007-12-19 00:42:22 +01:00
self.xml.get_widget('show_roster_menuitem').set_active(True)
# columns
2006-03-14 00:25:00 +01:00
# this col has 3 cells:
# first one img, second one text, third is sec pixbuf
col = gtk.TreeViewColumn()
def add_avatar_renderer():
render_pixbuf = gtk.CellRendererPixbuf() # avatar img
2008-09-02 22:34:11 +02:00
col.pack_start(render_pixbuf, expand=False)
2008-07-25 01:53:56 +02:00
col.add_attribute(render_pixbuf, 'pixbuf',
C_AVATAR_PIXBUF)
col.set_cell_data_func(render_pixbuf,
2008-12-03 22:58:08 +01:00
self._fill_avatar_pixbuf_renderer, None)
if gajim.config.get('avatar_position_in_roster') == 'left':
add_avatar_renderer()
2006-11-20 08:53:58 +01:00
render_image = cell_renderer_image.CellRendererImage(0, 0)
# show img or +-
2008-09-02 22:34:11 +02:00
col.pack_start(render_image, expand=False)
col.add_attribute(render_image, 'image', C_IMG)
col.set_cell_data_func(render_image, self._iconCellDataFunc, None)
render_text = gtk.CellRendererText() # contact or group or account name
render_text.set_property('ellipsize', pango.ELLIPSIZE_END)
2008-09-02 22:34:11 +02:00
col.pack_start(render_text, expand=True)
col.add_attribute(render_text, 'markup', C_NAME) # where we hold the name
col.set_cell_data_func(render_text, self._nameCellDataFunc, None)
render_pixbuf = gtk.CellRendererPixbuf()
2008-09-02 22:34:11 +02:00
col.pack_start(render_pixbuf, expand=False)
col.add_attribute(render_pixbuf, 'pixbuf', C_MOOD_PIXBUF)
col.set_cell_data_func(render_pixbuf,
2009-11-15 17:11:06 +01:00
self._fill_pep_pixbuf_renderer, C_MOOD_PIXBUF)
2008-07-25 01:53:56 +02:00
2008-07-29 04:32:57 +02:00
render_pixbuf = gtk.CellRendererPixbuf()
2008-09-02 22:34:11 +02:00
col.pack_start(render_pixbuf, expand=False)
2008-07-29 04:32:57 +02:00
col.add_attribute(render_pixbuf, 'pixbuf', C_ACTIVITY_PIXBUF)
col.set_cell_data_func(render_pixbuf,
2009-11-15 17:11:06 +01:00
self._fill_pep_pixbuf_renderer, C_ACTIVITY_PIXBUF)
2008-07-29 04:32:57 +02:00
2008-07-25 16:11:14 +02:00
render_pixbuf = gtk.CellRendererPixbuf()
2008-09-02 22:34:11 +02:00
col.pack_start(render_pixbuf, expand=False)
2008-07-25 16:11:14 +02:00
col.add_attribute(render_pixbuf, 'pixbuf', C_TUNE_PIXBUF)
col.set_cell_data_func(render_pixbuf,
2009-11-15 17:11:06 +01:00
self._fill_pep_pixbuf_renderer, C_TUNE_PIXBUF)
self._pep_type_to_model_column = {'mood': C_MOOD_PIXBUF,
'activity': C_ACTIVITY_PIXBUF,
'tune': C_TUNE_PIXBUF}
2008-07-25 16:11:14 +02:00
if gajim.config.get('avatar_position_in_roster') == 'right':
add_avatar_renderer()
render_pixbuf = gtk.CellRendererPixbuf() # tls/ssl img
2008-09-02 22:34:11 +02:00
col.pack_start(render_pixbuf, expand=False)
col.add_attribute(render_pixbuf, 'pixbuf', C_PADLOCK_PIXBUF)
col.set_cell_data_func(render_pixbuf,
2008-12-03 22:58:08 +01:00
self._fill_padlock_pixbuf_renderer, None)
self.tree.append_column(col)
# do not show gtk arrows workaround
col = gtk.TreeViewColumn()
render_pixbuf = gtk.CellRendererPixbuf()
2008-09-02 22:34:11 +02:00
col.pack_start(render_pixbuf, expand=False)
self.tree.append_column(col)
col.set_visible(False)
self.tree.set_expander_column(col)
2007-08-09 17:39:18 +02:00
# set search function
self.tree.set_search_equal_func(self._search_roster_func)
# signals
Merged revisions 5017-5020,5022-5029 via svnmerge from svn://svn.gajim.org/gajim/trunk ........ r5017 | asterix | 2006-01-06 01:55:51 -0700 (Fri, 06 Jan 2006) | 2 lines use escape for pango markup ........ r5018 | asterix | 2006-01-06 02:21:39 -0700 (Fri, 06 Jan 2006) | 2 lines missing new contacts function ........ r5019 | asterix | 2006-01-06 11:03:07 -0700 (Fri, 06 Jan 2006) | 2 lines handle the click on toggle_gpg_encryption menuitem ........ r5020 | asterix | 2006-01-06 11:14:14 -0700 (Fri, 06 Jan 2006) | 2 lines use the saved size even if a chat window is already opened ........ r5022 | asterix | 2006-01-07 03:43:47 -0700 (Sat, 07 Jan 2006) | 2 lines we can now resume filetransfert ........ r5023 | asterix | 2006-01-07 03:56:31 -0700 (Sat, 07 Jan 2006) | 2 lines [Knuckles] Google E-Mail Notification ........ r5024 | asterix | 2006-01-07 04:02:16 -0700 (Sat, 07 Jan 2006) | 2 lines better string ........ r5025 | asterix | 2006-01-07 04:14:32 -0700 (Sat, 07 Jan 2006) | 2 lines fix a TB ........ r5026 | asterix | 2006-01-07 05:36:55 -0700 (Sat, 07 Jan 2006) | 2 lines we can now drag a file on a contact in the roster to send him a file ........ r5027 | asterix | 2006-01-07 06:26:28 -0700 (Sat, 07 Jan 2006) | 2 lines contact.groups is always a list, even if emtpy ........ r5028 | asterix | 2006-01-07 06:54:30 -0700 (Sat, 07 Jan 2006) | 2 lines make all buttons insensitive on a category row in disco ........ r5029 | asterix | 2006-01-07 07:19:25 -0700 (Sat, 07 Jan 2006) | 2 lines auto open groupchat configuration window when we create a new room ........
2006-01-07 18:25:35 +01:00
self.TARGET_TYPE_URI_LIST = 80
2008-06-02 12:04:27 +02:00
TARGETS = [('MY_TREE_MODEL_ROW',
gtk.TARGET_SAME_APP | gtk.TARGET_SAME_WIDGET, 0)]
Merged revisions 5017-5020,5022-5029 via svnmerge from svn://svn.gajim.org/gajim/trunk ........ r5017 | asterix | 2006-01-06 01:55:51 -0700 (Fri, 06 Jan 2006) | 2 lines use escape for pango markup ........ r5018 | asterix | 2006-01-06 02:21:39 -0700 (Fri, 06 Jan 2006) | 2 lines missing new contacts function ........ r5019 | asterix | 2006-01-06 11:03:07 -0700 (Fri, 06 Jan 2006) | 2 lines handle the click on toggle_gpg_encryption menuitem ........ r5020 | asterix | 2006-01-06 11:14:14 -0700 (Fri, 06 Jan 2006) | 2 lines use the saved size even if a chat window is already opened ........ r5022 | asterix | 2006-01-07 03:43:47 -0700 (Sat, 07 Jan 2006) | 2 lines we can now resume filetransfert ........ r5023 | asterix | 2006-01-07 03:56:31 -0700 (Sat, 07 Jan 2006) | 2 lines [Knuckles] Google E-Mail Notification ........ r5024 | asterix | 2006-01-07 04:02:16 -0700 (Sat, 07 Jan 2006) | 2 lines better string ........ r5025 | asterix | 2006-01-07 04:14:32 -0700 (Sat, 07 Jan 2006) | 2 lines fix a TB ........ r5026 | asterix | 2006-01-07 05:36:55 -0700 (Sat, 07 Jan 2006) | 2 lines we can now drag a file on a contact in the roster to send him a file ........ r5027 | asterix | 2006-01-07 06:26:28 -0700 (Sat, 07 Jan 2006) | 2 lines contact.groups is always a list, even if emtpy ........ r5028 | asterix | 2006-01-07 06:54:30 -0700 (Sat, 07 Jan 2006) | 2 lines make all buttons insensitive on a category row in disco ........ r5029 | asterix | 2006-01-07 07:19:25 -0700 (Sat, 07 Jan 2006) | 2 lines auto open groupchat configuration window when we create a new room ........
2006-01-07 18:25:35 +01:00
TARGETS2 = [('MY_TREE_MODEL_ROW', gtk.TARGET_SAME_WIDGET, 0),
('text/uri-list', 0, self.TARGET_TYPE_URI_LIST)]
self.tree.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, TARGETS,
gtk.gdk.ACTION_DEFAULT | gtk.gdk.ACTION_MOVE | gtk.gdk.ACTION_COPY)
Merged revisions 5017-5020,5022-5029 via svnmerge from svn://svn.gajim.org/gajim/trunk ........ r5017 | asterix | 2006-01-06 01:55:51 -0700 (Fri, 06 Jan 2006) | 2 lines use escape for pango markup ........ r5018 | asterix | 2006-01-06 02:21:39 -0700 (Fri, 06 Jan 2006) | 2 lines missing new contacts function ........ r5019 | asterix | 2006-01-06 11:03:07 -0700 (Fri, 06 Jan 2006) | 2 lines handle the click on toggle_gpg_encryption menuitem ........ r5020 | asterix | 2006-01-06 11:14:14 -0700 (Fri, 06 Jan 2006) | 2 lines use the saved size even if a chat window is already opened ........ r5022 | asterix | 2006-01-07 03:43:47 -0700 (Sat, 07 Jan 2006) | 2 lines we can now resume filetransfert ........ r5023 | asterix | 2006-01-07 03:56:31 -0700 (Sat, 07 Jan 2006) | 2 lines [Knuckles] Google E-Mail Notification ........ r5024 | asterix | 2006-01-07 04:02:16 -0700 (Sat, 07 Jan 2006) | 2 lines better string ........ r5025 | asterix | 2006-01-07 04:14:32 -0700 (Sat, 07 Jan 2006) | 2 lines fix a TB ........ r5026 | asterix | 2006-01-07 05:36:55 -0700 (Sat, 07 Jan 2006) | 2 lines we can now drag a file on a contact in the roster to send him a file ........ r5027 | asterix | 2006-01-07 06:26:28 -0700 (Sat, 07 Jan 2006) | 2 lines contact.groups is always a list, even if emtpy ........ r5028 | asterix | 2006-01-07 06:54:30 -0700 (Sat, 07 Jan 2006) | 2 lines make all buttons insensitive on a category row in disco ........ r5029 | asterix | 2006-01-07 07:19:25 -0700 (Sat, 07 Jan 2006) | 2 lines auto open groupchat configuration window when we create a new room ........
2006-01-07 18:25:35 +01:00
self.tree.enable_model_drag_dest(TARGETS2, gtk.gdk.ACTION_DEFAULT)
2008-04-21 22:07:08 +02:00
self.tree.connect('drag_begin', self.drag_begin)
self.tree.connect('drag_end', self.drag_end)
self.tree.connect('drag_drop', self.drag_drop)
self.tree.connect('drag_data_get', self.drag_data_get_data)
self.tree.connect('drag_data_received', self.drag_data_received_data)
2006-12-29 22:23:24 +01:00
self.dragging = False
self.xml.signal_autoconnect(self)
self.combobox_callback_active = True
self.collapsed_rows = gajim.config.get('collapsed_rows').split('\t')
self.tooltip = tooltips.RosterTooltip()
# Workaroung: For strange reasons signal is behaving like row-changed
self._toggeling_row = False
self.setup_and_draw_roster()
if gajim.config.get('show_roster_on_startup'):
self.window.show_all()
else:
2009-11-24 15:42:31 +01:00
if gajim.config.get('trayicon') != 'always':
# Without trayicon, user should see the roster!
self.window.show_all()
gajim.config.set('show_roster_on_startup', True)
2005-07-21 16:56:39 +02:00
if len(gajim.connections) == 0: # if we have no account
2005-11-13 21:05:03 +01:00
gajim.interface.instances['account_creation_wizard'] = \
config.AccountCreationWizardWindow()
2007-08-09 17:39:18 +02:00
if not gajim.ZEROCONF_ACC_NAME in gajim.config.get_per('accounts'):
# Create zeroconf in config file
2008-08-06 22:19:16 +02:00
from common.zeroconf import connection_zeroconf
2008-12-02 16:53:23 +01:00
connection_zeroconf.ConnectionZeroconf(gajim.ZEROCONF_ACC_NAME)
2007-12-12 09:44:46 +01:00
# vim: se ts=3: