diff --git a/src/chat_control.py b/src/chat_control.py index d0b7d600d..f4089906b 100644 --- a/src/chat_control.py +++ b/src/chat_control.py @@ -230,7 +230,11 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools): helpers.launch_browser_mailer('url', url) def __init__(self, type_id, parent_win, widget_name, contact, acct, - resource = None): + resource=None): + # Undo needs this variable to know if space has been pressed. + # Initialize it to True so empty textview is saved in undo list + self.space_pressed = True + if resource is None: # We very likely got a contact with a random resource. # This is bad, we need the highest for caps etc. @@ -426,6 +430,11 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools): spell.set_language(lang) widget.set_active(True) + item = gtk.ImageMenuItem(gtk.STOCK_UNDO) + menu.prepend(item) + id_ = item.connect('activate', self.msg_textview.undo) + self.handlers[id_] = item + item = gtk.SeparatorMenuItem() menu.prepend(item) @@ -586,6 +595,20 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools): set_emoticons_menu_position, 1, 0) def _on_message_textview_key_press_event(self, widget, event): + if event.keyval == gtk.keysyms.space: + self.space_pressed = True + + elif (self.space_pressed or self.msg_textview.undo_pressed) and \ + event.keyval not in (gtk.keysyms.Control_L, gtk.keysyms.Control_R) and \ + not (event.keyval == gtk.keysyms.z and event.state & gtk.gdk.CONTROL_MASK): + # If the space key has been pressed and now it hasnt, + # we save the buffer into the undo list. But be carefull we're not + # pressiong Control again (as in ctrl+z) + _buffer = widget.get_buffer() + start_iter, end_iter = _buffer.get_bounds() + self.msg_textview.save_undo(_buffer.get_text(start_iter, end_iter)) + self.space_pressed = False + # Ctrl [+ Shift] + Tab are not forwarded to notebook. We handle it here if self.widget_name == 'groupchat_control': if event.keyval not in (gtk.keysyms.ISO_Left_Tab, gtk.keysyms.Tab): @@ -608,7 +631,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools): return False def _on_message_textview_mykeypress_event(self, widget, event_keyval, - event_keymod): + 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 @@ -665,6 +688,9 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools): if send_message: self.send_message(message, xhtml=xhtml) # send the message + elif event.keyval == gtk.keysyms.z: # CTRL+z + if event.state & gtk.gdk.CONTROL_MASK: + self.msg_textview.undo() else: # Give the control itself a chance to process self.handle_message_textview_mykey_press(widget, event_keyval, diff --git a/src/message_textview.py b/src/message_textview.py index ca9368244..37c865043 100644 --- a/src/message_textview.py +++ b/src/message_textview.py @@ -35,6 +35,7 @@ class MessageTextView(gtk.TextView): Class for the message textview (where user writes new messages) for chat/groupchat windows """ + UNDO_LIMIT = 20 __gsignals__ = dict( mykeypress = (gobject.SIGNAL_RUN_LAST | gobject.SIGNAL_ACTION, None, # return value @@ -56,6 +57,10 @@ class MessageTextView(gtk.TextView): self.set_pixels_above_lines(2) self.set_pixels_below_lines(2) + # set undo list + self.undo_list = [] + # needed to know if we undid something + self.undo_pressed = False self.lang = None # Lang used for spell checking _buffer = self.get_buffer() self.begin_tags = {} @@ -287,6 +292,20 @@ class MessageTextView(gtk.TextView): start, end = _buffer.get_bounds() _buffer.delete(start, end) + def save_undo(self, text): + self.undo_list.append(text) + if len(self.undo_list) > self.UNDO_LIMIT: + del self.undo_list[0] + self.undo_pressed = False + + def undo(self, widget=None): + """ + Undo text in the textview + """ + _buffer = self.get_buffer() + if self.undo_list: + _buffer.set_text(self.undo_list.pop()) + self.undo_pressed = True # We register depending on keysym and modifier some bindings # but we also pass those as param so we can construct fake Event @@ -340,4 +359,8 @@ gtk.binding_entry_add_signal(MessageTextView, gtk.keysyms.KP_Enter, gtk.gdk.CONTROL_MASK, 'mykeypress', int, gtk.keysyms.KP_Enter, gtk.gdk.ModifierType, gtk.gdk.CONTROL_MASK) +# Ctrl + z +gtk.binding_entry_add_signal(MessageTextView, gtk.keysyms.z, + gtk.gdk.CONTROL_MASK, 'mykeypress', int, gtk.keysyms.z, + gtk.gdk.ModifierType, gtk.gdk.CONTROL_MASK) # vim: se ts=3: