Refactor link context menu
- Move hyperlink handling into HtmlTextView - Use actions on the menuitems
This commit is contained in:
parent
4077e0d6d6
commit
06302cdc4d
|
@ -14,6 +14,9 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from gi.repository import Gtk
|
||||||
|
from gi.repository import Gdk
|
||||||
|
|
||||||
from gajim.common import app
|
from gajim.common import app
|
||||||
from gajim.common import helpers
|
from gajim.common import helpers
|
||||||
from gajim.common.app import interface
|
from gajim.common.app import interface
|
||||||
|
@ -130,24 +133,29 @@ def on_service_disco(action, param):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def on_join_gc(action, param):
|
def on_join_gc(_action, param):
|
||||||
account = None
|
account, jid = None, None
|
||||||
if param is None:
|
if param is None:
|
||||||
if not app.get_connected_accounts():
|
if not app.get_connected_accounts():
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
account = param.get_string()
|
account, jid = param.get_strv()
|
||||||
|
if not jid:
|
||||||
|
jid = None
|
||||||
window = app.get_app_window(JoinGroupchatWindow)
|
window = app.get_app_window(JoinGroupchatWindow)
|
||||||
if window is None:
|
if window is None:
|
||||||
JoinGroupchatWindow(account, None)
|
JoinGroupchatWindow(account, jid)
|
||||||
else:
|
else:
|
||||||
window.present()
|
window.present()
|
||||||
|
|
||||||
|
|
||||||
def on_add_contact(action, param):
|
def on_add_contact(_action, param):
|
||||||
window = app.get_app_window(AddNewContactWindow)
|
account, jid = param.get_strv()
|
||||||
|
if not jid:
|
||||||
|
jid = None
|
||||||
|
window = app.get_app_window(AddNewContactWindow, account)
|
||||||
if window is None:
|
if window is None:
|
||||||
AddNewContactWindow(param.get_string())
|
AddNewContactWindow(account, jid)
|
||||||
else:
|
else:
|
||||||
window.present()
|
window.present()
|
||||||
|
|
||||||
|
@ -337,3 +345,25 @@ def show_next_pending_event(action, param):
|
||||||
if not event:
|
if not event:
|
||||||
return
|
return
|
||||||
app.interface.handle_event(account, jid, event.type_)
|
app.interface.handle_event(account, jid, event.type_)
|
||||||
|
|
||||||
|
|
||||||
|
def open_link(_action, param):
|
||||||
|
kind, link = param.get_strv()
|
||||||
|
helpers.launch_browser_mailer(kind, link)
|
||||||
|
|
||||||
|
|
||||||
|
def copy_link(_action, param):
|
||||||
|
text = param.get_string()
|
||||||
|
clip = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
|
||||||
|
clip.set_text(text, -1)
|
||||||
|
|
||||||
|
|
||||||
|
def start_chat(_action, param):
|
||||||
|
account, jid = param.get_strv()
|
||||||
|
app.interface.new_chat_from_jid(account, jid)
|
||||||
|
|
||||||
|
|
||||||
|
def join_groupchat(_action, param):
|
||||||
|
account, jid = param.get_strv()
|
||||||
|
room_jid = jid.split('?')[0]
|
||||||
|
app.interface.join_gc_minimal(account, room_jid)
|
||||||
|
|
|
@ -363,6 +363,14 @@ class GajimApplication(Gtk.Application):
|
||||||
act.connect("activate", app_actions.on_add_contact_jid)
|
act.connect("activate", app_actions.on_add_contact_jid)
|
||||||
self.add_action(act)
|
self.add_action(act)
|
||||||
|
|
||||||
|
act = Gio.SimpleAction.new('copy-link', GLib.VariantType.new('s'))
|
||||||
|
act.connect("activate", app_actions.copy_link)
|
||||||
|
self.add_action(act)
|
||||||
|
|
||||||
|
act = Gio.SimpleAction.new('open-link', GLib.VariantType.new('as'))
|
||||||
|
act.connect("activate", app_actions.open_link)
|
||||||
|
self.add_action(act)
|
||||||
|
|
||||||
for action in general_actions:
|
for action in general_actions:
|
||||||
action_name, func = action
|
action_name, func = action
|
||||||
act = Gio.SimpleAction.new(action_name, None)
|
act = Gio.SimpleAction.new(action_name, None)
|
||||||
|
@ -388,8 +396,9 @@ class GajimApplication(Gtk.Application):
|
||||||
|
|
||||||
return [
|
return [
|
||||||
('-start-single-chat', a.on_single_message, 'online', 's'),
|
('-start-single-chat', a.on_single_message, 'online', 's'),
|
||||||
('-join-groupchat', a.on_join_gc, 'online', 's'),
|
('-start-chat', a.start_chat, 'online', 'as'),
|
||||||
('-add-contact', a.on_add_contact, 'online', 's'),
|
('-join-groupchat', a.on_join_gc, 'online', 'as'),
|
||||||
|
('-add-contact', a.on_add_contact, 'online', 'as'),
|
||||||
('-services', a.on_service_disco, 'online', 's'),
|
('-services', a.on_service_disco, 'online', 's'),
|
||||||
('-profile', a.on_profile, 'feature', 's'),
|
('-profile', a.on_profile, 'feature', 's'),
|
||||||
('-xml-console', a.on_xml_console, 'always', 's'),
|
('-xml-console', a.on_xml_console, 'always', 's'),
|
||||||
|
|
|
@ -23,21 +23,20 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import queue
|
||||||
|
import urllib
|
||||||
|
import logging
|
||||||
|
from calendar import timegm
|
||||||
|
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
from gi.repository import Gdk
|
|
||||||
from gi.repository import Pango
|
from gi.repository import Pango
|
||||||
from gi.repository import GObject
|
from gi.repository import GObject
|
||||||
from gi.repository import GLib
|
from gi.repository import GLib
|
||||||
import time
|
|
||||||
import os
|
|
||||||
|
|
||||||
import queue
|
|
||||||
import urllib
|
|
||||||
|
|
||||||
from gajim.gtk import AddNewContactWindow
|
|
||||||
from gajim.gtk import util
|
from gajim.gtk import util
|
||||||
from gajim.gtk.util import load_icon
|
from gajim.gtk.util import load_icon
|
||||||
from gajim.gtk.util import get_builder
|
|
||||||
from gajim.gtk.util import get_cursor
|
from gajim.gtk.util import get_cursor
|
||||||
from gajim.gtk.emoji_data import emoji_pixbufs
|
from gajim.gtk.emoji_data import emoji_pixbufs
|
||||||
from gajim.gtk.emoji_data import is_emoji
|
from gajim.gtk.emoji_data import is_emoji
|
||||||
|
@ -45,7 +44,7 @@ from gajim.gtk.emoji_data import get_emoji_pixbuf
|
||||||
from gajim.common import app
|
from gajim.common import app
|
||||||
from gajim.common import helpers
|
from gajim.common import helpers
|
||||||
from gajim.common import i18n
|
from gajim.common import i18n
|
||||||
from calendar import timegm
|
|
||||||
from gajim.common.fuzzyclock import FuzzyClock
|
from gajim.common.fuzzyclock import FuzzyClock
|
||||||
from gajim.common.const import StyleAttr
|
from gajim.common.const import StyleAttr
|
||||||
|
|
||||||
|
@ -55,7 +54,6 @@ NOT_SHOWN = 0
|
||||||
ALREADY_RECEIVED = 1
|
ALREADY_RECEIVED = 1
|
||||||
SHOWN = 2
|
SHOWN = 2
|
||||||
|
|
||||||
import logging
|
|
||||||
log = logging.getLogger('gajim.conversation_textview')
|
log = logging.getLogger('gajim.conversation_textview')
|
||||||
|
|
||||||
def is_selection_modified(mark):
|
def is_selection_modified(mark):
|
||||||
|
@ -172,10 +170,7 @@ class ConversationTextview(GObject.GObject):
|
||||||
self.fc = FuzzyClock()
|
self.fc = FuzzyClock()
|
||||||
|
|
||||||
# no need to inherit TextView, use it as atrribute is safer
|
# no need to inherit TextView, use it as atrribute is safer
|
||||||
self.tv = HtmlTextView()
|
self.tv = HtmlTextView(account)
|
||||||
# we have to override HtmlTextView Event handlers
|
|
||||||
# because we don't inherit
|
|
||||||
self.tv.hyperlink_handler = self.hyperlink_handler
|
|
||||||
self.tv.connect_tooltip(self.query_tooltip)
|
self.tv.connect_tooltip(self.query_tooltip)
|
||||||
|
|
||||||
# set properties
|
# set properties
|
||||||
|
@ -658,146 +653,6 @@ class ConversationTextview(GObject.GObject):
|
||||||
finish_sel.forward_word_end()
|
finish_sel.forward_word_end()
|
||||||
self.selected_phrase = buffer_.get_text(start_sel, finish_sel, True)
|
self.selected_phrase = buffer_.get_text(start_sel, finish_sel, True)
|
||||||
|
|
||||||
def on_open_link_activate(self, widget, kind, text):
|
|
||||||
helpers.launch_browser_mailer(kind, text)
|
|
||||||
|
|
||||||
def on_copy_link_activate(self, widget, text):
|
|
||||||
clip = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
|
|
||||||
clip.set_text(text, -1)
|
|
||||||
|
|
||||||
def on_start_chat_activate(self, widget, jid):
|
|
||||||
app.interface.new_chat_from_jid(self.account, jid)
|
|
||||||
|
|
||||||
def on_join_group_chat_menuitem_activate(self, widget, room_jid):
|
|
||||||
# Remove ?join
|
|
||||||
room_jid = room_jid.split('?')[0]
|
|
||||||
app.interface.join_gc_minimal(self.account, room_jid)
|
|
||||||
|
|
||||||
def on_add_to_roster_activate(self, widget, jid):
|
|
||||||
AddNewContactWindow(self.account, jid)
|
|
||||||
|
|
||||||
def make_link_menu(self, event, kind, text):
|
|
||||||
xml = get_builder('chat_context_menu.ui')
|
|
||||||
menu = xml.get_object('chat_context_menu')
|
|
||||||
childs = menu.get_children()
|
|
||||||
if kind == 'url':
|
|
||||||
id_ = childs[0].connect('activate', self.on_copy_link_activate, text)
|
|
||||||
self.handlers[id_] = childs[0]
|
|
||||||
id_ = childs[1].connect('activate', self.on_open_link_activate, kind,
|
|
||||||
text)
|
|
||||||
self.handlers[id_] = childs[1]
|
|
||||||
childs[2].hide() # copy mail/jid address
|
|
||||||
childs[3].hide() # open mail composer
|
|
||||||
childs[4].hide() # jid section separator
|
|
||||||
childs[5].hide() # start chat
|
|
||||||
childs[6].hide() # join group chat
|
|
||||||
childs[7].hide() # add to roster
|
|
||||||
else: # It's a mail or a JID
|
|
||||||
text = text.lower()
|
|
||||||
if text.startswith('xmpp:'):
|
|
||||||
text = text[5:]
|
|
||||||
id_ = childs[2].connect('activate', self.on_copy_link_activate, text)
|
|
||||||
self.handlers[id_] = childs[2]
|
|
||||||
id_ = childs[3].connect('activate', self.on_open_link_activate, kind,
|
|
||||||
text)
|
|
||||||
self.handlers[id_] = childs[3]
|
|
||||||
id_ = childs[5].connect('activate', self.on_start_chat_activate, text)
|
|
||||||
self.handlers[id_] = childs[5]
|
|
||||||
id_ = childs[6].connect('activate',
|
|
||||||
self.on_join_group_chat_menuitem_activate, text)
|
|
||||||
self.handlers[id_] = childs[6]
|
|
||||||
|
|
||||||
if self.account and app.connections[self.account].\
|
|
||||||
roster_supported:
|
|
||||||
id_ = childs[7].connect('activate',
|
|
||||||
self.on_add_to_roster_activate, text)
|
|
||||||
self.handlers[id_] = childs[7]
|
|
||||||
childs[7].show() # show add to roster menuitem
|
|
||||||
else:
|
|
||||||
childs[7].hide() # hide add to roster menuitem
|
|
||||||
|
|
||||||
if kind == 'xmpp':
|
|
||||||
id_ = childs[0].connect('activate', self.on_copy_link_activate,
|
|
||||||
'xmpp:' + text)
|
|
||||||
self.handlers[id_] = childs[0]
|
|
||||||
childs[0].set_label(_('Copy JID'))
|
|
||||||
childs[2].hide() # copy mail/jid address
|
|
||||||
childs[3].hide() # open mail composer
|
|
||||||
childs[4].hide() # jid section separator
|
|
||||||
elif kind == 'mail':
|
|
||||||
childs[2].set_label(_('Copy Email Address'))
|
|
||||||
childs[4].hide() # jid section separator
|
|
||||||
childs[5].hide() # start chat
|
|
||||||
childs[6].hide() # join group chat
|
|
||||||
childs[7].hide() # add to roster
|
|
||||||
|
|
||||||
if kind != 'xmpp':
|
|
||||||
childs[0].hide() # copy link location
|
|
||||||
childs[1].hide() # open link in browser
|
|
||||||
|
|
||||||
menu.attach_to_widget(self.tv, None)
|
|
||||||
menu.popup(None, None, None, None, event.button.button, event.time)
|
|
||||||
|
|
||||||
def hyperlink_handler(self, texttag, widget, event, iter_, kind):
|
|
||||||
if event.type == Gdk.EventType.BUTTON_PRESS:
|
|
||||||
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()
|
|
||||||
|
|
||||||
# Detect XHTML-IM link
|
|
||||||
word = getattr(texttag, 'href', None)
|
|
||||||
if word:
|
|
||||||
if word.startswith('xmpp'):
|
|
||||||
kind = 'xmpp'
|
|
||||||
elif word.startswith('mailto:'):
|
|
||||||
kind = 'mail'
|
|
||||||
elif app.interface.sth_at_sth_dot_sth_re.match(word):
|
|
||||||
# it's a JID or mail
|
|
||||||
kind = 'sth_at_sth'
|
|
||||||
else:
|
|
||||||
word = self.tv.get_buffer().get_text(begin_iter, end_iter, True)
|
|
||||||
|
|
||||||
if event.button.button == 3: # right click
|
|
||||||
self.make_link_menu(event, kind, word)
|
|
||||||
return True
|
|
||||||
|
|
||||||
self.plugin_modified = False
|
|
||||||
app.plugin_manager.extension_point(
|
|
||||||
'hyperlink_handler', word, kind, self,
|
|
||||||
self.tv.get_toplevel())
|
|
||||||
if self.plugin_modified:
|
|
||||||
return
|
|
||||||
|
|
||||||
# we launch the correct application
|
|
||||||
if kind == 'xmpp':
|
|
||||||
word = word[5:]
|
|
||||||
if '?' in word:
|
|
||||||
(jid, action) = word.split('?')
|
|
||||||
if action == 'join':
|
|
||||||
app.interface.join_gc_minimal(self.account, jid)
|
|
||||||
else:
|
|
||||||
self.on_start_chat_activate(None, jid)
|
|
||||||
else:
|
|
||||||
self.on_start_chat_activate(None, word)
|
|
||||||
# handle geo:-URIs
|
|
||||||
elif word[:4] == 'geo:':
|
|
||||||
location = word[4:]
|
|
||||||
lat, _, lon = location.partition(',')
|
|
||||||
if lon == '':
|
|
||||||
return
|
|
||||||
uri = 'https://www.openstreetmap.org/?' \
|
|
||||||
'mlat=%(lat)s&mlon=%(lon)s&zoom=16' % \
|
|
||||||
{'lat': lat, 'lon': lon}
|
|
||||||
helpers.launch_browser_mailer(kind, uri)
|
|
||||||
# other URIs
|
|
||||||
else:
|
|
||||||
helpers.launch_browser_mailer(kind, word)
|
|
||||||
|
|
||||||
def detect_and_print_special_text(self, otext, other_tags, graphics=True,
|
def detect_and_print_special_text(self, otext, other_tags, graphics=True,
|
||||||
iter_=None, additional_data=None):
|
iter_=None, additional_data=None):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!-- Generated with glade 3.18.3 -->
|
|
||||||
<interface>
|
|
||||||
<requires lib="gtk+" version="3.12"/>
|
|
||||||
<object class="GtkMenu" id="chat_context_menu">
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkMenuItem" id="copy_link_location_menuitem">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="label" translatable="yes">_Copy Link Location</property>
|
|
||||||
<property name="use_underline">True</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkMenuItem" id="open_link_in_browser_menuitem">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="label" translatable="yes">_Open Link in Browser</property>
|
|
||||||
<property name="use_underline">True</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkMenuItem" id="copy_email_address_menuitem">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="label" translatable="yes">_Copy JID/Email Address</property>
|
|
||||||
<property name="use_underline">True</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkMenuItem" id="open_email_composer_menuitem">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="label" translatable="yes">_Open Email Composer</property>
|
|
||||||
<property name="use_underline">True</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkSeparatorMenuItem" id="jid_section_separator">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkMenuItem" id="start_chat_menuitem">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="label" translatable="yes">_Start Chat</property>
|
|
||||||
<property name="use_underline">True</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkMenuItem" id="join_group_chat_menuitem">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="label" translatable="yes">Join _Group Chat</property>
|
|
||||||
<property name="use_underline">True</property>
|
|
||||||
<signal name="activate" handler="on_join_group_chat_menuitem_activate" swapped="no"/>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkMenuItem" id="add_to_roster_menuitem">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="label" translatable="yes">_Add to Roster...</property>
|
|
||||||
<property name="use_underline">True</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</interface>
|
|
|
@ -675,7 +675,7 @@ def get_bookmarks_menu(account, rebuild=False):
|
||||||
# Build Join Groupchat
|
# Build Join Groupchat
|
||||||
action = 'app.{}-join-groupchat'.format(account)
|
action = 'app.{}-join-groupchat'.format(account)
|
||||||
menuitem = Gio.MenuItem.new(_('Join Group Chat'), action)
|
menuitem = Gio.MenuItem.new(_('Join Group Chat'), action)
|
||||||
variant = GLib.Variant('s', account)
|
variant = GLib.Variant('as', [account, ''])
|
||||||
menuitem.set_action_and_target_value(action, variant)
|
menuitem.set_action_and_target_value(action, variant)
|
||||||
menu.append_item(menuitem)
|
menu.append_item(menuitem)
|
||||||
|
|
||||||
|
@ -749,7 +749,10 @@ def get_account_menu(account):
|
||||||
continue
|
continue
|
||||||
action = 'app.{}{}'.format(account, action)
|
action = 'app.{}{}'.format(account, action)
|
||||||
menuitem = Gio.MenuItem.new(label, action)
|
menuitem = Gio.MenuItem.new(label, action)
|
||||||
variant = GLib.Variant('s', account)
|
if 'add_contact' in action:
|
||||||
|
variant = GLib.Variant('as', [account, ''])
|
||||||
|
else:
|
||||||
|
variant = GLib.Variant('s', account)
|
||||||
menuitem.set_action_and_target_value(action, variant)
|
menuitem.set_action_and_target_value(action, variant)
|
||||||
menu.append_item(menuitem)
|
menu.append_item(menuitem)
|
||||||
else:
|
else:
|
||||||
|
@ -840,6 +843,75 @@ def get_encryption_menu(control_id, type_id, zeroconf=False):
|
||||||
return menu
|
return menu
|
||||||
|
|
||||||
|
|
||||||
|
def get_conv_context_menu(account, kind, text):
|
||||||
|
if kind == 'xmpp':
|
||||||
|
if '?join' in text:
|
||||||
|
context_menu = [
|
||||||
|
('copy-link', _('Copy JID')),
|
||||||
|
('-join-groupchat', _('Join Groupchat')),
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
context_menu = [
|
||||||
|
('copy-link', _('Copy JID')),
|
||||||
|
('-start-chat', _('Start Chat')),
|
||||||
|
('-add-contact', _('Add to Roster…')),
|
||||||
|
]
|
||||||
|
|
||||||
|
elif kind == 'url':
|
||||||
|
context_menu = [
|
||||||
|
('copy-link', _('Copy Link Location')),
|
||||||
|
('open-link', _('Open Link in Browser')),
|
||||||
|
]
|
||||||
|
|
||||||
|
elif kind == 'mail':
|
||||||
|
context_menu = [
|
||||||
|
('copy-link', _('Copy Email Address')),
|
||||||
|
('open-link', _('Open Email Composer')),
|
||||||
|
]
|
||||||
|
|
||||||
|
elif kind == 'sth_at_sth':
|
||||||
|
context_menu = [
|
||||||
|
('copy-link', _('Copy JID/Email')),
|
||||||
|
('open-link', _('Open Email Composer')),
|
||||||
|
('-start-chat', _('Start Chat')),
|
||||||
|
('-join-groupchat', _('Join Groupchat')),
|
||||||
|
('-add-contact', _('Add to Roster…')),
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
menu = Gtk.Menu()
|
||||||
|
for item in context_menu:
|
||||||
|
action, label = item
|
||||||
|
menuitem = Gtk.MenuItem()
|
||||||
|
menuitem.set_label(label)
|
||||||
|
|
||||||
|
if action.startswith('-'):
|
||||||
|
action = 'app.%s%s' % (account, action)
|
||||||
|
else:
|
||||||
|
action = 'app.%s' % action
|
||||||
|
menuitem.set_action_name(action)
|
||||||
|
|
||||||
|
if 'join-groupchat' in action:
|
||||||
|
text = text.replace('xmpp:', '')
|
||||||
|
text = text.split('?')[0]
|
||||||
|
|
||||||
|
if 'add-contact' in action:
|
||||||
|
text = text.replace('xmpp:', '')
|
||||||
|
text = text.split('?')[0]
|
||||||
|
|
||||||
|
if action == 'app.open-link':
|
||||||
|
value = GLib.Variant.new_strv([kind, text])
|
||||||
|
elif action == 'app.copy-link':
|
||||||
|
value = GLib.Variant.new_string(text)
|
||||||
|
else:
|
||||||
|
value = GLib.Variant.new_strv([account, text])
|
||||||
|
menuitem.set_action_target_value(value)
|
||||||
|
menuitem.show()
|
||||||
|
menu.append(menuitem)
|
||||||
|
return menu
|
||||||
|
|
||||||
|
|
||||||
def escape_mnemonic(label):
|
def escape_mnemonic(label):
|
||||||
if label is None:
|
if label is None:
|
||||||
return
|
return
|
||||||
|
|
|
@ -43,16 +43,16 @@ from gi.repository import Pango
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
from gi.repository import Gdk
|
from gi.repository import Gdk
|
||||||
from gi.repository import GdkPixbuf
|
from gi.repository import GdkPixbuf
|
||||||
|
from gi.repository import GLib
|
||||||
|
|
||||||
from gajim.common import app
|
from gajim.common import app
|
||||||
from gajim.common import helpers
|
from gajim.common import helpers
|
||||||
from gajim.common.i18n import _
|
from gajim.common.i18n import _
|
||||||
from gajim.common.const import StyleAttr
|
from gajim.common.const import StyleAttr
|
||||||
from gajim.gtk import JoinGroupchatWindow
|
|
||||||
from gajim.gtk import AddNewContactWindow
|
|
||||||
from gajim.gtk.util import load_icon
|
from gajim.gtk.util import load_icon
|
||||||
from gajim.gtk.util import get_cursor
|
from gajim.gtk.util import get_cursor
|
||||||
from gajim.gtk.util import get_builder
|
|
||||||
|
from gajim.gui_menu_builder import get_conv_context_menu
|
||||||
|
|
||||||
log = logging.getLogger('gajim.htmlview')
|
log = logging.getLogger('gajim.htmlview')
|
||||||
|
|
||||||
|
@ -825,7 +825,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
||||||
|
|
||||||
class HtmlTextView(Gtk.TextView):
|
class HtmlTextView(Gtk.TextView):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, account=None):
|
||||||
Gtk.TextView.__init__(self)
|
Gtk.TextView.__init__(self)
|
||||||
self.set_wrap_mode(Gtk.WrapMode.CHAR)
|
self.set_wrap_mode(Gtk.WrapMode.CHAR)
|
||||||
self.set_editable(False)
|
self.set_editable(False)
|
||||||
|
@ -835,11 +835,12 @@ class HtmlTextView(Gtk.TextView):
|
||||||
self.connect('unrealize', self.on_html_text_view_unrealized)
|
self.connect('unrealize', self.on_html_text_view_unrealized)
|
||||||
self.connect('copy-clipboard', self.on_html_text_view_copy_clipboard)
|
self.connect('copy-clipboard', self.on_html_text_view_copy_clipboard)
|
||||||
self.id_ = self.connect('button-release-event',
|
self.id_ = self.connect('button-release-event',
|
||||||
self.on_left_mouse_button_release)
|
self.on_left_mouse_button_release)
|
||||||
self.get_buffer().eol_tag = self.get_buffer().create_tag('eol')
|
self.get_buffer().eol_tag = self.get_buffer().create_tag('eol')
|
||||||
self.config = app.config
|
self.config = app.config
|
||||||
self.interface = app.interface
|
self.interface = app.interface
|
||||||
# end big hack
|
self.account = account
|
||||||
|
self.plugin_modified = False
|
||||||
|
|
||||||
def connect_tooltip(self, func=None):
|
def connect_tooltip(self, func=None):
|
||||||
self.connect('query-tooltip', func or self.__query_tooltip)
|
self.connect('query-tooltip', func or self.__query_tooltip)
|
||||||
|
@ -892,73 +893,21 @@ class HtmlTextView(Gtk.TextView):
|
||||||
self._changed_cursor = False
|
self._changed_cursor = False
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def on_open_link_activate(self, widget, kind, text):
|
def show_context_menu(self, _event, kind, text):
|
||||||
helpers.launch_browser_mailer(kind, text)
|
menu = get_conv_context_menu(self.account, kind, text)
|
||||||
|
if menu is None:
|
||||||
|
return
|
||||||
|
|
||||||
def on_copy_link_activate(self, widget, text):
|
def destroy(menu, pspec):
|
||||||
clip = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
|
visible = menu.get_property('visible')
|
||||||
clip.set_text(text, -1)
|
if not visible:
|
||||||
|
GLib.idle_add(menu.destroy)
|
||||||
|
|
||||||
# def on_start_chat_activate(self, widget, jid):
|
menu.attach_to_widget(self, None)
|
||||||
# app.interface.new_chat_from_jid(self.account, jid)
|
menu.connect('notify::visible', destroy)
|
||||||
|
menu.popup_at_pointer()
|
||||||
|
|
||||||
def on_join_group_chat_menuitem_activate(self, widget, room_jid):
|
def hyperlink_handler(self, texttag, _widget, event, iter_, kind):
|
||||||
JoinGroupchatWindow(None, room_jid)
|
|
||||||
|
|
||||||
def on_add_to_roster_activate(self, widget, jid):
|
|
||||||
AddNewContactWindow(self.account, jid)
|
|
||||||
|
|
||||||
def make_link_menu(self, event, kind, text):
|
|
||||||
ui = get_builder('chat_context_menu.ui')
|
|
||||||
menu = ui.get_object('chat_context_menu')
|
|
||||||
childs = menu.get_children()
|
|
||||||
if kind == 'url':
|
|
||||||
childs[0].connect('activate', self.on_copy_link_activate, text)
|
|
||||||
childs[1].connect('activate', self.on_open_link_activate, kind,
|
|
||||||
text)
|
|
||||||
childs[2].hide() # copy mail address
|
|
||||||
childs[3].hide() # open mail composer
|
|
||||||
childs[4].hide() # jid section separator
|
|
||||||
childs[5].hide() # start chat
|
|
||||||
childs[6].hide() # join group chat
|
|
||||||
childs[7].hide() # add to roster
|
|
||||||
else: # It's a mail or a JID
|
|
||||||
text = text.lower()
|
|
||||||
if text.startswith('xmpp:'):
|
|
||||||
text = text[5:]
|
|
||||||
childs[2].connect('activate', self.on_copy_link_activate, text)
|
|
||||||
childs[3].connect('activate', self.on_open_link_activate, kind,
|
|
||||||
text)
|
|
||||||
# childs[5].connect('activate', self.on_start_chat_activate, text)
|
|
||||||
childs[6].connect('activate',
|
|
||||||
self.on_join_group_chat_menuitem_activate, text)
|
|
||||||
|
|
||||||
# if self.account and app.connections[self.account].\
|
|
||||||
# roster_supported:
|
|
||||||
# childs[7].connect('activate',
|
|
||||||
# self.on_add_to_roster_activate, text)
|
|
||||||
# childs[7].show() # show add to roster menuitem
|
|
||||||
# else:
|
|
||||||
# childs[7].hide() # hide add to roster menuitem
|
|
||||||
|
|
||||||
if kind == 'xmpp':
|
|
||||||
childs[0].connect('activate', self.on_copy_link_activate,
|
|
||||||
'xmpp:' + text)
|
|
||||||
childs[2].hide() # copy mail address
|
|
||||||
childs[3].hide() # open mail composer
|
|
||||||
elif kind == 'mail':
|
|
||||||
childs[6].hide() # join group chat
|
|
||||||
|
|
||||||
if kind != 'xmpp':
|
|
||||||
childs[0].hide() # copy link location
|
|
||||||
childs[1].hide() # open link in browser
|
|
||||||
childs[4].hide() # jid section separator
|
|
||||||
childs[5].hide() # start chat
|
|
||||||
childs[7].hide() # add to roster
|
|
||||||
|
|
||||||
menu.popup(None, None, None, event.button, event.time)
|
|
||||||
|
|
||||||
def hyperlink_handler(self, texttag, widget, event, iter_, kind):
|
|
||||||
if event.type == Gdk.EventType.BUTTON_PRESS:
|
if event.type == Gdk.EventType.BUTTON_PRESS:
|
||||||
begin_iter = iter_.copy()
|
begin_iter = iter_.copy()
|
||||||
# we get the beginning of the tag
|
# we get the beginning of the tag
|
||||||
|
@ -980,31 +929,45 @@ class HtmlTextView(Gtk.TextView):
|
||||||
# it's a JID or mail
|
# it's a JID or mail
|
||||||
kind = 'sth_at_sth'
|
kind = 'sth_at_sth'
|
||||||
else:
|
else:
|
||||||
word = self.textview.get_buffer().get_text(begin_iter,
|
word = self.get_buffer().get_text(begin_iter, end_iter, True)
|
||||||
end_iter)
|
|
||||||
|
|
||||||
if event.button == 3: # right click
|
if event.button.button == 3: # right click
|
||||||
self.make_link_menu(event, kind, word)
|
self.show_context_menu(event, kind, word)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
self.plugin_modified = False
|
||||||
|
app.plugin_manager.extension_point(
|
||||||
|
'hyperlink_handler', word, kind, self,
|
||||||
|
self.get_toplevel())
|
||||||
|
if self.plugin_modified:
|
||||||
|
return
|
||||||
|
|
||||||
# we launch the correct application
|
# we launch the correct application
|
||||||
if kind == 'xmpp':
|
if kind == 'xmpp':
|
||||||
word = word[5:]
|
word = word[5:]
|
||||||
if '?' in word:
|
if '?' in word:
|
||||||
(jid, action) = word.split('?')
|
(jid, action) = word.split('?')
|
||||||
if action == 'join':
|
if action == 'join':
|
||||||
self.on_join_group_chat_menuitem_activate(None, jid)
|
app.interface.join_gc_minimal(self.account, jid)
|
||||||
else:
|
else:
|
||||||
self.on_start_chat_activate(None, jid)
|
app.interface.new_chat_from_jid(self.account, jid)
|
||||||
else:
|
else:
|
||||||
self.on_start_chat_activate(None, word)
|
app.interface.new_chat_from_jid(self.account, word)
|
||||||
|
|
||||||
|
# handle geo:-URIs
|
||||||
|
elif word[:4] == 'geo:':
|
||||||
|
location = word[4:]
|
||||||
|
lat, _, lon = location.partition(',')
|
||||||
|
if lon == '':
|
||||||
|
return
|
||||||
|
uri = 'https://www.openstreetmap.org/?' \
|
||||||
|
'mlat=%(lat)s&mlon=%(lon)s&zoom=16' % \
|
||||||
|
{'lat': lat, 'lon': lon}
|
||||||
|
helpers.launch_browser_mailer(kind, uri)
|
||||||
|
# other URIs
|
||||||
else:
|
else:
|
||||||
helpers.launch_browser_mailer(kind, word)
|
helpers.launch_browser_mailer(kind, word)
|
||||||
|
|
||||||
def _hyperlink_handler(self, texttag, widget, event, iter_, kind):
|
|
||||||
# self.hyperlink_handler can be overwritten, so call it when needed
|
|
||||||
self.hyperlink_handler(texttag, widget, event, iter_, kind)
|
|
||||||
|
|
||||||
def display_html(self, html, textview, conv_textview, iter_=None):
|
def display_html(self, html, textview, conv_textview, iter_=None):
|
||||||
buffer_ = self.get_buffer()
|
buffer_ = self.get_buffer()
|
||||||
if iter_:
|
if iter_:
|
||||||
|
|
|
@ -3679,7 +3679,7 @@ class RosterWindow:
|
||||||
When the join gc menuitem is clicked, show the join gc window
|
When the join gc menuitem is clicked, show the join gc window
|
||||||
"""
|
"""
|
||||||
app.app.activate_action('%s-join-groupchat' % account,
|
app.app.activate_action('%s-join-groupchat' % account,
|
||||||
GLib.Variant('s', account))
|
GLib.Variant('as', [account, '']))
|
||||||
|
|
||||||
def on_show_transports_action(self, action, param):
|
def on_show_transports_action(self, action, param):
|
||||||
app.config.set('show_transports_group', param.get_boolean())
|
app.config.set('show_transports_group', param.get_boolean())
|
||||||
|
|
Loading…
Reference in New Issue