add ability to set an avatar for a contact. fixes #2967

This commit is contained in:
Yann Leboulanger 2007-04-22 10:23:23 +00:00
parent 42bd8d64b3
commit 2ef20efac5
4 changed files with 258 additions and 6 deletions

View File

@ -392,7 +392,57 @@
<widget class="GtkVBox" id="vbox2"> <widget class="GtkVBox" id="vbox2">
<property name="visible">True</property> <property name="visible">True</property>
<property name="homogeneous">False</property> <property name="homogeneous">False</property>
<property name="spacing">0</property> <property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="label59">
<property name="visible">True</property>
<property name="label" translatable="yes">User avatar:</property>
<property name="use_underline">False</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="no_user_avatar_label">
<property name="visible">True</property>
<property name="label" translatable="yes">None</property>
<property name="use_underline">False</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child> <child>
<widget class="GtkEventBox" id="PHOTO_eventbox"> <widget class="GtkEventBox" id="PHOTO_eventbox">
@ -417,6 +467,65 @@
<property name="fill">False</property> <property name="fill">False</property>
</packing> </packing>
</child> </child>
<child>
<widget class="GtkLabel" id="label60">
<property name="visible">True</property>
<property name="label" translatable="yes">Configured avatar:</property>
<property name="use_underline">False</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="PHOTO_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes"></property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<signal name="button_press_event" handler="on_PHOTO_button_press_event" last_modification_time="Sat, 21 Apr 2007 23:35:12 GMT"/>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="NOPHOTO_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Click to force avatar</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_NOPHOTO_button_clicked" last_modification_time="Sat, 21 Apr 2007 23:25:59 GMT"/>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget> </widget>
<packing> <packing>
<property name="padding">0</property> <property name="padding">0</property>

View File

@ -528,7 +528,7 @@ def get_scaled_pixbuf(pixbuf, kind):
scaled_buf = pixbuf.scale_simple(w, h, gtk.gdk.INTERP_HYPER) scaled_buf = pixbuf.scale_simple(w, h, gtk.gdk.INTERP_HYPER)
return scaled_buf return scaled_buf
def get_avatar_pixbuf_from_cache(fjid, is_fake_jid = False): def get_avatar_pixbuf_from_cache(fjid, is_fake_jid = False, use_local = True):
'''checks if jid has cached avatar and if that avatar is valid image '''checks if jid has cached avatar and if that avatar is valid image
(can be shown) (can be shown)
returns None if there is no image in vcard returns None if there is no image in vcard
@ -545,8 +545,21 @@ def get_avatar_pixbuf_from_cache(fjid, is_fake_jid = False):
if is_fake_jid: if is_fake_jid:
puny_nick = helpers.sanitize_filename(nick) puny_nick = helpers.sanitize_filename(nick)
path = os.path.join(gajim.VCARD_PATH, puny_jid, puny_nick) path = os.path.join(gajim.VCARD_PATH, puny_jid, puny_nick)
local_avatar_basepath = os.path.join(gajim.AVATAR_PATH, puny_jid,
puny_nick) + '_local'
else: else:
path = os.path.join(gajim.VCARD_PATH, puny_jid) path = os.path.join(gajim.VCARD_PATH, puny_jid)
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):
avatar_file = open(local_avatar_path)
avatar_data = avatar_file.read()
avatar_file.close()
return get_pixbuf_from_data(avatar_data)
if not os.path.isfile(path): if not os.path.isfile(path):
return 'ask' return 'ask'
@ -591,6 +604,10 @@ def get_path_to_generic_or_avatar(generic, jid = None, suffix = None):
if jid: if jid:
puny_jid = helpers.sanitize_filename(jid) puny_jid = helpers.sanitize_filename(jid)
path_to_file = os.path.join(gajim.AVATAR_PATH, puny_jid) + suffix path_to_file = os.path.join(gajim.AVATAR_PATH, puny_jid) + suffix
filepath, extension = os.path.splitext(path_to_file)
path_to_local_file = filepath + '_local' + extension
if os.path.exists(path_to_local_file):
return path_to_local_file
if os.path.exists(path_to_file): if os.path.exists(path_to_file):
return path_to_file return path_to_file
return os.path.abspath(generic) return os.path.abspath(generic)
@ -773,7 +790,7 @@ default_name = ''):
is_fake = False is_fake = False
if account and gajim.contacts.is_pm_from_jid(account, jid): if account and gajim.contacts.is_pm_from_jid(account, jid):
is_fake = True is_fake = True
pixbuf = get_avatar_pixbuf_from_cache(jid, is_fake) pixbuf = get_avatar_pixbuf_from_cache(jid, is_fake, False)
ext = file_path.split('.')[-1] ext = file_path.split('.')[-1]
type_ = '' type_ = ''
if not ext: if not ext:

