2005-10-20 13:17:17 +02:00
## chat.py
2005-03-12 19:12:15 +01:00
##
2005-12-09 18:15:30 +01:00
## Contributors for this file:
2005-03-12 19:12:15 +01:00
## - Yann Le Boulanger <asterix@lagaule.org>
## - Nikos Kouremenos <kourem@gmail.com>
##
2005-12-10 00:30:28 +01:00
## Copyright (C) 2003-2004 Yann Le Boulanger <asterix@lagaule.org>
## Vincent Hanquez <tab@snarc.org>
## Copyright (C) 2005 Yann Le Boulanger <asterix@lagaule.org>
## Vincent Hanquez <tab@snarc.org>
## Nikos Kouremenos <nkour@jabber.org>
## Dimitur Kirov <dkirov@gmail.com>
## Travis Shirk <travis@pobox.com>
## Norman Rasmussen <norman@rasmussen.co.za>
2005-03-12 19:12:15 +01:00
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published
## by the Free Software Foundation; version 2 only.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
import gtk
import gtk . glade
import pango
import gobject
import time
2005-11-15 12:52:40 +01:00
import math
2005-11-17 19:29:31 +01:00
import os
2005-11-03 16:10:00 +01:00
2005-05-30 23:00:04 +02:00
import dialogs
2005-06-13 16:46:08 +02:00
import history_window
2005-09-04 18:57:09 +02:00
import gtkgui_helpers
2005-10-08 18:47:35 +02:00
import tooltips
2005-10-28 23:46:55 +02:00
import conversation_textview
2005-11-03 16:10:00 +01:00
import message_textview
2005-03-12 19:12:15 +01:00
2005-05-26 01:58:27 +02:00
try :
import gtkspell
2005-11-30 23:22:22 +01:00
HAS_GTK_SPELL = True
2005-05-26 01:58:27 +02:00
except :
2005-11-30 23:22:22 +01:00
HAS_GTK_SPELL = False
2005-05-26 01:58:27 +02:00
2005-04-14 19:07:55 +02:00
from common import gajim
2005-08-10 00:46:13 +02:00
from common import helpers
2005-03-12 19:12:15 +01:00
from common import i18n
_ = i18n . _
APP = i18n . APP
gtk . glade . bindtextdomain ( APP , i18n . DIR )
gtk . glade . textdomain ( APP )
2005-04-22 01:20:18 +02:00
GTKGUI_GLADE = ' gtkgui.glade '
2005-03-12 19:12:15 +01:00
2005-03-13 18:04:57 +01:00
class Chat :
2005-10-06 17:20:53 +02:00
''' Class for chat/groupchat windows '''
2005-10-20 13:17:17 +02:00
def __init__ ( self , account , widget_name ) :
2005-03-12 19:12:15 +01:00
self . xml = gtk . glade . XML ( GTKGUI_GLADE , widget_name , APP )
2005-04-22 16:00:35 +02:00
self . window = self . xml . get_widget ( widget_name )
2005-06-07 23:28:21 +02:00
2005-04-22 16:00:35 +02:00
self . widget_name = widget_name
2005-08-28 16:40:06 +02:00
2005-03-12 19:12:15 +01:00
self . account = account
self . change_cursor = None
self . xmls = { }
2005-11-03 16:10:00 +01:00
self . conversation_textviews = { } # holds per jid conversation textview
self . message_textviews = { } # holds per jid message (where we write) textview
2005-03-12 19:12:15 +01:00
self . nb_unread = { }
self . print_time_timeout_id = { }
2005-10-06 18:36:45 +02:00
self . names = { } # what is printed in the tab (eg. contact.name)
2005-06-21 00:22:54 +02:00
self . childs = { } # holds the contents for every tab (VBox)
2005-03-12 19:12:15 +01:00
2005-08-07 17:19:21 +02:00
# the following vars are used to keep history of user's messages
2005-06-07 18:25:55 +02:00
self . sent_history = { }
self . sent_history_pos = { }
self . typing_new = { }
self . orig_msg = { }
2005-11-24 19:12:51 +01:00
# alignment before notebook (to control top padding for when showing tabs)
self . alignment = self . xml . get_widget ( ' alignment ' )
2005-08-28 16:40:06 +02:00
# notebook customizations
self . notebook = self . xml . get_widget ( ' chat_notebook ' )
2005-11-28 16:38:07 +01:00
# Remove the page that is in glade
self . notebook . remove_page ( 0 )
2005-08-28 16:40:06 +02:00
pref_pos = gajim . config . get ( ' tabs_position ' )
if pref_pos != ' top ' :
if pref_pos == ' bottom ' :
nb_pos = gtk . POS_BOTTOM
elif pref_pos == ' left ' :
nb_pos = gtk . POS_LEFT
elif pref_pos == ' right ' :
nb_pos = gtk . POS_RIGHT
else :
nb_pos = gtk . POS_TOP
else :
nb_pos = gtk . POS_TOP
self . notebook . set_tab_pos ( nb_pos )
2005-11-24 19:12:51 +01:00
if gajim . config . get ( ' tabs_always_visible ' ) :
self . notebook . set_show_tabs ( True )
2005-11-25 15:14:01 +01:00
self . alignment . set_property ( ' top-padding ' , 2 )
2005-11-24 19:12:51 +01:00
else :
self . notebook . set_show_tabs ( False )
2005-08-28 16:40:06 +02:00
self . notebook . set_show_border ( gajim . config . get ( ' tabs_border ' ) )
2005-11-15 12:52:40 +01:00
if gajim . config . get ( ' useemoticons ' ) :
2005-11-17 18:08:56 +01:00
self . emoticons_menu = self . prepare_emoticons_menu ( )
2005-11-15 12:52:40 +01:00
2005-09-14 02:51:26 +02:00
# muc attention states (when we are mentioned in a muc)
# if the room jid is in the list, the room has mentioned us
self . muc_attentions = [ ]
2005-11-17 18:08:56 +01:00
def toggle_emoticons ( self ) :
2005-11-17 19:29:31 +01:00
''' hide show emoticons_button and make sure emoticons_menu is always there
when needed '''
if gajim . config . get ( ' useemoticons ' ) :
self . emoticons_menu = self . prepare_emoticons_menu ( )
2005-11-15 12:52:40 +01:00
for jid in self . xmls :
2005-11-17 19:29:31 +01:00
emoticons_button = self . xmls [ jid ] . get_widget ( ' emoticons_button ' )
2005-11-15 12:52:40 +01:00
if gajim . config . get ( ' useemoticons ' ) :
2005-11-17 19:29:31 +01:00
emoticons_button . show ( )
emoticons_button . set_no_show_all ( False )
2005-11-15 12:52:40 +01:00
else :
2005-11-17 19:29:31 +01:00
emoticons_button . hide ( )
emoticons_button . set_no_show_all ( True )
2005-11-15 12:52:40 +01:00
2005-08-07 20:58:36 +02:00
def update_font ( self ) :
font = pango . FontDescription ( gajim . config . get ( ' conversation_font ' ) )
2005-10-28 23:46:55 +02:00
for jid in self . xmls :
self . conversation_textviews [ jid ] . modify_font ( font )
2005-11-03 18:23:36 +01:00
msg_textview = self . message_textviews [ jid ]
2005-11-03 16:10:00 +01:00
msg_textview . modify_font ( font )
2005-08-07 20:58:36 +02:00
2005-03-12 19:12:15 +01:00
def update_tags ( self ) :
2005-10-28 23:46:55 +02:00
for jid in self . conversation_textviews :
self . conversation_textviews [ jid ] . update_tags ( )
2005-03-12 19:12:15 +01:00
def update_print_time ( self ) :
2005-04-12 23:09:06 +02:00
if gajim . config . get ( ' print_time ' ) != ' sometimes ' :
2005-03-12 19:12:15 +01:00
list_jid = self . print_time_timeout_id . keys ( )
for jid in list_jid :
gobject . source_remove ( self . print_time_timeout_id [ jid ] )
del self . print_time_timeout_id [ jid ]
else :
for jid in self . xmls :
2005-10-28 23:46:55 +02:00
if not self . print_time_timeout_id . has_key ( jid ) :
self . print_time_timeout ( jid )
self . print_time_timeout_id [ jid ] = gobject . timeout_add ( 300000 ,
self . print_time_timeout , jid )
def print_time_timeout ( self , jid ) :
if not jid in self . xmls . keys ( ) :
return False
if gajim . config . get ( ' print_time ' ) == ' sometimes ' :
conv_textview = self . conversation_textviews [ jid ]
buffer = conv_textview . get_buffer ( )
end_iter = buffer . get_end_iter ( )
tim = time . localtime ( )
tim_format = time . strftime ( ' % H: % M ' , tim )
buffer . insert_with_tags_by_name ( end_iter , ' \n ' + tim_format ,
' time_sometimes ' )
# scroll to the end of the textview
if conv_textview . at_the_end ( ) :
# we are at the end
conv_textview . scroll_to_end ( )
return True # loop again
if self . print_time_timeout_id . has_key ( jid ) :
del self . print_time_timeout_id [ jid ]
return False
2005-03-12 19:12:15 +01:00
2005-09-09 18:10:49 +02:00
def show_title ( self , urgent = True ) :
2005-10-06 17:20:53 +02:00
''' redraw the window ' s title '''
2005-03-12 19:12:15 +01:00
unread = 0
for jid in self . nb_unread :
unread + = self . nb_unread [ jid ]
2005-10-28 23:46:55 +02:00
start = ' '
2005-03-12 19:12:15 +01:00
if unread > 1 :
2005-08-26 02:52:44 +02:00
start = ' [ ' + unicode ( unread ) + ' ] '
2005-03-12 19:12:15 +01:00
elif unread == 1 :
2005-04-12 23:09:06 +02:00
start = ' * '
2005-03-12 19:12:15 +01:00
chat = self . names [ jid ]
2005-04-22 02:02:42 +02:00
if len ( self . xmls ) > 1 : # if more than one tab in the same window
2005-03-16 21:48:56 +01:00
if self . widget_name == ' tabbed_chat_window ' :
2005-08-08 18:42:30 +02:00
add = _ ( ' Chat ' )
2005-03-16 21:48:56 +01:00
elif self . widget_name == ' groupchat_window ' :
2005-08-08 18:42:30 +02:00
add = _ ( ' Group Chat ' )
elif len ( self . xmls ) == 1 : # just one tab
if self . widget_name == ' tabbed_chat_window ' :
c = gajim . get_first_contact_instance_from_jid ( self . account , jid )
2005-11-02 12:29:51 +01:00
if c is None :
add = ' '
else :
add = c . name
2005-08-08 18:42:30 +02:00
elif self . widget_name == ' groupchat_window ' :
name = gajim . get_nick_from_jid ( jid )
add = name
title = start + add
2005-04-14 09:05:10 +02:00
if len ( gajim . connections ) > = 2 : # if we have 2 or more accounts
2005-08-18 14:59:54 +02:00
title + = ' ( ' + _ ( ' account: ' ) + self . account + ' ) '
2005-04-22 02:02:42 +02:00
2005-03-16 02:27:37 +01:00
self . window . set_title ( title )
2005-09-09 18:10:49 +02:00
if urgent :
gtkgui_helpers . set_unset_urgency_hint ( self . window , unread )
2005-03-12 19:12:15 +01:00
2005-09-05 03:39:42 +02:00
def redraw_tab ( self , jid , chatstate = None ) :
2005-09-05 01:30:40 +02:00
''' redraw the label of the tab
if chatstate is given that means we have HE SENT US a chatstate '''
# Update status images
self . set_state_image ( jid )
2005-07-22 22:06:16 +02:00
2005-11-29 05:01:00 +01:00
unread = ' '
num_unread = 0
2005-03-12 22:30:50 +01:00
child = self . childs [ jid ]
2005-08-04 11:42:34 +02:00
hb = self . notebook . get_tab_label ( child ) . get_children ( ) [ 0 ]
2005-05-04 18:22:07 +02:00
if self . widget_name == ' tabbed_chat_window ' :
2005-08-04 11:42:34 +02:00
nickname = hb . get_children ( ) [ 1 ]
2005-08-28 16:40:06 +02:00
close_button = hb . get_children ( ) [ 2 ]
2005-09-05 01:30:40 +02:00
2005-09-14 02:51:26 +02:00
num_unread = self . nb_unread [ jid ]
if num_unread == 1 and not gajim . config . get ( ' show_unread_tab_icon ' ) :
2005-11-29 05:01:00 +01:00
unread = ' * '
2005-09-14 02:51:26 +02:00
elif num_unread > 1 :
2005-11-29 05:01:00 +01:00
unread = ' [ ' + unicode ( num_unread ) + ' ] '
2005-09-14 02:51:26 +02:00
2005-09-05 01:30:40 +02:00
# Draw tab label using chatstate
theme = gajim . config . get ( ' roster_theme ' )
color = None
2005-11-29 05:01:00 +01:00
if chatstate is not None :
2005-09-05 01:57:47 +02:00
if chatstate == ' composing ' :
2005-09-05 01:30:40 +02:00
color = gajim . config . get_per ( ' themes ' , theme ,
2005-10-28 23:46:55 +02:00
' state_composing_color ' )
2005-09-05 01:57:47 +02:00
elif chatstate == ' inactive ' :
2005-09-05 01:30:40 +02:00
color = gajim . config . get_per ( ' themes ' , theme ,
2005-10-28 23:46:55 +02:00
' state_inactive_color ' )
2005-09-05 01:57:47 +02:00
elif chatstate == ' gone ' :
2005-10-28 23:46:55 +02:00
color = gajim . config . get_per ( ' themes ' , theme , ' state_gone_color ' )
2005-09-05 01:57:47 +02:00
elif chatstate == ' paused ' :
2005-10-28 23:46:55 +02:00
color = gajim . config . get_per ( ' themes ' , theme , ' state_paused_color ' )
2005-09-05 01:30:40 +02:00
else :
2005-10-28 23:46:55 +02:00
color = gajim . config . get_per ( ' themes ' , theme , ' state_active_color ' )
2005-09-05 01:30:40 +02:00
if color :
2005-09-10 21:23:57 +02:00
color = gtk . gdk . colormap_get_system ( ) . alloc_color ( color )
2005-10-20 11:49:28 +02:00
# We set the color for when it's the current tab or not
nickname . modify_fg ( gtk . STATE_NORMAL , color )
2005-10-27 15:15:03 +02:00
if chatstate in ( ' inactive ' , ' gone ' ) :
2005-10-20 11:49:28 +02:00
# Adjust color to be lighter against the darker inactive
# background
p = 0.4
mask = 0
color . red = int ( ( color . red * p ) + ( mask * ( 1 - p ) ) )
color . green = int ( ( color . green * p ) + ( mask * ( 1 - p ) ) )
color . blue = int ( ( color . blue * p ) + ( mask * ( 1 - p ) ) )
nickname . modify_fg ( gtk . STATE_ACTIVE , color )
2005-05-04 18:22:07 +02:00
elif self . widget_name == ' groupchat_window ' :
2005-08-04 11:42:34 +02:00
nickname = hb . get_children ( ) [ 0 ]
2005-08-28 16:40:06 +02:00
close_button = hb . get_children ( ) [ 1 ]
2005-09-14 02:51:26 +02:00
has_focus = self . window . get_property ( ' has-toplevel-focus ' )
current_tab = ( self . notebook . page_num ( child ) == self . notebook . get_current_page ( ) )
color = None
theme = gajim . config . get ( ' roster_theme ' )
if chatstate == ' attention ' and ( not has_focus or not current_tab ) :
if jid not in self . muc_attentions :
self . muc_attentions . append ( jid )
color = gajim . config . get_per ( ' themes ' , theme , ' state_muc_directed_msg ' )
elif chatstate :
if chatstate == ' active ' or ( current_tab and has_focus ) :
if jid in self . muc_attentions :
self . muc_attentions . remove ( jid )
color = gajim . config . get_per ( ' themes ' , theme , ' state_active_color ' )
elif chatstate == ' newmsg ' and ( not has_focus or not current_tab ) and \
jid not in self . muc_attentions :
color = gajim . config . get_per ( ' themes ' , theme , ' state_muc_msg ' )
if color :
color = gtk . gdk . colormap_get_system ( ) . alloc_color ( color )
# The widget state depend on whether this tab is the "current" tab
if current_tab :
nickname . modify_fg ( gtk . STATE_NORMAL , color )
else :
nickname . modify_fg ( gtk . STATE_ACTIVE , color )
2005-08-28 17:56:08 +02:00
if gajim . config . get ( ' tabs_close_button ' ) :
close_button . show ( )
else :
2005-08-28 16:40:06 +02:00
close_button . hide ( )
2005-05-04 18:22:07 +02:00
2005-09-03 14:43:12 +02:00
nickname . set_max_width_chars ( 10 )
2005-11-29 05:01:00 +01:00
lbl = self . names [ jid ]
2005-11-29 11:20:39 +01:00
if num_unread : # if unread, text in the label becomes bold
lbl = ' <b> ' + unread + lbl + ' </b> '
2005-11-29 05:01:00 +01:00
nickname . set_markup ( lbl )
2005-03-12 19:12:15 +01:00
2005-09-24 13:35:56 +02:00
def get_message_type ( self , jid ) :
2005-09-24 11:42:10 +02:00
if self . widget_name == ' groupchat_window ' :
return ' gc '
if gajim . contacts [ self . account ] . has_key ( jid ) :
return ' chat '
return ' pm '
2005-07-22 22:06:16 +02:00
2005-03-12 19:12:15 +01:00
def on_window_destroy ( self , widget , kind ) : #kind is 'chats' or 'gc'
2005-11-13 16:08:47 +01:00
''' clean gajim.interface.instances[self.account][kind] '''
2005-03-12 19:12:15 +01:00
for jid in self . xmls :
2005-11-13 16:08:47 +01:00
windows = gajim . interface . instances [ self . account ] [ kind ]
2005-07-19 19:08:01 +02:00
if kind == ' chats ' :
# send 'gone' chatstate to every tabbed chat tab
2005-08-06 22:17:45 +02:00
windows [ jid ] . send_chatstate ( ' gone ' , jid )
2005-07-19 23:40:08 +02:00
gobject . source_remove ( self . possible_paused_timeout_id [ jid ] )
gobject . source_remove ( self . possible_inactive_timeout_id [ jid ] )
2005-10-20 13:17:17 +02:00
if gajim . interface . systray_enabled and self . nb_unread [ jid ] > 0 :
gajim . interface . systray . remove_jid ( jid , self . account ,
2005-09-24 13:35:56 +02:00
self . get_message_type ( jid ) )
2005-07-19 19:08:01 +02:00
del windows [ jid ]
2005-03-12 19:12:15 +01:00
if self . print_time_timeout_id . has_key ( jid ) :
gobject . source_remove ( self . print_time_timeout_id [ jid ] )
2005-07-19 19:08:01 +02:00
if windows . has_key ( ' tabbed ' ) :
del windows [ ' tabbed ' ]
2005-03-12 19:12:15 +01:00
def get_active_jid ( self ) :
2005-04-22 02:02:42 +02:00
notebook = self . notebook
active_child = notebook . get_nth_page ( notebook . get_current_page ( ) )
2005-03-12 19:12:15 +01:00
active_jid = ' '
for jid in self . xmls :
2005-03-12 22:30:50 +01:00
if self . childs [ jid ] == active_child :
2005-03-12 19:12:15 +01:00
active_jid = jid
break
return active_jid
def on_close_button_clicked ( self , button , jid ) :
2005-10-06 17:20:53 +02:00
''' When close button is pressed: close a tab '''
2005-03-12 19:12:15 +01:00
self . remove_tab ( jid )
2005-08-04 16:30:41 +02:00
def on_history_menuitem_clicked ( self , widget = None , jid = None ) :
2005-10-06 17:20:53 +02:00
''' When history menuitem is pressed: call history window '''
2005-12-02 13:40:55 +01:00
if jid is None : # None when viewing room and tc history
2005-08-04 16:30:41 +02:00
jid = self . get_active_jid ( )
2005-11-13 16:08:47 +01:00
if gajim . interface . instances [ ' logs ' ] . has_key ( jid ) :
gajim . interface . instances [ ' logs ' ] [ jid ] . window . present ( )
2005-06-13 16:46:08 +02:00
else :
2005-12-02 13:40:55 +01:00
gajim . interface . instances [ ' logs ' ] [ jid ] = history_window . HistoryWindow (
jid , self . account )
2005-06-13 16:46:08 +02:00
2005-03-12 19:12:15 +01:00
def on_chat_window_focus_in_event ( self , widget , event ) :
2005-10-06 17:20:53 +02:00
''' When window gets focus '''
2005-03-12 19:12:15 +01:00
jid = self . get_active_jid ( )
2005-09-05 01:30:40 +02:00
2005-10-28 23:46:55 +02:00
textview = self . conversation_textviews [ jid ]
if textview . at_the_end ( ) :
2005-03-12 19:12:15 +01:00
#we are at the end
if self . nb_unread [ jid ] > 0 :
2005-09-23 23:01:42 +02:00
self . nb_unread [ jid ] = 0 + self . get_specific_unread ( jid )
2005-03-12 19:12:15 +01:00
self . show_title ( )
2005-10-20 13:17:17 +02:00
if gajim . interface . systray_enabled :
gajim . interface . systray . remove_jid ( jid , self . account ,
2005-09-24 13:35:56 +02:00
self . get_message_type ( jid ) )
2005-09-04 18:57:09 +02:00
''' TC/GC window received focus, so if we had urgency REMOVE IT
NOTE : we do not have to read the message ( it maybe in a bg tab )
to remove urgency hint so this functions does that '''
if gtk . gtk_version > = ( 2 , 8 , 0 ) and gtk . pygtk_version > = ( 2 , 8 , 0 ) :
if widget . props . urgency_hint :
widget . props . urgency_hint = False
2005-09-05 02:29:20 +02:00
# Undo "unread" state display, etc.
2005-09-14 02:51:26 +02:00
if self . widget_name == ' groupchat_window ' :
self . redraw_tab ( jid , ' active ' )
else :
# NOTE: we do not send any chatstate to preserve inactive, gone, etc.
self . redraw_tab ( jid )
2005-08-03 17:42:44 +02:00
2005-06-30 15:31:31 +02:00
def on_compact_view_menuitem_activate ( self , widget ) :
isactive = widget . get_active ( )
self . set_compact_view ( isactive )
2005-08-04 16:57:36 +02:00
def on_actions_button_clicked ( self , widget ) :
''' popup action menu '''
2005-09-20 20:05:57 +02:00
#FIXME: BUG http://bugs.gnome.org/show_bug.cgi?id=316786
2005-11-15 13:21:30 +01:00
self . button_clicked = widget
2005-09-20 20:05:57 +02:00
2005-08-04 16:57:36 +02:00
menu = self . prepare_context_menu ( )
menu . show_all ( )
2005-11-16 11:06:31 +01:00
menu . popup ( None , None , self . position_menu_under_button , 1 , 0 )
2005-08-04 16:57:36 +02:00
2005-11-15 12:52:40 +01:00
def on_emoticons_button_clicked ( self , widget ) :
''' popup emoticons menu '''
2005-11-15 13:21:30 +01:00
#FIXME: BUG http://bugs.gnome.org/show_bug.cgi?id=316786
self . button_clicked = widget
self . emoticons_menu . popup ( None , None , self . position_menu_under_button , 1 , 0 )
2005-11-15 12:52:40 +01:00
2005-11-15 13:21:30 +01:00
def position_menu_under_button ( self , menu ) :
#FIXME: BUG http://bugs.gnome.org/show_bug.cgi?id=316786
# pass btn instance when this bug is over
button = self . button_clicked
2005-09-20 20:30:21 +02:00
# here I get the coordinates of the button relative to
# window (self.window)
2005-11-15 13:21:30 +01:00
button_x , button_y = button . allocation . x , button . allocation . y
2005-09-20 20:05:57 +02:00
# now convert them to X11-relative
window_x , window_y = self . window . window . get_origin ( )
x = window_x + button_x
y = window_y + button_y
2005-11-16 10:57:28 +01:00
menu_width , menu_height = menu . size_request ( )
## should we pop down or up?
if ( y + button . allocation . height + menu_height
< gtk . gdk . screen_height ( ) ) :
# now move the menu below the button
y + = button . allocation . height
else :
# now move the menu above the button
y - = menu_height
2005-09-20 20:05:57 +02:00
2005-11-20 17:17:23 +01:00
2005-11-16 11:06:31 +01:00
# push_in is True so all the menuitems are always inside screen
2005-09-20 20:05:57 +02:00
push_in = True
return ( x , y , push_in )
2005-06-30 15:31:31 +02:00
def remove_possible_switch_to_menuitems ( self , menu ) :
''' remove duplicate ' Switch to ' if they exist and return clean menu '''
childs = menu . get_children ( )
2005-08-04 14:46:31 +02:00
if self . widget_name == ' tabbed_chat_window ' :
jid = self . get_active_jid ( )
c = gajim . get_first_contact_instance_from_jid ( self . account , jid )
if _ ( ' not in the roster ' ) in c . groups : # for add_to_roster_menuitem
childs [ 5 ] . show ( )
childs [ 5 ] . set_no_show_all ( False )
else :
childs [ 5 ] . hide ( )
childs [ 5 ] . set_no_show_all ( True )
2005-08-08 17:47:10 +02:00
start_removing_from = 6 # this is from the seperator and after
else :
start_removing_from = 7 # # this is from the seperator and after
2005-08-04 14:46:31 +02:00
2005-08-08 17:47:10 +02:00
for child in childs [ start_removing_from : ] :
2005-08-08 17:38:07 +02:00
menu . remove ( child )
2005-08-04 14:46:31 +02:00
2005-06-30 15:31:31 +02:00
return menu
2005-08-04 16:57:36 +02:00
def prepare_context_menu ( self ) :
''' sets compact view menuitem active state
sets active and sensitivity state for toggle_gpg_menuitem
and remove possible ' Switch to ' menuitems '''
if self . widget_name == ' groupchat_window ' :
menu = self . gc_popup_menu
childs = menu . get_children ( )
# compact_view_menuitem
childs [ 5 ] . set_active ( self . compact_view_current_state )
elif self . widget_name == ' tabbed_chat_window ' :
menu = self . tabbed_chat_popup_menu
childs = menu . get_children ( )
# check if gpg capabitlies or else make gpg toggle insensitive
jid = self . get_active_jid ( )
gpg_btn = self . xmls [ jid ] . get_widget ( ' gpg_togglebutton ' )
isactive = gpg_btn . get_active ( )
issensitive = gpg_btn . get_property ( ' sensitive ' )
childs [ 3 ] . set_active ( isactive )
childs [ 3 ] . set_property ( ' sensitive ' , issensitive )
2005-10-12 21:28:31 +02:00
# If we don't have resource, we can't do file transfert
c = gajim . get_first_contact_instance_from_jid ( self . account , jid )
if not c . resource :
childs [ 2 ] . set_sensitive ( False )
else :
childs [ 2 ] . set_sensitive ( True )
2005-08-04 16:57:36 +02:00
# compact_view_menuitem
childs [ 4 ] . set_active ( self . compact_view_current_state )
menu = self . remove_possible_switch_to_menuitems ( menu )
return menu
2005-11-17 18:08:56 +01:00
def prepare_emoticons_menu ( self ) :
2005-11-15 12:52:40 +01:00
menu = gtk . Menu ( )
def append_emoticon ( w , d ) :
jid = self . get_active_jid ( )
message_textview = self . message_textviews [ jid ]
2005-11-20 14:53:47 +01:00
buffer = message_textview . get_buffer ( )
if buffer . get_char_count ( ) :
buffer . insert_at_cursor ( ' %s ' % d )
2005-11-20 15:11:50 +01:00
else : # we are the beginning of buffer
2005-11-20 14:53:47 +01:00
buffer . insert_at_cursor ( ' %s ' % d )
2005-11-15 12:52:40 +01:00
message_textview . grab_focus ( )
counter = 0
# Calculate the side lenght of the popup to make it a square
size = int ( round ( math . sqrt ( len ( gajim . interface . emoticons_images ) ) ) )
for image in gajim . interface . emoticons_images :
item = gtk . MenuItem ( )
img = gtk . Image ( )
if type ( image [ 1 ] ) == gtk . gdk . PixbufAnimation :
img . set_from_animation ( image [ 1 ] )
else :
img . set_from_pixbuf ( image [ 1 ] )
item . add ( img )
item . connect ( ' activate ' , append_emoticon , image [ 0 ] )
#FIXME: add tooltip with ascii
menu . attach ( item ,
counter % size , counter % size + 1 ,
counter / size , counter / size + 1 )
counter + = 1
menu . show_all ( )
return menu
2005-08-08 14:21:47 +02:00
def popup_menu ( self , event ) :
menu = self . prepare_context_menu ( )
# common menuitems (tab switches)
if len ( self . xmls ) > 1 : # if there is more than one tab
menu . append ( gtk . SeparatorMenuItem ( ) ) # seperator
for jid in self . xmls :
if jid != self . get_active_jid ( ) :
item = gtk . ImageMenuItem ( _ ( ' Switch to %s ' ) % self . names [ jid ] )
img = gtk . image_new_from_stock ( gtk . STOCK_JUMP_TO ,
gtk . ICON_SIZE_MENU )
item . set_image ( img )
item . connect ( ' activate ' , lambda obj , jid : self . set_active_tab (
jid ) , jid )
menu . append ( item )
# show the menu
menu . popup ( None , None , None , event . button , event . time )
menu . show_all ( )
2005-08-08 12:52:27 +02:00
def on_banner_eventbox_button_press_event ( self , widget , event ) :
2005-06-22 21:39:19 +02:00
''' If right-clicked, show popup '''
if event . button == 3 : # right click
2005-08-08 14:21:47 +02:00
self . popup_menu ( event )
2005-03-12 19:12:15 +01:00
def on_chat_notebook_switch_page ( self , notebook , page , page_num ) :
2005-07-22 20:10:28 +02:00
# get the index of the page and then the page that we're leaving
old_no = notebook . get_current_page ( )
old_child = notebook . get_nth_page ( old_no )
2005-03-12 19:12:15 +01:00
new_child = notebook . get_nth_page ( page_num )
2005-07-22 20:10:28 +02:00
old_jid = ' '
2005-03-12 19:12:15 +01:00
new_jid = ' '
for jid in self . xmls :
2005-03-12 22:30:50 +01:00
if self . childs [ jid ] == new_child :
2005-03-12 19:12:15 +01:00
new_jid = jid
2005-07-22 20:10:28 +02:00
elif self . childs [ jid ] == old_child :
old_jid = jid
if old_jid != ' ' and new_jid != ' ' : # we found both jids
break # so stop looping
if self . widget_name == ' tabbed_chat_window ' :
# send chatstate inactive to the one we're leaving
# and active to the one we visit
2005-07-22 22:06:16 +02:00
if old_jid != ' ' :
self . send_chatstate ( ' inactive ' , old_jid )
2005-07-22 20:10:28 +02:00
self . send_chatstate ( ' active ' , new_jid )
2005-04-22 02:02:42 +02:00
2005-10-28 23:46:55 +02:00
conv_textview = self . conversation_textviews [ new_jid ]
if conv_textview . at_the_end ( ) :
2005-03-12 19:12:15 +01:00
#we are at the end
if self . nb_unread [ new_jid ] > 0 :
2005-09-23 23:25:20 +02:00
self . nb_unread [ new_jid ] = 0 + self . get_specific_unread ( new_jid )
2005-03-12 19:12:15 +01:00
self . redraw_tab ( new_jid )
self . show_title ( )
2005-10-20 13:17:17 +02:00
if gajim . interface . systray_enabled :
gajim . interface . systray . remove_jid ( new_jid , self . account ,
2005-09-24 13:35:56 +02:00
self . get_message_type ( new_jid ) )
2005-09-23 23:25:20 +02:00
2005-10-28 23:46:55 +02:00
conv_textview . grab_focus ( )
2005-03-12 19:12:15 +01:00
2005-05-03 18:37:59 +02:00
def set_active_tab ( self , jid ) :
2005-05-04 18:40:41 +02:00
self . notebook . set_current_page ( self . notebook . page_num ( self . childs [ jid ] ) )
2005-03-12 19:12:15 +01:00
def remove_tab ( self , jid , kind ) : #kind is 'chats' or 'gc'
2005-08-08 18:42:30 +02:00
if len ( self . xmls ) == 1 : # only one tab when we asked to remove
# so destroy window
2005-09-23 23:25:20 +02:00
2005-07-22 01:41:13 +02:00
# we check and possibly save positions here, because Ctrl+W, Escape
# etc.. call remove_tab so similar code in delete_event callbacks
# is not enough
if gajim . config . get ( ' saveposition ' ) :
if kind == ' chats ' :
x , y = self . window . get_position ( )
gajim . config . set ( ' chat-x-position ' , x )
gajim . config . set ( ' chat-y-position ' , y )
width , height = self . window . get_size ( )
gajim . config . set ( ' chat-width ' , width )
gajim . config . set ( ' chat-height ' , height )
elif kind == ' gc ' :
gajim . config . set ( ' gc-hpaned-position ' , self . hpaned_position )
x , y = self . window . get_position ( )
gajim . config . set ( ' gc-x-position ' , x )
gajim . config . set ( ' gc-y-position ' , y )
width , height = self . window . get_size ( )
gajim . config . set ( ' gc-width ' , width )
gajim . config . set ( ' gc-height ' , height )
2005-03-12 19:12:15 +01:00
self . window . destroy ( )
2005-08-03 13:36:00 +02:00
else :
if self . nb_unread [ jid ] > 0 :
self . nb_unread [ jid ] = 0
2005-10-20 13:17:17 +02:00
if gajim . interface . systray_enabled :
gajim . interface . systray . remove_jid ( jid , self . account ,
2005-09-24 13:35:56 +02:00
self . get_message_type ( jid ) )
2005-08-03 13:36:00 +02:00
if self . print_time_timeout_id . has_key ( jid ) :
gobject . source_remove ( self . print_time_timeout_id [ jid ] )
del self . print_time_timeout_id [ jid ]
self . notebook . remove_page ( self . notebook . page_num ( self . childs [ jid ] ) )
2005-09-23 23:25:20 +02:00
2005-11-13 16:08:47 +01:00
if gajim . interface . instances [ self . account ] [ kind ] . has_key ( jid ) :
del gajim . interface . instances [ self . account ] [ kind ] [ jid ]
2005-04-22 02:02:42 +02:00
del self . nb_unread [ jid ]
2005-07-03 17:27:41 +02:00
del gajim . last_message_time [ self . account ] [ jid ]
2005-04-22 02:02:42 +02:00
del self . xmls [ jid ]
2005-08-03 13:36:00 +02:00
del self . childs [ jid ]
2005-09-06 19:33:01 +02:00
del self . sent_history [ jid ]
del self . sent_history_pos [ jid ]
del self . typing_new [ jid ]
2005-09-07 03:35:50 +02:00
del self . orig_msg [ jid ]
2005-09-23 23:25:20 +02:00
2005-08-08 18:42:30 +02:00
if len ( self . xmls ) == 1 : # we now have only one tab
2005-08-29 12:41:57 +02:00
show_tabs_if_one_tab = gajim . config . get ( ' tabs_always_visible ' )
self . notebook . set_show_tabs ( show_tabs_if_one_tab )
2005-11-24 19:12:51 +01:00
if not show_tabs_if_one_tab :
self . alignment . set_property ( ' top-padding ' , 0 )
2005-08-08 18:42:30 +02:00
self . show_title ( )
2005-09-23 23:25:20 +02:00
2005-07-25 22:58:19 +02:00
def bring_scroll_to_end ( self , textview , diff_y = 0 ) :
''' scrolls to the end of textview if end is not visible '''
buffer = textview . get_buffer ( )
end_iter = buffer . get_end_iter ( )
end_rect = textview . get_iter_location ( end_iter )
visible_rect = textview . get_visible_rect ( )
# scroll only if expected end is not visible
if end_rect . y > = ( visible_rect . y + visible_rect . height + diff_y ) :
gobject . idle_add ( self . scroll_to_end_iter , textview )
2005-09-23 23:25:20 +02:00
2005-07-25 22:58:19 +02:00
def scroll_to_end_iter ( self , textview ) :
buffer = textview . get_buffer ( )
end_iter = buffer . get_end_iter ( )
textview . scroll_to_iter ( end_iter , 0 , False , 1 , 1 )
return False
2005-09-23 23:25:20 +02:00
2005-11-03 16:10:00 +01:00
def size_request ( self , msg_textview , requisition , xml_top ) :
2005-07-25 16:27:48 +02:00
''' When message_textview changes its size. If the new height
2005-12-14 22:08:58 +01:00
will enlarge the window , enable the scrollbar automatic policy
Also enable scrollbar automatic policy for horizontal scrollbar
if message we have in message_textview is too big '''
2005-11-03 16:10:00 +01:00
if msg_textview . window is None :
2005-07-26 01:52:22 +02:00
return
2005-07-26 16:58:42 +02:00
message_scrolledwindow = xml_top . get_widget ( ' message_scrolledwindow ' )
2005-10-29 16:28:46 +02:00
conversation_scrolledwindow = xml_top . get_widget (
' conversation_scrolledwindow ' )
2005-10-28 23:46:55 +02:00
conv_textview = conversation_scrolledwindow . get_children ( ) [ 0 ]
2005-07-26 01:52:22 +02:00
min_height = conversation_scrolledwindow . get_property ( ' height-request ' )
2005-10-28 23:46:55 +02:00
conversation_height = conv_textview . window . get_size ( ) [ 1 ]
2005-11-03 16:10:00 +01:00
message_height = msg_textview . window . get_size ( ) [ 1 ]
2005-12-14 21:56:31 +01:00
message_width = msg_textview . window . get_size ( ) [ 0 ]
2005-07-26 16:58:42 +02:00
# new tab is not exposed yet
if conversation_height < 2 :
return
2005-09-23 23:25:20 +02:00
2005-07-26 16:58:42 +02:00
if conversation_height < min_height :
min_height = conversation_height
2005-09-23 23:25:20 +02:00
2005-12-14 22:08:58 +01:00
# we don't want to always resize in height the message_textview
# so we have minimum on conversation_textview's scrolled window
# but we also want to avoid window resizing so if we reach that
# minimum for conversation_textview and maximum for message_textview
# we set to automatic the scrollbar policy
2005-07-26 01:52:22 +02:00
diff_y = message_height - requisition . height
2005-12-14 22:08:58 +01:00
if diff_y != 0 :
if conversation_height + diff_y < min_height :
2005-08-07 21:35:12 +02:00
if message_height + conversation_height - min_height > min_height :
message_scrolledwindow . set_property ( ' vscrollbar-policy ' ,
gtk . POLICY_AUTOMATIC )
message_scrolledwindow . set_property ( ' height-request ' ,
message_height + conversation_height - min_height )
2005-11-03 16:10:00 +01:00
self . bring_scroll_to_end ( msg_textview )
2005-07-25 22:58:19 +02:00
else :
2005-07-26 16:58:42 +02:00
message_scrolledwindow . set_property ( ' vscrollbar-policy ' ,
gtk . POLICY_NEVER )
2005-07-25 22:58:19 +02:00
message_scrolledwindow . set_property ( ' height-request ' , - 1 )
2005-12-14 22:08:58 +01:00
conv_textview . bring_scroll_to_end ( diff_y - 18 )
# enable scrollbar automatic policy for horizontal scrollbar
# if message we have in message_textview is too big
2005-12-14 21:56:31 +01:00
if requisition . width > message_width :
message_scrolledwindow . set_property ( ' hscrollbar-policy ' ,
gtk . POLICY_AUTOMATIC )
2005-12-14 22:21:01 +01:00
else :
message_scrolledwindow . set_property ( ' hscrollbar-policy ' ,
gtk . POLICY_NEVER )
2005-12-14 22:08:58 +01:00
2005-07-25 16:27:48 +02:00
return True
2005-08-04 11:42:34 +02:00
def on_tab_eventbox_button_press_event ( self , widget , event , child ) :
if event . button == 3 :
n = self . notebook . page_num ( child )
self . notebook . set_current_page ( n )
2005-08-08 14:21:47 +02:00
self . popup_menu ( event )
2005-08-04 11:42:34 +02:00
2005-03-12 19:12:15 +01:00
def new_tab ( self , jid ) :
2005-07-01 19:55:41 +02:00
#FIXME: text formating buttons will be hidden in 0.8 release
2005-10-27 15:15:03 +02:00
for w in ( ' bold_togglebutton ' , ' italic_togglebutton ' ,
' underline_togglebutton ' ) :
2005-07-01 19:55:41 +02:00
self . xmls [ jid ] . get_widget ( w ) . set_no_show_all ( True )
2005-11-03 16:10:00 +01:00
# add ConversationTextView to UI and connect signals
2005-10-28 23:46:55 +02:00
conv_textview = self . conversation_textviews [ jid ] = \
conversation_textview . ConversationTextview ( self . account )
conv_textview . show_all ( )
conversation_scrolledwindow = self . xmls [ jid ] . get_widget (
' conversation_scrolledwindow ' )
conversation_scrolledwindow . add ( conv_textview )
conv_textview . connect ( ' key_press_event ' , self . on_conversation_textview_key_press_event )
2005-11-03 16:10:00 +01:00
# add MessageTextView to UI and connect signals
message_scrolledwindow = self . xmls [ jid ] . get_widget (
' message_scrolledwindow ' )
msg_textview = self . message_textviews [ jid ] = \
message_textview . MessageTextView ( )
msg_textview . connect ( ' mykeypress ' ,
self . on_message_textview_mykeypress_event )
message_scrolledwindow . add ( msg_textview )
msg_textview . connect ( ' key_press_event ' ,
self . on_message_textview_key_press_event )
2005-06-30 15:31:31 +02:00
self . set_compact_view ( self . always_compact_view )
2005-03-12 19:12:15 +01:00
self . nb_unread [ jid ] = 0
2005-07-03 17:27:41 +02:00
gajim . last_message_time [ self . account ] [ jid ] = 0
2005-08-07 20:58:36 +02:00
font = pango . FontDescription ( gajim . config . get ( ' conversation_font ' ) )
2005-03-12 19:12:15 +01:00
2005-11-30 23:22:22 +01:00
if gajim . config . get ( ' use_speller ' ) and HAS_GTK_SPELL :
2005-05-30 23:00:04 +02:00
try :
2005-11-03 16:10:00 +01:00
gtkspell . Spell ( msg_textview )
2005-05-30 23:00:04 +02:00
except gobject . GError , msg :
2005-08-17 22:07:59 +02:00
#FIXME: add a ui for this use spell.set_language()
2005-08-26 02:52:44 +02:00
dialogs . ErrorDialog ( unicode ( msg ) , _ ( ' If that is not your language for which you want to highlight misspelled words, then please set your $LANG as appropriate. Eg. for French do export LANG=fr_FR or export LANG=fr_FR.UTF-8 in ~/.bash_profile or to make it global in /etc/profile. \n \n Highlighting misspelled words feature will not be used ' ) ) . get_response ( )
2005-05-30 23:00:04 +02:00
gajim . config . set ( ' use_speller ' , False )
2005-05-26 01:58:27 +02:00
2005-11-17 19:29:31 +01:00
emoticons_button = self . xmls [ jid ] . get_widget ( ' emoticons_button ' )
# set image no matter if user wants at this time emoticons or not
# (so toggle works ok)
img = self . xmls [ jid ] . get_widget ( ' emoticons_button_image ' )
img . set_from_file ( os . path . join ( gajim . DATA_DIR , ' emoticons ' , ' smile.png ' ) )
2005-11-15 12:52:40 +01:00
if gajim . config . get ( ' useemoticons ' ) :
2005-11-17 19:29:31 +01:00
emoticons_button . show ( )
emoticons_button . set_no_show_all ( False )
2005-11-15 12:52:40 +01:00
else :
2005-11-17 19:29:31 +01:00
emoticons_button . hide ( )
emoticons_button . set_no_show_all ( True )
2005-11-15 12:52:40 +01:00
2005-10-28 23:46:55 +02:00
conv_textview . modify_font ( font )
conv_buffer = conv_textview . get_buffer ( )
end_iter = conv_buffer . get_end_iter ( )
2005-03-12 19:12:15 +01:00
self . xmls [ jid ] . signal_autoconnect ( self )
2005-05-03 18:37:59 +02:00
conversation_scrolledwindow . get_vadjustment ( ) . connect ( ' value-changed ' ,
2005-03-12 19:12:15 +01:00
self . on_conversation_vadjustment_value_changed )
2005-05-04 18:22:07 +02:00
2005-03-12 19:12:15 +01:00
if len ( self . xmls ) > 1 :
self . notebook . set_show_tabs ( True )
2005-11-25 15:14:01 +01:00
self . alignment . set_property ( ' top-padding ' , 2 )
2005-03-12 19:12:15 +01:00
2005-05-04 18:22:07 +02:00
if self . widget_name == ' tabbed_chat_window ' :
2005-08-04 11:42:34 +02:00
xm = gtk . glade . XML ( GTKGUI_GLADE , ' chats_eventbox ' , APP )
tab_hbox = xm . get_widget ( ' chats_eventbox ' )
2005-05-04 18:22:07 +02:00
elif self . widget_name == ' groupchat_window ' :
2005-08-04 11:42:34 +02:00
xm = gtk . glade . XML ( GTKGUI_GLADE , ' gc_eventbox ' , APP )
tab_hbox = xm . get_widget ( ' gc_eventbox ' )
child = self . childs [ jid ]
2005-06-23 17:23:24 +02:00
xm . signal_connect ( ' on_close_button_clicked ' ,
self . on_close_button_clicked , jid )
2005-08-04 11:42:34 +02:00
xm . signal_connect ( ' on_tab_eventbox_button_press_event ' ,
self . on_tab_eventbox_button_press_event , child )
2005-06-03 17:37:17 +02:00
2005-06-23 23:16:10 +02:00
self . notebook . append_page ( child , tab_hbox )
2005-10-29 16:28:46 +02:00
2005-11-03 16:10:00 +01:00
msg_textview . modify_font ( font )
2005-11-30 23:22:22 +01:00
msg_textview . connect ( ' size-request ' , self . size_request , self . xmls [ jid ] )
2005-10-28 23:46:55 +02:00
# init new sent history for this conversation
2005-06-07 18:25:55 +02:00
self . sent_history [ jid ] = [ ]
self . sent_history_pos [ jid ] = 0
self . typing_new [ jid ] = True
self . orig_msg [ jid ] = ' '
2005-03-12 19:12:15 +01:00
self . show_title ( )
2005-11-03 16:10:00 +01:00
def on_message_textview_key_press_event ( self , widget , event ) :
jid = self . get_active_jid ( )
conv_textview = self . conversation_textviews [ jid ]
if self . widget_name == ' groupchat_window ' :
if event . keyval not in ( gtk . keysyms . ISO_Left_Tab , gtk . keysyms . Tab ) :
room_jid = self . get_active_jid ( )
self . last_key_tabs [ room_jid ] = False
if event . keyval == gtk . keysyms . Page_Down : # PAGE DOWN
if event . state & gtk . gdk . CONTROL_MASK : # CTRL + PAGE DOWN
self . notebook . emit ( ' key_press_event ' , event )
elif event . state & gtk . gdk . SHIFT_MASK : # SHIFT + PAGE DOWN
conv_textview . emit ( ' key_press_event ' , event )
elif event . keyval == gtk . keysyms . Page_Up : # PAGE UP
if event . state & gtk . gdk . CONTROL_MASK : # CTRL + PAGE UP
self . notebook . emit ( ' key_press_event ' , event )
elif event . state & gtk . gdk . SHIFT_MASK : # SHIFT + PAGE UP
conv_textview . emit ( ' key_press_event ' , event )
2005-03-31 17:03:07 +02:00
def on_conversation_textview_key_press_event ( self , widget , event ) :
2005-10-06 17:20:53 +02:00
''' Do not block these events and send them to the notebook '''
2005-05-15 22:58:04 +02:00
if event . state & gtk . gdk . CONTROL_MASK :
2005-04-12 17:30:09 +02:00
if event . keyval == gtk . keysyms . Tab : # CTRL + TAB
2005-03-31 17:03:07 +02:00
self . notebook . emit ( ' key_press_event ' , event )
2005-05-15 22:58:04 +02:00
elif event . keyval == gtk . keysyms . ISO_Left_Tab : # CTRL + SHIFT + TAB
self . notebook . emit ( ' key_press_event ' , event )
2005-04-12 17:30:09 +02:00
elif event . keyval == gtk . keysyms . Page_Down : # CTRL + PAGE DOWN
self . notebook . emit ( ' key_press_event ' , event )
elif event . keyval == gtk . keysyms . Page_Up : # CTRL + PAGE UP
self . notebook . emit ( ' key_press_event ' , event )
2005-06-11 19:55:31 +02:00
elif event . keyval == gtk . keysyms . l or \
2005-06-30 15:31:31 +02:00
event . keyval == gtk . keysyms . L : # CTRL + L
2005-08-24 21:16:44 +02:00
jid = self . get_active_jid ( )
2005-10-28 23:46:55 +02:00
conv_textview = self . conversation_textviews [ jid ]
conv_textview . get_buffer ( ) . set_text ( ' ' )
2005-04-21 00:56:33 +02:00
elif event . keyval == gtk . keysyms . v : # CTRL + V
2005-04-21 18:41:22 +02:00
jid = self . get_active_jid ( )
2005-11-03 18:23:36 +01:00
msg_textview = self . message_textviews [ jid ]
2005-11-03 16:10:00 +01:00
if not msg_textview . is_focus ( ) :
msg_textview . grab_focus ( )
msg_textview . emit ( ' key_press_event ' , event )
2005-10-28 23:46:55 +02:00
2005-03-12 22:30:50 +01:00
def on_chat_notebook_key_press_event ( self , widget , event ) :
2005-08-07 17:19:21 +02:00
st = ' 1234567890 ' # alt+1 means the first tab (tab 0)
2005-03-12 19:12:15 +01:00
jid = self . get_active_jid ( )
2005-04-21 18:41:22 +02:00
if event . keyval == gtk . keysyms . Escape : # ESCAPE
if self . widget_name == ' tabbed_chat_window ' :
2005-04-21 00:56:33 +02:00
self . remove_tab ( jid )
2005-04-12 17:30:09 +02:00
elif event . keyval == gtk . keysyms . F4 and \
2005-05-30 23:00:04 +02:00
( event . state & gtk . gdk . CONTROL_MASK ) : # CTRL + F4
2005-04-12 17:30:09 +02:00
self . remove_tab ( jid )
2005-07-18 17:35:15 +02:00
elif event . keyval == gtk . keysyms . w and \
( event . state & gtk . gdk . CONTROL_MASK ) : # CTRL + W
self . remove_tab ( jid )
2005-04-22 02:02:42 +02:00
elif event . string and event . string in st and \
2005-05-30 23:00:04 +02:00
( event . state & gtk . gdk . MOD1_MASK ) : # alt + 1,2,3..
2005-03-12 19:12:15 +01:00
self . notebook . set_current_page ( st . index ( event . string ) )
2005-06-22 23:58:45 +02:00
elif event . keyval == gtk . keysyms . c and \
2005-06-30 15:31:31 +02:00
( event . state & gtk . gdk . MOD1_MASK ) : # alt + C toggles compact view
self . set_compact_view ( not self . compact_view_current_state )
2005-11-15 12:52:40 +01:00
elif event . keyval == gtk . keysyms . e and \
( event . state & gtk . gdk . MOD1_MASK ) : # alt + E opens emoticons menu
if gajim . config . get ( ' useemoticons ' ) :
2005-11-20 18:01:49 +01:00
msg_tv = self . message_textviews [ jid ]
def set_emoticons_menu_position ( w , msg_tv = msg_tv ) :
window = msg_tv . get_window ( gtk . TEXT_WINDOW_WIDGET )
2005-11-15 15:31:27 +01:00
# get the window position
2005-11-15 12:52:40 +01:00
origin = window . get_origin ( )
size = window . get_size ( )
2005-11-20 18:01:49 +01:00
buf = msg_tv . get_buffer ( )
2005-11-15 15:31:27 +01:00
# get the cursor position
2005-11-20 18:01:49 +01:00
cursor = msg_tv . get_iter_location ( buf . get_iter_at_mark (
2005-11-20 17:17:23 +01:00
buf . get_insert ( ) ) )
2005-11-20 18:01:49 +01:00
cursor = msg_tv . buffer_to_window_coords ( gtk . TEXT_WINDOW_TEXT ,
2005-11-20 17:17:23 +01:00
cursor . x , cursor . y )
x = origin [ 0 ] + cursor [ 0 ]
y = origin [ 1 ] + size [ 1 ]
menu_width , menu_height = self . emoticons_menu . size_request ( )
2005-11-21 20:07:42 +01:00
#FIXME: get_line_count is not so good
#get the iter of cursor, then tv.get_line_yrange
# so we know in which y we are typing (not how many lines we have
# then go show just above the current cursor line for up
# or just below the current cursor line for down
#TEST with having 3 lines and writing in the 2nd
2005-11-20 17:17:23 +01:00
if y + menu_height > gtk . gdk . screen_height ( ) :
2005-11-20 18:01:49 +01:00
# move menu just above cursor
y - = menu_height + ( msg_tv . allocation . height / buf . get_line_count ( ) )
2005-11-21 20:07:42 +01:00
#else: # move menu just below cursor
# y -= (msg_tv.allocation.height / buf.get_line_count())
2005-11-20 17:17:23 +01:00
return ( x , y , True ) # push_in True
2005-11-15 12:52:40 +01:00
self . emoticons_menu . popup ( None , None , set_emoticons_menu_position , 1 , 0 )
2005-04-12 17:30:09 +02:00
elif event . keyval == gtk . keysyms . Page_Down :
2005-06-27 10:37:02 +02:00
if event . state & gtk . gdk . SHIFT_MASK : # SHIFT + PAGE DOWN
2005-10-28 23:46:55 +02:00
conv_textview = self . conversation_textviews [ jid ]
rect = conv_textview . get_visible_rect ( )
2005-11-07 22:33:18 +01:00
iter = conv_textview . get_iter_at_location ( rect . x ,
2005-03-12 19:12:15 +01:00
rect . y + rect . height )
2005-10-28 23:46:55 +02:00
conv_textview . scroll_to_iter ( iter , 0.1 , True , 0 , 0 )
2005-04-12 17:30:09 +02:00
elif event . keyval == gtk . keysyms . Page_Up :
2005-06-27 10:37:02 +02:00
if event . state & gtk . gdk . SHIFT_MASK : # SHIFT + PAGE UP
2005-10-28 23:46:55 +02:00
conv_textview = self . conversation_textviews [ jid ]
rect = conv_textview . get_visible_rect ( )
iter = conv_textview . get_iter_at_location ( rect . x , rect . y )
conv_textview . scroll_to_iter ( iter , 0.1 , True , 0 , 1 )
2005-04-12 17:30:09 +02:00
elif event . keyval == gtk . keysyms . Up :
if event . state & gtk . gdk . SHIFT_MASK : # SHIFT + UP
2005-04-22 02:02:42 +02:00
conversation_scrolledwindow = self . xml . get_widget ( ' conversation_scrolledwindow ' )
conversation_scrolledwindow . emit ( ' scroll-child ' ,
2005-04-12 17:30:09 +02:00
gtk . SCROLL_PAGE_BACKWARD , False )
2005-05-15 22:58:04 +02:00
elif event . keyval == gtk . keysyms . ISO_Left_Tab : # SHIFT + TAB
2005-05-30 23:00:04 +02:00
if event . state & gtk . gdk . CONTROL_MASK : # CTRL + SHIFT + TAB
2005-04-12 17:30:09 +02:00
current = self . notebook . get_current_page ( )
if current > 0 :
2005-06-27 02:07:20 +02:00
self . notebook . prev_page ( )
else : # traverse for ever (eg. don't stop at first tab)
2005-04-12 17:30:09 +02:00
self . notebook . set_current_page ( self . notebook . get_n_pages ( ) - 1 )
2005-05-15 22:58:04 +02:00
elif event . keyval == gtk . keysyms . Tab : # TAB
if event . state & gtk . gdk . CONTROL_MASK : # CTRL + TAB
2005-04-12 17:30:09 +02:00
current = self . notebook . get_current_page ( )
if current < ( self . notebook . get_n_pages ( ) - 1 ) :
2005-06-27 02:07:20 +02:00
self . notebook . next_page ( )
else : # traverse for ever (eg. don't stop at last tab)
2005-04-12 17:30:09 +02:00
self . notebook . set_current_page ( 0 )
2005-06-30 21:47:08 +02:00
elif ( event . keyval == gtk . keysyms . l or event . keyval == gtk . keysyms . L ) \
and event . state & gtk . gdk . CONTROL_MASK : # CTRL + L
2005-10-28 23:46:55 +02:00
conv_textview = self . conversation_textviews [ jid ]
conv_textview . get_buffer ( ) . set_text ( ' ' )
2005-06-30 21:47:08 +02:00
elif event . keyval == gtk . keysyms . v and event . state & gtk . gdk . CONTROL_MASK :
# CTRL + V
2005-11-03 18:23:36 +01:00
msg_textview = self . message_textviews [ jid ]
2005-11-03 16:10:00 +01:00
if not msg_textview . is_focus ( ) :
msg_textview . grab_focus ( )
msg_textview . emit ( ' key_press_event ' , event )
2005-05-30 23:00:04 +02:00
elif event . state & gtk . gdk . CONTROL_MASK or \
( event . keyval == gtk . keysyms . Control_L ) or \
( event . keyval == gtk . keysyms . Control_R ) :
2005-04-22 02:02:42 +02:00
# we pressed a control key or ctrl+sth: we don't block
# the event in order to let ctrl+c (copy text) and
# others do their default work
2005-04-21 18:41:22 +02:00
pass
2005-03-12 19:12:15 +01:00
else : # it's a normal key press make sure message_textview has focus
2005-11-03 18:23:36 +01:00
msg_textview = self . message_textviews [ jid ]
2005-11-03 16:10:00 +01:00
if msg_textview . get_property ( ' sensitive ' ) :
if not msg_textview . is_focus ( ) :
msg_textview . grab_focus ( )
msg_textview . emit ( ' key_press_event ' , event )
2005-03-12 19:12:15 +01:00
def on_conversation_vadjustment_value_changed ( self , widget ) :
jid = self . get_active_jid ( )
if not self . nb_unread [ jid ] :
return
2005-10-28 23:46:55 +02:00
conv_textview = self . conversation_textviews [ jid ]
if conv_textview . at_the_end ( ) and self . window . is_active ( ) :
2005-03-12 19:12:15 +01:00
#we are at the end
2005-10-28 23:46:55 +02:00
self . nb_unread [ jid ] = self . get_specific_unread ( jid )
2005-03-12 19:12:15 +01:00
self . redraw_tab ( jid )
self . show_title ( )
2005-10-20 13:17:17 +02:00
if gajim . interface . systray_enabled :
gajim . interface . systray . remove_jid ( jid , self . account ,
2005-09-24 13:35:56 +02:00
self . get_message_type ( jid ) )
2005-10-28 23:46:55 +02:00
def clear ( self , tv ) :
buffer = tv . get_buffer ( )
2005-05-11 21:40:37 +02:00
start , end = buffer . get_bounds ( )
buffer . delete ( start , end )
2005-04-22 02:02:42 +02:00
def print_conversation_line ( self , text , jid , kind , name , tim ,
2005-06-02 21:38:22 +02:00
other_tags_for_name = [ ] , other_tags_for_time = [ ] ,
2005-07-05 23:35:37 +02:00
other_tags_for_text = [ ] , count_as_new = True , subject = None ) :
2005-10-08 00:29:06 +02:00
''' prints ' chat ' type messages '''
2005-10-28 23:46:55 +02:00
textview = self . conversation_textviews [ jid ]
2005-03-16 18:22:20 +01:00
end = False
2005-10-28 23:46:55 +02:00
if textview . at_the_end ( ) or kind == ' outgoing ' :
2005-03-16 18:22:20 +01:00
end = True
2005-10-28 23:46:55 +02:00
textview . print_conversation_line ( text , jid , kind , name , tim ,
other_tags_for_name , other_tags_for_time , other_tags_for_text , subject )
2005-06-23 23:35:54 +02:00
2005-07-01 20:29:23 +02:00
if not count_as_new :
return
2005-10-28 23:46:55 +02:00
if kind == ' incoming_queue ' :
2005-07-03 17:27:41 +02:00
gajim . last_message_time [ self . account ] [ jid ] = time . time ( )
2005-09-09 18:10:49 +02:00
urgent = True
2005-05-30 23:00:04 +02:00
if ( jid != self . get_active_jid ( ) or \
not self . window . is_active ( ) or \
2005-11-06 00:43:43 +01:00
not end ) and kind in ( ' incoming ' , ' incoming_queue ' ) :
2005-09-09 18:10:49 +02:00
if self . widget_name == ' groupchat_window ' :
2005-12-05 14:26:08 +01:00
if not self . needs_visual_notification ( text , self . nicks [ jid ] ) :
2005-09-09 18:10:49 +02:00
# Do not notify us for gc messages that are not for us
urgent = False
if not gajim . config . get ( ' notify_on_all_muc_messages ' ) :
return
2005-03-16 18:22:20 +01:00
self . nb_unread [ jid ] + = 1
2005-10-20 13:17:17 +02:00
if gajim . interface . systray_enabled and gajim . config . get (
2005-08-11 20:23:39 +02:00
' trayicon_notification_on_new_messages ' ) :
2005-10-20 13:17:17 +02:00
gajim . interface . systray . add_jid ( jid , self . account , self . get_message_type ( jid ) )
2005-03-16 18:22:20 +01:00
self . redraw_tab ( jid )
2005-09-09 18:10:49 +02:00
self . show_title ( urgent )
2005-06-07 18:25:55 +02:00
def save_sent_message ( self , jid , message ) :
#save the message, so user can scroll though the list with key up/down
size = len ( self . sent_history [ jid ] )
#we don't want size of the buffer to grow indefinately
max_size = gajim . config . get ( ' key_up_lines ' )
if size > = max_size :
2005-10-27 14:47:54 +02:00
for i in xrange ( 0 , size - 1 ) :
2005-06-07 18:25:55 +02:00
self . sent_history [ jid ] [ i ] = self . sent_history [ jid ] [ i + 1 ]
self . sent_history [ jid ] [ max_size - 1 ] = message
else :
self . sent_history [ jid ] . append ( message )
2005-07-23 18:08:33 +02:00
self . sent_history_pos [ jid ] = size + 1
2005-06-07 18:25:55 +02:00
self . typing_new [ jid ] = True
self . orig_msg [ jid ] = ' '
def sent_messages_scroll ( self , jid , direction , conv_buf ) :
size = len ( self . sent_history [ jid ] )
2005-09-03 20:18:33 +02:00
if self . typing_new [ jid ] :
#user was typing something and then went into history, so save
#whatever is already typed
start_iter = conv_buf . get_start_iter ( )
end_iter = conv_buf . get_end_iter ( )
self . orig_msg [ jid ] = conv_buf . get_text ( start_iter , end_iter , 0 ) . decode ( ' utf-8 ' )
self . typing_new [ jid ] = False
2005-06-07 18:25:55 +02:00
if direction == ' up ' :
if self . sent_history_pos [ jid ] == 0 :
return
self . sent_history_pos [ jid ] = self . sent_history_pos [ jid ] - 1
conv_buf . set_text ( self . sent_history [ jid ] [ self . sent_history_pos [ jid ] ] )
elif direction == ' down ' :
if self . sent_history_pos [ jid ] > = size - 1 :
conv_buf . set_text ( self . orig_msg [ jid ] ) ;
self . typing_new [ jid ] = True
self . sent_history_pos [ jid ] = size
return
self . sent_history_pos [ jid ] = self . sent_history_pos [ jid ] + 1
conv_buf . set_text ( self . sent_history [ jid ] [ self . sent_history_pos [ jid ] ] )
2005-06-10 22:06:01 +02:00
2005-06-14 00:11:09 +02:00
def paint_banner ( self , jid ) :
theme = gajim . config . get ( ' roster_theme ' )
bgcolor = gajim . config . get_per ( ' themes ' , theme , ' bannerbgcolor ' )
textcolor = gajim . config . get_per ( ' themes ' , theme , ' bannertextcolor ' )
2005-06-30 15:31:31 +02:00
# the backgrounds are colored by using an eventbox by
# setting the bg color of the eventbox and the fg of the name_label
2005-10-05 12:23:48 +02:00
banner_eventbox = self . xmls [ jid ] . get_widget ( ' banner_eventbox ' )
banner_name_label = self . xmls [ jid ] . get_widget ( ' banner_name_label ' )
2005-09-16 23:32:57 +02:00
if bgcolor :
2005-10-05 12:23:48 +02:00
banner_eventbox . modify_bg ( gtk . STATE_NORMAL ,
gtk . gdk . color_parse ( bgcolor ) )
else :
banner_eventbox . modify_bg ( gtk . STATE_NORMAL , None )
2005-09-16 23:32:57 +02:00
if textcolor :
banner_name_label . modify_fg ( gtk . STATE_NORMAL ,
gtk . gdk . color_parse ( textcolor ) )
2005-10-05 12:23:48 +02:00
else :
banner_name_label . modify_fg ( gtk . STATE_NORMAL , None )
2005-06-14 00:11:09 +02:00
2005-06-10 22:06:01 +02:00
def repaint_colored_widgets ( self ) :
2005-10-06 17:20:53 +02:00
''' Repaint widgets (banner) in the window/tab with theme color '''
2005-06-10 22:06:01 +02:00
# iterate through tabs/windows and repaint
for jid in self . xmls :
2005-06-14 00:11:09 +02:00
self . paint_banner ( jid )
2005-06-22 23:58:45 +02:00
2005-06-30 15:31:31 +02:00
def set_compact_view ( self , state ) :
2005-08-04 16:57:36 +02:00
''' Toggle compact view. state is bool '''
2005-06-30 15:31:31 +02:00
self . compact_view_current_state = state
2005-06-22 23:58:45 +02:00
for jid in self . xmls :
2005-06-30 15:31:31 +02:00
if self . widget_name == ' tabbed_chat_window ' :
widgets = [
self . xmls [ jid ] . get_widget ( ' banner_eventbox ' ) ,
self . xmls [ jid ] . get_widget ( ' actions_hbox ' ) ,
]
elif self . widget_name == ' groupchat_window ' :
widgets = [ self . xmls [ jid ] . get_widget ( ' banner_eventbox ' ) ,
self . xmls [ jid ] . get_widget ( ' gc_actions_hbox ' ) ,
self . xmls [ jid ] . get_widget ( ' list_scrolledwindow ' ) ,
]
2005-06-22 23:58:45 +02:00
for widget in widgets :
if state :
widget . set_no_show_all ( True )
widget . hide ( )
else :
widget . set_no_show_all ( False )
2005-06-23 10:15:13 +02:00
widget . show_all ( )
2005-07-29 20:10:23 +02:00
# make the last message visible, when changing to "full view"
if not state :
2005-10-28 23:46:55 +02:00
conv_textview = self . conversation_textviews [ jid ]
gobject . idle_add ( conv_textview . scroll_to_end_iter )