1 # -*- coding: utf-8 -*-
4 ## Copyright (C) 2005 Alex Mauer <hawke AT hawkesnest.net>
5 ## Stéphan Kochen <stephan AT kochen.nl>
6 ## Copyright (C) 2005-2006 Dimitur Kirov <dkirov AT gmail.com>
7 ## Copyright (C) 2005-2007 Nikos Kouremenos <kourem AT gmail.com>
8 ## Copyright (C) 2005-2010 Yann Leboulanger <asterix AT lagaule.org>
9 ## Copyright (C) 2006 Travis Shirk <travis AT pobox.com>
10 ## Stefan Bethge <stefan AT lanpartei.de>
11 ## Copyright (C) 2006-2007 Jean-Marie Traissard <jim AT lapin.org>
12 ## Copyright (C) 2007 Julien Pivotto <roidelapluie AT gmail.com>
13 ## Copyright (C) 2007-2008 Stephan Erb <steve-e AT h3c.de>
14 ## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
16 ## This file is part of Gajim.
18 ## Gajim is free software; you can redistribute it and/or modify
19 ## it under the terms of the GNU General Public License as published
20 ## by the Free Software Foundation; version 3 only.
22 ## Gajim is distributed in the hope that it will be useful,
23 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
24 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 ## GNU General Public License for more details.
27 ## You should have received a copy of the GNU General Public License
28 ## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
36 from datetime
import datetime
37 from datetime
import timedelta
41 from common
import gajim
42 from common
import helpers
43 from common
.pep
import MOODS
, ACTIVITIES
44 from common
.i18n
import Q_
51 tooltip = BaseTooltip()
53 tooltip.show_tooltip(data, widget_height, widget_y_position)
55 if tooltip.timeout != 0:
56 tooltip.hide_tooltip()
58 * data - the text to be displayed (extenders override this argument and
59 display more complex contents)
60 * widget_height - the height of the widget on which we want to show tooltip
61 * widget_y_position - the vertical position of the widget on the screen
63 Tooltip is displayed aligned centered to the mouse poiner and 4px below the widget.
64 In case tooltip goes below the visible area it is shown above the widget.
69 self
.preferred_position
= [0, 0]
73 self
.check_last_time
= None
75 def populate(self
, data
):
77 This method must be overriden by all extenders. This is the most simple
78 implementation: show data as value of a label
81 self
.win
.add(gtk
.Label(data
))
83 def create_window(self
):
85 Create a popup window each time tooltip is requested
87 self
.win
= gtk
.Window(gtk
.WINDOW_POPUP
)
88 self
.win
.set_border_width(3)
89 self
.win
.set_resizable(False)
90 self
.win
.set_name('gtk-tooltips')
91 self
.win
.set_type_hint(gtk
.gdk
.WINDOW_TYPE_HINT_TOOLTIP
)
93 self
.win
.set_events(gtk
.gdk
.POINTER_MOTION_MASK
)
94 self
.win
.connect_after('expose_event', self
.expose
)
95 self
.win
.connect('size-request', self
.on_size_request
)
96 self
.win
.connect('motion-notify-event', self
.motion_notify_event
)
97 self
.screen
= self
.win
.get_screen()
99 def _get_icon_name_for_tooltip(self
, contact
):
101 Helper function used for tooltip contacts/acounts
103 Tooltip on account has fake contact with sub == '', in this case we show
104 real status of the account
106 if contact
.ask
== 'subscribe':
108 elif contact
.sub
in ('both', 'to', ''):
110 return 'not in roster'
112 def motion_notify_event(self
, widget
, event
):
115 def on_size_request(self
, widget
, requisition
):
116 half_width
= requisition
.width
/ 2 + 1
117 if self
.preferred_position
[0] < half_width
:
118 self
.preferred_position
[0] = 0
119 elif self
.preferred_position
[0] + requisition
.width
> \
120 self
.screen
.get_width() + half_width
:
121 self
.preferred_position
[0] = self
.screen
.get_width() - \
123 elif not self
.check_last_time
:
124 self
.preferred_position
[0] -= half_width
125 if self
.preferred_position
[1] + requisition
.height
> \
126 self
.screen
.get_height():
128 self
.preferred_position
[1] -= requisition
.height
+ \
129 self
.widget_height
+ 8
130 if self
.preferred_position
[1] < 0:
131 self
.preferred_position
[1] = 0
132 self
.win
.move(self
.preferred_position
[0], self
.preferred_position
[1])
134 def expose(self
, widget
, event
):
135 style
= self
.win
.get_style()
136 size
= self
.win
.get_size()
137 style
.paint_flat_box(self
.win
.window
, gtk
.STATE_NORMAL
, gtk
.SHADOW_OUT
,
138 None, self
.win
, 'tooltip', 0, 0, -1, 1)
139 style
.paint_flat_box(self
.win
.window
, gtk
.STATE_NORMAL
, gtk
.SHADOW_OUT
,
140 None, self
.win
, 'tooltip', 0, size
[1] - 1, -1, 1)
141 style
.paint_flat_box(self
.win
.window
, gtk
.STATE_NORMAL
, gtk
.SHADOW_OUT
,
142 None, self
.win
, 'tooltip', 0, 0, 1, -1)
143 style
.paint_flat_box(self
.win
.window
, gtk
.STATE_NORMAL
, gtk
.SHADOW_OUT
,
144 None, self
.win
, 'tooltip', size
[0] - 1, 0, 1, -1)
147 def show_tooltip(self
, data
, widget_height
, widget_y_position
):
149 Show tooltip on widget
151 Data contains needed data for tooltip contents.
152 widget_height is the height of the widget on which we show the tooltip.
153 widget_y_position is vertical position of the widget on the screen.
156 # set tooltip contents
159 # get the X position of mouse pointer on the screen
160 pointer_x
= self
.screen
.get_display().get_pointer()[1]
162 # get the prefered X position of the tooltip on the screen in case this position is >
163 # than the height of the screen, tooltip will be shown above the widget
164 preferred_y
= widget_y_position
+ widget_height
+ 4
166 self
.preferred_position
= [pointer_x
, preferred_y
]
167 self
.widget_height
= widget_height
168 self
.win
.ensure_style()
171 def hide_tooltip(self
):
173 gobject
.source_remove(self
.timeout
)
180 self
.check_last_time
= None
183 def colorize_status(status
):
185 Colorize the status message inside the tooltip by it's
186 semantics. Color palette is the Tango.
188 formatted
= "<span foreground='%s'>%s</span>"
189 if status
.startswith(Q_("?user status:Available")):
190 status
= formatted
% ('#73D216', status
)
191 elif status
.startswith(_("Free for Chat")):
192 status
= formatted
% ('#3465A4', status
)
193 elif status
.startswith(_("Away")):
194 status
= formatted
% ('#EDD400', status
)
195 elif status
.startswith(_("Busy")):
196 status
= formatted
% ('#F57900', status
)
197 elif status
.startswith(_("Not Available")):
198 status
= formatted
% ('#CC0000', status
)
199 elif status
.startswith(_("Offline")):
200 status
= formatted
% ('#555753', status
)
204 def colorize_affiliation(affiliation
):
206 Color the affiliation of a MUC participant inside the tooltip by
207 it's semantics. Color palette is the Tango.
209 formatted
= "<span foreground='%s'>%s</span>"
210 if affiliation
.startswith(Q_("?Group Chat Contact Affiliation:None")):
211 affiliation
= formatted
% ('#555753', affiliation
)
212 elif affiliation
.startswith(_("Member")):
213 affiliation
= formatted
% ('#73D216', affiliation
)
214 elif affiliation
.startswith(_("Administrator")):
215 affiliation
= formatted
% ('#F57900', affiliation
)
216 elif affiliation
.startswith(_("Owner")):
217 affiliation
= formatted
% ('#CC0000', affiliation
)
222 Contains methods for creating status table. This is used in Roster and
223 NotificationArea tooltips
229 self
.text_label
= None
230 self
.spacer_label
= ' '
232 def create_table(self
):
233 self
.table
= gtk
.Table(4, 1)
234 self
.table
.set_property('column-spacing', 2)
236 def add_text_row(self
, text
, col_inc
= 0):
237 self
.current_row
+= 1
238 self
.text_label
= gtk
.Label()
239 self
.text_label
.set_line_wrap(True)
240 self
.text_label
.set_alignment(0, 0)
241 self
.text_label
.set_selectable(False)
242 self
.text_label
.set_markup(text
)
243 self
.table
.attach(self
.text_label
, 1 + col_inc
, 4, self
.current_row
,
244 self
.current_row
+ 1)
246 def get_status_info(self
, resource
, priority
, show
, status
):
247 str_status
= resource
+ ' (' + unicode(priority
) + ')'
249 status
= status
.strip()
251 # make sure 'status' is unicode before we send to to reduce_chars
252 if isinstance(status
, str):
253 status
= unicode(status
, encoding
='utf-8')
254 # reduce to 100 chars, 1 line
255 status
= helpers
.reduce_chars_newlines(status
, 100, 1)
256 str_status
= gobject
.markup_escape_text(str_status
)
257 status
= gobject
.markup_escape_text(status
)
258 str_status
+= ' - <i>' + status
+ '</i>'
261 def add_status_row(self
, file_path
, show
, str_status
, status_time
=None,
262 show_lock
=False, indent
=True):
264 Append a new row with status icon to the table
266 self
.current_row
+= 1
267 state_file
= show
.replace(' ', '_')
269 files
.append(os
.path
.join(file_path
, state_file
+ '.png'))
270 files
.append(os
.path
.join(file_path
, state_file
+ '.gif'))
272 image
.set_from_pixbuf(None)
274 if os
.path
.exists(f
):
275 image
.set_from_file(f
)
277 spacer
= gtk
.Label(self
.spacer_label
)
278 image
.set_alignment(1, 0.5)
280 self
.table
.attach(spacer
, 1, 2, self
.current_row
,
281 self
.current_row
+ 1, 0, 0, 0, 0)
282 self
.table
.attach(image
, 2, 3, self
.current_row
,
283 self
.current_row
+ 1, gtk
.FILL
, gtk
.FILL
, 2, 0)
284 status_label
= gtk
.Label()
285 status_label
.set_markup(str_status
)
286 status_label
.set_alignment(0, 0)
287 status_label
.set_line_wrap(True)
288 self
.table
.attach(status_label
, 3, 4, self
.current_row
,
289 self
.current_row
+ 1, gtk
.FILL | gtk
.EXPAND
, 0, 0, 0)
291 lock_image
= gtk
.Image()
292 lock_image
.set_from_stock(gtk
.STOCK_DIALOG_AUTHENTICATION
,
294 self
.table
.attach(lock_image
, 4, 5, self
.current_row
,
295 self
.current_row
+ 1, 0, 0, 0, 0)
297 class NotificationAreaTooltip(BaseTooltip
, StatusTable
):
299 Tooltip that is shown in the notification area
303 BaseTooltip
.__init
__(self
)
304 StatusTable
.__init
__(self
)
306 def fill_table_with_accounts(self
, accounts
):
307 iconset
= gajim
.config
.get('iconset')
310 file_path
= os
.path
.join(helpers
.get_iconset_path(iconset
), '16x16')
311 for acct
in accounts
:
312 message
= acct
['message']
313 # before reducing the chars we should assure we send unicode, else
314 # there are possible pango TBs on 'set_markup'
315 if isinstance(message
, str):
316 message
= unicode(message
, encoding
= 'utf-8')
317 message
= helpers
.reduce_chars_newlines(message
, 100, 1)
318 message
= gobject
.markup_escape_text(message
)
319 if acct
['name'] in gajim
.con_types
and \
320 gajim
.con_types
[acct
['name']] in ('tls', 'ssl'):
325 self
.add_status_row(file_path
, acct
['show'],
326 gobject
.markup_escape_text(acct
['name']) + \
327 ' - ' + message
, show_lock
=show_lock
, indent
=False)
329 self
.add_status_row(file_path
, acct
['show'],
330 gobject
.markup_escape_text(acct
['name'])
331 , show_lock
=show_lock
, indent
=False)
332 for line
in acct
['event_lines']:
333 self
.add_text_row(' ' + line
, 1)
335 def populate(self
, data
=''):
339 accounts
= helpers
.get_notification_icon_tooltip_dict()
340 self
.table
.resize(2, 1)
341 self
.fill_table_with_accounts(accounts
)
342 self
.hbox
= gtk
.HBox()
343 self
.table
.set_property('column-spacing', 1)
345 self
.hbox
.add(self
.table
)
348 class GCTooltip(BaseTooltip
):
350 Tooltip that is shown in the GC treeview
355 self
.text_label
= gtk
.Label()
356 self
.text_label
.set_line_wrap(True)
357 self
.text_label
.set_alignment(0, 0)
358 self
.text_label
.set_selectable(False)
359 self
.avatar_image
= gtk
.Image()
361 BaseTooltip
.__init
__(self
)
363 def populate(self
, contact
):
367 vcard_table
= gtk
.Table(3, 1)
368 vcard_table
.set_property('column-spacing', 2)
369 vcard_table
.set_homogeneous(False)
370 vcard_current_row
= 1
373 nick_markup
= '<b>' + \
374 gobject
.markup_escape_text(contact
.get_shown_name()) \
376 properties
.append((nick_markup
, None))
378 if contact
.status
: # status message
379 status
= contact
.status
.strip()
381 # escape markup entities
382 status
= helpers
.reduce_chars_newlines(status
, 300, 5)
384 gobject
.markup_escape_text(status
) + '</i>'
385 properties
.append((status
, None))
387 show
= helpers
.get_uf_show(contact
.show
)
388 show
= self
.colorize_status(show
)
389 properties
.append((show
, None))
391 if contact
.jid
.strip():
392 properties
.append((_('Jabber ID: '), "<b>%s</b>" % contact
.jid
))
394 if hasattr(contact
, 'resource') and contact
.resource
.strip():
395 properties
.append((_('Resource: '),
396 gobject
.markup_escape_text(contact
.resource
)))
398 if contact
.affiliation
!= 'none':
399 uf_affiliation
= helpers
.get_uf_affiliation(contact
.affiliation
)
401 _('%(owner_or_admin_or_member)s of this group chat') %\
402 {'owner_or_admin_or_member': uf_affiliation
}
403 uf_affiliation
= self
.colorize_affiliation(uf_affiliation
)
404 properties
.append((uf_affiliation
, None))
407 puny_name
= helpers
.sanitize_filename(contact
.name
)
408 puny_room
= helpers
.sanitize_filename(contact
.room_jid
)
409 file_
= helpers
.get_avatar_path(os
.path
.join(gajim
.AVATAR_PATH
, puny_room
,
412 self
.avatar_image
.set_from_file(file_
)
413 pix
= self
.avatar_image
.get_pixbuf()
414 pix
= gtkgui_helpers
.get_scaled_pixbuf(pix
, 'tooltip')
415 self
.avatar_image
.set_from_pixbuf(pix
)
417 self
.avatar_image
.set_from_pixbuf(None)
419 property_
= properties
.pop(0)
420 vcard_current_row
+= 1
421 vertical_fill
= gtk
.FILL
423 vertical_fill |
= gtk
.EXPAND
425 label
.set_alignment(0, 0)
427 label
.set_markup(property_
[0])
428 vcard_table
.attach(label
, 1, 2, vcard_current_row
,
429 vcard_current_row
+ 1, gtk
.FILL
, vertical_fill
, 0, 0)
431 label
.set_alignment(0, 0)
432 label
.set_markup(property_
[1])
433 label
.set_line_wrap(True)
434 vcard_table
.attach(label
, 2, 3, vcard_current_row
,
435 vcard_current_row
+ 1, gtk
.EXPAND | gtk
.FILL
,
438 label
.set_markup(property_
[0])
439 label
.set_line_wrap(True)
440 vcard_table
.attach(label
, 1, 3, vcard_current_row
,
441 vcard_current_row
+ 1, gtk
.FILL
, vertical_fill
, 0)
443 self
.avatar_image
.set_alignment(0, 0)
444 vcard_table
.attach(self
.avatar_image
, 3, 4, 2, vcard_current_row
+ 1,
445 gtk
.FILL
, gtk
.FILL | gtk
.EXPAND
, 3, 3)
446 self
.win
.add(vcard_table
)
448 class RosterTooltip(NotificationAreaTooltip
):
450 Tooltip that is shown in the roster treeview
455 self
.image
= gtk
.Image()
456 self
.image
.set_alignment(0, 0)
457 # padding is independent of the total length and better than alignment
458 self
.image
.set_padding(1, 2)
459 self
.avatar_image
= gtk
.Image()
460 NotificationAreaTooltip
.__init
__(self
)
462 def populate(self
, contacts
):
466 if not contacts
or len(contacts
) == 0:
467 # Tooltip for merged accounts row
468 accounts
= helpers
.get_notification_icon_tooltip_dict()
469 self
.table
.resize(2, 1)
470 self
.spacer_label
= ''
471 self
.fill_table_with_accounts(accounts
)
472 self
.win
.add(self
.table
)
476 prim_contact
= gajim
.contacts
.get_highest_prio_contact_from_contacts(
479 puny_jid
= helpers
.sanitize_filename(prim_contact
.jid
)
482 file_
= helpers
.get_avatar_path(os
.path
.join(gajim
.AVATAR_PATH
, puny_jid
))
484 self
.avatar_image
.set_from_file(file_
)
485 pix
= self
.avatar_image
.get_pixbuf()
486 pix
= gtkgui_helpers
.get_scaled_pixbuf(pix
, 'tooltip')
487 self
.avatar_image
.set_from_pixbuf(pix
)
490 self
.avatar_image
.set_from_pixbuf(None)
491 vcard_table
= gtk
.Table(table_size
, 1)
492 vcard_table
.set_property('column-spacing', 2)
493 vcard_table
.set_homogeneous(False)
494 vcard_current_row
= 1
497 name_markup
= u
'<span weight="bold">' + \
498 gobject
.markup_escape_text(prim_contact
.get_shown_name())\
500 if self
.account
and helpers
.jid_is_blocked(self
.account
,
502 name_markup
+= _(' [blocked]')
503 if self
.account
and \
504 self
.account
in gajim
.interface
.minimized_controls
and \
505 prim_contact
.jid
in gajim
.interface
.minimized_controls
[self
.account
]:
506 name_markup
+= _(' [minimized]')
507 properties
.append((name_markup
, None))
510 # put contacts in dict, where key is priority
512 for contact
in contacts
:
515 if contact
.priority
in contacts_dict
:
516 contacts_dict
[contact
.priority
].append(contact
)
518 contacts_dict
[contact
.priority
] = [contact
]
520 if num_resources
> 1:
521 properties
.append((_('Status: '), ' '))
522 transport
= gajim
.get_transport_name_from_jid(
525 file_path
= os
.path
.join(helpers
.get_transport_path(transport
),
528 iconset
= gajim
.config
.get('iconset')
531 file_path
= os
.path
.join(helpers
.get_iconset_path(iconset
), '16x16')
533 contact_keys
= sorted(contacts_dict
.keys())
534 contact_keys
.reverse()
535 for priority
in contact_keys
:
536 for acontact
in contacts_dict
[priority
]:
537 status_line
= self
.get_status_info(acontact
.resource
,
538 acontact
.priority
, acontact
.show
, acontact
.status
)
540 icon_name
= self
._get
_icon
_name
_for
_tooltip
(acontact
)
541 self
.add_status_row(file_path
, icon_name
, status_line
,
542 acontact
.last_status_time
)
543 properties
.append((self
.table
, None))
545 else: # only one resource
547 show
= helpers
.get_uf_show(contact
.show
)
548 if not self
.check_last_time
and self
.account
:
549 if contact
.show
== 'offline':
550 if not contact
.last_status_time
:
551 gajim
.connections
[self
.account
].request_last_status_time(
554 self
.check_last_time
= contact
.last_status_time
555 elif contact
.resource
:
556 gajim
.connections
[self
.account
].request_last_status_time(
557 contact
.jid
, contact
.resource
)
558 if contact
.last_activity_time
:
559 self
.check_last_time
= contact
.last_activity_time
561 self
.check_last_time
= None
562 if contact
.last_status_time
:
563 vcard_current_row
+= 1
564 if contact
.show
== 'offline':
565 text
= ' - ' + _('Last status: %s')
567 text
= _(' since %s')
569 if time
.strftime('%j', time
.localtime())== \
570 time
.strftime('%j', contact
.last_status_time
):
571 # it's today, show only the locale hour representation
572 local_time
= time
.strftime('%X',
573 contact
.last_status_time
)
575 # time.strftime returns locale encoded string
576 local_time
= time
.strftime('%c',
577 contact
.last_status_time
)
578 local_time
= local_time
.decode(
579 locale
.getpreferredencoding())
580 text
= text
% local_time
582 if self
.account
and \
583 prim_contact
.jid
in gajim
.gc_connected
[self
.account
]:
584 if gajim
.gc_connected
[self
.account
][prim_contact
.jid
]:
585 show
= _('Connected')
587 show
= _('Disconnected')
588 show
= self
.colorize_status(show
)
591 status
= contact
.status
.strip()
594 # (no more than 300 chars on line and no more than 5 lines)
596 status
= helpers
.reduce_chars_newlines(status
, 300, 5)
597 # escape markup entities.
598 status
= gobject
.markup_escape_text(status
)
599 properties
.append(('<i>%s</i>' % status
, None))
600 properties
.append((show
, None))
602 self
._append
_pep
_info
(contact
, properties
)
604 properties
.append((_('Jabber ID: '), "<b>%s</b>" % prim_contact
.jid
))
606 # contact has only one ressource
607 if num_resources
== 1 and contact
.resource
:
608 properties
.append((_('Resource: '),
609 gobject
.markup_escape_text(contact
.resource
) +\
610 ' (' + unicode(contact
.priority
) + ')'))
612 if self
.account
and prim_contact
.sub
and prim_contact
.sub
!= 'both' and\
613 prim_contact
.jid
not in gajim
.gc_connected
[self
.account
]:
614 # ('both' is the normal sub so we don't show it)
615 properties
.append(( _('Subscription: '),
616 gobject
.markup_escape_text(helpers
.get_uf_sub(prim_contact
.sub
))))
618 if prim_contact
.keyID
:
620 if len(prim_contact
.keyID
) == 8:
621 keyID
= prim_contact
.keyID
622 elif len(prim_contact
.keyID
) == 16:
623 keyID
= prim_contact
.keyID
[8:]
625 properties
.append((_('OpenPGP: '),
626 gobject
.markup_escape_text(keyID
)))
628 if contact
.last_activity_time
:
629 last_active
= datetime(*contact
.last_activity_time
[:6])
630 current
= datetime
.now()
632 diff
= current
- last_active
633 diff
= timedelta(diff
.days
, diff
.seconds
)
635 if last_active
.date() == current
.date():
636 formatted
= last_active
.strftime("%X")
638 formatted
= last_active
.strftime("%c")
640 # Do not show the "Idle since" and "Idle for" items if there
641 # is no meaningful difference between last activity time and
643 if diff
.days
> 0 or diff
.seconds
> 0:
644 cs
= "<span foreground='#888A85'>%s</span>"
645 properties
.append((str(), None))
646 properties
.append(((cs
% _("Idle since %s")) % formatted
, None))
647 properties
.append(((cs
% _("Idle for %s")) % str(diff
), None))
650 property_
= properties
.pop(0)
651 vcard_current_row
+= 1
652 vertical_fill
= gtk
.FILL
653 if not properties
and table_size
== 4:
654 vertical_fill |
= gtk
.EXPAND
656 label
.set_alignment(0, 0)
658 label
.set_markup(property_
[0])
659 vcard_table
.attach(label
, 1, 2, vcard_current_row
,
660 vcard_current_row
+ 1, gtk
.FILL
, vertical_fill
, 0, 0)
662 label
.set_alignment(0, 0)
663 label
.set_markup(property_
[1])
664 label
.set_line_wrap(True)
665 vcard_table
.attach(label
, 2, 3, vcard_current_row
,
666 vcard_current_row
+ 1, gtk
.EXPAND | gtk
.FILL
,
669 if isinstance(property_
[0], (unicode, str)): # FIXME: rm unicode?
670 label
.set_markup(property_
[0])
671 label
.set_line_wrap(True)
674 vcard_table
.attach(label
, 1, 3, vcard_current_row
,
675 vcard_current_row
+ 1, gtk
.FILL
, vertical_fill
, 0)
676 self
.avatar_image
.set_alignment(0, 0)
678 vcard_table
.attach(self
.avatar_image
, 3, 4, 2,
679 vcard_current_row
+ 1, gtk
.FILL
, gtk
.FILL | gtk
.EXPAND
, 3, 3)
680 self
.win
.add(vcard_table
)
682 def update_last_time(self
, last_time
):
683 if not self
.check_last_time
or time
.strftime('%x %I:%M %p', last_time
) !=\
684 time
.strftime('%x %I:%M %p', self
.check_last_time
):
687 self
.populate(self
.cur_data
)
688 self
.win
.ensure_style()
691 def _append_pep_info(self
, contact
, properties
):
693 Append Tune, Mood, Activity, Location information of the specified contact
694 to the given property list.
696 if 'mood' in contact
.pep
:
697 mood
= contact
.pep
['mood'].asMarkupText()
698 properties
.append((_("Mood: %s") % mood
, None))
700 if 'activity' in contact
.pep
:
701 activity
= contact
.pep
['activity'].asMarkupText()
702 properties
.append((_("Activity: %s") % activity
, None))
704 if 'tune' in contact
.pep
:
705 tune
= contact
.pep
['tune'].asMarkupText()
706 properties
.append((_("Tune: %s") % tune
, None))
708 if 'location' in contact
.pep
:
709 location
= contact
.pep
['location'].asMarkupText()
710 properties
.append((_("Location: %s") % location
, None))
713 class FileTransfersTooltip(BaseTooltip
):
715 Tooltip that is shown in the notification area
719 BaseTooltip
.__init
__(self
)
721 def populate(self
, file_props
):
722 ft_table
= gtk
.Table(2, 1)
723 ft_table
.set_property('column-spacing', 2)
727 name
= file_props
['name']
728 if file_props
['type'] == 'r':
729 file_name
= os
.path
.split(file_props
['file-name'])[1]
731 file_name
= file_props
['name']
732 properties
.append((_('Name: '),
733 gobject
.markup_escape_text(file_name
)))
734 if file_props
['type'] == 'r':
735 type_
= _('Download')
736 actor
= _('Sender: ')
737 sender
= unicode(file_props
['sender']).split('/')[0]
738 name
= gajim
.contacts
.get_first_contact_from_jid(
739 file_props
['tt_account'], sender
).get_shown_name()
742 actor
= _('Recipient: ')
743 receiver
= file_props
['receiver']
744 if hasattr(receiver
, 'name'):
745 name
= receiver
.get_shown_name()
747 name
= receiver
.split('/')[0]
748 properties
.append((_('Type: '), type_
))
749 properties
.append((actor
, gobject
.markup_escape_text(name
)))
751 transfered_len
= file_props
.get('received-len', 0)
752 properties
.append((_('Transferred: '), helpers
.convert_bytes(transfered_len
)))
754 if 'started' not in file_props
or not file_props
['started']:
755 status
= _('Not started')
756 elif 'connected' in file_props
:
757 if 'stopped' in file_props
and \
758 file_props
['stopped'] == True:
759 status
= _('Stopped')
760 elif file_props
['completed']:
761 status
= _('Completed')
762 elif file_props
['connected'] == False:
763 if file_props
['completed']:
764 status
= _('Completed')
766 if 'paused' in file_props
and \
767 file_props
['paused'] == True:
768 status
= _('?transfer status:Paused')
769 elif 'stalled' in file_props
and \
770 file_props
['stalled'] == True:
771 #stalled is not paused. it is like 'frozen' it stopped alone
772 status
= _('Stalled')
774 status
= _('Transferring')
776 status
= _('Not started')
777 properties
.append((_('Status: '), status
))
778 if 'desc' in file_props
:
779 file_desc
= file_props
['desc']
780 properties
.append((_('Description: '), gobject
.markup_escape_text(
783 property_
= properties
.pop(0)
786 label
.set_alignment(0, 0)
787 label
.set_markup(property_
[0])
788 ft_table
.attach(label
, 1, 2, current_row
, current_row
+ 1,
789 gtk
.FILL
, gtk
.FILL
, 0, 0)
791 label
.set_alignment(0, 0)
792 label
.set_line_wrap(True)
793 label
.set_markup(property_
[1])
794 ft_table
.attach(label
, 2, 3, current_row
, current_row
+ 1,
795 gtk
.EXPAND | gtk
.FILL
, gtk
.FILL
, 0, 0)
797 self
.win
.add(ft_table
)
800 class ServiceDiscoveryTooltip(BaseTooltip
):
802 Tooltip that is shown when hovering over a service discovery row
804 def populate(self
, status
):
807 label
.set_line_wrap(True)
808 label
.set_alignment(0, 0)
809 label
.set_selectable(False)
812 _('This service has not yet responded with detailed information'))
815 _('This service could not respond with detailed information.\n'
816 'It is most likely legacy or broken'))