View File

@ -118,15 +118,16 @@ class ProfileWindow:
def on_ok(widget, path_to_file): def on_ok(widget, path_to_file):
must_delete = False must_delete = False
filesize = os.path.getsize(path_to_file) # in bytes filesize = os.path.getsize(path_to_file) # in bytes
#FIXME: use messages for invalid file for 0.11
invalid_file = False invalid_file = False
msg = '' msg = ''
if os.path.isfile(path_to_file): if os.path.isfile(path_to_file):
stat = os.stat(path_to_file) stat = os.stat(path_to_file)
if stat[6] == 0: if stat[6] == 0:
invalid_file = True invalid_file = True
msg = _('File is emty')
else: else:
invalid_file = True invalid_file = True
msg = _('File does not exist')
if not invalid_file and filesize > 16384: # 16 kb if not invalid_file and filesize > 16384: # 16 kb
try: try:
pixbuf = gtk.gdk.pixbuf_new_from_file(path_to_file) pixbuf = gtk.gdk.pixbuf_new_from_file(path_to_file)
@ -183,7 +184,8 @@ class ProfileWindow:
menu = gtk.Menu() menu = gtk.Menu()
# Try to get pixbuf # Try to get pixbuf
pixbuf = gtkgui_helpers.get_avatar_pixbuf_from_cache(self.jid) pixbuf = gtkgui_helpers.get_avatar_pixbuf_from_cache(self.jid,
use_local = False)
if pixbuf: if pixbuf:
nick = gajim.config.get_per('accounts', self.account, 'name') nick = gajim.config.get_per('accounts', self.account, 'name')

View File

