[clickable_nicknames] Rewrite plugin
This commit is contained in:
@@ -2,147 +2,116 @@ from gi.repository import Gtk
|
|||||||
from gi.repository import Gdk
|
from gi.repository import Gdk
|
||||||
|
|
||||||
from gajim.common import app
|
from gajim.common import app
|
||||||
|
|
||||||
from gajim.plugins import GajimPlugin
|
from gajim.plugins import GajimPlugin
|
||||||
from gajim.plugins.helpers import log_calls
|
|
||||||
from gajim.plugins.plugins_i18n import _
|
from gajim.plugins.plugins_i18n import _
|
||||||
|
|
||||||
|
from gajim.gtk.util import get_cursor
|
||||||
|
|
||||||
|
|
||||||
class ClickableNicknames(GajimPlugin):
|
class ClickableNicknames(GajimPlugin):
|
||||||
|
|
||||||
@log_calls('ClickableNicknamesPlugin')
|
|
||||||
def init(self):
|
def init(self):
|
||||||
|
# pylint: disable=attribute-defined-outside-init
|
||||||
self.description = _('Clickable nicknames '
|
self.description = _('Clickable nicknames '
|
||||||
'in the conversation textview.')
|
'in the conversation textview.')
|
||||||
self.config_dialog = None
|
self.config_dialog = None
|
||||||
self.gui_extension_points = {
|
self.gui_extension_points = {
|
||||||
'chat_control_base': (self.connect_with_chat_control,
|
'chat_control_base': (self._on_connect_chat_control,
|
||||||
self.disconnect_from_chat_control)}
|
self._on_disconnect_chat_control)}
|
||||||
|
|
||||||
self.is_active = None
|
self._pointer_active = {}
|
||||||
self.gc_controls = {}
|
self._event_ids = {}
|
||||||
|
|
||||||
self.tag_names = []
|
def _on_connect_chat_control(self, control):
|
||||||
colors = app.config.get('gc_nicknames_colors')
|
if not control.type.is_groupchat:
|
||||||
colors = colors.split(':')
|
|
||||||
for i, color in enumerate(colors):
|
|
||||||
tagname = 'gc_nickname_color_' + str(i)
|
|
||||||
self.tag_names.append(tagname)
|
|
||||||
|
|
||||||
@log_calls('ClickableNicknamesPlugin')
|
|
||||||
def activate(self):
|
|
||||||
for gc_control in app.interface.msg_win_mgr.get_controls('gc'):
|
|
||||||
# TODO support minimized groupchat
|
|
||||||
if gc_control not in self.gc_controls.keys():
|
|
||||||
control = Base(self, gc_control)
|
|
||||||
self.gc_controls[gc_control] = control
|
|
||||||
else:
|
|
||||||
self.gc_controls[gc_control].connect_signals()
|
|
||||||
self.is_active = True
|
|
||||||
|
|
||||||
@log_calls('ClickableNicknamesPlugin')
|
|
||||||
def deactivate(self):
|
|
||||||
for control in self.gc_controls.keys():
|
|
||||||
self.gc_controls[control].disconnect_from_chat_control()
|
|
||||||
self.gc_controls.clear()
|
|
||||||
self.is_active = None
|
|
||||||
|
|
||||||
@log_calls('ClickableNicknamesPlugin')
|
|
||||||
def connect_with_chat_control(self, chat_control):
|
|
||||||
if chat_control.widget_name != 'groupchat_control':
|
|
||||||
return
|
return
|
||||||
if self.is_active:
|
|
||||||
control = Base(self, chat_control)
|
|
||||||
self.gc_controls[chat_control] = control
|
|
||||||
|
|
||||||
@log_calls('ClickableNicknamesPlugin')
|
textview = control.conv_textview.tv
|
||||||
def disconnect_from_chat_control(self, chat_control):
|
nickname_tag = self._get_nickname_tag(textview)
|
||||||
pass
|
|
||||||
|
|
||||||
|
tag_table = textview.get_buffer().get_tag_table()
|
||||||
|
tag = tag_table.lookup('nickname')
|
||||||
|
event_id = tag.connect('event',
|
||||||
|
self._on_nickname_clicked,
|
||||||
|
control.msg_textview)
|
||||||
|
|
||||||
class Base(object):
|
motion_id = textview.connect('motion-notify-event',
|
||||||
|
self._on_textview_motion_notify,
|
||||||
|
nickname_tag)
|
||||||
|
|
||||||
def __init__(self, plugin, chat_control):
|
self._event_ids[control.control_id] = (event_id, motion_id)
|
||||||
self.plugin = plugin
|
|
||||||
self.chat_control = chat_control
|
|
||||||
self.textview = self.chat_control.conv_textview
|
|
||||||
self.tags_id = []
|
|
||||||
self.change_cursor = False
|
|
||||||
self.connect_signals()
|
|
||||||
|
|
||||||
def connect_signals(self):
|
def _on_disconnect_chat_control(self, control):
|
||||||
# connect signals with textbuffer tags
|
if not control.type.is_groupchat:
|
||||||
self.tag_names = self.plugin.tag_names
|
return
|
||||||
tag_table = self.textview.tv.get_buffer().get_tag_table()
|
|
||||||
for name in self.tag_names:
|
|
||||||
tag = tag_table.lookup(name)
|
|
||||||
if tag:
|
|
||||||
id_ = tag.connect('event', self.insert_nick, name)
|
|
||||||
self.chat_control.handlers[id_] = tag
|
|
||||||
self.tags_id.append((id_, tag))
|
|
||||||
|
|
||||||
self.id_ = self.textview.tv.connect('motion_notify_event',
|
textview = control.conv_textview.tv
|
||||||
self.on_textview_motion_notify_event)
|
nickname_tag = self._get_nickname_tag(textview)
|
||||||
self.chat_control.handlers[self.id_] = self.textview.tv
|
|
||||||
|
|
||||||
def on_textview_motion_notify_event(self, widget, event):
|
event_id, motion_id = self._event_ids.pop(control.control_id)
|
||||||
# change cursor on the nicks
|
textview.disconnect(motion_id)
|
||||||
pointer_x, pointer_y = self.textview.tv.get_window(
|
nickname_tag.disconnect(event_id)
|
||||||
Gtk.TextWindowType.TEXT).get_pointer()[1:3]
|
self._pointer_active.pop(id(textview), None)
|
||||||
x, y = self.textview.tv.window_to_buffer_coords(Gtk.TextWindowType.TEXT,
|
|
||||||
pointer_x, pointer_y)
|
|
||||||
tags = self.textview.tv.get_iter_at_location(x, y)[1].get_tags()
|
|
||||||
tag_table = self.textview.tv.get_buffer().get_tag_table()
|
|
||||||
if self.change_cursor:
|
|
||||||
self.textview.tv.get_window(Gtk.TextWindowType.TEXT).set_cursor(
|
|
||||||
Gdk.Cursor.new(Gdk.CursorType.XTERM))
|
|
||||||
self.change_cursor = False
|
|
||||||
for tag in tags:
|
|
||||||
if tag in [x[1] for x in self.tags_id]:
|
|
||||||
self.textview.tv.get_window(Gtk.TextWindowType.TEXT).set_cursor(
|
|
||||||
Gdk.Cursor.new(Gdk.CursorType.HAND2))
|
|
||||||
self.change_cursor = True
|
|
||||||
|
|
||||||
def insert_nick(self, texttag, widget, event, iter_, kind):
|
@staticmethod
|
||||||
# insert nickname to message buffer
|
def _get_nickname_tag(textview):
|
||||||
if event.type == Gdk.EventType.BUTTON_PRESS and event.button.button == 1:
|
tag_table = textview.get_buffer().get_tag_table()
|
||||||
# left mouse button clicked
|
return tag_table.lookup('nickname')
|
||||||
begin_iter = iter_.copy()
|
|
||||||
# we get the beginning of the tag
|
|
||||||
while not begin_iter.begins_tag(texttag):
|
|
||||||
begin_iter.backward_char()
|
|
||||||
end_iter = iter_.copy()
|
|
||||||
# we get the end of the tag
|
|
||||||
while not end_iter.ends_tag(texttag):
|
|
||||||
end_iter.forward_char()
|
|
||||||
buffer_ = self.textview.tv.get_buffer()
|
|
||||||
word = buffer_.get_text(begin_iter, end_iter, True)
|
|
||||||
nick = word.rstrip().rstrip(app.config.get('after_nickname'))
|
|
||||||
if nick.startswith('* '):
|
|
||||||
nick = nick.lstrip('* ').split(' ')[0] + ' '
|
|
||||||
nick = nick.lstrip(app.config.get('before_nickname'))
|
|
||||||
nicks = app.contacts.get_nick_list(self.chat_control.account,
|
|
||||||
self.chat_control.room_jid)
|
|
||||||
if nick[:-1] not in nicks:
|
|
||||||
return
|
|
||||||
|
|
||||||
message_buffer = self.chat_control.msg_textview.get_buffer()
|
def _is_pointer_active(self, textview):
|
||||||
# delete PLACEHOLDER
|
return self._pointer_active.get(id(textview), False)
|
||||||
start, end = message_buffer.get_bounds()
|
|
||||||
placeholder = self.chat_control.msg_textview.PLACEHOLDER
|
|
||||||
text = message_buffer.get_text(start, end, False)
|
|
||||||
if text == placeholder or len(text) == 0:
|
|
||||||
message_buffer.set_text('', -1)
|
|
||||||
nick = nick + app.config.get('gc_refer_to_nick_char')
|
|
||||||
elif len(text) > 0 and text[-1] != ' ':
|
|
||||||
nick = ' ' + nick
|
|
||||||
nick += ' '
|
|
||||||
message_buffer.insert_at_cursor(nick)
|
|
||||||
self.chat_control.msg_textview.grab_focus()
|
|
||||||
|
|
||||||
def disconnect_from_chat_control(self):
|
def _set_pointer_state(self, textview, state):
|
||||||
# disconnect signals from textbuffer tags
|
self._pointer_active[id(textview)] = state
|
||||||
for item in self.tags_id:
|
|
||||||
if item[1].handler_is_connected(item[0]):
|
def _on_textview_motion_notify(self, textview, event, nickname_tag):
|
||||||
item[1].disconnect(item[0])
|
window = textview.get_window(Gtk.TextWindowType.TEXT)
|
||||||
if self.textview.tv.handler_is_connected(self.id_):
|
x_pos, y_pos = textview.window_to_buffer_coords(Gtk.TextWindowType.TEXT,
|
||||||
self.textview.tv.disconnect(self.id_)
|
event.x,
|
||||||
|
event.y)
|
||||||
|
|
||||||
|
iter_ = textview.get_iter_at_position(x_pos, y_pos)[1]
|
||||||
|
if iter_.has_tag(nickname_tag):
|
||||||
|
window.set_cursor(get_cursor('pointer'))
|
||||||
|
self._set_pointer_state(textview, True)
|
||||||
|
|
||||||
|
elif self._is_pointer_active(textview):
|
||||||
|
window.set_cursor(get_cursor('default'))
|
||||||
|
self._set_pointer_state(textview, False)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _on_nickname_clicked(text_tag, textview, event, iter_, message_input):
|
||||||
|
if event.type != Gdk.EventType.BUTTON_PRESS:
|
||||||
|
return
|
||||||
|
if event.button.button != 1:
|
||||||
|
return
|
||||||
|
|
||||||
|
start = iter_.copy()
|
||||||
|
end = iter_.copy()
|
||||||
|
|
||||||
|
start.backward_to_tag_toggle(text_tag)
|
||||||
|
end.forward_to_tag_toggle(text_tag)
|
||||||
|
|
||||||
|
nickname = textview.get_buffer().get_text(start, end, False)
|
||||||
|
|
||||||
|
# Remove Space
|
||||||
|
nickname = nickname[:-1]
|
||||||
|
nickname = nickname.rstrip(app.config.get('after_nickname'))
|
||||||
|
# Remove direction mark
|
||||||
|
nickname = nickname[:-3]
|
||||||
|
nickname = nickname.lstrip(app.config.get('before_nickname'))
|
||||||
|
|
||||||
|
message_input.grab_focus()
|
||||||
|
if not message_input.has_text():
|
||||||
|
# There is no text add refer char
|
||||||
|
nickname = '%s%s ' % (nickname,
|
||||||
|
app.config.get('gc_refer_to_nick_char'))
|
||||||
|
else:
|
||||||
|
input_buffer = message_input.get_buffer()
|
||||||
|
start, end = input_buffer.get_bounds()
|
||||||
|
text = input_buffer.get_text(start, end, False)
|
||||||
|
if text[:-1] != ' ':
|
||||||
|
# Add space in front
|
||||||
|
nickname = ' %s' % nickname
|
||||||
|
|
||||||
|
message_input.insert_text(nickname)
|
||||||
|
|||||||
Reference in New Issue
Block a user