All keybindings are working and with a biut less code duplication

This commit is contained in:
Travis Shirk 2006-01-03 03:34:32 +00:00
parent f195c47ea7
commit 2726e33172
4 changed files with 257 additions and 138 deletions

View File

@ -28,6 +28,8 @@ from common import helpers
from message_control import MessageControl
from conversation_textview import ConversationTextview
from message_textview import MessageTextView
from common.logger import Constants
constants = Constants()
try:
import gtkspell
@ -76,6 +78,8 @@ class ChatControlBase(MessageControl):
'underline_togglebutton'):
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
self.conv_textview = ConversationTextview(None) # FIXME: remove account arg
self.conv_textview.show_all()
@ -83,22 +87,21 @@ class ChatControlBase(MessageControl):
self.conv_scrolledwindow.add(self.conv_textview)
self.conv_scrolledwindow.get_vadjustment().connect('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
self.msg_scrolledwindow = self.xml.get_widget('message_scrolledwindow')
self.msg_textview = MessageTextView()
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_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.update_font()
# the following vars are used to keep history of user's messages
self.sent_history = []
self.sent_history_pos = -1
self.sent_history_pos = 0
self.typing_new = False
self.orig_msg = ''
@ -143,34 +146,43 @@ class ChatControlBase(MessageControl):
banner_name_label.modify_fg(gtk.STATE_NORMAL, None)
def on_conversation_textview_key_press_event(self, widget, event):
'''Handle events from the ConversationTextview'''
print "ChatControl.on_conversation_textview_key_press_event", event
def _on_keypress_event(self, widget, event):
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:
self.conv_textview.get_buffer().set_text('')
# CTRL + v
return True
# CTRL + v: Paste into msg_textview
elif event.keyval == gtk.keysyms.v:
if not self.msg_textview.is_focus():
self.msg_textview.grab_focus()
# Paste into the msg textview
self.msg_textview.emit('key_press_event', event)
return False
def on_message_textview_key_press_event(self, widget, event):
print "ChatControl.on_message_textview_key_press_event", event
if event.keyval == gtk.keysyms.Page_Down: # PAGE DOWN
if event.state & gtk.gdk.SHIFT_MASK: # SHIFT + PAGE DOWN
self.conv_textview.emit('key_press_event', event)
elif event.keyval == gtk.keysyms.Page_Up: # PAGE UP
if event.state & gtk.gdk.SHIFT_MASK: # SHIFT + PAGE UP
def _on_message_textview_key_press_event(self, widget, event):
print "_on_message_textview_key_press_event"
if event.state & gtk.gdk.SHIFT_MASK:
# SHIFT + PAGE_[UP|DOWN]: send to conv_textview
if event.keyval == gtk.keysyms.Page_Down or \
event.keyval == gtk.keysyms.Page_Up:
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):
'''When a key is pressed:
if enter is pressed without the shift key, message (if not empty) is sent
and printed in the conversation'''
print "ChatControlBase._on_message_textview_mykeypress_event"
# NOTE: handles mykeypress which is custom signal connected to this
# 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.state & gtk.gdk.CONTROL_MASK: # Ctrl+UP
self.sent_messages_scroll('up', widget.get_buffer())
return
elif event.keyval == gtk.keysyms.Down:
if event.state & gtk.gdk.CONTROL_MASK: # Ctrl+Down
self.sent_messages_scroll('down', widget.get_buffer())
return
elif event.keyval == gtk.keysyms.Return or \
event.keyval == gtk.keysyms.KP_Enter: # ENTER
# NOTE: SHIFT + ENTER is not needed to be emulated as it is not
@ -295,8 +305,8 @@ class ChatControlBase(MessageControl):
self.nb_unread += 1
if gajim.interface.systray_enabled and\
gajim.config.get('trayicon_notification_on_new_messages'):
gajim.interface.systray.add_jid(jid, self.account, self.type)
self.parent_win.redraw_tab(jid)
gajim.interface.systray.add_jid(jid, self.account, self.type_id)
self.parent_win.redraw_tab(self.contact)
self.show_title(urgent)
def toggle_emoticons(self):
@ -419,7 +429,7 @@ class ChatControlBase(MessageControl):
gajim.interface.systray.remove_jid(jid,
self.account,
self.type)
self.conv_textview.grab_focus()
self.msg_textview.grab_focus()
def bring_scroll_to_end(self, textview, diff_y = 0):
''' 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.signal_autoconnect(self)
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.dnd_list = [ ( 'text/uri-list', 0, self.TARGET_TYPE_URI_LIST ) ]
self.widget.connect('drag_data_received', self._on_drag_data_received)
@ -558,8 +567,58 @@ class ChatControl(ChatControlBase):
# chatstate timers and state
self.reset_kbd_mouse_timeout_vars()
self._schedule_activity_timers()
# Hook up signals
# FIXME: This does not seem to be working
self.parent_win.window.connect('motion-notify-event',
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):
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):
''' sends OUR chatstate as STANDLONE chat state message (eg. no body)
to jid only if new chatstate is different
from the previous one
to contact only if new chatstate is different from the previous one
if jid is not specified, send to active tab'''
# JEP 85 does not allow resending the same chatstate
# 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
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 event.button == 3: # right click
self.parent_win.popup_menu(event)
@ -1109,3 +1167,117 @@ class ChatControl(ChatControlBase):
if os.path.isfile(path): # is it file?
ft = gajim.interface.instances['file_transfers']
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)

View File

@ -19081,7 +19081,6 @@ Maybe I'll refactor later</property>
<property name="visible">True</property>
<property name="visible_window">True</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>
<widget class="GtkHBox" id="hbox3004">
@ -19150,8 +19149,8 @@ Status message</property>
<property name="visible">True</property>
<property name="visible_window">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="leave_notify_event" handler="on_avatar_eventbox_leave_notify_event" last_modification_time="Sun, 02 Oct 2005 22:58:52 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="Mon, 02 Jan 2006 23:13:55 GMT"/>
<child>
<widget class="GtkImage" id="avatar_image">

View File

@ -61,6 +61,12 @@ class MessageControl:
or inactive (state is False)'''
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):
# NOTE: Derived classes MUST implement this
assert(False)
@ -92,12 +98,6 @@ class MessageControl:
def set_compact_view(self, state):
# NOTE: Derived classes MAY implement this
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):
'''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):
pass # Derived classes SHOULD implement this
def get_specific_unread(self, jid):
return 0
def send_message(self, message, keyID = '', type = 'chat', chatstate = None):
'''Send the given message to the active tab'''
# refresh timers

View File

@ -20,6 +20,7 @@ import gobject
import common
import gtkgui_helpers
import message_control
from chat_control import ChatControlBase
from common import gajim
@ -47,7 +48,12 @@ class MessageWindow:
# so this line adds that
#self.window.set_events(gtk.gdk.POINTER_MOTION_MASK)
self.alignment = self.xml.get_widget('alignment')
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
while self.notebook.get_n_pages():
@ -72,10 +78,6 @@ class MessageWindow:
else:
self.notebook.set_show_tabs(False)
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
self.window.connect('delete-event', self._on_window_delete)
@ -92,6 +94,8 @@ class MessageWindow:
gajim.config.get('msgwin-width'),
gajim.config.get('msgwin-height'))
self.window.show_all()
def _on_window_focus(self, widget, event):
# 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)
@ -144,13 +148,9 @@ class MessageWindow:
self.alignment.set_property('top-padding', 2)
# Connect to keyboard events
control.widget.connect('key_press_event',
self.on_conversation_textview_key_press_event)
# FIXME: need to get this event without access to message_textvier
#control.widget.connect('mykeypress',
# self.on_message_textview_mykeypress_event)
control.widget.connect('key_press_event',
self.on_message_textview_key_press_event)
if isinstance(control, ChatControlBase):
control.msg_textview.connect('mykeypress',
self._on_message_textview_mykeypress_event)
# Add notebook page and connect up to the tab's close button
xml = gtk.glade.XML(GTKGUI_GLADE, 'chat_tab_ebox', APP)
@ -163,10 +163,11 @@ class MessageWindow:
self.redraw_tab(control.contact)
self.show_title()
control.draw_widgets()
self.window.show_all()
# NOTE: we do not call set_control_active(True) since we don't know whether
# the tab is the active one.
self.show_title()
def on_tab_eventbox_button_press_event(self, widget, event, child):
if event.button == 3:
@ -174,10 +175,8 @@ class MessageWindow:
self.notebook.set_current_page(n)
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):
# FIXME: Not called yet
print "MessageWindow.on_message_textview_mykeypress_event:", event
# NOTE: handles mykeypress which is custom signal; see message_textview.py
# construct event instance from binding
@ -186,26 +185,8 @@ class MessageWindow:
event.state = event_keymod
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:
# Tab switch bindings
if event.keyval == gtk.keysyms.Tab: # CTRL + TAB
self.notebook.emit('key_press_event', event)
elif event.keyval == gtk.keysyms.ISO_Left_Tab: # CTRL + SHIFT + TAB
@ -283,6 +264,7 @@ class MessageWindow:
self.show_title()
def redraw_tab(self, contact, chatstate = None):
print self._controls
ctl = self._controls[contact.jid]
ctl.update_state()
@ -430,7 +412,7 @@ class MessageWindow:
jid = ctl.contact.jid
if jid != self.get_active_jid():
item = gtk.ImageMenuItem(_('Switch to %s') %\
self.names[jid])
ctl.contact.name)
img = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO,
gtk.ICON_SIZE_MENU)
item.set_image(img)
@ -450,24 +432,42 @@ class MessageWindow:
new_ctl.set_control_active(True)
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)
ctl = self.get_active_control()
jid = ctl.jid
if event.keyval == gtk.keysyms.Escape: # ESCAPE
if ctl.type == TYPE_CHAT:
self.remove_tab(jid)
contact = ctl.contact
jid = ctl.contact.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 \
(event.state & gtk.gdk.CONTROL_MASK): # CTRL + F4
self.remove_tab(jid)
self.remove_tab(contact)
elif event.keyval == gtk.keysyms.w and \
(event.state & gtk.gdk.CONTROL_MASK): # CTRL + W
self.remove_tab(jid)
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))
self.remove_tab(contact)
elif event.keyval == gtk.keysyms.c and \
(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
elif event.keyval == gtk.keysyms.e and \
(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())
return (x, y, True) # push_in True
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:
@ -581,7 +527,6 @@ class MessageWindowMgr:
def _new_window(self):
win = MessageWindow()
win.window.show_all()
# we track the lifetime of this window
win.window.connect('destroy', self._on_window_destroy)
return win