make completion work

This commit is contained in:
Yann Leboulanger 2015-07-25 21:40:51 +02:00
parent 62bf23a587
commit 20a0f9c5a6
4 changed files with 50 additions and 259 deletions

View File

@ -216,59 +216,6 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
return
self.print_conversation(_('Error.'), 'status')
def handle_message_textview_mykey_press(self, widget, event_keyval,
event_keymod):
"""
Derives types SHOULD implement this, rather than connection to the even
itself
"""
event = Gdk.Event(Gdk.EventType.KEY_PRESS)
event.keyval = event_keyval
event.state = event_keymod
event.time = 0
_buffer = widget.get_buffer()
start, end = _buffer.get_bounds()
if event.keyval -- Gdk.KEY_Tab:
position = _buffer.get_insert()
end = _buffer.get_iter_at_mark(position)
text = _buffer.get_text(start, end, False)
splitted = text.split()
if (text.startswith(self.COMMAND_PREFIX) and not
text.startswith(self.COMMAND_PREFIX * 2) and len(splitted) == 1):
text = splitted[0]
bare = text.lstrip(self.COMMAND_PREFIX)
if len(text) == 1:
self.command_hits = []
for command in self.list_commands():
for name in command.names:
self.command_hits.append(name)
else:
if (self.last_key_tabs and self.command_hits and
self.command_hits[0].startswith(bare)):
self.command_hits.append(self.command_hits.pop(0))
else:
self.command_hits = []
for command in self.list_commands():
for name in command.names:
if name.startswith(bare):
self.command_hits.append(name)
if self.command_hits:
_buffer.delete(start, end)
_buffer.insert_at_cursor(self.COMMAND_PREFIX + self.command_hits[0] + ' ')
self.last_key_tabs = True
return True
self.last_key_tabs = False
def status_url_clicked(self, widget, url):
helpers.launch_browser_mailer('url', url)
@ -401,9 +348,6 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
# add MessageTextView to UI and connect signals
self.msg_scrolledwindow = self.xml.get_object('message_scrolledwindow')
self.msg_textview = MessageTextView()
id_ = self.msg_textview.connect('mykeypress',
self._on_message_textview_mykeypress_event)
self.handlers[id_] = self.msg_textview
self.msg_scrolledwindow.add(self.msg_textview)
id_ = self.msg_textview.connect('key_press_event',
self._on_message_textview_key_press_event)
@ -708,10 +652,43 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
if event.keyval == Gdk.KEY_Tab: # CTRL + TAB
self.parent_win.move_to_next_unread_tab(True)
return True
################################################################################
# temporary solution instead Gtk.binding_entry_add_signal
message_buffer = self.msg_textview.get_buffer()
event_state = event.get_state()
if event.keyval == Gdk.KEY_Tab:
start, end = message_buffer.get_bounds()
position = message_buffer.get_insert()
end = message_buffer.get_iter_at_mark(position)
text = message_buffer.get_text(start, end, False)
splitted = text.split()
if (text.startswith(self.COMMAND_PREFIX) and not
text.startswith(self.COMMAND_PREFIX * 2) and len(splitted) == 1):
text = splitted[0]
bare = text.lstrip(self.COMMAND_PREFIX)
if len(text) == 1:
self.command_hits = []
for command in self.list_commands():
for name in command.names:
self.command_hits.append(name)
else:
if (self.last_key_tabs and self.command_hits and
self.command_hits[0].startswith(bare)):
self.command_hits.append(self.command_hits.pop(0))
else:
self.command_hits = []
for command in self.list_commands():
for name in command.names:
if name.startswith(bare):
self.command_hits.append(name)
if self.command_hits:
message_buffer.delete(start, end)
message_buffer.insert_at_cursor(self.COMMAND_PREFIX + \
self.command_hits[0] + ' ')
self.last_key_tabs = True
return True
if self.widget_name != 'groupchat_control':
self.last_key_tabs = False
if event.keyval == Gdk.KEY_Up:
if event_state & Gdk.ModifierType.CONTROL_MASK:
if event_state & Gdk.ModifierType.SHIFT_MASK: # Ctrl+Shift+UP
@ -764,81 +741,9 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
if event_state & Gdk.ModifierType.CONTROL_MASK:
self.msg_textview.undo()
return True
################################################################################
return False
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
"""
# NOTE: handles mykeypress which is custom signal connected to this
# CB in new_tab(). for this singal see message_textview.py
message_textview = widget
message_buffer = message_textview.get_buffer()
start_iter, end_iter = message_buffer.get_bounds()
message = message_buffer.get_text(start_iter, end_iter, False)
xhtml = self.msg_textview.get_xhtml()
# construct event instance from binding
event = Gdk.Event(Gdk.EventType.KEY_PRESS) # it's always a key-press here
event.keyval = event_keyval
event.state = event_keymod
event.time = 0 # assign current time
if event.keyval == Gdk.KEY_Up:
if event.get_state() == Gdk.ModifierType.CONTROL_MASK: # Ctrl+UP
self.scroll_messages('up', message_buffer, 'sent')
# Ctrl+Shift+UP
elif event.get_state() == (Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK):
self.scroll_messages('up', message_buffer, 'received')
elif event.keyval == Gdk.KEY_Down:
if event.get_state() == Gdk.ModifierType.CONTROL_MASK: # Ctrl+Down
self.scroll_messages('down', message_buffer, 'sent')
# Ctrl+Shift+Down
elif event.get_state() == (Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK):
self.scroll_messages('down', message_buffer, 'received')
elif event.keyval == Gdk.KEY_Return or \
event.keyval == Gdk.KEY_KP_Enter: # ENTER
# NOTE: SHIFT + ENTER is not needed to be emulated as it is not
# binding at all (textview's default action is newline)
if gajim.config.get('send_on_ctrl_enter'):
# here, we emulate GTK default action on ENTER (add new line)
# normally I would add in keypress but it gets way to complex
# to get instant result on changing this advanced setting
if event.get_state() == 0: # no ctrl, no shift just ENTER add newline
end_iter = message_buffer.get_end_iter()
message_buffer.insert_at_cursor('\n')
send_message = False
elif event.get_state() & Gdk.ModifierType.CONTROL_MASK: # CTRL + ENTER
send_message = True
else: # send on Enter, do newline on Ctrl Enter
if event.get_state() & Gdk.ModifierType.CONTROL_MASK: # Ctrl + ENTER
end_iter = message_buffer.get_end_iter()
message_buffer.insert_at_cursor('\n')
send_message = False
else: # ENTER
send_message = True
if gajim.connections[self.account].connected < 2 and send_message:
# we are not connected
dialogs.ErrorDialog(_('A connection is not available'),
_('Your message can not be sent until you are connected.'),
transient_for=self.parent_win.window)
send_message = False
if send_message:
self.send_message(message, xhtml=xhtml) # send the message
elif event.keyval == Gdk.KEY_z: # CTRL+z
if event.get_state() & Gdk.ModifierType.CONTROL_MASK:
self.msg_textview.undo()
else:
# Give the control itself a chance to process
self.handle_message_textview_mykey_press(widget, event_keyval,
event_keymod)
def _on_drag_data_received(self, widget, context, x, y, selection,
target_type, timestamp):
"""

View File

@ -2290,39 +2290,21 @@ class GroupchatControl(ChatControlBase):
self.print_conversation(_('%(jid)s has been invited in this room') % {
'jid': contact_jid}, graphics=False)
def handle_message_textview_mykey_press(self, widget, event_keyval,
event_keymod):
# NOTE: handles mykeypress which is custom signal connected to this
# CB in new_room(). for this singal see message_textview.py
if not widget.get_sensitive():
# Textview is not sensitive, don't handle keypress
return
# construct event instance from binding
event = Gdk.Event(Gdk.EventType.KEY_PRESS) # it's always a key-press here
event.keyval = event_keyval
event.state = event_keymod
event.time = 0 # assign current time
message_buffer = widget.get_buffer()
start_iter, end_iter = message_buffer.get_bounds()
def _on_message_textview_key_press_event(self, widget, event):
res = ChatControlBase._on_message_textview_key_press_event(self, widget,
event)
if res:
return True
if event.keyval == Gdk.KEY_Tab: # TAB
message_buffer = widget.get_buffer()
start_iter, end_iter = message_buffer.get_bounds()
cursor_position = message_buffer.get_insert()
end_iter = message_buffer.get_iter_at_mark(cursor_position)
text = message_buffer.get_text(start_iter, end_iter, False).decode(
'utf-8')
text = message_buffer.get_text(start_iter, end_iter, False)
splitted_text = text.split()
# HACK: Not the best soltution.
if (text.startswith(self.COMMAND_PREFIX) and not
text.startswith(self.COMMAND_PREFIX * 2) and \
len(splitted_text) == 1):
return super(GroupchatControl, self).\
handle_message_textview_mykey_press(widget, event_keyval,
event_keymod)
# nick completion
# check if tab is pressed with empty message
if len(splitted_text): # if there are any words
@ -2340,7 +2322,7 @@ class GroupchatControl(ChatControlBase):
with_refer_to_nick_char = True
after_nick_len = len(gc_refer_to_nick_char + ' ')
if len(self.nick_hits) and self.last_key_tabs and \
text[:-after_nick_len].endswith(self.nick_hits[0]):
text[:-after_nick_len].endswith(self.nick_hits[0]):
# we should cycle
# Previous nick in list may had a space inside, so we check text
# and not splitted_text and store it into 'begin' var
@ -2349,7 +2331,7 @@ class GroupchatControl(ChatControlBase):
else:
self.nick_hits = [] # clear the hit list
list_nick = gajim.contacts.get_nick_list(self.account,
self.room_jid)
self.room_jid)
list_nick.sort(key=str.lower) # case-insensitive sort
if begin == '':
# empty message, show lasts nicks that highlighted us first
@ -2362,7 +2344,7 @@ class GroupchatControl(ChatControlBase):
for nick in list_nick:
fjid = self.room_jid + '/' + nick
if nick.lower().startswith(begin.lower()) and not \
helpers.jid_is_blocked(self.account, fjid):
helpers.jid_is_blocked(self.account, fjid):
# the word is the begining of a nick
self.nick_hits.append(nick)
if len(self.nick_hits):
@ -2374,17 +2356,17 @@ class GroupchatControl(ChatControlBase):
add = ' '
start_iter = end_iter.copy()
if self.last_key_tabs and with_refer_to_nick_char or (text and \
text[-1] == ' '):
text[-1] == ' '):
# have to accomodate for the added space from last
# completion
# gc_refer_to_nick_char may be more than one char!
start_iter.backward_chars(len(begin) + len(add))
elif self.last_key_tabs and not gajim.config.get(
'shell_like_completion'):
'shell_like_completion'):
# have to accomodate for the added space from last
# completion
start_iter.backward_chars(len(begin) + \
len(gc_refer_to_nick_char))
len(gc_refer_to_nick_char))
else:
start_iter.backward_chars(len(begin))

