2008-08-15 19:31:51 +02:00
|
|
|
# -*- coding:utf-8 -*-
|
2008-08-15 05:20:23 +02:00
|
|
|
## src/gtkgui_helpers.py
|
2005-07-21 23:39:47 +02:00
|
|
|
##
|
2008-08-15 05:20:23 +02:00
|
|
|
## Copyright (C) 2003-2008 Yann Leboulanger <asterix AT lagaule.org>
|
|
|
|
## Copyright (C) 2005-2006 Dimitur Kirov <dkirov AT gmail.com>
|
|
|
|
## Copyright (C) 2005-2007 Nikos Kouremenos <kourem AT gmail.com>
|
|
|
|
## Copyright (C) 2006 Travis Shirk <travis AT pobox.com>
|
2008-08-15 19:31:51 +02:00
|
|
|
## Copyright (C) 2006-2007 Junglecow J <junglecow AT gmail.com>
|
2008-08-15 05:20:23 +02:00
|
|
|
## Copyright (C) 2006-2008 Jean-Marie Traissard <jim AT lapin.org>
|
|
|
|
## Copyright (C) 2007 James Newton <redshodan AT gmail.com>
|
|
|
|
## Julien Pivotto <roidelapluie AT gmail.com>
|
|
|
|
## Copyright (C) 2007-2008 Stephan Erb <steve-e AT h3c.de>
|
|
|
|
## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
|
2005-07-21 23:39:47 +02:00
|
|
|
##
|
2007-10-22 13:13:13 +02:00
|
|
|
## This file is part of Gajim.
|
|
|
|
##
|
|
|
|
## Gajim is free software; you can redistribute it and/or modify
|
2005-07-21 23:39:47 +02:00
|
|
|
## it under the terms of the GNU General Public License as published
|
2007-10-22 13:13:13 +02:00
|
|
|
## by the Free Software Foundation; version 3 only.
|
2005-07-21 23:39:47 +02:00
|
|
|
##
|
2007-10-22 13:13:13 +02:00
|
|
|
## Gajim is distributed in the hope that it will be useful,
|
2005-07-21 23:39:47 +02:00
|
|
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2008-08-15 05:20:23 +02:00
|
|
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2005-07-21 23:39:47 +02:00
|
|
|
## GNU General Public License for more details.
|
|
|
|
##
|
2007-10-22 13:13:13 +02:00
|
|
|
## You should have received a copy of the GNU General Public License
|
2008-08-15 05:20:23 +02:00
|
|
|
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
2007-10-22 13:13:13 +02:00
|
|
|
##
|
2005-07-21 23:39:47 +02:00
|
|
|
|
2005-07-23 14:45:17 +02:00
|
|
|
import xml.sax.saxutils
|
2005-07-23 15:09:36 +02:00
|
|
|
import gtk
|
2006-07-17 21:30:53 +02:00
|
|
|
import gtk.glade
|
2005-09-02 21:26:52 +02:00
|
|
|
import gobject
|
2005-09-17 10:32:55 +02:00
|
|
|
import pango
|
2005-08-05 01:11:55 +02:00
|
|
|
import os
|
2005-09-08 16:03:19 +02:00
|
|
|
import sys
|
2005-11-01 21:01:14 +01:00
|
|
|
|
2005-11-12 22:24:54 +01:00
|
|
|
import vcard
|
2006-05-26 15:19:52 +02:00
|
|
|
import dialogs
|
2005-11-12 22:24:54 +01:00
|
|
|
|
2007-01-06 16:31:30 +01:00
|
|
|
import logging
|
|
|
|
log = logging.getLogger('gajim.gtkgui_helpers')
|
|
|
|
|
2005-11-02 11:52:12 +01:00
|
|
|
|
|
|
|
HAS_PYWIN32 = True
|
2005-11-01 21:01:14 +01:00
|
|
|
if os.name == 'nt':
|
2005-11-02 11:52:12 +01:00
|
|
|
try:
|
|
|
|
import win32file
|
|
|
|
import win32con
|
|
|
|
import pywintypes
|
|
|
|
except ImportError:
|
|
|
|
HAS_PYWIN32 = False
|
2005-11-01 21:01:14 +01:00
|
|
|
|
2005-07-30 12:20:24 +02:00
|
|
|
from common import i18n
|
2005-08-05 01:11:55 +02:00
|
|
|
from common import gajim
|
2005-08-26 14:08:14 +02:00
|
|
|
from common import helpers
|
2005-08-05 01:11:55 +02:00
|
|
|
|
2008-12-03 22:56:12 +01:00
|
|
|
gtk.glade.bindtextdomain(i18n.APP, i18n.DIR)
|
2006-07-17 21:30:53 +02:00
|
|
|
gtk.glade.textdomain(i18n.APP)
|
|
|
|
|
2005-08-29 22:18:24 +02:00
|
|
|
screen_w = gtk.gdk.screen_width()
|
|
|
|
screen_h = gtk.gdk.screen_height()
|
2005-09-17 11:37:40 +02:00
|
|
|
|
2009-02-11 10:44:17 +01:00
|
|
|
GLADE_DIR = os.path.join(gajim.DATA_DIR, 'glade')
|
2006-05-02 17:53:25 +02:00
|
|
|
def get_glade(file_name, root = None):
|
|
|
|
file_path = os.path.join(GLADE_DIR, file_name)
|
|
|
|
return gtk.glade.XML(file_path, root=root, domain=i18n.APP)
|
|
|
|
|
2006-05-08 23:59:09 +02:00
|
|
|
def get_completion_liststore(entry):
|
|
|
|
''' create a completion model for entry widget
|
|
|
|
completion list consists of (Pixbuf, Text) rows'''
|
|
|
|
completion = gtk.EntryCompletion()
|
|
|
|
liststore = gtk.ListStore(gtk.gdk.Pixbuf, str)
|
2008-12-03 22:56:12 +01:00
|
|
|
|
2006-05-08 23:59:09 +02:00
|
|
|
render_pixbuf = gtk.CellRendererPixbuf()
|
|
|
|
completion.pack_start(render_pixbuf, expand = False)
|
|
|
|
completion.add_attribute(render_pixbuf, 'pixbuf', 0)
|
2008-12-03 22:56:12 +01:00
|
|
|
|
2006-05-08 23:59:09 +02:00
|
|
|
render_text = gtk.CellRendererText()
|
|
|
|
completion.pack_start(render_text, expand = True)
|
|
|
|
completion.add_attribute(render_text, 'text', 1)
|
|
|
|
completion.set_property('text_column', 1)
|
|
|
|
completion.set_model(liststore)
|
|
|
|
entry.set_completion(completion)
|
|
|
|
return liststore
|
2008-12-03 22:56:12 +01:00
|
|
|
|
|
|
|
|
2006-04-17 23:59:04 +02:00
|
|
|
def popup_emoticons_under_button(menu, button, parent_win):
|
|
|
|
''' pops emoticons menu under button, which is in parent_win'''
|
2006-04-18 17:36:16 +02:00
|
|
|
window_x1, window_y1 = parent_win.get_origin()
|
2006-04-17 23:59:04 +02:00
|
|
|
def position_menu_under_button(menu):
|
|
|
|
# inline function, which will not keep refs, when used as CB
|
|
|
|
button_x, button_y = button.allocation.x, button.allocation.y
|
2008-12-03 22:56:12 +01:00
|
|
|
|
2006-04-17 23:59:04 +02:00
|
|
|
# now convert them to X11-relative
|
2006-04-18 17:36:16 +02:00
|
|
|
window_x, window_y = window_x1, window_y1
|
2006-04-17 23:59:04 +02:00
|
|
|
x = window_x + button_x
|
|
|
|
y = window_y + button_y
|
|
|
|
|
2008-12-02 16:53:23 +01:00
|
|
|
menu_height = menu.size_request()[1]
|
2006-04-17 23:59:04 +02:00
|
|
|
|
|
|
|
## should we pop down or up?
|
|
|
|
if (y + button.allocation.height + menu_height
|
|
|
|
< gtk.gdk.screen_height()):
|
|
|
|
# now move the menu below the button
|
|
|
|
y += button.allocation.height
|
|
|
|
else:
|
|
|
|
# now move the menu above the button
|
|
|
|
y -= menu_height
|
|
|
|
|
|
|
|
# push_in is True so all the menuitems are always inside screen
|
|
|
|
push_in = True
|
|
|
|
return (x, y, push_in)
|
2006-04-18 17:36:16 +02:00
|
|
|
|
2006-04-17 23:59:04 +02:00
|
|
|
menu.popup(None, None, position_menu_under_button, 1, 0)
|
2008-12-03 22:56:12 +01:00
|
|
|
|
2005-09-17 10:32:55 +02:00
|
|
|
def get_theme_font_for_option(theme, option):
|
2005-09-17 13:26:15 +02:00
|
|
|
'''return string description of the font, stored in
|
2005-09-17 10:32:55 +02:00
|
|
|
theme preferences'''
|
|
|
|
font_name = gajim.config.get_per('themes', theme, option)
|
|
|
|
font_desc = pango.FontDescription()
|
|
|
|
font_prop_str = gajim.config.get_per('themes', theme, option + 'attrs')
|
2005-09-17 10:42:37 +02:00
|
|
|
if font_prop_str:
|
|
|
|
if font_prop_str.find('B') != -1:
|
|
|
|
font_desc.set_weight(pango.WEIGHT_BOLD)
|
|
|
|
if font_prop_str.find('I') != -1:
|
|
|
|
font_desc.set_style(pango.STYLE_ITALIC)
|
2005-09-17 10:32:55 +02:00
|
|
|
fd = pango.FontDescription(font_name)
|
|
|
|
fd.merge(font_desc, True)
|
|
|
|
return fd.to_string()
|
2008-12-03 22:56:12 +01:00
|
|
|
|
2005-08-12 00:06:26 +02:00
|
|
|
def get_default_font():
|
2005-09-17 13:26:15 +02:00
|
|
|
'''Get the desktop setting for application font
|
2007-11-26 11:17:12 +01:00
|
|
|
first check for GNOME, then Xfce and last KDE
|
2005-08-14 23:43:16 +02:00
|
|
|
it returns None on failure or else a string 'Font Size' '''
|
2008-12-03 22:56:12 +01:00
|
|
|
|
2005-08-14 23:43:16 +02:00
|
|
|
try:
|
|
|
|
import gconf
|
2005-08-15 00:30:28 +02:00
|
|
|
# in try because daemon may not be there
|
|
|
|
client = gconf.client_get_default()
|
2005-10-13 21:44:33 +02:00
|
|
|
|
2006-09-13 18:47:58 +02:00
|
|
|
return client.get_string('/desktop/gnome/interface/font_name'
|
|
|
|
).decode('utf-8')
|
2008-10-11 11:37:13 +02:00
|
|
|
except Exception:
|
2005-10-13 21:44:33 +02:00
|
|
|
pass
|
2005-08-12 02:33:48 +02:00
|
|
|
|
|
|
|
# try to get xfce default font
|
|
|
|
# Xfce 4.2 adopts freedesktop.org's Base Directory Specification
|
|
|
|
# see http://www.xfce.org/~benny/xfce/file-locations.html
|
|
|
|
# and http://freedesktop.org/Standards/basedir-spec
|
|
|
|
xdg_config_home = os.environ.get('XDG_CONFIG_HOME', '')
|
|
|
|
if xdg_config_home == '':
|
2008-12-03 22:56:12 +01:00
|
|
|
xdg_config_home = os.path.expanduser('~/.config') # default
|
2005-08-12 02:33:48 +02:00
|
|
|
xfce_config_file = os.path.join(xdg_config_home, 'xfce4/mcs_settings/gtk.xml')
|
2008-12-03 22:56:12 +01:00
|
|
|
|
2005-08-14 23:43:16 +02:00
|
|
|
kde_config_file = os.path.expanduser('~/.kde/share/config/kdeglobals')
|
2008-12-03 22:56:12 +01:00
|
|
|
|
2005-08-12 02:33:48 +02:00
|
|
|
if os.path.exists(xfce_config_file):
|
|
|
|
try:
|
2008-10-11 11:38:17 +02:00
|
|
|
for line in open(xfce_config_file):
|
2005-08-12 02:33:48 +02:00
|
|
|
if line.find('name="Gtk/FontName"') != -1:
|
|
|
|
start = line.find('value="') + 7
|
2006-09-13 18:47:58 +02:00
|
|
|
return line[start:line.find('"', start)].decode('utf-8')
|
2008-10-11 11:37:13 +02:00
|
|
|
except Exception:
|
2005-08-17 14:17:09 +02:00
|
|
|
#we talk about file
|
2005-11-01 21:01:14 +01:00
|
|
|
print >> sys.stderr, _('Error: cannot open %s for reading') % xfce_config_file
|
2008-12-03 22:56:12 +01:00
|
|
|
|
2005-08-14 23:43:16 +02:00
|
|
|
elif os.path.exists(kde_config_file):
|
|
|
|
try:
|
2008-10-11 11:38:17 +02:00
|
|
|
for line in open(kde_config_file):
|
2005-08-14 23:43:16 +02:00
|
|
|
if line.find('font=') == 0: # font=Verdana,9,other_numbers
|
|
|
|
start = 5 # 5 is len('font=')
|
|
|
|
line = line[start:]
|
|
|
|
values = line.split(',')
|
|
|
|
font_name = values[0]
|
|
|
|
font_size = values[1]
|
|
|
|
font_string = '%s %s' % (font_name, font_size) # Verdana 9
|
2006-09-13 18:47:58 +02:00
|
|
|
return font_string.decode('utf-8')
|
2008-10-11 11:37:13 +02:00
|
|
|
except Exception:
|
2005-08-17 14:17:09 +02:00
|
|
|
#we talk about file
|
2005-11-01 21:01:14 +01:00
|
|
|
print >> sys.stderr, _('Error: cannot open %s for reading') % kde_config_file
|
2008-12-03 22:56:12 +01:00
|
|
|
|
2005-08-14 23:43:16 +02:00
|
|
|
return None
|
2008-12-03 22:56:12 +01:00
|
|
|
|
2005-08-05 01:11:55 +02:00
|
|
|
def autodetect_browser_mailer():
|
2006-11-18 21:52:28 +01:00
|
|
|
# recognize the environment and set appropriate browser/mailer
|
|
|
|
if user_runs_gnome():
|
|
|
|
gajim.config.set('openwith', 'gnome-open')
|
|
|
|
elif user_runs_kde():
|
|
|
|
gajim.config.set('openwith', 'kfmclient exec')
|
|
|
|
elif user_runs_xfce():
|
|
|
|
gajim.config.set('openwith', 'exo-open')
|
|
|
|
else:
|
|
|
|
gajim.config.set('openwith', 'custom')
|
|
|
|
|
|
|
|
def user_runs_gnome():
|
|
|
|
return 'gnome-session' in get_running_processes()
|
|
|
|
|
|
|
|
def user_runs_kde():
|
|
|
|
return 'startkde' in get_running_processes()
|
|
|
|
|
|
|
|
def user_runs_xfce():
|
|
|
|
procs = get_running_processes()
|
|
|
|
if 'startxfce4' in procs or 'xfce4-session' in procs:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def get_running_processes():
|
|
|
|
'''returns running processes or None (if not /proc exists)'''
|
2005-07-25 16:38:21 +02:00
|
|
|
if os.path.isdir('/proc'):
|
|
|
|
# under Linux: checking if 'gnome-session' or
|
|
|
|
# 'startkde' programs were run before gajim, by
|
|
|
|
# checking /proc (if it exists)
|
|
|
|
#
|
|
|
|
# if something is unclear, read `man proc`;
|
|
|
|
# if /proc exists, directories that have only numbers
|
|
|
|
# in their names contain data about processes.
|
|
|
|
# /proc/[xxx]/exe is a symlink to executable started
|
|
|
|
# as process number [xxx].
|
|
|
|
# filter out everything that we are not interested in:
|
|
|
|
files = os.listdir('/proc')
|
|
|
|
|
|
|
|
# files that doesn't have only digits in names...
|
|
|
|
files = filter(str.isdigit, files)
|
|
|
|
|
|
|
|
# files that aren't directories...
|
2008-12-03 23:04:42 +01:00
|
|
|
files = [f for f in files if os.path.isdir('/proc/' + f)]
|
2005-07-25 16:38:21 +02:00
|
|
|
|
|
|
|
# processes owned by somebody not running gajim...
|
|
|
|
# (we check if we have access to that file)
|
2008-12-03 23:04:42 +01:00
|
|
|
files = [f for f in files if os.access('/proc/' + f +'/exe', os.F_OK)]
|
2005-07-25 16:38:21 +02:00
|
|
|
|
|
|
|
# be sure that /proc/[number]/exe is really a symlink
|
|
|
|
# to avoid TBs in incorrectly configured systems
|
2008-12-03 23:04:42 +01:00
|
|
|
files = [f for f in files if os.path.islink('/proc/' + f + '/exe')]
|
2005-07-25 16:38:21 +02:00
|
|
|
|
|
|
|
# list of processes
|
|
|
|
processes = [os.path.basename(os.readlink('/proc/' + f +'/exe')) for f in files]
|
2008-12-03 22:56:12 +01:00
|
|
|
|
2006-11-18 21:52:28 +01:00
|
|
|
return processes
|
|
|
|
return []
|
2005-08-28 12:57:08 +02:00
|
|
|
|
|
|
|
def move_window(window, x, y):
|
2005-09-04 18:57:09 +02:00
|
|
|
'''moves the window but also checks if out of screen'''
|
2005-08-28 12:57:08 +02:00
|
|
|
if x < 0:
|
|
|
|
x = 0
|
|
|
|
if y < 0:
|
|
|
|
y = 0
|
2008-01-22 18:47:56 +01:00
|
|
|
w, h = window.get_size()
|
|
|
|
if x + w > screen_w:
|
|
|
|
x = screen_w - w
|
|
|
|
if y + h > screen_h:
|
|
|
|
y = screen_h - h
|
2005-08-28 12:57:08 +02:00
|
|
|
window.move(x, y)
|
|
|
|
|
|
|
|
def resize_window(window, w, h):
|
2005-09-04 18:57:09 +02:00
|
|
|
'''resizes window but also checks if huge window or negative values'''
|
2005-12-31 07:27:22 +01:00
|
|
|
if not w or not h:
|
|
|
|
return
|
2005-08-28 12:57:08 +02:00
|
|
|
if w > screen_w:
|
|
|
|
w = screen_w
|
|
|
|
if h > screen_h:
|
|
|
|
h = screen_h
|
2005-08-29 22:18:24 +02:00
|
|
|
window.resize(abs(w), abs(h))
|
2005-08-29 22:20:08 +02:00
|
|
|
|
2006-12-23 00:30:23 +01:00
|
|
|
class HashDigest:
|
|
|
|
def __init__(self, algo, digest):
|
2006-12-23 22:18:07 +01:00
|
|
|
self.algo = self.cleanID(algo)
|
|
|
|
self.digest = self.cleanID(digest)
|
2006-12-23 00:30:23 +01:00
|
|
|
|
2008-10-11 12:22:04 +02:00
|
|
|
def cleanID(self, id_):
|
|
|
|
id_ = id_.strip().lower()
|
|
|
|
for strip in (' :.-_'): id_ = id_.replace(strip, '')
|
|
|
|
return id_
|
2006-12-23 00:30:23 +01:00
|
|
|
|
|
|
|
def __eq__(self, other):
|
|
|
|
sa, sd = self.algo, self.digest
|
|
|
|
if isinstance(other, self.__class__):
|
|
|
|
oa, od = other.algo, other.digest
|
|
|
|
elif isinstance(other, basestring):
|
2006-12-23 22:18:07 +01:00
|
|
|
sa, oa, od = None, None, self.cleanID(other)
|
2006-12-23 00:30:23 +01:00
|
|
|
elif isinstance(other, tuple) and len(other) == 2:
|
2006-12-23 22:18:07 +01:00
|
|
|
oa, od = self.cleanID(other[0]), self.cleanID(other[1])
|
2006-12-23 00:30:23 +01:00
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
|
|
|
return sa == oa and sd == od
|
|
|
|
|
|
|
|
def __ne__(self, other):
|
|
|
|
return not self == other
|
|
|
|
|
|
|
|
def __hash__(self):
|
|
|
|
return self.algo ^ self.digest
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
prettydigest = ''
|
|
|
|
for i in xrange(0, len(self.digest), 2):
|
|
|
|
prettydigest += self.digest[i:i + 2] + ':'
|
|
|
|
return prettydigest[:-1]
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return "%s(%s, %s)" % (self.__class__, repr(self.algo), repr(str(self)))
|
|
|
|
|
|
|
|
class ServersXMLHandler(xml.sax.ContentHandler):
|
|
|
|
def __init__(self):
|
2005-09-18 17:03:04 +02:00
|
|
|
xml.sax.ContentHandler.__init__(self)
|
|
|
|
self.servers = []
|
|
|
|
|
|
|
|
def startElement(self, name, attributes):
|
2006-12-23 00:30:23 +01:00
|
|
|
if name == 'item':
|
|
|
|
# we will get the port next time so we just set it 0 here
|
|
|
|
sitem = [None, 0, {}]
|
|
|
|
sitem[2]['digest'] = {}
|
|
|
|
sitem[2]['hidden'] = False
|
2005-09-18 17:03:04 +02:00
|
|
|
for attribute in attributes.getNames():
|
|
|
|
if attribute == 'jid':
|
|
|
|
jid = attributes.getValue(attribute)
|
2006-12-23 00:30:23 +01:00
|
|
|
sitem[0] = jid
|
|
|
|
elif attribute == 'hidden':
|
|
|
|
hidden = attributes.getValue(attribute)
|
2006-12-23 22:18:07 +01:00
|
|
|
if hidden.lower() in ('1', 'y', 'yes', 't', 'true', 'on'):
|
2006-12-23 00:30:23 +01:00
|
|
|
sitem[2]['hidden'] = True
|
|
|
|
self.servers.append(sitem)
|
|
|
|
elif name == 'active':
|
2005-09-18 17:03:04 +02:00
|
|
|
for attribute in attributes.getNames():
|
|
|
|
if attribute == 'port':
|
|
|
|
port = attributes.getValue(attribute)
|
2005-10-07 12:33:52 +02:00
|
|
|
# we received the jid last time, so we now assign the port
|
|
|
|
# number to the last jid in the list
|
2005-09-18 17:03:04 +02:00
|
|
|
self.servers[-1][1] = port
|
2006-12-23 00:30:23 +01:00
|
|
|
elif name == 'digest':
|
2006-12-23 22:18:07 +01:00
|
|
|
algo, digest = None, None
|
2006-12-23 00:30:23 +01:00
|
|
|
for attribute in attributes.getNames():
|
|
|
|
if attribute == 'algo':
|
|
|
|
algo = attributes.getValue(attribute)
|
|
|
|
elif attribute == 'value':
|
|
|
|
digest = attributes.getValue(attribute)
|
|
|
|
hd = HashDigest(algo, digest)
|
|
|
|
self.servers[-1][2]['digest'][hd.algo] = hd
|
2005-09-18 17:03:04 +02:00
|
|
|
|
|
|
|
def endElement(self, name):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def parse_server_xml(path_to_file):
|
|
|
|
try:
|
2006-12-23 00:30:23 +01:00
|
|
|
handler = ServersXMLHandler()
|
2005-09-18 17:03:04 +02:00
|
|
|
xml.sax.parse(path_to_file, handler)
|
|
|
|
return handler.servers
|
|
|
|
# handle exception if unable to open file
|
|
|
|
except IOError, message:
|
2005-10-07 12:33:52 +02:00
|
|
|
print >> sys.stderr, _('Error reading file:'), message
|
2005-09-18 17:03:04 +02:00
|
|
|
# handle exception parsing file
|
|
|
|
except xml.sax.SAXParseException, message:
|
2005-10-07 12:33:52 +02:00
|
|
|
print >> sys.stderr, _('Error parsing file:'), message
|
2005-09-18 17:03:04 +02:00
|
|
|
|
2005-09-25 20:37:50 +02:00
|
|
|
def set_unset_urgency_hint(window, unread_messages_no):
|
2005-09-04 18:57:09 +02:00
|
|
|
'''sets/unsets urgency hint in window argument
|
|
|
|
depending if we have unread messages or not'''
|
2007-01-17 00:26:38 +01:00
|
|
|
if gajim.config.get('use_urgency_hint'):
|
2005-09-04 18:57:09 +02:00
|
|
|
if unread_messages_no > 0:
|
|
|
|
window.props.urgency_hint = True
|
|
|
|
else:
|
|
|
|
window.props.urgency_hint = False
|
2005-09-07 23:12:30 +02:00
|
|
|
|
|
|
|
def get_abspath_for_script(scriptname, want_type = False):
|
|
|
|
'''checks if we are svn or normal user and returns abspath to asked script
|
|
|
|
if want_type is True we return 'svn' or 'install' '''
|
|
|
|
if os.path.isdir('.svn'): # we are svn user
|
2008-12-03 18:16:04 +01:00
|
|
|
type_ = 'svn'
|
2005-09-07 23:12:30 +02:00
|
|
|
cwd = os.getcwd() # it's always ending with src
|
|
|
|
|
|
|
|
if scriptname == 'gajim-remote':
|
|
|
|
path_to_script = cwd + '/gajim-remote.py'
|
2008-12-03 22:56:12 +01:00
|
|
|
|
2005-09-07 23:12:30 +02:00
|
|
|
elif scriptname == 'gajim':
|
|
|
|
script = '#!/bin/sh\n' # the script we may create
|
|
|
|
script += 'cd %s' % cwd
|
|
|
|
path_to_script = cwd + '/../scripts/gajim_sm_script'
|
2008-12-03 22:56:12 +01:00
|
|
|
|
2005-09-08 15:53:32 +02:00
|
|
|
try:
|
|
|
|
if os.path.exists(path_to_script):
|
|
|
|
os.remove(path_to_script)
|
|
|
|
|
|
|
|
f = open(path_to_script, 'w')
|
|
|
|
script += '\nexec python -OOt gajim.py $0 $@\n'
|
|
|
|
f.write(script)
|
|
|
|
f.close()
|
|
|
|
os.chmod(path_to_script, 0700)
|
|
|
|
except OSError: # do not traceback (could be a permission problem)
|
|
|
|
#we talk about a file here
|
|
|
|
s = _('Could not write to %s. Session Management support will not work') % path_to_script
|
|
|
|
print >> sys.stderr, s
|
2005-09-07 23:12:30 +02:00
|
|
|
|
|
|
|
else: # normal user (not svn user)
|
2008-12-03 18:16:04 +01:00
|
|
|
type_ = 'install'
|
2005-09-07 23:12:30 +02:00
|
|
|
# always make it like '/usr/local/bin/gajim'
|
|
|
|
path_to_script = helpers.is_in_path(scriptname, True)
|
2008-12-03 22:56:12 +01:00
|
|
|
|
|
|
|
|
2005-09-07 23:12:30 +02:00
|
|
|
if want_type:
|
2008-12-03 18:16:04 +01:00
|
|
|
return path_to_script, type_
|
2005-09-07 23:12:30 +02:00
|
|
|
else:
|
|
|
|
return path_to_script
|
2005-10-03 20:19:31 +02:00
|
|
|
|
2006-01-14 14:50:35 +01:00
|
|
|
def get_pixbuf_from_data(file_data, want_type = False):
|
|
|
|
'''Gets image data and returns gtk.gdk.Pixbuf
|
|
|
|
if want_type is True it also returns 'jpeg', 'png' etc'''
|
2005-10-03 20:19:31 +02:00
|
|
|
pixbufloader = gtk.gdk.PixbufLoader()
|
|
|
|
try:
|
|
|
|
pixbufloader.write(file_data)
|
|
|
|
pixbufloader.close()
|
|
|
|
pixbuf = pixbufloader.get_pixbuf()
|
|
|
|
except gobject.GError: # 'unknown image format'
|
2007-01-21 21:16:29 +01:00
|
|
|
pixbufloader.close()
|
2005-10-03 20:19:31 +02:00
|
|
|
pixbuf = None
|
2006-12-19 23:50:53 +01:00
|
|
|
if want_type:
|
|
|
|
return None, None
|
|
|
|
else:
|
|
|
|
return None
|
2005-10-03 20:19:31 +02:00
|
|
|
|
2006-01-14 14:50:35 +01:00
|
|
|
if want_type:
|
|
|
|
typ = pixbufloader.get_format()['name']
|
|
|
|
return pixbuf, typ
|
|
|
|
else:
|
|
|
|
return pixbuf
|
2005-10-16 16:19:02 +02:00
|
|
|
|
|
|
|
def get_invisible_cursor():
|
|
|
|
pixmap = gtk.gdk.Pixmap(None, 1, 1, 1)
|
|
|
|
color = gtk.gdk.Color()
|
|
|
|
cursor = gtk.gdk.Cursor(pixmap, pixmap, color, color, 0, 0)
|
|
|
|
return cursor
|
2005-10-31 19:06:36 +01:00
|
|
|
|
|
|
|
def get_current_desktop(window):
|
|
|
|
'''returns the current virtual desktop for given window
|
|
|
|
NOTE: window is GDK window'''
|
|
|
|
prop = window.property_get('_NET_CURRENT_DESKTOP')
|
|
|
|
if prop is None: # it means it's normal window (not root window)
|
|
|
|
# so we look for it's current virtual desktop in another property
|
|
|
|
prop = window.property_get('_NET_WM_DESKTOP')
|
|
|
|
|
|
|
|
if prop is not None:
|
|
|
|
# f.e. prop is ('CARDINAL', 32, [0]) we want 0 or 1.. from [0]
|
|
|
|
current_virtual_desktop_no = prop[2][0]
|
|
|
|
return current_virtual_desktop_no
|
2005-10-31 20:35:17 +01:00
|
|
|
|
|
|
|
def possibly_move_window_in_current_desktop(window):
|
|
|
|
'''moves GTK window to current virtual desktop if it is not in the
|
|
|
|
current virtual desktop
|
|
|
|
window is GTK window'''
|
|
|
|
if os.name == 'nt':
|
2006-11-18 21:52:28 +01:00
|
|
|
return False
|
2005-10-31 20:35:17 +01:00
|
|
|
|
|
|
|
root_window = gtk.gdk.screen_get_default().get_root_window()
|
|
|
|
# current user's vd
|
|
|
|
current_virtual_desktop_no = get_current_desktop(root_window)
|
2008-12-03 22:56:12 +01:00
|
|
|
|
2005-10-31 20:35:17 +01:00
|
|
|
# vd roster window is in
|
|
|
|
window_virtual_desktop = get_current_desktop(window.window)
|
|
|
|
|
|
|
|
# if one of those is None, something went wrong and we cannot know
|
|
|
|
# VD info, just hide it (default action) and not show it afterwards
|
|
|
|
if None not in (window_virtual_desktop, current_virtual_desktop_no):
|
|
|
|
if current_virtual_desktop_no != window_virtual_desktop:
|
|
|
|
# we are in another VD that the window was
|
|
|
|
# so show it in current VD
|
2006-09-13 18:47:58 +02:00
|
|
|
window.present()
|
2006-11-18 21:52:28 +01:00
|
|
|
return True
|
|
|
|
return False
|
2005-11-01 21:01:14 +01:00
|
|
|
|
|
|
|
def file_is_locked(path_to_file):
|
|
|
|
'''returns True if file is locked (WINDOWS ONLY)'''
|
|
|
|
if os.name != 'nt': # just in case
|
|
|
|
return
|
2008-12-03 22:56:12 +01:00
|
|
|
|
2005-11-02 11:52:12 +01:00
|
|
|
if not HAS_PYWIN32:
|
|
|
|
return
|
2008-12-03 22:56:12 +01:00
|
|
|
|
2005-11-01 21:01:14 +01:00
|
|
|
secur_att = pywintypes.SECURITY_ATTRIBUTES()
|
|
|
|
secur_att.Initialize()
|
2008-12-03 22:56:12 +01:00
|
|
|
|
2005-11-01 21:01:14 +01:00
|
|
|
try:
|
|
|
|
# try make a handle for READING the file
|
|
|
|
hfile = win32file.CreateFile(
|
|
|
|
path_to_file, # path to file
|
|
|
|
win32con.GENERIC_READ, # open for reading
|
|
|
|
0, # do not share with other proc
|
|
|
|
secur_att,
|
|
|
|
win32con.OPEN_EXISTING, # existing file only
|
|
|
|
win32con.FILE_ATTRIBUTE_NORMAL, # normal file
|
|
|
|
0 # no attr. template
|
|
|
|
)
|
2008-12-02 16:53:23 +01:00
|
|
|
except pywintypes.error:
|
2005-11-01 21:01:14 +01:00
|
|
|
return True
|
|
|
|
else: # in case all went ok, close file handle (go to hell WinAPI)
|
|
|
|
hfile.Close()
|
|
|
|
return False
|
2005-11-07 12:07:55 +01:00
|
|
|
|
2005-11-08 15:09:56 +01:00
|
|
|
def _get_fade_color(treeview, selected, focused):
|
|
|
|
'''get a gdk color that is between foreground and background in 0.3
|
|
|
|
0.7 respectively colors of the cell for the given treeview'''
|
2005-11-07 12:07:55 +01:00
|
|
|
style = treeview.style
|
|
|
|
if selected:
|
2005-11-08 15:09:56 +01:00
|
|
|
if focused: # is the window focused?
|
|
|
|
state = gtk.STATE_SELECTED
|
|
|
|
else: # is it not? NOTE: many gtk themes change bg on this
|
|
|
|
state = gtk.STATE_ACTIVE
|
2005-11-07 12:07:55 +01:00
|
|
|
else:
|
|
|
|
state = gtk.STATE_NORMAL
|
|
|
|
bg = style.base[state]
|
|
|
|
fg = style.text[state]
|
|
|
|
|
2005-11-08 15:09:56 +01:00
|
|
|
p = 0.3 # background
|
|
|
|
q = 0.7 # foreground # p + q should do 1.0
|
|
|
|
return gtk.gdk.Color(int(bg.red*p + fg.red*q),
|
2007-02-04 14:01:04 +01:00
|
|
|
int(bg.green*p + fg.green*q),
|
|
|
|
int(bg.blue*p + fg.blue*q))
|
2005-11-08 14:04:59 +01:00
|
|
|
|
2006-02-09 17:47:31 +01:00
|
|
|
def get_scaled_pixbuf(pixbuf, kind):
|
2006-04-07 21:03:38 +02:00
|
|
|
'''returns scaled pixbuf, keeping ratio etc or None
|
2006-09-13 18:47:58 +02:00
|
|
|
kind is either "chat", "roster", "notification", "tooltip", "vcard"'''
|
2008-12-03 22:56:12 +01:00
|
|
|
|
2005-11-08 14:04:59 +01:00
|
|
|
# resize to a width / height for the avatar not to have distortion
|
|
|
|
# (keep aspect ratio)
|
2006-03-08 16:56:49 +01:00
|
|
|
width = gajim.config.get(kind + '_avatar_width')
|
|
|
|
height = gajim.config.get(kind + '_avatar_height')
|
2006-04-07 21:03:38 +02:00
|
|
|
if width < 1 or height < 1:
|
|
|
|
return None
|
2005-11-29 19:29:03 +01:00
|
|
|
|
2006-03-08 16:56:49 +01:00
|
|
|
# Pixbuf size
|
|
|
|
pix_width = pixbuf.get_width()
|
|
|
|
pix_height = pixbuf.get_height()
|
2005-11-29 19:37:01 +01:00
|
|
|
# don't make avatars bigger than they are
|
2006-03-08 16:56:49 +01:00
|
|
|
if pix_width < width and pix_height < height:
|
2005-11-29 19:29:03 +01:00
|
|
|
return pixbuf # we don't want to make avatar bigger
|
2005-11-29 19:37:01 +01:00
|
|
|
|
2006-03-08 16:56:49 +01:00
|
|
|
ratio = float(pix_width) / float(pix_height)
|
2005-11-08 14:04:59 +01:00
|
|
|
if ratio > 1:
|
2006-03-08 16:56:49 +01:00
|
|
|
w = width
|
2005-11-08 14:04:59 +01:00
|
|
|
h = int(w / ratio)
|
|
|
|
else:
|
2006-03-08 16:56:49 +01:00
|
|
|
h = height
|
2005-11-08 14:04:59 +01:00
|
|
|
w = int(h * ratio)
|
|
|
|
scaled_buf = pixbuf.scale_simple(w, h, gtk.gdk.INTERP_HYPER)
|
|
|
|
return scaled_buf
|
2005-11-12 22:24:54 +01:00
|
|
|
|
2007-04-22 12:23:23 +02:00
|
|
|
def get_avatar_pixbuf_from_cache(fjid, is_fake_jid = False, use_local = True):
|
2005-11-12 22:24:54 +01:00
|
|
|
'''checks if jid has cached avatar and if that avatar is valid image
|
|
|
|
(can be shown)
|
2005-11-16 00:26:22 +01:00
|
|
|
returns None if there is no image in vcard
|
2005-11-29 11:16:31 +01:00
|
|
|
returns 'ask' if cached vcard should not be used (user changed his vcard,
|
|
|
|
so we have new sha) or if we don't have the vcard'''
|
2005-12-02 14:10:02 +01:00
|
|
|
|
2006-03-09 19:41:57 +01:00
|
|
|
jid, nick = gajim.get_room_and_nick_from_fjid(fjid)
|
2005-12-02 14:10:02 +01:00
|
|
|
if gajim.config.get('hide_avatar_of_transport') and\
|
|
|
|
gajim.jid_is_transport(jid):
|
|
|
|
# don't show avatar for the transport itself
|
|
|
|
return None
|
2006-03-09 19:41:57 +01:00
|
|
|
|
2006-03-26 13:46:04 +02:00
|
|
|
puny_jid = helpers.sanitize_filename(jid)
|
2006-03-09 19:41:57 +01:00
|
|
|
if is_fake_jid:
|
2006-03-26 13:46:04 +02:00
|
|
|
puny_nick = helpers.sanitize_filename(nick)
|
2006-03-10 19:48:14 +01:00
|
|
|
path = os.path.join(gajim.VCARD_PATH, puny_jid, puny_nick)
|
2007-04-22 12:23:23 +02:00
|
|
|
local_avatar_basepath = os.path.join(gajim.AVATAR_PATH, puny_jid,
|
|
|
|
puny_nick) + '_local'
|
2006-03-09 19:41:57 +01:00
|
|
|
else:
|
2006-03-10 19:48:14 +01:00
|
|
|
path = os.path.join(gajim.VCARD_PATH, puny_jid)
|
2007-04-22 12:23:23 +02:00
|
|
|
local_avatar_basepath = os.path.join(gajim.AVATAR_PATH, puny_jid) + \
|
|
|
|
'_local'
|
|
|
|
if use_local:
|
|
|
|
for extension in ('.png', '.jpeg'):
|
|
|
|
local_avatar_path = local_avatar_basepath + extension
|
|
|
|
if os.path.isfile(local_avatar_path):
|
2007-04-22 20:05:53 +02:00
|
|
|
avatar_file = open(local_avatar_path, 'rb')
|
2007-04-22 12:23:23 +02:00
|
|
|
avatar_data = avatar_file.read()
|
|
|
|
avatar_file.close()
|
|
|
|
return get_pixbuf_from_data(avatar_data)
|
|
|
|
|
2006-03-09 19:41:57 +01:00
|
|
|
if not os.path.isfile(path):
|
2005-11-12 22:24:54 +01:00
|
|
|
return 'ask'
|
|
|
|
|
2006-03-09 19:41:57 +01:00
|
|
|
vcard_dict = gajim.connections.values()[0].get_cached_vcard(fjid,
|
|
|
|
is_fake_jid)
|
2005-11-12 22:24:54 +01:00
|
|
|
if not vcard_dict: # This can happen if cached vcard is too old
|
|
|
|
return 'ask'
|
2008-10-07 22:41:59 +02:00
|
|
|
if 'PHOTO' not in vcard_dict:
|
2005-11-12 22:24:54 +01:00
|
|
|
return None
|
|
|
|
pixbuf = vcard.get_avatar_pixbuf_encoded_mime(vcard_dict['PHOTO'])[0]
|
|
|
|
return pixbuf
|
2005-11-20 22:58:08 +01:00
|
|
|
|
|
|
|
def make_gtk_month_python_month(month):
|
|
|
|
'''gtk start counting months from 0, so January is 0
|
|
|
|
but python's time start from 1, so align to python
|
|
|
|
month MUST be integer'''
|
|
|
|
return month + 1
|
2005-11-24 02:39:47 +01:00
|
|
|
|
|
|
|
def make_python_month_gtk_month(month):
|
|
|
|
return month - 1
|
2005-12-01 19:16:30 +01:00
|
|
|
|
|
|
|
def make_color_string(color):
|
|
|
|
'''create #aabbcc color string from gtk color'''
|
2006-02-05 18:12:36 +01:00
|
|
|
col = '#'
|
2007-06-17 14:09:45 +02:00
|
|
|
for i in ('red', 'green', 'blue'):
|
|
|
|
h = hex(getattr(color, i) / (16*16)).split('x')[1]
|
2006-02-05 18:12:36 +01:00
|
|
|
if len(h) == 1:
|
|
|
|
h = '0' + h
|
|
|
|
col += h
|
|
|
|
return col
|
2006-01-12 23:48:49 +01:00
|
|
|
|
|
|
|
def make_pixbuf_grayscale(pixbuf):
|
|
|
|
pixbuf2 = pixbuf.copy()
|
|
|
|
pixbuf.saturate_and_pixelate(pixbuf2, 0.0, False)
|
|
|
|
return pixbuf2
|
2006-01-18 20:50:16 +01:00
|
|
|
|
2006-01-22 00:15:35 +01:00
|
|
|
def get_path_to_generic_or_avatar(generic, jid = None, suffix = None):
|
|
|
|
'''Chooses between avatar image and default image.
|
|
|
|
Returns full path to the avatar image if it exists,
|
2008-07-27 12:21:51 +02:00
|
|
|
otherwise returns full path to the image.
|
|
|
|
generic must be with extension and suffix without'''
|
2006-01-22 00:15:35 +01:00
|
|
|
if jid:
|
2008-07-27 12:21:51 +02:00
|
|
|
# we want an avatar
|
2006-03-26 13:46:04 +02:00
|
|
|
puny_jid = helpers.sanitize_filename(jid)
|
2006-03-10 19:58:28 +01:00
|
|
|
path_to_file = os.path.join(gajim.AVATAR_PATH, puny_jid) + suffix
|
2008-07-27 12:21:51 +02:00
|
|
|
path_to_local_file = path_to_file + '_local'
|
|
|
|
for extension in ('.png', '.jpeg'):
|
|
|
|
path_to_local_file_full = path_to_local_file + extension
|
|
|
|
if os.path.exists(path_to_local_file_full):
|
2008-12-03 22:56:12 +01:00
|
|
|
return path_to_local_file_full
|
2008-07-27 12:21:51 +02:00
|
|
|
for extension in ('.png', '.jpeg'):
|
|
|
|
path_to_file_full = path_to_file + extension
|
|
|
|
if os.path.exists(path_to_file_full):
|
|
|
|
return path_to_file_full
|
2006-02-08 01:55:16 +01:00
|
|
|
return os.path.abspath(generic)
|
2006-01-22 00:15:35 +01:00
|
|
|
|
2006-01-18 20:50:16 +01:00
|
|
|
def decode_filechooser_file_paths(file_paths):
|
|
|
|
'''decode as UTF-8 under Windows and
|
|
|
|
ask sys.getfilesystemencoding() in POSIX
|
|
|
|
file_paths MUST be LIST'''
|
|
|
|
file_paths_list = list()
|
2008-12-03 22:56:12 +01:00
|
|
|
|
2006-01-18 20:50:16 +01:00
|
|
|
if os.name == 'nt': # decode as UTF-8 under Windows
|
|
|
|
for file_path in file_paths:
|
|
|
|
file_path = file_path.decode('utf8')
|
|
|
|
file_paths_list.append(file_path)
|
|
|
|
else:
|
|
|
|
for file_path in file_paths:
|
2006-04-12 15:56:30 +02:00
|
|
|
try:
|
|
|
|
file_path = file_path.decode(sys.getfilesystemencoding())
|
2008-10-11 11:37:13 +02:00
|
|
|
except Exception:
|
2006-04-12 15:56:30 +02:00
|
|
|
try:
|
|
|
|
file_path = file_path.decode('utf-8')
|
2008-10-11 11:37:13 +02:00
|
|
|
except Exception:
|
2006-04-12 15:56:30 +02:00
|
|
|
pass
|
2006-01-18 20:50:16 +01:00
|
|
|
file_paths_list.append(file_path)
|
2008-12-03 22:56:12 +01:00
|
|
|
|
2006-01-18 20:50:16 +01:00
|
|
|
return file_paths_list
|
2006-01-20 18:36:22 +01:00
|
|
|
|
|
|
|
def possibly_set_gajim_as_xmpp_handler():
|
|
|
|
'''registers (by default only the first time) xmmp: to Gajim.'''
|
|
|
|
path_to_dot_kde = os.path.expanduser('~/.kde')
|
|
|
|
if os.path.exists(path_to_dot_kde):
|
2008-12-03 22:56:12 +01:00
|
|
|
path_to_kde_file = os.path.join(path_to_dot_kde,
|
2006-01-20 18:36:22 +01:00
|
|
|
'share/services/xmpp.protocol')
|
|
|
|
else:
|
|
|
|
path_to_kde_file = None
|
2007-01-05 18:20:58 +01:00
|
|
|
|
2007-10-01 19:11:47 +02:00
|
|
|
def set_gajim_as_xmpp_handler(is_checked=None):
|
2008-04-18 02:26:07 +02:00
|
|
|
if is_checked is not None:
|
2007-01-05 18:20:58 +01:00
|
|
|
# come from confirmation dialog
|
2007-10-01 19:11:47 +02:00
|
|
|
gajim.config.set('check_if_gajim_is_default', is_checked)
|
2007-01-05 18:20:58 +01:00
|
|
|
path_to_gajim_script, typ = get_abspath_for_script('gajim-remote', True)
|
|
|
|
if path_to_gajim_script:
|
|
|
|
if typ == 'svn':
|
|
|
|
command = path_to_gajim_script + ' handle_uri %s'
|
|
|
|
else: # 'installed'
|
|
|
|
command = 'gajim-remote handle_uri %s'
|
|
|
|
|
|
|
|
# setting for GNOME/Gconf
|
|
|
|
client.set_bool('/desktop/gnome/url-handlers/xmpp/enabled', True)
|
|
|
|
client.set_string('/desktop/gnome/url-handlers/xmpp/command', command)
|
|
|
|
client.set_bool('/desktop/gnome/url-handlers/xmpp/needs_terminal', False)
|
|
|
|
|
|
|
|
# setting for KDE
|
|
|
|
if path_to_kde_file is not None: # user has run kde at least once
|
2007-01-06 10:45:12 +01:00
|
|
|
try:
|
|
|
|
f = open(path_to_kde_file, 'a')
|
|
|
|
f.write('''\
|
2006-01-21 22:23:30 +01:00
|
|
|
[Protocol]
|
2006-01-20 18:36:22 +01:00
|
|
|
exec=%s "%%u"
|
|
|
|
protocol=xmpp
|
|
|
|
input=none
|
|
|
|
output=none
|
|
|
|
helper=true
|
|
|
|
listing=false
|
|
|
|
reading=false
|
|
|
|
writing=false
|
|
|
|
makedir=false
|
|
|
|
deleting=false
|
|
|
|
icon=gajim
|
|
|
|
Description=xmpp
|
|
|
|
''' % command)
|
2007-01-06 10:45:12 +01:00
|
|
|
f.close()
|
2007-01-06 15:15:49 +01:00
|
|
|
except IOError:
|
2007-01-06 16:31:30 +01:00
|
|
|
log.debug("I/O Error writing settings to %s", repr(path_to_kde_file), exc_info=True)
|
2007-02-12 17:53:59 +01:00
|
|
|
else: # no gajim remote, stop ask user everytime
|
|
|
|
gajim.config.set('check_if_gajim_is_default', False)
|
2007-01-05 18:20:58 +01:00
|
|
|
|
|
|
|
try:
|
|
|
|
import gconf
|
|
|
|
# in try because daemon may not be there
|
|
|
|
client = gconf.client_get_default()
|
2008-10-11 11:37:13 +02:00
|
|
|
except Exception:
|
2007-01-05 18:20:58 +01:00
|
|
|
return
|
|
|
|
|
|
|
|
old_command = client.get_string('/desktop/gnome/url-handlers/xmpp/command')
|
|
|
|
if not old_command or old_command.endswith(' open_chat %s'):
|
|
|
|
# first time (GNOME/GCONF) or old Gajim version
|
|
|
|
we_set = True
|
|
|
|
elif path_to_kde_file is not None and not os.path.exists(path_to_kde_file):
|
|
|
|
# only the first time (KDE)
|
|
|
|
we_set = True
|
|
|
|
else:
|
|
|
|
we_set = False
|
|
|
|
|
|
|
|
if we_set:
|
|
|
|
set_gajim_as_xmpp_handler()
|
|
|
|
elif old_command and not old_command.endswith(' handle_uri %s'):
|
2007-01-05 20:26:10 +01:00
|
|
|
# xmpp: is currently handled by another program, so ask the user
|
2007-01-05 18:20:58 +01:00
|
|
|
pritext = _('Gajim is not the default Jabber client')
|
|
|
|
sectext = _('Would you like to make Gajim the default Jabber client?')
|
|
|
|
checktext = _('Always check to see if Gajim is the default Jabber client '
|
|
|
|
'on startup')
|
2008-08-08 17:19:08 +02:00
|
|
|
def on_cancel(checked):
|
|
|
|
gajim.config.set('check_if_gajim_is_default', checked)
|
2007-01-05 18:20:58 +01:00
|
|
|
dlg = dialogs.ConfirmationDialogCheck(pritext, sectext, checktext,
|
|
|
|
set_gajim_as_xmpp_handler, on_cancel)
|
|
|
|
if gajim.config.get('check_if_gajim_is_default'):
|
|
|
|
dlg.checkbutton.set_active(True)
|
2006-02-08 06:13:26 +01:00
|
|
|
|
|
|
|
def escape_underscore(s):
|
|
|
|
'''Escape underlines to prevent them from being interpreted
|
|
|
|
as keyboard accelerators'''
|
|
|
|
return s.replace('_', '__')
|
2006-02-26 15:33:44 +01:00
|
|
|
|
|
|
|
def get_state_image_from_file_path_show(file_path, show):
|
|
|
|
state_file = show.replace(' ', '_')
|
|
|
|
files = []
|
|
|
|
files.append(os.path.join(file_path, state_file + '.png'))
|
|
|
|
files.append(os.path.join(file_path, state_file + '.gif'))
|
|
|
|
image = gtk.Image()
|
|
|
|
image.set_from_pixbuf(None)
|
|
|
|
for file_ in files:
|
|
|
|
if os.path.exists(file_):
|
|
|
|
image.set_from_file(file_)
|
|
|
|
break
|
2006-02-26 15:47:23 +01:00
|
|
|
|
|
|
|
return image
|
2006-03-29 18:39:14 +02:00
|
|
|
|
2006-03-29 18:46:12 +02:00
|
|
|
def get_possible_button_event(event):
|
2006-03-29 18:39:14 +02:00
|
|
|
'''mouse or keyboard caused the event?'''
|
|
|
|
if event.type == gtk.gdk.KEY_PRESS:
|
2006-11-19 20:45:43 +01:00
|
|
|
return 0 # no event.button so pass 0
|
|
|
|
# BUTTON_PRESS event, so pass event.button
|
|
|
|
return event.button
|
2006-04-07 17:51:17 +02:00
|
|
|
|
|
|
|
def destroy_widget(widget):
|
|
|
|
widget.destroy()
|
2006-05-26 15:19:52 +02:00
|
|
|
|
|
|
|
def on_avatar_save_as_menuitem_activate(widget, jid, account,
|
|
|
|
default_name = ''):
|
2008-08-10 22:43:38 +02:00
|
|
|
def on_continue(response, file_path):
|
2008-08-07 15:25:25 +02:00
|
|
|
if response < 0:
|
|
|
|
return
|
2006-05-26 15:19:52 +02:00
|
|
|
# Get pixbuf
|
|
|
|
pixbuf = None
|
|
|
|
is_fake = False
|
2006-06-09 16:42:20 +02:00
|
|
|
if account and gajim.contacts.is_pm_from_jid(account, jid):
|
2006-05-26 15:19:52 +02:00
|
|
|
is_fake = True
|
2007-04-22 12:23:23 +02:00
|
|
|
pixbuf = get_avatar_pixbuf_from_cache(jid, is_fake, False)
|
2006-05-26 15:19:52 +02:00
|
|
|
ext = file_path.split('.')[-1]
|
|
|
|
type_ = ''
|
|
|
|
if not ext:
|
|
|
|
# Silently save as Jpeg image
|
|
|
|
file_path += '.jpeg'
|
|
|
|
type_ = 'jpeg'
|
|
|
|
elif ext == 'jpg':
|
|
|
|
type_ = 'jpeg'
|
|
|
|
else:
|
|
|
|
type_ = ext
|
|
|
|
|
|
|
|
# Save image
|
|
|
|
try:
|
|
|
|
pixbuf.save(file_path, type_)
|
2008-12-03 22:37:05 +01:00
|
|
|
except Exception:
|
2006-11-18 21:52:28 +01:00
|
|
|
if os.path.exists(file_path):
|
|
|
|
os.remove(file_path)
|
2006-05-26 15:19:52 +02:00
|
|
|
new_file_path = '.'.join(file_path.split('.')[:-1]) + '.jpeg'
|
2008-08-10 22:43:38 +02:00
|
|
|
def on_ok(file_path, pixbuf):
|
|
|
|
pixbuf.save(file_path, 'jpeg')
|
2007-10-07 19:22:47 +02:00
|
|
|
dialogs.ConfirmationDialog(_('Extension not supported'),
|
2006-05-26 15:19:52 +02:00
|
|
|
_('Image cannot be saved in %(type)s format. Save as %(new_filename)s?') % {'type': type_, 'new_filename': new_file_path},
|
2008-08-10 22:43:38 +02:00
|
|
|
on_response_ok = (on_ok, new_file_path, pixbuf))
|
2006-05-26 15:19:52 +02:00
|
|
|
else:
|
|
|
|
dialog.destroy()
|
|
|
|
|
2008-08-07 15:25:25 +02:00
|
|
|
def on_ok(widget):
|
|
|
|
file_path = dialog.get_filename()
|
|
|
|
file_path = decode_filechooser_file_paths((file_path,))[0]
|
|
|
|
if os.path.exists(file_path):
|
|
|
|
# check if we have write permissions
|
|
|
|
if not os.access(file_path, os.W_OK):
|
|
|
|
file_name = os.path.basename(file_path)
|
2008-12-03 22:56:12 +01:00
|
|
|
dialogs.ErrorDialog(_('Cannot overwrite existing file "%s"' %
|
2008-08-07 15:25:25 +02:00
|
|
|
file_name),
|
|
|
|
_('A file with this name already exists and you do not have '
|
|
|
|
'permission to overwrite it.'))
|
|
|
|
return
|
|
|
|
dialog2 = dialogs.FTOverwriteConfirmationDialog(
|
|
|
|
_('This file already exists'), _('What do you want to do?'),
|
2008-08-10 22:43:38 +02:00
|
|
|
propose_resume=False, on_response=(on_continue, file_path))
|
2008-08-07 15:25:25 +02:00
|
|
|
dialog2.set_transient_for(dialog)
|
|
|
|
dialog2.set_destroy_with_parent(True)
|
|
|
|
else:
|
|
|
|
dirname = os.path.dirname(file_path)
|
|
|
|
if not os.access(dirname, os.W_OK):
|
|
|
|
dialogs.ErrorDialog(_('Directory "%s" is not writable') % \
|
|
|
|
dirname, _('You do not have permission to create files in this'
|
|
|
|
' directory.'))
|
|
|
|
return
|
|
|
|
|
2008-08-10 22:43:38 +02:00
|
|
|
on_continue(0, file_path)
|
2008-08-07 15:25:25 +02:00
|
|
|
|
2006-05-26 15:19:52 +02:00
|
|
|
def on_cancel(widget):
|
|
|
|
dialog.destroy()
|
|
|
|
|
2008-12-03 22:56:12 +01:00
|
|
|
dialog = dialogs.FileChooserDialog(title_text=_('Save Image as...'),
|
2008-08-07 15:25:25 +02:00
|
|
|
action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL,
|
|
|
|
gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK),
|
|
|
|
default_response=gtk.RESPONSE_OK,
|
|
|
|
current_folder=gajim.config.get('last_save_dir'), on_response_ok=on_ok,
|
|
|
|
on_response_cancel=on_cancel)
|
2006-05-26 15:19:52 +02:00
|
|
|
|
|
|
|
dialog.set_current_name(default_name)
|
|
|
|
dialog.connect('delete-event', lambda widget, event:
|
|
|
|
on_cancel(widget))
|
2006-11-18 21:52:28 +01:00
|
|
|
|
|
|
|
def on_bm_header_changed_state(widget, event):
|
|
|
|
widget.set_state(gtk.STATE_NORMAL) #do not allow selected_state
|
2007-03-20 15:09:27 +01:00
|
|
|
|
|
|
|
def create_combobox(value_list, selected_value = None):
|
|
|
|
'''Value_list is [(label1, value1), ]'''
|
|
|
|
liststore = gtk.ListStore(str, str)
|
|
|
|
combobox = gtk.ComboBox(liststore)
|
|
|
|
cell = gtk.CellRendererText()
|
|
|
|
combobox.pack_start(cell, True)
|
|
|
|
combobox.add_attribute(cell, 'text', 0)
|
|
|
|
i = -1
|
|
|
|
for value in value_list:
|
|
|
|
liststore.append(value)
|
|
|
|
if selected_value == value[1]:
|
|
|
|
i = value_list.index(value)
|
|
|
|
if i > -1:
|
|
|
|
combobox.set_active(i)
|
|
|
|
combobox.show_all()
|
|
|
|
return combobox
|
2008-04-17 16:17:14 +02:00
|
|
|
|
2009-08-31 21:45:52 +02:00
|
|
|
def create_list_multi(value_list, selected_values=None):
|
|
|
|
'''Value_list is [(label1, value1), ]'''
|
|
|
|
liststore = gtk.ListStore(str, str)
|
|
|
|
treeview = gtk.TreeView(liststore)
|
|
|
|
treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
|
|
|
|
treeview.set_headers_visible(False)
|
|
|
|
col = gtk.TreeViewColumn()
|
|
|
|
treeview.append_column(col)
|
|
|
|
cell = gtk.CellRendererText()
|
|
|
|
col.pack_start(cell, True)
|
|
|
|
col.set_attributes(cell, text=0)
|
|
|
|
for value in value_list:
|
|
|
|
iter = liststore.append(value)
|
|
|
|
if value[1] in selected_values:
|
|
|
|
treeview.get_selection().select_iter(iter)
|
|
|
|
treeview.show_all()
|
|
|
|
return treeview
|
|
|
|
|
|
|
|
def load_iconset(path, pixbuf2=None, transport=False):
|
2008-04-17 16:17:14 +02:00
|
|
|
'''load full iconset from the given path, and add
|
|
|
|
pixbuf2 on top left of each static images'''
|
|
|
|
path += '/'
|
|
|
|
if transport:
|
2008-12-03 18:16:04 +01:00
|
|
|
list_ = ('online', 'chat', 'away', 'xa', 'dnd', 'offline',
|
2008-04-17 16:17:14 +02:00
|
|
|
'not in roster')
|
|
|
|
else:
|
2008-12-03 18:16:04 +01:00
|
|
|
list_ = ('connecting', 'online', 'chat', 'away', 'xa', 'dnd',
|
2008-04-17 16:17:14 +02:00
|
|
|
'invisible', 'offline', 'error', 'requested', 'event', 'opened',
|
|
|
|
'closed', 'not in roster', 'muc_active', 'muc_inactive')
|
|
|
|
if pixbuf2:
|
2008-12-03 18:16:04 +01:00
|
|
|
list_ = ('connecting', 'online', 'chat', 'away', 'xa', 'dnd',
|
2008-04-17 16:17:14 +02:00
|
|
|
'offline', 'error', 'requested', 'event', 'not in roster')
|
2008-12-03 18:16:04 +01:00
|
|
|
return _load_icon_list(list_, path, pixbuf2)
|
2008-04-17 16:17:14 +02:00
|
|
|
|
|
|
|
def load_icon(icon_name):
|
|
|
|
'''load an icon from the iconset in 16x16'''
|
|
|
|
iconset = gajim.config.get('iconset')
|
2008-07-22 23:08:52 +02:00
|
|
|
path = os.path.join(helpers.get_iconset_path(iconset), '16x16', '')
|
|
|
|
icon_list = _load_icon_list([icon_name], path)
|
|
|
|
return icon_list[icon_name]
|
|
|
|
|
|
|
|
def load_mood_icon(icon_name):
|
|
|
|
'''load an icon from the mood iconset in 16x16'''
|
|
|
|
iconset = gajim.config.get('mood_iconset')
|
|
|
|
path = os.path.join(helpers.get_mood_iconset_path(iconset), '')
|
2008-04-17 16:17:14 +02:00
|
|
|
icon_list = _load_icon_list([icon_name], path)
|
|
|
|
return icon_list[icon_name]
|
|
|
|
|
2008-10-22 16:21:57 +02:00
|
|
|
def load_activity_icon(category, activity = None):
|
2008-07-28 22:57:56 +02:00
|
|
|
'''load an icon from the activity iconset in 16x16'''
|
|
|
|
iconset = gajim.config.get('activity_iconset')
|
|
|
|
path = os.path.join(helpers.get_activity_iconset_path(iconset),
|
2008-10-22 16:21:57 +02:00
|
|
|
category, '')
|
|
|
|
if activity is None:
|
|
|
|
activity = 'category'
|
|
|
|
icon_list = _load_icon_list([activity], path)
|
|
|
|
return icon_list[activity]
|
2008-07-28 22:57:56 +02:00
|
|
|
|
2008-04-17 16:17:14 +02:00
|
|
|
def load_icons_meta():
|
|
|
|
'''load and return - AND + small icons to put on top left of an icon
|
|
|
|
for meta contacts.'''
|
|
|
|
iconset = gajim.config.get('iconset')
|
|
|
|
path = os.path.join(helpers.get_iconset_path(iconset), '16x16')
|
|
|
|
# try to find opened_meta.png file, else opened.png else nopixbuf merge
|
|
|
|
path_opened = os.path.join(path, 'opened_meta.png')
|
|
|
|
if not os.path.isfile(path_opened):
|
|
|
|
path_opened = os.path.join(path, 'opened.png')
|
|
|
|
if os.path.isfile(path_opened):
|
|
|
|
pixo = gtk.gdk.pixbuf_new_from_file(path_opened)
|
|
|
|
else:
|
|
|
|
pixo = None
|
|
|
|
# Same thing for closed
|
|
|
|
path_closed = os.path.join(path, 'opened_meta.png')
|
|
|
|
if not os.path.isfile(path_closed):
|
|
|
|
path_closed = os.path.join(path, 'closed.png')
|
|
|
|
if os.path.isfile(path_closed):
|
|
|
|
pixc = gtk.gdk.pixbuf_new_from_file(path_closed)
|
|
|
|
else:
|
|
|
|
pixc = None
|
|
|
|
return pixo, pixc
|
|
|
|
|
|
|
|
def _load_icon_list(icons_list, path, pixbuf2 = None):
|
|
|
|
'''load icons in icons_list from the given path,
|
|
|
|
and add pixbuf2 on top left of each static images'''
|
|
|
|
imgs = {}
|
|
|
|
for icon in icons_list:
|
|
|
|
# try to open a pixfile with the correct method
|
|
|
|
icon_file = icon.replace(' ', '_')
|
|
|
|
files = []
|
|
|
|
files.append(path + icon_file + '.gif')
|
|
|
|
files.append(path + icon_file + '.png')
|
|
|
|
image = gtk.Image()
|
|
|
|
image.show()
|
|
|
|
imgs[icon] = image
|
2008-12-03 18:16:04 +01:00
|
|
|
for file_ in files: # loop seeking for either gif or png
|
|
|
|
if os.path.exists(file_):
|
|
|
|
image.set_from_file(file_)
|
2008-04-17 16:17:14 +02:00
|
|
|
if pixbuf2 and image.get_storage_type() == gtk.IMAGE_PIXBUF:
|
|
|
|
# add pixbuf2 on top-left corner of image
|
|
|
|
pixbuf1 = image.get_pixbuf()
|
|
|
|
pixbuf2.composite(pixbuf1, 0, 0,
|
|
|
|
pixbuf2.get_property('width'),
|
|
|
|
pixbuf2.get_property('height'), 0, 0, 1.0, 1.0,
|
|
|
|
gtk.gdk.INTERP_NEAREST, 255)
|
|
|
|
image.set_from_pixbuf(pixbuf1)
|
|
|
|
break
|
|
|
|
return imgs
|
|
|
|
|
|
|
|
def make_jabber_state_images():
|
|
|
|
'''initialise jabber_state_images dict'''
|
|
|
|
iconset = gajim.config.get('iconset')
|
|
|
|
if iconset:
|
2009-06-10 11:44:58 +02:00
|
|
|
if helpers.get_iconset_path(iconset):
|
|
|
|
path = os.path.join(helpers.get_iconset_path(iconset), '16x16')
|
|
|
|
if not os.path.exists(path):
|
|
|
|
iconset = gajim.config.DEFAULT_ICONSET
|
|
|
|
gajim.config.set('iconset', iconset)
|
|
|
|
else:
|
2008-04-17 16:17:14 +02:00
|
|
|
iconset = gajim.config.DEFAULT_ICONSET
|
2009-06-10 11:44:58 +02:00
|
|
|
gajim.config.set('iconset', iconset)
|
2008-04-17 16:17:14 +02:00
|
|
|
else:
|
|
|
|
iconset = gajim.config.DEFAULT_ICONSET
|
2009-06-10 11:44:58 +02:00
|
|
|
gajim.config.set('iconset', iconset)
|
2008-04-17 16:17:14 +02:00
|
|
|
|
|
|
|
path = os.path.join(helpers.get_iconset_path(iconset), '32x32')
|
|
|
|
gajim.interface.jabber_state_images['32'] = load_iconset(path)
|
|
|
|
|
|
|
|
path = os.path.join(helpers.get_iconset_path(iconset), '16x16')
|
|
|
|
gajim.interface.jabber_state_images['16'] = load_iconset(path)
|
|
|
|
|
|
|
|
pixo, pixc = load_icons_meta()
|
|
|
|
gajim.interface.jabber_state_images['opened'] = load_iconset(path, pixo)
|
|
|
|
gajim.interface.jabber_state_images['closed'] = load_iconset(path, pixc)
|
|
|
|
|
|
|
|
def reload_jabber_state_images():
|
|
|
|
make_jabber_state_images()
|
|
|
|
gajim.interface.roster.update_jabber_state_images()
|
2008-07-29 21:49:31 +02:00
|
|
|
|
2009-04-08 20:52:50 +02:00
|
|
|
def label_set_autowrap(widget):
|
|
|
|
'''Make labels automatically re-wrap if their containers are resized.
|
|
|
|
Accepts label or container widgets.'''
|
|
|
|
if isinstance (widget, gtk.Container):
|
|
|
|
children = widget.get_children()
|
|
|
|
for i in xrange (len (children)):
|
|
|
|
label_set_autowrap(children[i])
|
|
|
|
elif isinstance(widget, gtk.Label):
|
|
|
|
widget.set_line_wrap(True)
|
|
|
|
widget.connect_after('size-allocate', __label_size_allocate)
|
|
|
|
|
|
|
|
def __label_size_allocate(widget, allocation):
|
|
|
|
'''Callback which re-allocates the size of a label.'''
|
|
|
|
layout = widget.get_layout()
|
|
|
|
|
|
|
|
lw_old, lh_old = layout.get_size()
|
|
|
|
# fixed width labels
|
|
|
|
if lw_old/pango.SCALE == allocation.width:
|
|
|
|
return
|
|
|
|
|
|
|
|
# set wrap width to the pango.Layout of the labels ###
|
|
|
|
layout.set_width (allocation.width * pango.SCALE)
|
|
|
|
lw, lh = layout.get_size ()
|
|
|
|
|
|
|
|
if lh_old != lh:
|
|
|
|
widget.set_size_request (-1, lh / pango.SCALE)
|
|
|
|
|
2008-08-06 22:19:16 +02:00
|
|
|
# vim: se ts=3:
|