@ -21,8 +21,11 @@ import gobject
import base64 import base64
import time import time
import locale import locale
import os
import gtkgui_helpers import gtkgui_helpers
import dialogs
import message_control
from common import helpers from common import helpers
from common import gajim from common import gajim
@ -67,6 +70,27 @@ class VcardWindow:
self.account = account self.account = account
self.gc_contact = gc_contact self.gc_contact = gc_contact
self.xml.get_widget('no_user_avatar_label').set_no_show_all(True)
self.xml.get_widget('no_user_avatar_label').hide()
self.xml.get_widget('PHOTO_image').set_no_show_all(True)
self.xml.get_widget('PHOTO_image').hide()
image = gtk.Image()
self.photo_button = self.xml.get_widget('PHOTO_button')
self.photo_button.set_image(image)
self.nophoto_button = self.xml.get_widget('NOPHOTO_button')
puny_jid = helpers.sanitize_filename(contact.jid)
local_avatar_basepath = os.path.join(gajim.AVATAR_PATH, puny_jid) + \
'_local'
for extension in ('.png', '.jpeg'):
local_avatar_path = local_avatar_basepath + extension
if os.path.isfile(local_avatar_path):
image.set_from_file(local_avatar_path)
self.nophoto_button.set_no_show_all(True)
self.nophoto_button.hide()
break
else:
self.photo_button.set_no_show_all(True)
self.photo_button.hide()
self.avatar_mime_type = None self.avatar_mime_type = None
self.avatar_encoded = None self.avatar_encoded = None
self.vcard_arrived = False self.vcard_arrived = False
@ -88,6 +112,104 @@ class VcardWindow:
self.progressbar.pulse() self.progressbar.pulse()
return True # loop forever return True # loop forever
def update_avatar_in_gui(self):
jid = self.contact.jid
# Update roster
gajim.interface.roster.draw_avatar(jid, self.account)
# Update chat window
if gajim.interface.msg_win_mgr.has_window(jid, self.account):
win = gajim.interface.msg_win_mgr.get_window(jid, self.account)
ctrl = win.get_control(jid, self.account)
if win and ctrl.type_id != message_control.TYPE_GC:
ctrl.show_avatar()
def on_NOPHOTO_button_clicked(self, button):
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
msg = _('File is emty')
else:
invalid_file = True
msg = _('File does not exist')
if invalid_file:
dialogs.ErrorDialog(_('Could not load image'), msg)
return
pixbuf = gtk.gdk.pixbuf_new_from_file(path_to_file)
if filesize > 16384: # 16 kb
try:
# get the image at 'notification size'
# and use 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)
invalid_file = True
puny_jid = helpers.sanitize_filename(self.contact.jid)
path_to_file = os.path.join(gajim.AVATAR_PATH, puny_jid) + '_local.png'
pixbuf.save(path_to_file, 'png')
self.dialog.destroy()
self.update_avatar_in_gui()
# rescale it
pixbuf = gtkgui_helpers.get_scaled_pixbuf(pixbuf, 'vcard')
image = self.photo_button.get_image()
image.set_from_pixbuf(pixbuf)
self.photo_button.show()
self.nophoto_button.hide()
def on_clear(widget):
self.dialog.destroy()
self.on_clear_button_clicked(widget)
self.dialog = dialogs.AvatarChooserDialog(on_response_ok = on_ok,
on_response_clear = on_clear)
def on_clear_button_clicked(self, widget):
# empty the image
image = self.photo_button.get_image()
image.set_from_pixbuf(None)
self.photo_button.hide()
self.nophoto_button.show()
# Delete file:
puny_jid = helpers.sanitize_filename(self.contact.jid)
path_to_file = os.path.join(gajim.AVATAR_PATH, puny_jid) + '_local.png'
try:
os.remove(path_to_file)
except OSError:
gajim.log.debug('Cannot remove %s' % path_to_file)
self.update_avatar_in_gui()
def on_PHOTO_button_press_event(self, widget, event):
'''If right-clicked, show popup'''
if event.button == 3 and self.avatar_encoded: # right click
menu = gtk.Menu()
# Try to get pixbuf
# pixbuf = gtkgui_helpers.get_avatar_pixbuf_from_cache(self.jid)
# if pixbuf:
# nick = self.contact.get_shown_name()
# menuitem = gtk.ImageMenuItem(gtk.STOCK_SAVE_AS)
# menuitem.connect('activate',
# gtkgui_helpers.on_avatar_save_as_menuitem_activate, self.jid,
# None, nick + '.jpeg')
# menu.append(menuitem)
# show clear
menuitem = gtk.ImageMenuItem(gtk.STOCK_CLEAR)
menuitem.connect('activate', self.on_clear_button_clicked)
menu.append(menuitem)
menu.connect('selection-done', lambda w:w.destroy())
# show the menu
menu.show_all()
menu.popup(None, None, None, event.button, event.time)
elif event.button == 1: # left click
self.on_set_avatar_button_clicked(widget)
def on_vcard_information_window_destroy(self, widget): def on_vcard_information_window_destroy(self, widget):
if self.update_progressbar_timeout_id is not None: if self.update_progressbar_timeout_id is not None:
gobject.source_remove(self.update_progressbar_timeout_id) gobject.source_remove(self.update_progressbar_timeout_id)
@ -100,7 +222,6 @@ class VcardWindow:
connection.annotations[self.contact.jid] = annotation connection.annotations[self.contact.jid] = annotation
connection.store_annotations() connection.store_annotations()
def on_vcard_information_window_key_press_event(self, widget, event): def on_vcard_information_window_key_press_event(self, widget, event):
if event.keyval == gtk.keysyms.Escape: if event.keyval == gtk.keysyms.Escape:
self.window.destroy() self.window.destroy()
@ -137,12 +258,15 @@ class VcardWindow:
pass pass
def set_values(self, vcard): def set_values(self, vcard):
if not 'PHOTO' in vcard:
self.xml.get_widget('no_user_avatar_label').show()
for i in vcard.keys(): for i in vcard.keys():
if i == 'PHOTO' and self.xml.get_widget('information_notebook').\ if i == 'PHOTO' and self.xml.get_widget('information_notebook').\
get_n_pages() > 4: get_n_pages() > 4:
pixbuf, self.avatar_encoded, self.avatar_mime_type = \ pixbuf, self.avatar_encoded, self.avatar_mime_type = \
get_avatar_pixbuf_encoded_mime(vcard[i]) get_avatar_pixbuf_encoded_mime(vcard[i])
image = self.xml.get_widget('PHOTO_image') image = self.xml.get_widget('PHOTO_image')
image.show()
if not pixbuf: if not pixbuf:
image.set_from_icon_name('stock_person', image.set_from_icon_name('stock_person',
gtk.ICON_SIZE_DIALOG) gtk.ICON_SIZE_DIALOG)