View File

@ -38,12 +38,6 @@ class MessageTextView(Gtk.TextView):
chat/groupchat windows
"""
UNDO_LIMIT = 20
__gsignals__ = dict(
mykeypress = (GObject.SignalFlags.RUN_LAST | GObject.SignalFlags.ACTION,
None, # return value
(int, Gdk.ModifierType ) # arguments
)
)
def __init__(self):
GObject.GObject.__init__(self)
@ -316,72 +310,3 @@ class MessageTextView(Gtk.TextView):
return super(MessageTextView, self).get_sensitive()
except AttributeError:
return self.get_property('sensitive')
# We register depending on keysym and modifier some bindings
# but we also pass those as param so we can construct fake Event
# Here we register bindings for those combinations that there is NO DEFAULT
# action to be done by gtk TextView. In such case we should not add a binding
# as the default action comes first and our bindings is useless. In that case
# we catch and do stuff before default action in normal key_press_event
# and we also return True there to stop the default action from running
# CTRL + SHIFT + TAB
#Gtk.binding_entry_add_signal(MessageTextView, Gdk.KEY_ISO_Left_Tab,
#Gdk.ModifierType.CONTROL_MASK, 'mykeypress', int, Gdk.KEY_ISO_Left_Tab,
#Gdk.ModifierType, Gdk.ModifierType.CONTROL_MASK)
## CTRL + TAB
#Gtk.binding_entry_add_signal(MessageTextView, Gdk.KEY_Tab,
#Gdk.ModifierType.CONTROL_MASK, 'mykeypress', int, Gdk.KEY_Tab,
#Gdk.ModifierType, Gdk.ModifierType.CONTROL_MASK)
## TAB
#Gtk.binding_entry_add_signal(MessageTextView, Gdk.KEY_Tab,
#0, 'mykeypress', int, Gdk.KEY_Tab, Gdk.ModifierType, 0)
## CTRL + UP
#Gtk.binding_entry_add_signal(MessageTextView, Gdk.KEY_Up,
#Gdk.ModifierType.CONTROL_MASK, 'mykeypress', int, Gdk.KEY_Up,
#Gdk.ModifierType, Gdk.ModifierType.CONTROL_MASK)
## CTRL + DOWN
#Gtk.binding_entry_add_signal(MessageTextView, Gdk.KEY_Down,
#Gdk.ModifierType.CONTROL_MASK, 'mykeypress', int, Gdk.KEY_Down,
#Gdk.ModifierType, Gdk.ModifierType.CONTROL_MASK)
## CTRL + SHIFT + UP
#Gtk.binding_entry_add_signal(MessageTextView, Gdk.KEY_Up,
#Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK, 'mykeypress', int,
#Gdk.KEY_Up, Gdk.ModifierType, Gdk.ModifierType.CONTROL_MASK |
#Gdk.ModifierType.SHIFT_MASK)
## CTRL + SHIFT + DOWN
#Gtk.binding_entry_add_signal(MessageTextView, Gdk.KEY_Down,
#Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK, 'mykeypress', int,
#Gdk.KEY_Down, Gdk.ModifierType, Gdk.ModifierType.CONTROL_MASK |
#Gdk.ModifierType.SHIFT_MASK)
## ENTER
#Gtk.binding_entry_add_signal(MessageTextView, Gdk.KEY_Return,
#0, 'mykeypress', int, Gdk.KEY_Return,
#Gdk.ModifierType, 0)
## Ctrl + Enter
#Gtk.binding_entry_add_signal(MessageTextView, Gdk.KEY_Return,
#Gdk.ModifierType.CONTROL_MASK, 'mykeypress', int, Gdk.KEY_Return,
#Gdk.ModifierType, Gdk.ModifierType.CONTROL_MASK)
## Keypad Enter
#Gtk.binding_entry_add_signal(MessageTextView, Gdk.KEY_KP_Enter,
#0, 'mykeypress', int, Gdk.KEY_KP_Enter,
#Gdk.ModifierType, 0)
## Ctrl + Keypad Enter
#Gtk.binding_entry_add_signal(MessageTextView, Gdk.KEY_KP_Enter,
#Gdk.ModifierType.CONTROL_MASK, 'mykeypress', int, Gdk.KEY_KP_Enter,
#Gdk.ModifierType, Gdk.ModifierType.CONTROL_MASK)
## Ctrl + z
#Gtk.binding_entry_add_signal(MessageTextView, Gdk.KEY_z,
#Gdk.ModifierType.CONTROL_MASK, 'mykeypress', int, Gdk.KEY_z,
#Gdk.ModifierType, Gdk.ModifierType.CONTROL_MASK)

View File

@ -329,27 +329,6 @@ class MessageWindow(object):
ctrl = self._widget_to_control(child)
GLib.idle_add(ctrl.msg_textview.grab_focus)
def _on_message_textview_mykeypress_event(self, widget, event_keyval,
event_keymod):
# NOTE: handles mykeypress which is custom signal; see message_textview.py
# construct event instance from binding
event = Gdk.Event(Gdk.EventType.KEY_PRESS) # it's always a key-press here
event.keyval = event_keyval
event.state = event_keymod
event.time = 0 # assign current time
if event.get_state() & Gdk.ModifierType.CONTROL_MASK:
# Tab switch bindings
if event.keyval == Gdk.KEY_Tab: # CTRL + TAB
self.move_to_next_unread_tab(True)
elif event.keyval == Gdk.KEY_ISO_Left_Tab: # CTRL + SHIFT + TAB
self.move_to_next_unread_tab(False)
elif event.keyval == Gdk.KEY_Page_Down: # CTRL + PAGE DOWN
self.notebook.event(event)
elif event.keyval == Gdk.KEY_Page_Up: # CTRL + PAGE UP
self.notebook.event(event)
def accel_group_func(self, accel_group, acceleratable, keyval, modifier):
st = '1234567890' # alt+1 means the first tab (tab 0)
control = self.get_active_control()