All keybindings are working and with a biut less code duplication
This commit is contained in:
parent
f195c47ea7
commit
2726e33172
4 changed files with 257 additions and 138 deletions
|
@ -28,6 +28,8 @@ from common import helpers
|
||||||
from message_control import MessageControl
|
from message_control import MessageControl
|
||||||
from conversation_textview import ConversationTextview
|
from conversation_textview import ConversationTextview
|
||||||
from message_textview import MessageTextView
|
from message_textview import MessageTextView
|
||||||
|
from common.logger import Constants
|
||||||
|
constants = Constants()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import gtkspell
|
import gtkspell
|
||||||
|
@ -76,6 +78,8 @@ class ChatControlBase(MessageControl):
|
||||||
'underline_togglebutton'):
|
'underline_togglebutton'):
|
||||||
self.xml.get_widget(w).set_no_show_all(True)
|
self.xml.get_widget(w).set_no_show_all(True)
|
||||||
|
|
||||||
|
self.widget.connect('key_press_event', self._on_keypress_event)
|
||||||
|
|
||||||
# Create textviews and connect signals
|
# Create textviews and connect signals
|
||||||
self.conv_textview = ConversationTextview(None) # FIXME: remove account arg
|
self.conv_textview = ConversationTextview(None) # FIXME: remove account arg
|
||||||
self.conv_textview.show_all()
|
self.conv_textview.show_all()
|
||||||
|
@ -83,22 +87,21 @@ class ChatControlBase(MessageControl):
|
||||||
self.conv_scrolledwindow.add(self.conv_textview)
|
self.conv_scrolledwindow.add(self.conv_textview)
|
||||||
self.conv_scrolledwindow.get_vadjustment().connect('value-changed',
|
self.conv_scrolledwindow.get_vadjustment().connect('value-changed',
|
||||||
self.on_conversation_vadjustment_value_changed)
|
self.on_conversation_vadjustment_value_changed)
|
||||||
self.conv_textview.connect('key_press_event',
|
|
||||||
self.on_conversation_textview_key_press_event)
|
|
||||||
# add MessageTextView to UI and connect signals
|
# add MessageTextView to UI and connect signals
|
||||||
self.msg_scrolledwindow = self.xml.get_widget('message_scrolledwindow')
|
self.msg_scrolledwindow = self.xml.get_widget('message_scrolledwindow')
|
||||||
self.msg_textview = MessageTextView()
|
self.msg_textview = MessageTextView()
|
||||||
self.msg_textview.connect('mykeypress',
|
self.msg_textview.connect('mykeypress',
|
||||||
self.on_message_textview_mykeypress_event)
|
self._on_message_textview_mykeypress_event)
|
||||||
self.msg_scrolledwindow.add(self.msg_textview)
|
self.msg_scrolledwindow.add(self.msg_textview)
|
||||||
self.msg_textview.connect('key_press_event',
|
self.msg_textview.connect('key_press_event',
|
||||||
self.on_message_textview_key_press_event)
|
self._on_message_textview_key_press_event)
|
||||||
self.msg_textview.connect('size-request', self.size_request, self.xml)
|
self.msg_textview.connect('size-request', self.size_request, self.xml)
|
||||||
self.update_font()
|
self.update_font()
|
||||||
|
|
||||||
|
|
||||||
# the following vars are used to keep history of user's messages
|
# the following vars are used to keep history of user's messages
|
||||||
self.sent_history = []
|
self.sent_history = []
|
||||||
self.sent_history_pos = -1
|
self.sent_history_pos = 0
|
||||||
self.typing_new = False
|
self.typing_new = False
|
||||||
self.orig_msg = ''
|
self.orig_msg = ''
|
||||||
|
|
||||||
|
@ -143,34 +146,43 @@ class ChatControlBase(MessageControl):
|
||||||
banner_name_label.modify_fg(gtk.STATE_NORMAL, None)
|
banner_name_label.modify_fg(gtk.STATE_NORMAL, None)
|
||||||
|
|
||||||
|
|
||||||
def on_conversation_textview_key_press_event(self, widget, event):
|
def _on_keypress_event(self, widget, event):
|
||||||
'''Handle events from the ConversationTextview'''
|
|
||||||
print "ChatControl.on_conversation_textview_key_press_event", event
|
|
||||||
if event.state & gtk.gdk.CONTROL_MASK:
|
if event.state & gtk.gdk.CONTROL_MASK:
|
||||||
# CTRL + l|L
|
# CTRL + l|L: clear conv_textview
|
||||||
if event.keyval == gtk.keysyms.l or event.keyval == gtk.keysyms.L:
|
if event.keyval == gtk.keysyms.l or event.keyval == gtk.keysyms.L:
|
||||||
self.conv_textview.get_buffer().set_text('')
|
self.conv_textview.get_buffer().set_text('')
|
||||||
# CTRL + v
|
return True
|
||||||
|
# CTRL + v: Paste into msg_textview
|
||||||
elif event.keyval == gtk.keysyms.v:
|
elif event.keyval == gtk.keysyms.v:
|
||||||
if not self.msg_textview.is_focus():
|
if not self.msg_textview.is_focus():
|
||||||
self.msg_textview.grab_focus()
|
self.msg_textview.grab_focus()
|
||||||
|
# Paste into the msg textview
|
||||||
self.msg_textview.emit('key_press_event', event)
|
self.msg_textview.emit('key_press_event', event)
|
||||||
|
return False
|
||||||
|
|
||||||
def on_message_textview_key_press_event(self, widget, event):
|
def _on_message_textview_key_press_event(self, widget, event):
|
||||||
print "ChatControl.on_message_textview_key_press_event", event
|
print "_on_message_textview_key_press_event"
|
||||||
|
if event.state & gtk.gdk.SHIFT_MASK:
|
||||||
if event.keyval == gtk.keysyms.Page_Down: # PAGE DOWN
|
# SHIFT + PAGE_[UP|DOWN]: send to conv_textview
|
||||||
if event.state & gtk.gdk.SHIFT_MASK: # SHIFT + PAGE DOWN
|
if event.keyval == gtk.keysyms.Page_Down or \
|
||||||
self.conv_textview.emit('key_press_event', event)
|
event.keyval == gtk.keysyms.Page_Up:
|
||||||
elif event.keyval == gtk.keysyms.Page_Up: # PAGE UP
|
|
||||||
if event.state & gtk.gdk.SHIFT_MASK: # SHIFT + PAGE UP
|
|
||||||
self.conv_textview.emit('key_press_event', event)
|
self.conv_textview.emit('key_press_event', event)
|
||||||
|
return True
|
||||||
|
elif event.state & gtk.gdk.CONTROL_MASK or \
|
||||||
|
(event.keyval == gtk.keysyms.Control_L) or \
|
||||||
|
(event.keyval == gtk.keysyms.Control_R):
|
||||||
|
# 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
|
||||||
|
self.conv_textview.emit('key_press_event', event)
|
||||||
|
return False
|
||||||
|
|
||||||
def on_message_textview_mykeypress_event(self, widget, event_keyval,
|
def _on_message_textview_mykeypress_event(self, widget, event_keyval,
|
||||||
event_keymod):
|
event_keymod):
|
||||||
'''When a key is pressed:
|
'''When a key is pressed:
|
||||||
if enter is pressed without the shift key, message (if not empty) is sent
|
if enter is pressed without the shift key, message (if not empty) is sent
|
||||||
and printed in the conversation'''
|
and printed in the conversation'''
|
||||||
|
print "ChatControlBase._on_message_textview_mykeypress_event"
|
||||||
|
|
||||||
# NOTE: handles mykeypress which is custom signal connected to this
|
# NOTE: handles mykeypress which is custom signal connected to this
|
||||||
# CB in new_tab(). for this singal see message_textview.py
|
# CB in new_tab(). for this singal see message_textview.py
|
||||||
|
@ -189,11 +201,9 @@ class ChatControlBase(MessageControl):
|
||||||
if event.keyval == gtk.keysyms.Up:
|
if event.keyval == gtk.keysyms.Up:
|
||||||
if event.state & gtk.gdk.CONTROL_MASK: # Ctrl+UP
|
if event.state & gtk.gdk.CONTROL_MASK: # Ctrl+UP
|
||||||
self.sent_messages_scroll('up', widget.get_buffer())
|
self.sent_messages_scroll('up', widget.get_buffer())
|
||||||
return
|
|
||||||
elif event.keyval == gtk.keysyms.Down:
|
elif event.keyval == gtk.keysyms.Down:
|
||||||
if event.state & gtk.gdk.CONTROL_MASK: # Ctrl+Down
|
if event.state & gtk.gdk.CONTROL_MASK: # Ctrl+Down
|
||||||
self.sent_messages_scroll('down', widget.get_buffer())
|
self.sent_messages_scroll('down', widget.get_buffer())
|
||||||
return
|
|
||||||
elif event.keyval == gtk.keysyms.Return or \
|
elif event.keyval == gtk.keysyms.Return or \
|
||||||
event.keyval == gtk.keysyms.KP_Enter: # ENTER
|
event.keyval == gtk.keysyms.KP_Enter: # ENTER
|
||||||
# NOTE: SHIFT + ENTER is not needed to be emulated as it is not
|
# NOTE: SHIFT + ENTER is not needed to be emulated as it is not
|
||||||
|
@ -295,8 +305,8 @@ class ChatControlBase(MessageControl):
|
||||||
self.nb_unread += 1
|
self.nb_unread += 1
|
||||||
if gajim.interface.systray_enabled and\
|
if gajim.interface.systray_enabled and\
|
||||||
gajim.config.get('trayicon_notification_on_new_messages'):
|
gajim.config.get('trayicon_notification_on_new_messages'):
|
||||||
gajim.interface.systray.add_jid(jid, self.account, self.type)
|
gajim.interface.systray.add_jid(jid, self.account, self.type_id)
|
||||||
self.parent_win.redraw_tab(jid)
|
self.parent_win.redraw_tab(self.contact)
|
||||||
self.show_title(urgent)
|
self.show_title(urgent)
|
||||||
|
|
||||||
def toggle_emoticons(self):
|
def toggle_emoticons(self):
|
||||||
|
@ -419,7 +429,7 @@ class ChatControlBase(MessageControl):
|
||||||
gajim.interface.systray.remove_jid(jid,
|
gajim.interface.systray.remove_jid(jid,
|
||||||
self.account,
|
self.account,
|
||||||
self.type)
|
self.type)
|
||||||
self.conv_textview.grab_focus()
|
self.msg_textview.grab_focus()
|
||||||
|
|
||||||
def bring_scroll_to_end(self, textview, diff_y = 0):
|
def bring_scroll_to_end(self, textview, diff_y = 0):
|
||||||
''' scrolls to the end of textview if end is not visible '''
|
''' scrolls to the end of textview if end is not visible '''
|
||||||
|
@ -539,9 +549,8 @@ class ChatControl(ChatControlBase):
|
||||||
xm = gtk.glade.XML(GTKGUI_GLADE, 'chat_control_popup_menu', APP)
|
xm = gtk.glade.XML(GTKGUI_GLADE, 'chat_control_popup_menu', APP)
|
||||||
xm.signal_autoconnect(self)
|
xm.signal_autoconnect(self)
|
||||||
self.popup_menu = xm.get_widget('chat_control_popup_menu')
|
self.popup_menu = xm.get_widget('chat_control_popup_menu')
|
||||||
xm = gtk.glade.XML(GTKGUI_GLADE, 'banner_eventbox', APP)
|
|
||||||
xm.signal_autoconnect(self)
|
|
||||||
|
|
||||||
|
# Initialize drag-n-drop
|
||||||
self.TARGET_TYPE_URI_LIST = 80
|
self.TARGET_TYPE_URI_LIST = 80
|
||||||
self.dnd_list = [ ( 'text/uri-list', 0, self.TARGET_TYPE_URI_LIST ) ]
|
self.dnd_list = [ ( 'text/uri-list', 0, self.TARGET_TYPE_URI_LIST ) ]
|
||||||
self.widget.connect('drag_data_received', self._on_drag_data_received)
|
self.widget.connect('drag_data_received', self._on_drag_data_received)
|
||||||
|
@ -558,8 +567,58 @@ class ChatControl(ChatControlBase):
|
||||||
# chatstate timers and state
|
# chatstate timers and state
|
||||||
self.reset_kbd_mouse_timeout_vars()
|
self.reset_kbd_mouse_timeout_vars()
|
||||||
self._schedule_activity_timers()
|
self._schedule_activity_timers()
|
||||||
|
|
||||||
|
# Hook up signals
|
||||||
|
# FIXME: This does not seem to be working
|
||||||
self.parent_win.window.connect('motion-notify-event',
|
self.parent_win.window.connect('motion-notify-event',
|
||||||
self._on_window_motion_notify)
|
self._on_window_motion_notify)
|
||||||
|
message_tv_buffer = self.msg_textview.get_buffer()
|
||||||
|
message_tv_buffer.connect('changed', self._on_message_tv_buffer_changed)
|
||||||
|
|
||||||
|
self.xml.get_widget('banner_eventbox').connect('button-press-event',
|
||||||
|
self._on_banner_eventbox_button_press_event)
|
||||||
|
self.xml.get_widget('banner_eventbox').connect('button-press-event',
|
||||||
|
self._on_banner_eventbox_button_press_event)
|
||||||
|
xm = gtk.glade.XML(GTKGUI_GLADE, 'avatar_eventbox', APP)
|
||||||
|
xm.signal_autoconnect(self)
|
||||||
|
|
||||||
|
if self.contact.jid in gajim.encrypted_chats[self.account]:
|
||||||
|
self.xml.get_widget('gpg_togglebutton').set_active(True)
|
||||||
|
|
||||||
|
# restore previous conversation
|
||||||
|
self.restore_conversation()
|
||||||
|
|
||||||
|
if gajim.awaiting_events[self.account].has_key(self.contact.jid):
|
||||||
|
self.read_queue()
|
||||||
|
|
||||||
|
def _on_avatar_eventbox_enter_notify_event(self, widget, event):
|
||||||
|
'''we enter the eventbox area so we under conditions add a timeout
|
||||||
|
to show a bigger avatar after 0.5 sec'''
|
||||||
|
jid = self.contact.jid
|
||||||
|
real_jid = gajim.get_real_jid_from_fjid(self.account, jid)
|
||||||
|
if not real_jid: # this can happend if we're in a moderate room
|
||||||
|
return
|
||||||
|
avatar_pixbuf = gtkgui_helpers.get_avatar_pixbuf_from_cache(real_jid)
|
||||||
|
if avatar_pixbuf in ('ask', None):
|
||||||
|
return
|
||||||
|
avatar_w = avatar_pixbuf.get_width()
|
||||||
|
avatar_h = avatar_pixbuf.get_height()
|
||||||
|
|
||||||
|
scaled_buf = self.xmls[jid].get_widget('avatar_image').get_pixbuf()
|
||||||
|
scaled_buf_w = scaled_buf.get_width()
|
||||||
|
scaled_buf_h = scaled_buf.get_height()
|
||||||
|
|
||||||
|
# do we have something bigger to show?
|
||||||
|
if avatar_w > scaled_buf_w or avatar_h > scaled_buf_h:
|
||||||
|
# wait for 0.5 sec in case we leave earlier
|
||||||
|
self.show_bigger_avatar_timeout_id = gobject.timeout_add(500,
|
||||||
|
self.show_bigger_avatar, widget)
|
||||||
|
|
||||||
|
def _on_avatar_eventbox_leave_notify_event(self, widget, event):
|
||||||
|
'''we left the eventbox area that holds the avatar img'''
|
||||||
|
# did we add a timeout? if yes remove it
|
||||||
|
if self.show_bigger_avatar_timeout_id is not None:
|
||||||
|
gobject.source_remove(self.show_bigger_avatar_timeout_id)
|
||||||
|
|
||||||
def save_var(self, jid):
|
def save_var(self, jid):
|
||||||
gpg_enabled = self.xmls[jid].get_widget('gpg_togglebutton').get_active()
|
gpg_enabled = self.xmls[jid].get_widget('gpg_togglebutton').get_active()
|
||||||
|
@ -949,8 +1008,7 @@ class ChatControl(ChatControlBase):
|
||||||
|
|
||||||
def send_chatstate(self, state, contact = None):
|
def send_chatstate(self, state, contact = None):
|
||||||
''' sends OUR chatstate as STANDLONE chat state message (eg. no body)
|
''' sends OUR chatstate as STANDLONE chat state message (eg. no body)
|
||||||
to jid only if new chatstate is different
|
to contact only if new chatstate is different from the previous one
|
||||||
from the previous one
|
|
||||||
if jid is not specified, send to active tab'''
|
if jid is not specified, send to active tab'''
|
||||||
# JEP 85 does not allow resending the same chatstate
|
# JEP 85 does not allow resending the same chatstate
|
||||||
# this function checks for that and just returns so it's safe to call it
|
# this function checks for that and just returns so it's safe to call it
|
||||||
|
@ -1058,7 +1116,7 @@ class ChatControl(ChatControlBase):
|
||||||
# update chatstate in tab for this chat
|
# update chatstate in tab for this chat
|
||||||
self.parent_win.redraw_tab(self.contact, self.contact.chatstate)
|
self.parent_win.redraw_tab(self.contact, self.contact.chatstate)
|
||||||
|
|
||||||
def on_banner_eventbox_button_press_event(self, widget, event):
|
def _on_banner_eventbox_button_press_event(self, widget, event):
|
||||||
'''If right-clicked, show popup'''
|
'''If right-clicked, show popup'''
|
||||||
if event.button == 3: # right click
|
if event.button == 3: # right click
|
||||||
self.parent_win.popup_menu(event)
|
self.parent_win.popup_menu(event)
|
||||||
|
@ -1109,3 +1167,117 @@ class ChatControl(ChatControlBase):
|
||||||
if os.path.isfile(path): # is it file?
|
if os.path.isfile(path): # is it file?
|
||||||
ft = gajim.interface.instances['file_transfers']
|
ft = gajim.interface.instances['file_transfers']
|
||||||
ft.send_file(self.account, self.contact, path)
|
ft.send_file(self.account, self.contact, path)
|
||||||
|
|
||||||
|
def _on_message_tv_buffer_changed(self, textbuffer):
|
||||||
|
self.kbd_activity_in_last_5_secs = True
|
||||||
|
self.kbd_activity_in_last_30_secs = True
|
||||||
|
if textbuffer.get_char_count():
|
||||||
|
self.send_chatstate('composing', self.contact)
|
||||||
|
else:
|
||||||
|
self.send_chatstate('active', self.contact)
|
||||||
|
|
||||||
|
def restore_conversation(self):
|
||||||
|
jid = self.contact.jid
|
||||||
|
# don't restore lines if it's a transport
|
||||||
|
if gajim.jid_is_transport(jid):
|
||||||
|
return
|
||||||
|
|
||||||
|
# How many lines to restore and when to time them out
|
||||||
|
restore_how_many = gajim.config.get('restore_lines')
|
||||||
|
timeout = gajim.config.get('restore_timeout') # in minutes
|
||||||
|
# number of messages that are in queue and are already logged
|
||||||
|
pending_how_many = 0 # we want to avoid duplication
|
||||||
|
|
||||||
|
if gajim.awaiting_events[self.account].has_key(jid):
|
||||||
|
events = gajim.awaiting_events[self.account][jid]
|
||||||
|
for event in events:
|
||||||
|
if event[0] == 'chat':
|
||||||
|
pending_how_many += 1
|
||||||
|
|
||||||
|
rows = gajim.logger.get_last_conversation_lines(jid, restore_how_many,
|
||||||
|
pending_how_many, timeout)
|
||||||
|
|
||||||
|
for row in rows: # row[0] time, row[1] has kind, row[2] the message
|
||||||
|
if not row[2]: # message is empty, we don't print it
|
||||||
|
continue
|
||||||
|
if row[1] in (constants.KIND_CHAT_MSG_SENT,
|
||||||
|
constants.KIND_SINGLE_MSG_SENT):
|
||||||
|
kind = 'outgoing'
|
||||||
|
name = gajim.nicks[self.account]
|
||||||
|
elif row[1] in (constants.KIND_SINGLE_MSG_RECV,
|
||||||
|
constants.KIND_CHAT_MSG_RECV):
|
||||||
|
kind = 'incoming'
|
||||||
|
name = self.contact.name
|
||||||
|
|
||||||
|
tim = time.localtime(float(row[0]))
|
||||||
|
|
||||||
|
ChatControlBase.print_conversation_line(self, row[2], kind, name, tim,
|
||||||
|
['small'],
|
||||||
|
['small', 'restored_message'],
|
||||||
|
['small', 'restored_message'],
|
||||||
|
False)
|
||||||
|
if len(rows):
|
||||||
|
self.conv_textview.print_empty_line()
|
||||||
|
|
||||||
|
def read_queue(self):
|
||||||
|
'''read queue and print messages containted in it'''
|
||||||
|
jid = self.contact.jid
|
||||||
|
l = gajim.awaiting_events[self.account][jid]
|
||||||
|
|
||||||
|
# Is it a pm ?
|
||||||
|
is_pm = False
|
||||||
|
room_jid, nick = gajim.get_room_and_nick_from_fjid(jid)
|
||||||
|
# FIXME: Accessing gc's, here?
|
||||||
|
gcs = gajim.interface.instances[self.account]['gc']
|
||||||
|
if gcs.has_key(room_jid):
|
||||||
|
is_pm = True
|
||||||
|
events_to_keep = []
|
||||||
|
for event in l:
|
||||||
|
typ = event[0]
|
||||||
|
if typ != 'chat':
|
||||||
|
events_to_keep.append(event)
|
||||||
|
continue
|
||||||
|
data = event[1]
|
||||||
|
kind = data[2]
|
||||||
|
if kind == 'error':
|
||||||
|
kind = 'status'
|
||||||
|
else:
|
||||||
|
kind = 'print_queue'
|
||||||
|
self.print_conversation(data[0], kind, tim = data[3],
|
||||||
|
encrypted = data[4], subject = data[1])
|
||||||
|
|
||||||
|
# remove from gc nb_unread if it's pm or from roster
|
||||||
|
if is_pm:
|
||||||
|
gcs[room_jid].nb_unread[room_jid] -= 1
|
||||||
|
else:
|
||||||
|
gajim.interface.roster.nb_unread -= 1
|
||||||
|
|
||||||
|
if is_pm:
|
||||||
|
gcs[room_jid].show_title()
|
||||||
|
else:
|
||||||
|
gajim.interface.roster.show_title()
|
||||||
|
# Keep only non-messages events
|
||||||
|
if len(events_to_keep):
|
||||||
|
gajim.awaiting_events[self.account][jid] = events_to_keep
|
||||||
|
else:
|
||||||
|
del gajim.awaiting_events[self.account][jid]
|
||||||
|
typ = 'chat' # Is it a normal chat or a pm ?
|
||||||
|
# reset to status image in gc if it is a pm
|
||||||
|
# FIXME: New data structure
|
||||||
|
gcs = gajim.interface.instances[self.account]['gc']
|
||||||
|
if gcs.has_key(room_jid):
|
||||||
|
gcs[room_jid].draw_all_roster()
|
||||||
|
typ = 'pm'
|
||||||
|
|
||||||
|
gajim.interface.roster.draw_contact(jid, self.account)
|
||||||
|
if gajim.interface.systray_enabled:
|
||||||
|
gajim.interface.systray.remove_jid(jid, self.account, typ)
|
||||||
|
if (self.contact.show == 'offline' or self.contact.show == 'error'):
|
||||||
|
showOffline = gajim.config.get('showoffline')
|
||||||
|
if not showOffline and typ == 'chat' and \
|
||||||
|
len(gajim.contacts[self.account][jid]) == 1:
|
||||||
|
gajim.interface.roster.really_remove_contact(self.contact,
|
||||||
|
self.account)
|
||||||
|
elif typ == 'pm':
|
||||||
|
gcs[room_jid].remove_contact(room_jid, nick)
|
||||||
|
|
||||||
|
|
|
@ -19081,7 +19081,6 @@ Maybe I'll refactor later</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="visible_window">True</property>
|
<property name="visible_window">True</property>
|
||||||
<property name="above_child">False</property>
|
<property name="above_child">False</property>
|
||||||
<signal name="button_press_event" handler="on_banner_eventbox_button_press_event" last_modification_time="Mon, 08 Aug 2005 10:39:20 GMT"/>
|
|
||||||
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkHBox" id="hbox3004">
|
<widget class="GtkHBox" id="hbox3004">
|
||||||
|
@ -19150,8 +19149,8 @@ Status message</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="visible_window">False</property>
|
<property name="visible_window">False</property>
|
||||||
<property name="above_child">False</property>
|
<property name="above_child">False</property>
|
||||||
<signal name="enter_notify_event" handler="on_avatar_eventbox_enter_notify_event" last_modification_time="Sun, 02 Oct 2005 22:58:47 GMT"/>
|
<signal name="enter_notify_event" handler="_on_avatar_eventbox_enter_notify_event" last_modification_time="Mon, 02 Jan 2006 23:13:50 GMT"/>
|
||||||
<signal name="leave_notify_event" handler="on_avatar_eventbox_leave_notify_event" last_modification_time="Sun, 02 Oct 2005 22:58:52 GMT"/>
|
<signal name="leave_notify_event" handler="_on_avatar_eventbox_leave_notify_event" last_modification_time="Mon, 02 Jan 2006 23:13:55 GMT"/>
|
||||||
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkImage" id="avatar_image">
|
<widget class="GtkImage" id="avatar_image">
|
||||||
|
|
|
@ -61,6 +61,12 @@ class MessageControl:
|
||||||
or inactive (state is False)'''
|
or inactive (state is False)'''
|
||||||
pass # Derived types MUST implement this method
|
pass # Derived types MUST implement this method
|
||||||
|
|
||||||
|
def allow_shutdown(self):
|
||||||
|
'''Called to check is a control is allowed to shutdown.
|
||||||
|
If a control is not in a suitable shutdown state this method
|
||||||
|
should return False'''
|
||||||
|
# NOTE: Derived classes MAY implement this
|
||||||
|
return True
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
# NOTE: Derived classes MUST implement this
|
# NOTE: Derived classes MUST implement this
|
||||||
assert(False)
|
assert(False)
|
||||||
|
@ -92,12 +98,6 @@ class MessageControl:
|
||||||
def set_compact_view(self, state):
|
def set_compact_view(self, state):
|
||||||
# NOTE: Derived classes MAY implement this
|
# NOTE: Derived classes MAY implement this
|
||||||
self.compact_view_current = state
|
self.compact_view_current = state
|
||||||
def allow_shutdown(self):
|
|
||||||
'''Called to check is a control is allowed to shutdown.
|
|
||||||
If a control is not in a suitable shutdown state this method
|
|
||||||
should return False'''
|
|
||||||
# NOTE: Derived classes MAY implement this
|
|
||||||
return True
|
|
||||||
|
|
||||||
def save_var(self, jid):
|
def save_var(self, jid):
|
||||||
'''When called, the derived type should serialize it's state in the form of a
|
'''When called, the derived type should serialize it's state in the form of a
|
||||||
|
@ -107,6 +107,9 @@ class MessageControl:
|
||||||
def load_var(self, jid, var):
|
def load_var(self, jid, var):
|
||||||
pass # Derived classes SHOULD implement this
|
pass # Derived classes SHOULD implement this
|
||||||
|
|
||||||
|
def get_specific_unread(self, jid):
|
||||||
|
return 0
|
||||||
|
|
||||||
def send_message(self, message, keyID = '', type = 'chat', chatstate = None):
|
def send_message(self, message, keyID = '', type = 'chat', chatstate = None):
|
||||||
'''Send the given message to the active tab'''
|
'''Send the given message to the active tab'''
|
||||||
# refresh timers
|
# refresh timers
|
||||||
|
|
|
@ -20,6 +20,7 @@ import gobject
|
||||||
import common
|
import common
|
||||||
import gtkgui_helpers
|
import gtkgui_helpers
|
||||||
import message_control
|
import message_control
|
||||||
|
from chat_control import ChatControlBase
|
||||||
|
|
||||||
from common import gajim
|
from common import gajim
|
||||||
|
|
||||||
|
@ -47,7 +48,12 @@ class MessageWindow:
|
||||||
# so this line adds that
|
# so this line adds that
|
||||||
#self.window.set_events(gtk.gdk.POINTER_MOTION_MASK)
|
#self.window.set_events(gtk.gdk.POINTER_MOTION_MASK)
|
||||||
self.alignment = self.xml.get_widget('alignment')
|
self.alignment = self.xml.get_widget('alignment')
|
||||||
|
|
||||||
self.notebook = self.xml.get_widget('notebook')
|
self.notebook = self.xml.get_widget('notebook')
|
||||||
|
self.notebook.connect('switch-page',
|
||||||
|
self._on_notebook_switch_page)
|
||||||
|
self.notebook.connect('key-press-event',
|
||||||
|
self._on_notebook_key_press)
|
||||||
|
|
||||||
# Remove the glade pages
|
# Remove the glade pages
|
||||||
while self.notebook.get_n_pages():
|
while self.notebook.get_n_pages():
|
||||||
|
@ -72,10 +78,6 @@ class MessageWindow:
|
||||||
else:
|
else:
|
||||||
self.notebook.set_show_tabs(False)
|
self.notebook.set_show_tabs(False)
|
||||||
self.notebook.set_show_border(gajim.config.get('tabs_border'))
|
self.notebook.set_show_border(gajim.config.get('tabs_border'))
|
||||||
self.notebook.connect('switch-page',
|
|
||||||
self._on_notebook_switch_page)
|
|
||||||
self.notebook.connect('key-press-event',
|
|
||||||
self._on_notebook_key_press)
|
|
||||||
|
|
||||||
# Connect event handling for this Window
|
# Connect event handling for this Window
|
||||||
self.window.connect('delete-event', self._on_window_delete)
|
self.window.connect('delete-event', self._on_window_delete)
|
||||||
|
@ -92,6 +94,8 @@ class MessageWindow:
|
||||||
gajim.config.get('msgwin-width'),
|
gajim.config.get('msgwin-width'),
|
||||||
gajim.config.get('msgwin-height'))
|
gajim.config.get('msgwin-height'))
|
||||||
|
|
||||||
|
self.window.show_all()
|
||||||
|
|
||||||
def _on_window_focus(self, widget, event):
|
def _on_window_focus(self, widget, event):
|
||||||
# window received focus, so if we had urgency REMOVE IT
|
# 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)
|
# NOTE: we do not have to read the message (it maybe in a bg tab)
|
||||||
|
@ -144,13 +148,9 @@ class MessageWindow:
|
||||||
self.alignment.set_property('top-padding', 2)
|
self.alignment.set_property('top-padding', 2)
|
||||||
|
|
||||||
# Connect to keyboard events
|
# Connect to keyboard events
|
||||||
control.widget.connect('key_press_event',
|
if isinstance(control, ChatControlBase):
|
||||||
self.on_conversation_textview_key_press_event)
|
control.msg_textview.connect('mykeypress',
|
||||||
# FIXME: need to get this event without access to message_textvier
|
self._on_message_textview_mykeypress_event)
|
||||||
#control.widget.connect('mykeypress',
|
|
||||||
# self.on_message_textview_mykeypress_event)
|
|
||||||
control.widget.connect('key_press_event',
|
|
||||||
self.on_message_textview_key_press_event)
|
|
||||||
|
|
||||||
# Add notebook page and connect up to the tab's close button
|
# Add notebook page and connect up to the tab's close button
|
||||||
xml = gtk.glade.XML(GTKGUI_GLADE, 'chat_tab_ebox', APP)
|
xml = gtk.glade.XML(GTKGUI_GLADE, 'chat_tab_ebox', APP)
|
||||||
|
@ -163,10 +163,11 @@ class MessageWindow:
|
||||||
|
|
||||||
|
|
||||||
self.redraw_tab(control.contact)
|
self.redraw_tab(control.contact)
|
||||||
self.show_title()
|
control.draw_widgets()
|
||||||
self.window.show_all()
|
self.window.show_all()
|
||||||
# NOTE: we do not call set_control_active(True) since we don't know whether
|
# NOTE: we do not call set_control_active(True) since we don't know whether
|
||||||
# the tab is the active one.
|
# the tab is the active one.
|
||||||
|
self.show_title()
|
||||||
|
|
||||||
def on_tab_eventbox_button_press_event(self, widget, event, child):
|
def on_tab_eventbox_button_press_event(self, widget, event, child):
|
||||||
if event.button == 3:
|
if event.button == 3:
|
||||||
|
@ -174,10 +175,8 @@ class MessageWindow:
|
||||||
self.notebook.set_current_page(n)
|
self.notebook.set_current_page(n)
|
||||||
self.popup_menu(event)
|
self.popup_menu(event)
|
||||||
|
|
||||||
def on_message_textview_mykeypress_event(self, widget, event_keyval,
|
def _on_message_textview_mykeypress_event(self, widget, event_keyval,
|
||||||
event_keymod):
|
event_keymod):
|
||||||
# FIXME: Not called yet
|
|
||||||
print "MessageWindow.on_message_textview_mykeypress_event:", event
|
|
||||||
# NOTE: handles mykeypress which is custom signal; see message_textview.py
|
# NOTE: handles mykeypress which is custom signal; see message_textview.py
|
||||||
|
|
||||||
# construct event instance from binding
|
# construct event instance from binding
|
||||||
|
@ -186,26 +185,8 @@ class MessageWindow:
|
||||||
event.state = event_keymod
|
event.state = event_keymod
|
||||||
event.time = 0 # assign current time
|
event.time = 0 # assign current time
|
||||||
|
|
||||||
if event.keyval == gtk.keysyms.ISO_Left_Tab: # SHIFT + TAB
|
|
||||||
if event.state & gtk.gdk.CONTROL_MASK: # CTRL + SHIFT + TAB
|
|
||||||
self.notebook.emit('key_press_event', event)
|
|
||||||
if event.keyval == gtk.keysyms.Tab:
|
|
||||||
if event.state & gtk.gdk.CONTROL_MASK: # CTRL + TAB
|
|
||||||
self.notebook.emit('key_press_event', event)
|
|
||||||
|
|
||||||
def on_message_textview_key_press_event(self, widget, event):
|
|
||||||
print "MessageWindow.on_message_textview_key_press_event:", event
|
|
||||||
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.keyval == gtk.keysyms.Page_Up: # PAGE UP
|
|
||||||
if event.state & gtk.gdk.CONTROL_MASK: # CTRL + PAGE UP
|
|
||||||
self.notebook.emit('key_press_event', event)
|
|
||||||
|
|
||||||
def on_conversation_textview_key_press_event(self, widget, event):
|
|
||||||
'''Do not block these events and send them to the notebook'''
|
|
||||||
print "MessageWindow.on_conversation_textview_key_press_event:", event
|
|
||||||
if event.state & gtk.gdk.CONTROL_MASK:
|
if event.state & gtk.gdk.CONTROL_MASK:
|
||||||
|
# Tab switch bindings
|
||||||
if event.keyval == gtk.keysyms.Tab: # CTRL + TAB
|
if event.keyval == gtk.keysyms.Tab: # CTRL + TAB
|
||||||
self.notebook.emit('key_press_event', event)
|
self.notebook.emit('key_press_event', event)
|
||||||
elif event.keyval == gtk.keysyms.ISO_Left_Tab: # CTRL + SHIFT + TAB
|
elif event.keyval == gtk.keysyms.ISO_Left_Tab: # CTRL + SHIFT + TAB
|
||||||
|
@ -283,6 +264,7 @@ class MessageWindow:
|
||||||
self.show_title()
|
self.show_title()
|
||||||
|
|
||||||
def redraw_tab(self, contact, chatstate = None):
|
def redraw_tab(self, contact, chatstate = None):
|
||||||
|
print self._controls
|
||||||
ctl = self._controls[contact.jid]
|
ctl = self._controls[contact.jid]
|
||||||
ctl.update_state()
|
ctl.update_state()
|
||||||
|
|
||||||
|
@ -430,7 +412,7 @@ class MessageWindow:
|
||||||
jid = ctl.contact.jid
|
jid = ctl.contact.jid
|
||||||
if jid != self.get_active_jid():
|
if jid != self.get_active_jid():
|
||||||
item = gtk.ImageMenuItem(_('Switch to %s') %\
|
item = gtk.ImageMenuItem(_('Switch to %s') %\
|
||||||
self.names[jid])
|
ctl.contact.name)
|
||||||
img = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO,
|
img = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO,
|
||||||
gtk.ICON_SIZE_MENU)
|
gtk.ICON_SIZE_MENU)
|
||||||
item.set_image(img)
|
item.set_image(img)
|
||||||
|
@ -450,24 +432,42 @@ class MessageWindow:
|
||||||
new_ctl.set_control_active(True)
|
new_ctl.set_control_active(True)
|
||||||
|
|
||||||
def _on_notebook_key_press(self, widget, event):
|
def _on_notebook_key_press(self, widget, event):
|
||||||
|
print "MessageWindow._on_notebook_key_press event"
|
||||||
st = '1234567890' # alt+1 means the first tab (tab 0)
|
st = '1234567890' # alt+1 means the first tab (tab 0)
|
||||||
ctl = self.get_active_control()
|
ctl = self.get_active_control()
|
||||||
jid = ctl.jid
|
contact = ctl.contact
|
||||||
if event.keyval == gtk.keysyms.Escape: # ESCAPE
|
jid = ctl.contact.jid
|
||||||
if ctl.type == TYPE_CHAT:
|
|
||||||
self.remove_tab(jid)
|
# MOD1 (ALT) mask
|
||||||
|
if event.state & gtk.gdk.MOD1_MASK:
|
||||||
|
# Tab switch bindings
|
||||||
|
if event.keyval == gtk.keysyms.Right: # ALT + RIGHT
|
||||||
|
new = self.notebook.get_current_page() + 1
|
||||||
|
if new >= self.notebook.get_n_pages():
|
||||||
|
new = 0
|
||||||
|
self.notebook.set_current_page(new)
|
||||||
|
elif event.keyval == gtk.keysyms.Left: # ALT + LEFT
|
||||||
|
new = self.notebook.get_current_page() - 1
|
||||||
|
if new < 0:
|
||||||
|
new = self.notebook.get_n_pages() - 1
|
||||||
|
self.notebook.set_current_page(new)
|
||||||
|
elif event.string and event.string in st and \
|
||||||
|
(event.state & gtk.gdk.MOD1_MASK): # ALT + 1,2,3..
|
||||||
|
self.notebook.set_current_page(st.index(event.string))
|
||||||
|
# Close tab bindings
|
||||||
|
elif event.keyval == gtk.keysyms.Escape: # ESCAPE
|
||||||
|
if ctl.type_id == message_control.TYPE_CHAT:
|
||||||
|
self.remove_tab(contact)
|
||||||
elif event.keyval == gtk.keysyms.F4 and \
|
elif event.keyval == gtk.keysyms.F4 and \
|
||||||
(event.state & gtk.gdk.CONTROL_MASK): # CTRL + F4
|
(event.state & gtk.gdk.CONTROL_MASK): # CTRL + F4
|
||||||
self.remove_tab(jid)
|
self.remove_tab(contact)
|
||||||
elif event.keyval == gtk.keysyms.w and \
|
elif event.keyval == gtk.keysyms.w and \
|
||||||
(event.state & gtk.gdk.CONTROL_MASK): # CTRL + W
|
(event.state & gtk.gdk.CONTROL_MASK): # CTRL + W
|
||||||
self.remove_tab(jid)
|
self.remove_tab(contact)
|
||||||
elif event.string and event.string in st and \
|
|
||||||
(event.state & gtk.gdk.MOD1_MASK): # alt + 1,2,3..
|
|
||||||
self.notebook.set_current_page(st.index(event.string))
|
|
||||||
elif event.keyval == gtk.keysyms.c and \
|
elif event.keyval == gtk.keysyms.c and \
|
||||||
(event.state & gtk.gdk.MOD1_MASK): # alt + C toggles compact view
|
(event.state & gtk.gdk.MOD1_MASK): # alt + C toggles compact view
|
||||||
ctl.set_compact_view(not self.compact_view_current_state)
|
ctl.set_compact_view(not ctl.compact_view_current)
|
||||||
|
|
||||||
# FIXME: Move this to ChatControlBase
|
# FIXME: Move this to ChatControlBase
|
||||||
elif event.keyval == gtk.keysyms.e and \
|
elif event.keyval == gtk.keysyms.e and \
|
||||||
(event.state & gtk.gdk.MOD1_MASK): # alt + E opens emoticons menu
|
(event.state & gtk.gdk.MOD1_MASK): # alt + E opens emoticons menu
|
||||||
|
@ -500,60 +500,6 @@ class MessageWindow:
|
||||||
# y -= (msg_tv.allocation.height / buf.get_line_count())
|
# y -= (msg_tv.allocation.height / buf.get_line_count())
|
||||||
return (x, y, True) # push_in True
|
return (x, y, True) # push_in True
|
||||||
self.emoticons_menu.popup(None, None, set_emoticons_menu_position, 1, 0)
|
self.emoticons_menu.popup(None, None, set_emoticons_menu_position, 1, 0)
|
||||||
# FIXME Move to ChatControlBase
|
|
||||||
elif event.keyval == gtk.keysyms.Page_Down:
|
|
||||||
if event.state & gtk.gdk.SHIFT_MASK: # SHIFT + PAGE DOWN
|
|
||||||
conv_textview = self.conversation_textviews[jid]
|
|
||||||
rect = conv_textview.get_visible_rect()
|
|
||||||
iter = conv_textview.get_iter_at_location(rect.x,
|
|
||||||
rect.y + rect.height)
|
|
||||||
conv_textview.scroll_to_iter(iter, 0.1, True, 0, 0)
|
|
||||||
# FIXME Move to ChatControlBase
|
|
||||||
elif event.keyval == gtk.keysyms.Page_Up:
|
|
||||||
if event.state & gtk.gdk.SHIFT_MASK: # SHIFT + PAGE UP
|
|
||||||
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)
|
|
||||||
# FIXME Move to ChatControlBase
|
|
||||||
elif event.keyval == gtk.keysyms.Up:
|
|
||||||
if event.state & gtk.gdk.SHIFT_MASK: # SHIFT + UP
|
|
||||||
conversation_scrolledwindow = self.xml.get_widget('conversation_scrolledwindow')
|
|
||||||
conversation_scrolledwindow.emit('scroll-child',
|
|
||||||
gtk.SCROLL_PAGE_BACKWARD, False)
|
|
||||||
elif event.keyval == gtk.keysyms.ISO_Left_Tab: # SHIFT + TAB
|
|
||||||
if event.state & gtk.gdk.CONTROL_MASK: # CTRL + SHIFT + TAB
|
|
||||||
self.move_to_next_unread_tab(False)
|
|
||||||
elif event.keyval == gtk.keysyms.Tab: # TAB
|
|
||||||
if event.state & gtk.gdk.CONTROL_MASK: # CTRL + TAB
|
|
||||||
self.move_to_next_unread_tab(True)
|
|
||||||
# FIXME Move to ChatControlBase
|
|
||||||
elif (event.keyval == gtk.keysyms.l or event.keyval == gtk.keysyms.L) \
|
|
||||||
and event.state & gtk.gdk.CONTROL_MASK: # CTRL + L
|
|
||||||
conv_textview = self.conversation_textviews[jid]
|
|
||||||
conv_textview.get_buffer().set_text('')
|
|
||||||
# FIXME Move to ChatControlBase
|
|
||||||
elif event.keyval == gtk.keysyms.v and event.state & gtk.gdk.CONTROL_MASK:
|
|
||||||
# CTRL + V
|
|
||||||
msg_textview = self.message_textviews[jid]
|
|
||||||
if not msg_textview.is_focus():
|
|
||||||
msg_textview.grab_focus()
|
|
||||||
msg_textview.emit('key_press_event', event)
|
|
||||||
elif event.state & gtk.gdk.CONTROL_MASK or \
|
|
||||||
(event.keyval == gtk.keysyms.Control_L) or \
|
|
||||||
(event.keyval == gtk.keysyms.Control_R):
|
|
||||||
# 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
|
|
||||||
pass
|
|
||||||
# FIXME Move to ChatControlBase
|
|
||||||
else: # it's a normal key press make sure message_textview has focus
|
|
||||||
msg_textview = self.message_textviews[jid]
|
|
||||||
if msg_textview.get_property('sensitive'):
|
|
||||||
if not msg_textview.is_focus():
|
|
||||||
msg_textview.grab_focus()
|
|
||||||
msg_textview.emit('key_press_event', event)
|
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
class MessageWindowMgr:
|
class MessageWindowMgr:
|
||||||
|
@ -581,7 +527,6 @@ class MessageWindowMgr:
|
||||||
|
|
||||||
def _new_window(self):
|
def _new_window(self):
|
||||||
win = MessageWindow()
|
win = MessageWindow()
|
||||||
win.window.show_all()
|
|
||||||
# we track the lifetime of this window
|
# we track the lifetime of this window
|
||||||
win.window.connect('destroy', self._on_window_destroy)
|
win.window.connect('destroy', self._on_window_destroy)
|
||||||
return win
|
return win
|
||||||
|
|
Loading…
Add table
Reference in a new issue