root/branches/gajim_0.8.2/src/vcard.py

Revision 3453, 14.6 kB (checked in by nk, 3 years ago)

more fchooser fixes

Line 
1##      vcard.py (has VcardWindow class)
2##
3## Gajim Team:
4##      - Yann Le Boulanger <asterix@lagaule.org>
5##      - Vincent Hanquez <tab@snarc.org>
6##      - Nikos Kouremenos <kourem@gmail.com>
7##
8##      Copyright (C) 2003-2005 Gajim Team
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 gtk
21import gtk.glade
22import gobject
23import urllib
24import base64
25import mimetypes
26import os
27import sys
28import dialogs
29
30from common import helpers
31from common import gajim
32from common import i18n
33_ = i18n._
34Q_ = i18n.Q_
35APP = i18n.APP
36gtk.glade.bindtextdomain (APP, i18n.DIR)
37gtk.glade.textdomain (APP)
38
39GTKGUI_GLADE = 'gtkgui.glade'
40
41class VcardWindow:
42        '''Class for contact's information window'''
43
44        def __init__(self, contact, plugin, account, vcard = False):
45                #the contact variable is the jid if vcard is true
46                self.xml = gtk.glade.XML(GTKGUI_GLADE, 'vcard_information_window', APP)
47                self.window = self.xml.get_widget('vcard_information_window')
48                self.xml.get_widget('photo_vbuttonbox').set_no_show_all(True)
49               
50                self.publish_button = self.xml.get_widget('publish_button')
51                self.retrieve_button = self.xml.get_widget('retrieve_button')
52                self.publish_button.set_no_show_all(True)
53                self.retrieve_button.set_no_show_all(True)
54               
55                self.plugin = plugin
56                self.contact = contact #don't use it if vcard is true
57                self.account = account
58                self.vcard = vcard
59                self.avatar_mime_type = None
60                self.avatar_encoded = None
61
62                if vcard:
63                        self.jid = contact
64                        # remove Jabber tab & show publish/retrieve/set_avatar buttons
65                        self.change_to_vcard()
66                else:
67                        self.jid = contact.jid
68                        self.publish_button.hide()
69                        self.retrieve_button.hide()
70                        self.fill_jabber_page()
71
72                self.xml.signal_autoconnect(self)
73                self.window.show_all()
74
75        def on_vcard_information_window_destroy(self, widget = None):
76                del self.plugin.windows[self.account]['infos'][self.jid]
77
78        def on_vcard_information_window_key_press_event(self, widget, event):
79                if event.keyval == gtk.keysyms.Escape:
80                        self.window.destroy()
81
82        def on_close_button_clicked(self, widget):
83                '''Save contact information and update the roster on the Jabber server'''
84                if self.vcard:
85                        self.window.destroy()
86                        return
87                #update contact.name if it's not ''
88                name_entry = self.xml.get_widget('nickname_entry')
89                new_name = name_entry.get_text().decode('utf-8')
90                if new_name != self.contact.name and new_name != '':
91                        self.contact.name = new_name
92                        for i in self.plugin.roster.get_contact_iter(self.contact.jid, self.account):
93                                self.plugin.roster.tree.get_model().set_value(i, 1, new_name)
94                        gajim.connections[self.account].update_contact(self.contact.jid,
95                                self.contact.name, self.contact.groups)
96                #log history ?
97                oldlog = True
98                no_log_for = gajim.config.get_per('accounts', self.account,
99                        'no_log_for').split()
100                if self.contact.jid in no_log_for:
101                        oldlog = False
102                log = self.xml.get_widget('log_checkbutton').get_active()
103                if not log and not self.contact.jid in no_log_for:
104                        no_log_for.append(self.contact.jid)
105                if log and self.contact.jid in no_log_for:
106                        no_log_for.remove(self.contact.jid)
107                if oldlog != log:
108                        gajim.config.set_per('accounts', self.account, 'no_log_for',
109                                ' '.join(no_log_for))
110                self.window.destroy()
111
112        def on_clear_button_clicked(self, widget):
113                # empty the image
114                self.xml.get_widget('PHOTO_image').set_from_pixbuf(None)
115                self.avatar_encoded = None
116
117        def image_is_ok(self, image):
118                if not os.path.exists(image):
119                        return False
120                return True
121
122        def update_preview(self, widget):
123                path_to_file = widget.get_preview_filename()
124                if path_to_file is None or os.path.isdir(path_to_file):
125                        # nothing to preview or directory
126                        # make sure you clean image do show nothing
127                        widget.get_preview_widget().set_from_file(None)
128                        return
129                try:
130                        pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(path_to_file, 100, 100)
131                except gobject.GError:
132                        return
133                widget.get_preview_widget().set_from_pixbuf(pixbuf)
134
135        def on_set_avatar_button_clicked(self, widget):
136                f = None
137                dialog = gtk.FileChooserDialog(_('Choose Avatar'), None,
138                        gtk.FILE_CHOOSER_ACTION_OPEN,
139                        (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
140                        gtk.STOCK_OPEN, gtk.RESPONSE_OK))
141                dialog.set_default_response(gtk.RESPONSE_OK)
142                filtr = gtk.FileFilter()
143                filtr.set_name(_('All files'))
144                filtr.add_pattern('*')
145                dialog.add_filter(filtr)
146
147                filtr = gtk.FileFilter()
148                filtr.set_name(_('Images'))
149                filtr.add_mime_type('image/png')
150                filtr.add_mime_type('image/jpeg')
151                filtr.add_mime_type('image/gif')
152                filtr.add_pattern('*.png')
153                filtr.add_pattern('*.jpg')
154                filtr.add_pattern('*.gif')
155                filtr.add_pattern('*.tif')
156                filtr.add_pattern('*.xpm')
157                dialog.add_filter(filtr)
158                dialog.set_filter(filtr)
159                dialog.set_use_preview_label(False)
160                dialog.set_preview_widget(gtk.Image())
161                dialog.connect('selection-changed', self.update_preview)
162
163                ok = False
164                while not ok:
165                        response = dialog.run()
166                        if response == gtk.RESPONSE_OK:
167                                f = dialog.get_filename()
168                                f = f.decode(sys.getfilesystemencoding())
169                                if self.image_is_ok(f):
170                                        ok = True
171                        else:
172                                ok = True
173                dialog.destroy()
174
175                if f:
176                        filesize = os.path.getsize(f) # in bytes
177                        if filesize > 8192: # 8 kb
178                                dialogs.ErrorDialog(_('The filesize of image "%s" is too large')\
179                                        % f,
180                                        _('The file must not be more than 8 kilobytes.')).get_response()
181                                return
182                        fd = open(f, 'rb')
183                        data = fd.read()
184                        pixbufloader = gtk.gdk.PixbufLoader()
185                        pixbufloader.write(data)
186                        pixbufloader.close()
187                        pixbuf = pixbufloader.get_pixbuf()
188                        image = self.xml.get_widget('PHOTO_image')
189                        image.set_from_pixbuf(pixbuf)
190                        self.avatar_encoded = base64.encodestring(data)
191                        self.avatar_mime_type = mimetypes.guess_type(f)[0]
192
193        def set_value(self, entry_name, value):
194                try:
195                        self.xml.get_widget(entry_name).set_text(value)
196                except AttributeError:
197                        pass
198
199        def set_values(self, vcard):
200                for i in vcard.keys():
201                        if i == 'PHOTO':
202                                if not isinstance(vcard[i], dict):
203                                        continue
204                                img_decoded = None
205                                if vcard[i].has_key('BINVAL') and vcard[i].has_key('TYPE'):
206                                        img_encoded = vcard[i]['BINVAL']
207                                        self.avatar_encoded = img_encoded
208                                        self.avatar_mime_type = vcard[i]['TYPE']
209                                        try:
210                                                img_decoded = base64.decodestring(img_encoded)
211                                        except:
212                                                pass
213                                elif vcard[i].has_key('EXTVAL'):
214                                        url = vcard[i]['EXTVAL']
215                                        try:
216                                                fd = urllib.urlopen(url)
217                                                img_decoded = fd.read()
218                                        except:
219                                                pass
220                                if img_decoded:
221                                        pixbufloader = gtk.gdk.PixbufLoader()
222                                        pixbufloader.write(img_decoded)
223                                        pixbufloader.close()
224                                        pixbuf = pixbufloader.get_pixbuf()
225                                        image = self.xml.get_widget('PHOTO_image')
226                                        image.set_from_pixbuf(pixbuf)
227                                continue
228                        if i == 'ADR' or i == 'TEL' or i == 'EMAIL':
229                                for entry in vcard[i]:
230                                        add_on = '_HOME'
231                                        if 'WORK' in entry:
232                                                add_on = '_WORK'
233                                        for j in entry.keys():
234                                                self.set_value(i + add_on + '_' + j + '_entry', entry[j])
235                        if isinstance(vcard[i], dict):
236                                for j in vcard[i].keys():
237                                        self.set_value(i + '_' + j + '_entry', vcard[i][j])
238                        else:
239                                if i == 'DESC':
240                                        self.xml.get_widget('DESC_textview').get_buffer().set_text(
241                                                vcard[i], 0)
242                                else:
243                                        self.set_value(i + '_entry', vcard[i])
244       
245        def set_os_info(self, resource, client_info, os_info):
246                i = 0
247                client = ''
248                os = ''
249                while self.os_info.has_key(i):
250                        if not self.os_info[i]['resource'] or \
251                                        self.os_info[i]['resource'] == resource:
252                                self.os_info[i]['client'] = client_info
253                                self.os_info[i]['os'] = os_info
254                        if i > 0:
255                                client += '\n'
256                                os += '\n'
257                        client += self.os_info[i]['client']
258                        os += self.os_info[i]['os']
259                        i += 1
260
261                if client == '':
262                        client = Q_('?Client:Unknown')
263                if os == '':
264                        os = Q_('?OS:Unknown')
265                self.xml.get_widget('client_name_version_label').set_text(client)
266                self.xml.get_widget('os_label').set_text(os)
267
268        def fill_jabber_page(self):
269                self.xml.get_widget('nickname_label').set_text(self.contact.name)
270                self.xml.get_widget('jid_label').set_text(self.contact.jid)
271                uf_sub = helpers.get_uf_sub(self.contact.sub)
272                self.xml.get_widget('subscription_label').set_text(uf_sub)
273                label = self.xml.get_widget('ask_label')
274               
275                uf_ask = helpers.get_uf_ask(self.contact.ask)
276                label.set_text(uf_ask)
277                self.xml.get_widget('nickname_entry').set_text(self.contact.name)
278                log = 1
279                if self.contact.jid in gajim.config.get_per('accounts', self.account,
280                        'no_log_for').split(' '):
281                        log = 0
282                self.xml.get_widget('log_checkbutton').set_active(log)
283                resources = '%s (%s)' % (self.contact.resource, unicode(
284                        self.contact.priority))
285                uf_resources = self.contact.resource + _(' resource with priority ')\
286                        + unicode(self.contact.priority)
287                if not self.contact.status:
288                        self.contact.status = ''
289               
290                # stats holds show and status message
291                stats = helpers.get_uf_show(self.contact.show)
292                if self.contact.status:
293                        stats += ': ' + self.contact.status
294                gajim.connections[self.account].request_os_info(self.contact.jid,
295                        self.contact.resource)
296                self.os_info = {0: {'resource': self.contact.resource, 'client': '',
297                        'os': ''}}
298                i = 1
299                if gajim.contacts[self.account].has_key(self.contact.jid):
300                        for c in gajim.contacts[self.account][self.contact.jid]:
301                                if c.resource != self.contact.resource:
302                                        resources += '\n%s (%s)' % (c.resource,
303                                                unicode(c.priority))
304                                        uf_resources += '\n' + c.resource + _(' resource with priority ')\
305                                                + unicode(c.priority)
306                                        if not c.status:
307                                                c.status = ''
308                                        stats += '\n' + c.show + ': ' + c.status
309                                        gajim.connections[self.account].request_os_info(self.contact.jid,
310                                                c.resource)
311                                        self.os_info[i] = {'resource': c.resource, 'client': '',
312                                                'os': ''}
313                                        i += 1
314                self.xml.get_widget('resource_prio_label').set_text(resources)
315                tip = gtk.Tooltips()
316                resource_prio_label_eventbox = self.xml.get_widget(
317                        'resource_prio_label_eventbox')
318                tip.set_tip(resource_prio_label_eventbox, uf_resources)
319               
320                status_label = self.xml.get_widget('status_label')
321                #FIXME: when gtk2.4 is OOOOLD do it via glade2.10+
322                if gtk.pygtk_version >= (2, 6, 0) and gtk.gtk_version >= (2, 6, 0):
323                        tip = gtk.Tooltips()
324                        status_label_eventbox = self.xml.get_widget('status_label_eventbox')
325                        tip.set_tip(status_label_eventbox, stats)
326                        status_label.set_max_width_chars(15)
327               
328                status_label.set_text(stats)
329               
330                gajim.connections[self.account].request_vcard(self.contact.jid)
331
332        def add_to_vcard(self, vcard, entry, txt):
333                '''Add an information to the vCard dictionary'''
334                entries = entry.split('_')
335                loc = vcard
336                if len(entries) == 3: # We need to use lists
337                        if not loc.has_key(entries[0]):
338                                loc[entries[0]] = []
339                        found = False
340                        for e in loc[entries[0]]:
341                                if entries[1] in e:
342                                        found = True
343                                        break
344                        if found:
345                                e[entries[2]] = txt
346                        else:
347                                loc[entries[0]].append({entries[1]: '', entries[2]: txt})
348                        return vcard
349                while len(entries) > 1:
350                        if not loc.has_key(entries[0]):
351                                loc[entries[0]] = {}
352                        loc = loc[entries[0]]
353                        del entries[0]
354                loc[entries[0]] = txt
355                return vcard
356
357        def make_vcard(self):
358                '''make the vCard dictionary'''
359                entries = ['FN', 'NICKNAME', 'BDAY', 'EMAIL_HOME_USERID', 'URL',
360                        'TEL_HOME_NUMBER', 'N_FAMILY', 'N_GIVEN', 'N_MIDDLE', 'N_PREFIX',
361                        'N_SUFFIX', 'ADR_HOME_STREET', 'ADR_HOME_EXTADR', 'ADR_HOME_LOCALITY',
362                        'ADR_HOME_REGION', 'ADR_HOME_PCODE', 'ADR_HOME_CTRY', 'ORG_ORGNAME',
363                        'ORG_ORGUNIT', 'TITLE', 'ROLE', 'TEL_WORK_NUMBER', 'EMAIL_WORK_USERID',
364                        'ADR_WORK_STREET', 'ADR_WORK_EXTADR', 'ADR_WORK_LOCALITY',
365                        'ADR_WORK_REGION', 'ADR_WORK_PCODE', 'ADR_WORK_CTRY']
366                vcard = {}
367                for e in entries: 
368                        txt = self.xml.get_widget(e + '_entry').get_text().decode('utf-8')
369                        if txt != '':
370                                vcard = self.add_to_vcard(vcard, e, txt)
371
372                # DESC textview
373                buff = self.xml.get_widget('DESC_textview').get_buffer()
374                start_iter = buff.get_start_iter()
375                end_iter = buff.get_end_iter()
376                txt = buff.get_text(start_iter, end_iter, 0)
377                if txt != '':
378                        vcard['DESC'] = txt.decode('utf-8')
379
380                # Avatar
381                if self.avatar_encoded:
382                        vcard['PHOTO'] = {'TYPE': self.avatar_mime_type,
383                                'BINVAL': self.avatar_encoded}
384                return vcard
385
386        def on_publish_button_clicked(self, widget):
387                if gajim.connections[self.account].connected < 2:
388                        ErrorDialog(_('You are not connected to the server'),
389                    _('Without a connection you can not publish your contact information.')).get_response()
390                        return
391                vcard = self.make_vcard()
392                nick = ''
393                if vcard.has_key('NICKNAME'):
394                        nick = vcard['NICKNAME']
395                if nick == '':
396                        nick = gajim.config.get_per('accounts', self.account, 'name')
397                gajim.nicks[self.account] = nick
398                gajim.connections[self.account].send_vcard(vcard)
399
400        def on_retrieve_button_clicked(self, widget):
401                entries = ['FN', 'NICKNAME', 'BDAY', 'EMAIL_HOME_USERID', 'URL',
402                        'TEL_HOME_NUMBER', 'N_FAMILY', 'N_GIVEN', 'N_MIDDLE', 'N_PREFIX',
403                        'N_SUFFIX', 'ADR_HOME_STREET', 'ADR_HOME_EXTADR', 'ADR_HOME_LOCALITY',
404                        'ADR_HOME_REGION', 'ADR_HOME_PCODE', 'ADR_HOME_CTRY', 'ORG_ORGNAME',
405                        'ORG_ORGUNIT', 'TITLE', 'ROLE', 'ADR_WORK_STREET', 'ADR_WORK_EXTADR',
406                        'ADR_WORK_LOCALITY', 'ADR_WORK_REGION', 'ADR_WORK_PCODE',
407                        'ADR_WORK_CTRY']
408                if gajim.connections[self.account].connected > 1:
409                        # clear all entries
410                        for e in entries:
411                                self.xml.get_widget(e + '_entry').set_text('')
412                        self.xml.get_widget('DESC_textview').get_buffer().set_text('')
413                        self.xml.get_widget('PHOTO_image').set_from_pixbuf(None)
414                        gajim.connections[self.account].request_vcard(self.jid)
415                else:
416                        ErrorDialog(_('You are not connected to the server'),
417                                                _('Without a connection, you can not get your contact information.')).get_response()
418
419        def change_to_vcard(self):
420                self.xml.get_widget('information_notebook').remove_page(0)
421                self.xml.get_widget('nickname_label').set_text('Personal details')
422               
423                self.publish_button.show()
424                self.retrieve_button.show()
425               
426                #photo_vbuttonbox visible
427                self.xml.get_widget('photo_vbuttonbox').show()
428               
429                #make all entries editable
430                entries = ['FN', 'NICKNAME', 'BDAY', 'EMAIL_HOME_USERID', 'URL',
431                        'TEL_HOME_NUMBER', 'N_FAMILY', 'N_GIVEN', 'N_MIDDLE', 'N_PREFIX',
432                        'N_SUFFIX', 'ADR_HOME_STREET', 'ADR_HOME_EXTADR', 'ADR_HOME_LOCALITY',
433                        'ADR_HOME_REGION', 'ADR_HOME_PCODE', 'ADR_HOME_CTRY', 'ORG_ORGNAME',
434                        'ORG_ORGUNIT', 'TITLE', 'ROLE', 'TEL_WORK_NUMBER', 'EMAIL_WORK_USERID',
435                        'ADR_WORK_STREET', 'ADR_WORK_EXTADR', 'ADR_WORK_LOCALITY',
436                        'ADR_WORK_REGION', 'ADR_WORK_PCODE', 'ADR_WORK_CTRY']
437                for e in entries:
438                        self.xml.get_widget(e + '_entry').set_property('editable', True)
439
440                description_textview = self.xml.get_widget('DESC_textview')
441                description_textview.set_editable(True)
442                description_textview.set_cursor_visible(True)
Note: See TracBrowser for help on using the browser.