root/branches/gajim_0.11.1/src/gtkgui_helpers.py

Revision 8615, 23.5 kB (checked in by roidelapluie, 12 months ago)

Use another function to get color string. Fix #2906.

  • Property svn:eol-style set to LF
Line 
1##      gtkgui_helpers.py
2##
3## Copyright (C) 2003-2006 Yann Le Boulanger <asterix@lagaule.org>
4## Copyright (C) 2004-2005 Vincent Hanquez <tab@snarc.org>
5## Copyright (C) 2005-2006 Nikos Kouremenos <kourem@gmail.com>
6## Copyright (C) 2005 Dimitur Kirov <dkirov@gmail.com>
7## Copyright (C) 2005 Travis Shirk <travis@pobox.com>
8## Copyright (C) 2005 Norman Rasmussen <norman@rasmussen.co.za>
9##
10## This program is free software; you can redistribute it and/or modify
11## it under the terms of the GNU General Public License as published
12## by the Free Software Foundation; version 2 only.
13##
14## This program is distributed in the hope that it will be useful,
15## but WITHOUT ANY WARRANTY; without even the implied warranty of
16## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17## GNU General Public License for more details.
18##
19
20import xml.sax.saxutils
21import gtk
22import gtk.glade
23import gobject
24import pango
25import os
26import sys
27
28import vcard
29import dialogs
30
31
32HAS_PYWIN32 = True
33if os.name == 'nt':
34        try:
35                import win32file
36                import win32con
37                import pywintypes
38        except ImportError:
39                HAS_PYWIN32 = False
40
41from common import i18n
42from common import gajim
43from common import helpers
44
45gtk.glade.bindtextdomain(i18n.APP, i18n.DIR)
46gtk.glade.textdomain(i18n.APP)
47
48screen_w = gtk.gdk.screen_width()
49screen_h = gtk.gdk.screen_height()
50
51GLADE_DIR = os.path.join('..', 'data', 'glade')
52def get_glade(file_name, root = None):
53        file_path = os.path.join(GLADE_DIR, file_name)
54        return gtk.glade.XML(file_path, root=root, domain=i18n.APP)
55
56def get_completion_liststore(entry):
57        ''' create a completion model for entry widget
58        completion list consists of (Pixbuf, Text) rows'''
59        completion = gtk.EntryCompletion()
60        liststore = gtk.ListStore(gtk.gdk.Pixbuf, str)
61       
62        render_pixbuf = gtk.CellRendererPixbuf()
63        completion.pack_start(render_pixbuf, expand = False)
64        completion.add_attribute(render_pixbuf, 'pixbuf', 0)
65       
66        render_text = gtk.CellRendererText()
67        completion.pack_start(render_text, expand = True)
68        completion.add_attribute(render_text, 'text', 1)
69        completion.set_property('text_column', 1)
70        completion.set_model(liststore)
71        entry.set_completion(completion)
72        return liststore
73       
74       
75def popup_emoticons_under_button(menu, button, parent_win):
76        ''' pops emoticons menu under button, which is in parent_win'''
77        window_x1, window_y1 = parent_win.get_origin()
78        def position_menu_under_button(menu):
79                # inline function, which will not keep refs, when used as CB
80                button_x, button_y = button.allocation.x, button.allocation.y
81               
82                # now convert them to X11-relative
83                window_x, window_y = window_x1, window_y1
84                x = window_x + button_x
85                y = window_y + button_y
86
87                menu_width, menu_height = menu.size_request()
88
89                ## should we pop down or up?
90                if (y + button.allocation.height + menu_height
91                        < gtk.gdk.screen_height()):
92                        # now move the menu below the button
93                        y += button.allocation.height
94                else:
95                        # now move the menu above the button
96                        y -= menu_height
97
98                # push_in is True so all the menuitems are always inside screen
99                push_in = True
100                return (x, y, push_in)
101
102        menu.popup(None, None, position_menu_under_button, 1, 0)
103       
104def get_theme_font_for_option(theme, option):
105        '''return string description of the font, stored in
106        theme preferences'''
107        font_name = gajim.config.get_per('themes', theme, option)
108        font_desc = pango.FontDescription()
109        font_prop_str =  gajim.config.get_per('themes', theme, option + 'attrs')
110        if font_prop_str:
111                if font_prop_str.find('B') != -1:
112                        font_desc.set_weight(pango.WEIGHT_BOLD)
113                if font_prop_str.find('I') != -1:
114                        font_desc.set_style(pango.STYLE_ITALIC)
115        fd = pango.FontDescription(font_name)
116        fd.merge(font_desc, True)
117        return fd.to_string()
118       
119def get_default_font():
120        '''Get the desktop setting for application font
121        first check for GNOME, then XFCE and last KDE
122        it returns None on failure or else a string 'Font Size' '''
123       
124        try:
125                import gconf
126                # in try because daemon may not be there
127                client = gconf.client_get_default()
128
129                return client.get_string('/desktop/gnome/interface/font_name'
130                        ).decode('utf-8')
131        except:
132                pass
133
134        # try to get xfce default font
135        # Xfce 4.2 adopts freedesktop.org's Base Directory Specification
136        # see http://www.xfce.org/~benny/xfce/file-locations.html
137        # and http://freedesktop.org/Standards/basedir-spec
138        xdg_config_home = os.environ.get('XDG_CONFIG_HOME', '')
139        if xdg_config_home == '':
140                xdg_config_home = os.path.expanduser('~/.config') # default     
141        xfce_config_file = os.path.join(xdg_config_home, 'xfce4/mcs_settings/gtk.xml')
142       
143        kde_config_file = os.path.expanduser('~/.kde/share/config/kdeglobals')
144       
145        if os.path.exists(xfce_config_file):
146                try:
147                        for line in file(xfce_config_file):
148                                if line.find('name="Gtk/FontName"') != -1:
149                                        start = line.find('value="') + 7
150                                        return line[start:line.find('"', start)].decode('utf-8')
151                except:
152                        #we talk about file
153                        print >> sys.stderr, _('Error: cannot open %s for reading') % xfce_config_file
154       
155        elif os.path.exists(kde_config_file):
156                try:
157                        for line in file(kde_config_file):
158                                if line.find('font=') == 0: # font=Verdana,9,other_numbers
159                                        start = 5 # 5 is len('font=')
160                                        line = line[start:]
161                                        values = line.split(',')
162                                        font_name = values[0]
163                                        font_size = values[1]
164                                        font_string = '%s %s' % (font_name, font_size) # Verdana 9
165                                        return font_string.decode('utf-8')
166                except:
167                        #we talk about file
168                        print >> sys.stderr, _('Error: cannot open %s for reading') % kde_config_file
169       
170        return None
171       
172def escape_for_pango_markup(string):
173        # escapes < > & ' "
174        # for pango markup not to break
175        if string is None:
176                return
177        if gtk.pygtk_version >= (2, 8, 0) and gtk.gtk_version >= (2, 8, 0):
178                escaped_str = gobject.markup_escape_text(string)
179        else:
180                escaped_str = xml.sax.saxutils.escape(string, {"'": '&apos;',
181                        '"': '&quot;'})
182       
183        return escaped_str
184
185def autodetect_browser_mailer():
186        # recognize the environment and set appropriate browser/mailer
187        if user_runs_gnome():
188                gajim.config.set('openwith', 'gnome-open')
189        elif user_runs_kde():
190                gajim.config.set('openwith', 'kfmclient exec')
191        elif user_runs_xfce():
192                gajim.config.set('openwith', 'exo-open')
193        else:
194                gajim.config.set('openwith', 'custom')
195
196def user_runs_gnome():
197        return 'gnome-session' in get_running_processes()
198
199def user_runs_kde():
200        return 'startkde' in get_running_processes()
201
202def user_runs_xfce():
203        procs = get_running_processes()
204        if 'startxfce4' in procs or 'xfce4-session' in procs:
205                return True
206        return False
207
208def get_running_processes():
209        '''returns running processes or None (if not /proc exists)'''
210        if os.path.isdir('/proc'):
211                # under Linux: checking if 'gnome-session' or
212                # 'startkde' programs were run before gajim, by
213                # checking /proc (if it exists)
214                #
215                # if something is unclear, read `man proc`;
216                # if /proc exists, directories that have only numbers
217                # in their names contain data about processes.
218                # /proc/[xxx]/exe is a symlink to executable started
219                # as process number [xxx].
220                # filter out everything that we are not interested in:
221                files = os.listdir('/proc')
222
223                # files that doesn't have only digits in names...
224                files = filter(str.isdigit, files)
225
226                # files that aren't directories...
227                files = filter(lambda f:os.path.isdir('/proc/' + f), files)
228
229                # processes owned by somebody not running gajim...
230                # (we check if we have access to that file)
231                files = filter(lambda f:os.access('/proc/' + f +'/exe', os.F_OK), files)
232
233                # be sure that /proc/[number]/exe is really a symlink
234                # to avoid TBs in incorrectly configured systems
235                files = filter(lambda f:os.path.islink('/proc/' + f + '/exe'), files)
236
237                # list of processes
238                processes = [os.path.basename(os.readlink('/proc/' + f +'/exe')) for f in files]
239               
240                return processes
241        return []
242
243def move_window(window, x, y):
244        '''moves the window but also checks if out of screen'''
245        if x < 0:
246                x = 0
247        if y < 0:
248                y = 0
249        window.move(x, y)
250
251def resize_window(window, w, h):
252        '''resizes window but also checks if huge window or negative values'''
253        if not w or not h:
254                return
255        if w > screen_w:
256                w = screen_w
257        if h > screen_h:
258                h = screen_h
259        window.resize(abs(w), abs(h))
260
261class TagInfoHandler(xml.sax.ContentHandler):
262        def __init__(self, tagname1, tagname2):
263                xml.sax.ContentHandler.__init__(self)
264                self.tagname1 = tagname1
265                self.tagname2 = tagname2
266                self.servers = []
267
268        def startElement(self, name, attributes):
269                if name == self.tagname1:
270                        for attribute in attributes.getNames():
271                                if attribute == 'jid':
272                                        jid = attributes.getValue(attribute)
273                                        # we will get the port next time so we just set it 0 here
274                                        self.servers.append([jid, 0])
275                elif name == self.tagname2:
276                        for attribute in attributes.getNames():
277                                if attribute == 'port':
278                                        port = attributes.getValue(attribute)
279                                        # we received the jid last time, so we now assign the port
280                                        # number to the last jid in the list
281                                        self.servers[-1][1] = port
282
283        def endElement(self, name):
284                pass
285
286def parse_server_xml(path_to_file):
287        try:
288                handler = TagInfoHandler('item', 'active')
289                xml.sax.parse(path_to_file, handler)
290                return handler.servers
291        # handle exception if unable to open file
292        except IOError, message:
293                print >> sys.stderr, _('Error reading file:'), message
294        # handle exception parsing file
295        except xml.sax.SAXParseException, message:
296                print >> sys.stderr, _('Error parsing file:'), message
297
298def set_unset_urgency_hint(window, unread_messages_no):
299        '''sets/unsets urgency hint in window argument
300        depending if we have unread messages or not'''
301        if gtk.gtk_version >= (2, 8, 0) and gtk.pygtk_version >= (2, 8, 0) and \
302                gajim.config.get('use_urgency_hint'):
303                if unread_messages_no > 0:
304                        window.props.urgency_hint = True
305                else:
306                        window.props.urgency_hint = False
307
308def get_abspath_for_script(scriptname, want_type = False):
309        '''checks if we are svn or normal user and returns abspath to asked script
310        if want_type is True we return 'svn' or 'install' '''
311        if os.path.isdir('.svn'): # we are svn user
312                type = 'svn'
313                cwd = os.getcwd() # it's always ending with src
314
315                if scriptname == 'gajim-remote':
316                        path_to_script = cwd + '/gajim-remote.py'
317               
318                elif scriptname == 'gajim':
319                        script = '#!/bin/sh\n' # the script we may create
320                        script += 'cd %s' % cwd
321                        path_to_script = cwd + '/../scripts/gajim_sm_script'
322                               
323                        try:
324                                if os.path.exists(path_to_script):
325                                        os.remove(path_to_script)
326
327                                f = open(path_to_script, 'w')
328                                script += '\nexec python -OOt gajim.py $0 $@\n'
329                                f.write(script)
330                                f.close()
331                                os.chmod(path_to_script, 0700)
332                        except OSError: # do not traceback (could be a permission problem)
333                                #we talk about a file here
334                                s = _('Could not write to %s. Session Management support will not work') % path_to_script
335                                print >> sys.stderr, s
336
337        else: # normal user (not svn user)
338                type = 'install'
339                # always make it like '/usr/local/bin/gajim'
340                path_to_script = helpers.is_in_path(scriptname, True)
341               
342       
343        if want_type:
344                return path_to_script, type
345        else:
346                return path_to_script
347
348def get_pixbuf_from_data(file_data, want_type = False):
349        '''Gets image data and returns gtk.gdk.Pixbuf
350        if want_type is True it also returns 'jpeg', 'png' etc'''
351        pixbufloader = gtk.gdk.PixbufLoader()
352        try:
353                pixbufloader.write(file_data)
354                pixbufloader.close()
355                pixbuf = pixbufloader.get_pixbuf()
356        except gobject.GError: # 'unknown image format'
357                pixbufloader.close()
358                pixbuf = None
359                if want_type:
360                        return None, None
361                else:
362                        return None
363
364        if want_type:
365                typ = pixbufloader.get_format()['name']
366                return pixbuf, typ
367        else:
368                return pixbuf
369
370def get_invisible_cursor():
371        pixmap = gtk.gdk.Pixmap(None, 1, 1, 1)
372        color = gtk.gdk.Color()
373        cursor = gtk.gdk.Cursor(pixmap, pixmap, color, color, 0, 0)
374        return cursor
375
376def get_current_desktop(window):
377        '''returns the current virtual desktop for given window
378        NOTE: window is GDK window'''
379        prop = window.property_get('_NET_CURRENT_DESKTOP')
380        if prop is None: # it means it's normal window (not root window)
381                # so we look for it's current virtual desktop in another property
382                prop = window.property_get('_NET_WM_DESKTOP')
383
384        if prop is not None:
385                # f.e. prop is ('CARDINAL', 32, [0]) we want 0 or 1.. from [0]
386                current_virtual_desktop_no = prop[2][0]
387                return current_virtual_desktop_no
388
389def possibly_move_window_in_current_desktop(window):
390        '''moves GTK window to current virtual desktop if it is not in the
391        current virtual desktop
392        window is GTK window'''
393        if os.name == 'nt':
394                return False
395
396        root_window = gtk.gdk.screen_get_default().get_root_window()
397        # current user's vd
398        current_virtual_desktop_no = get_current_desktop(root_window)
399       
400        # vd roster window is in
401        window_virtual_desktop = get_current_desktop(window.window)
402
403        # if one of those is None, something went wrong and we cannot know
404        # VD info, just hide it (default action) and not show it afterwards
405        if None not in (window_virtual_desktop, current_virtual_desktop_no):
406                if current_virtual_desktop_no != window_virtual_desktop:
407                        # we are in another VD that the window was
408                        # so show it in current VD
409                        window.present()
410                        return True
411        return False
412
413def file_is_locked(path_to_file):
414        '''returns True if file is locked (WINDOWS ONLY)'''
415        if os.name != 'nt': # just in case
416                return
417       
418        if not HAS_PYWIN32:
419                return
420       
421        secur_att = pywintypes.SECURITY_ATTRIBUTES()
422        secur_att.Initialize()
423       
424        try:
425                # try make a handle for READING the file
426                hfile = win32file.CreateFile(
427                        path_to_file,                                   # path to file
428                        win32con.GENERIC_READ,                  # open for reading
429                        0,                                                              # do not share with other proc
430                        secur_att,
431                        win32con.OPEN_EXISTING,                 # existing file only
432                        win32con.FILE_ATTRIBUTE_NORMAL, # normal file
433                        0                                                               # no attr. template
434                )
435        except pywintypes.error, e:
436                return True
437        else: # in case all went ok, close file handle (go to hell WinAPI)
438                hfile.Close()
439                return False
440
441def _get_fade_color(treeview, selected, focused):
442        '''get a gdk color that is between foreground and background in 0.3
443        0.7 respectively colors of the cell for the given treeview'''
444        style = treeview.style
445        if selected:
446                if focused: # is the window focused?
447                        state = gtk.STATE_SELECTED
448                else: # is it not? NOTE: many gtk themes change bg on this
449                        state = gtk.STATE_ACTIVE
450        else:
451                state = gtk.STATE_NORMAL
452        bg = style.base[state]
453        fg = style.text[state]
454
455        p = 0.3 # background
456        q = 0.7 # foreground # p + q should do 1.0
457        return gtk.gdk.Color(int(bg.red*p + fg.red*q),
458                                        int(bg.green*p + fg.green*q),
459                                        int(bg.blue*p + fg.blue*q))
460
461def get_scaled_pixbuf(pixbuf, kind):
462        '''returns scaled pixbuf, keeping ratio etc or None
463        kind is either "chat", "roster", "notification", "tooltip", "vcard"'''
464       
465        # resize to a width / height for the avatar not to have distortion
466        # (keep aspect ratio)
467        width = gajim.config.get(kind + '_avatar_width')
468        height = gajim.config.get(kind + '_avatar_height')
469        if width < 1 or height < 1:
470                return None
471
472        # Pixbuf size
473        pix_width = pixbuf.get_width()
474        pix_height = pixbuf.get_height()
475        # don't make avatars bigger than they are
476        if pix_width < width and pix_height < height:
477                return pixbuf # we don't want to make avatar bigger
478
479        ratio = float(pix_width) / float(pix_height)
480        if ratio > 1:
481                w = width
482                h = int(w / ratio)
483        else:
484                h = height
485                w = int(h * ratio)
486        scaled_buf = pixbuf.scale_simple(w, h, gtk.gdk.INTERP_HYPER)
487        return scaled_buf
488
489def get_avatar_pixbuf_from_cache(fjid, is_fake_jid = False):
490        '''checks if jid has cached avatar and if that avatar is valid image
491        (can be shown)
492        returns None if there is no image in vcard
493        returns 'ask' if cached vcard should not be used (user changed his vcard,
494        so we have new sha) or if we don't have the vcard'''
495
496        jid, nick = gajim.get_room_and_nick_from_fjid(fjid)
497        if gajim.config.get('hide_avatar_of_transport') and\
498                gajim.jid_is_transport(jid):
499                # don't show avatar for the transport itself
500                return None
501
502        puny_jid = helpers.sanitize_filename(jid)
503        if is_fake_jid:
504                puny_nick = helpers.sanitize_filename(nick)
505                path = os.path.join(gajim.VCARD_PATH, puny_jid, puny_nick)
506        else:
507                path = os.path.join(gajim.VCARD_PATH, puny_jid)
508        if not os.path.isfile(path):
509                return 'ask'
510
511        vcard_dict = gajim.connections.values()[0].get_cached_vcard(fjid,
512                is_fake_jid)
513        if not vcard_dict: # This can happen if cached vcard is too old
514                return 'ask'
515        if not vcard_dict.has_key('PHOTO'):
516                return None
517        pixbuf = vcard.get_avatar_pixbuf_encoded_mime(vcard_dict['PHOTO'])[0]
518        return pixbuf
519
520def make_gtk_month_python_month(month):
521        '''gtk start counting months from 0, so January is 0
522        but python's time start from 1, so align to python
523        month MUST be integer'''
524        return month + 1
525
526def make_python_month_gtk_month(month):
527        return month - 1
528
529def make_color_string(color):
530        '''create #aabbcc color string from gtk color'''
531        col = '#'
532        for i in ('red', 'green', 'blue'):
533                h = hex(getattr(color, i) / (16*16)).split('x')[1]
534                if len(h) == 1:
535                        h = '0' + h
536                col += h
537        return col
538
539def make_pixbuf_grayscale(pixbuf):
540        pixbuf2 = pixbuf.copy()
541        pixbuf.saturate_and_pixelate(pixbuf2, 0.0, False)
542        return pixbuf2
543
544def get_path_to_generic_or_avatar(generic, jid = None, suffix = None):
545        '''Chooses between avatar image and default image.
546        Returns full path to the avatar image if it exists,
547        otherwise returns full path to the image.'''
548        if jid:
549                puny_jid = helpers.sanitize_filename(jid)
550                path_to_file = os.path.join(gajim.AVATAR_PATH, puny_jid) + suffix
551                if os.path.exists(path_to_file):
552                        return path_to_file
553        return os.path.abspath(generic)
554
555def decode_filechooser_file_paths(file_paths):
556        '''decode as UTF-8 under Windows and
557        ask sys.getfilesystemencoding() in POSIX
558        file_paths MUST be LIST'''
559        file_paths_list = list()
560       
561        if os.name == 'nt': # decode as UTF-8 under Windows
562                for file_path in file_paths:
563                        file_path = file_path.decode('utf8')
564                        file_paths_list.append(file_path)
565        else:
566                for file_path in file_paths:
567                        try:
568                                file_path = file_path.decode(sys.getfilesystemencoding())
569                        except:
570                                try:
571                                        file_path = file_path.decode('utf-8')
572                                except:
573                                        pass
574                        file_paths_list.append(file_path)
575       
576        return file_paths_list
577
578def possibly_set_gajim_as_xmpp_handler():
579        '''registers (by default only the first time) xmmp: to Gajim.'''
580        path_to_dot_kde = os.path.expanduser('~/.kde')
581        if os.path.exists(path_to_dot_kde):
582                path_to_kde_file = os.path.join(path_to_dot_kde,
583                        'share/services/xmpp.protocol')
584        else:
585                path_to_kde_file = None
586
587        def set_gajim_as_xmpp_handler(widget = None):
588                if widget:
589                        # come from confirmation dialog
590                        gajim.config.set('check_if_gajim_is_default',
591                                dlg.checkbutton.get_active())
592                        dlg.destroy()
593                path_to_gajim_script, typ = get_abspath_for_script('gajim-remote', True)
594                if path_to_gajim_script:
595                        if typ == 'svn':
596                                command = path_to_gajim_script + ' handle_uri %s'
597                        else: # 'installed'
598                                command = 'gajim-remote handle_uri %s'
599
600                        # setting for GNOME/Gconf
601                        client.set_bool('/desktop/gnome/url-handlers/xmpp/enabled', True)
602                        client.set_string('/desktop/gnome/url-handlers/xmpp/command', command)
603                        client.set_bool('/desktop/gnome/url-handlers/xmpp/needs_terminal', False)
604
605                        # setting for KDE
606                        if path_to_kde_file is not None: # user has run kde at least once
607                                try:
608                                        f = open(path_to_kde_file, 'a')
609                                        f.write('''\
610[Protocol]
611exec=%s "%%u"
612protocol=xmpp
613input=none
614output=none
615helper=true
616listing=false
617reading=false
618writing=false
619makedir=false
620deleting=false
621icon=gajim
622Description=xmpp
623''' % command)
624                                        f.close()
625                                except IOError:
626                                        pass
627
628        try:
629                import gconf
630                # in try because daemon may not be there
631                client = gconf.client_get_default()
632        except:
633                return
634
635        old_command = client.get_string('/desktop/gnome/url-handlers/xmpp/command')
636        if not old_command or old_command.endswith(' open_chat %s'):
637                # first time (GNOME/GCONF) or old Gajim version
638                we_set = True
639        elif path_to_kde_file is not None and not os.path.exists(path_to_kde_file):
640                # only the first time (KDE)
641                we_set = True
642        else:
643                we_set = False
644
645        if we_set:
646                set_gajim_as_xmpp_handler()
647        elif old_command and not old_command.endswith(' handle_uri %s'):
648                # xmpp: is currently handled by another program, so ask the user
649                pritext = _('Gajim is not the default Jabber client')
650                sectext = _('Would you like to make Gajim the default Jabber client?')
651                checktext = _('Always check to see if Gajim is the default Jabber client '
652                        'on startup')
653                def on_cancel(widget):
654                        gajim.config.set('check_if_gajim_is_default',
655                                dlg.checkbutton.get_active())
656                        dlg.destroy()
657                dlg = dialogs.ConfirmationDialogCheck(pritext, sectext, checktext,
658                        set_gajim_as_xmpp_handler, on_cancel)
659                if gajim.config.get('check_if_gajim_is_default'):
660                        dlg.checkbutton.set_active(True)
661
662def escape_underscore(s):
663        '''Escape underlines to prevent them from being interpreted
664        as keyboard accelerators'''
665        return s.replace('_', '__')
666
667def get_state_image_from_file_path_show(file_path, show):
668        state_file = show.replace(' ', '_')
669        files = []
670        files.append(os.path.join(file_path, state_file + '.png'))
671        files.append(os.path.join(file_path, state_file + '.gif'))
672        image = gtk.Image()
673        image.set_from_pixbuf(None)
674        for file_ in files:
675                if os.path.exists(file_):
676                        image.set_from_file(file_)
677                        break
678
679        return image
680
681def get_possible_button_event(event):
682        '''mouse or keyboard caused the event?'''
683        if event.type == gtk.gdk.KEY_PRESS:
684                return 0 # no event.button so pass 0
685        # BUTTON_PRESS event, so pass event.button
686        return event.button
687
688def destroy_widget(widget):
689        widget.destroy()
690
691def on_avatar_save_as_menuitem_activate(widget, jid, account,
692default_name = ''):
693        def on_ok(widget):
694                def on_ok2(widget, file_path, pixbuf):
695                        pixbuf.save(file_path, 'jpeg')
696                        dialog2.destroy()
697                        dialog.destroy()
698
699                file_path = dialog.get_filename()
700                file_path = decode_filechooser_file_paths((file_path,))[0]
701                if os.path.exists(file_path):
702                        # check if we have write permissions
703                        if not os.access(file_path, os.W_OK):
704                                file_name = os.path.basename(file_path)
705                                dialogs.ErrorDialog(_('Cannot overwrite existing file "%s"' %
706                                        file_name),
707                                _('A file with this name already exists and you do not have '
708                                'permission to overwrite it.'))
709                                return
710                        dialog2 = dialogs.FTOverwriteConfirmationDialog(
711                                _('This file already exists'), _('What do you want to do?'),
712                                False)
713                        dialog2.set_transient_for(dialog)
714                        dialog2.set_destroy_with_parent(True)
715                        response = dialog2.get_response()
716                        if response < 0:
717                                return
718                else:
719                        dirname = os.path.dirname(file_path)
720                        if not os.access(dirname, os.W_OK):
721                                dialogs.ErrorDialog(_('Directory "%s" is not writable') % \
722                                dirname, _('You do not have permission to create files in this'
723                                ' directory.'))
724                                return
725
726                # Get pixbuf
727                pixbuf = None
728                is_fake = False
729                if account and gajim.contacts.is_pm_from_jid(account, jid):
730                        is_fake = True
731                pixbuf = get_avatar_pixbuf_from_cache(jid, is_fake)
732                ext = file_path.split('.')[-1]
733                type_ = ''
734                if not ext:
735                        # Silently save as Jpeg image
736                        file_path += '.jpeg'
737                        type_ = 'jpeg'
738                elif ext == 'jpg':
739                        type_ = 'jpeg'
740                else:
741                        type_ = ext
742
743                # Save image
744                try:
745                        pixbuf.save(file_path, type_)
746                except:
747                        if os.path.exists(file_path):
748                                os.remove(file_path)
749                        new_file_path = '.'.join(file_path.split('.')[:-1]) + '.jpeg'
750                        dialog2 = dialogs.ConfirmationDialog(_('Extension not supported'),
751                                _('Image cannot be saved in %(type)s format. Save as %(new_filename)s?') % {'type': type_, 'new_filename': new_file_path},
752                                on_response_ok = (on_ok2, new_file_path, pixbuf))
753                else:
754                        dialog.destroy()
755
756        def on_cancel(widget):
757                dialog.destroy()
758
759        dialog = dialogs.FileChooserDialog(
760                title_text = _('Save Image as...'),
761                action = gtk.FILE_CHOOSER_ACTION_SAVE,
762                buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
763                gtk.STOCK_SAVE, gtk.RESPONSE_OK),
764                default_response = gtk.RESPONSE_OK,
765                current_folder = gajim.config.get('last_save_dir'),
766                on_response_ok = on_ok,
767                on_response_cancel = on_cancel)
768
769        dialog.set_current_name(default_name)
770        dialog.connect('delete-event', lambda widget, event:
771                on_cancel(widget))
772
773def on_bm_header_changed_state(widget, event):
774        widget.set_state(gtk.STATE_NORMAL) #do not allow selected_state
Note: See TracBrowser for help on using the browser.