Philipp Hörist pushed to branch master at gajim / gajim
Commits:
-
06302cdc
by Philipp Hörist at 2018-09-22T11:35:07Z
7 changed files:
- gajim/app_actions.py
- gajim/application.py
- gajim/conversation_textview.py
- − gajim/data/gui/chat_context_menu.ui
- gajim/gui_menu_builder.py
- gajim/htmltextview.py
- gajim/roster_window.py
Changes:
| ... | ... | @@ -14,6 +14,9 @@ |
| 14 | 14 |
# You should have received a copy of the GNU General Public License
|
| 15 | 15 |
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
| 16 | 16 |
|
| 17 |
+from gi.repository import Gtk
|
|
| 18 |
+from gi.repository import Gdk
|
|
| 19 |
+ |
|
| 17 | 20 |
from gajim.common import app
|
| 18 | 21 |
from gajim.common import helpers
|
| 19 | 22 |
from gajim.common.app import interface
|
| ... | ... | @@ -130,24 +133,29 @@ def on_service_disco(action, param): |
| 130 | 133 |
pass
|
| 131 | 134 |
|
| 132 | 135 |
|
| 133 |
-def on_join_gc(action, param):
|
|
| 134 |
- account = None
|
|
| 136 |
+def on_join_gc(_action, param):
|
|
| 137 |
+ account, jid = None, None
|
|
| 135 | 138 |
if param is None:
|
| 136 | 139 |
if not app.get_connected_accounts():
|
| 137 | 140 |
return
|
| 138 | 141 |
else:
|
| 139 |
- account = param.get_string()
|
|
| 142 |
+ account, jid = param.get_strv()
|
|
| 143 |
+ if not jid:
|
|
| 144 |
+ jid = None
|
|
| 140 | 145 |
window = app.get_app_window(JoinGroupchatWindow)
|
| 141 | 146 |
if window is None:
|
| 142 |
- JoinGroupchatWindow(account, None)
|
|
| 147 |
+ JoinGroupchatWindow(account, jid)
|
|
| 143 | 148 |
else:
|
| 144 | 149 |
window.present()
|
| 145 | 150 |
|
| 146 | 151 |
|
| 147 |
-def on_add_contact(action, param):
|
|
| 148 |
- window = app.get_app_window(AddNewContactWindow)
|
|
| 152 |
+def on_add_contact(_action, param):
|
|
| 153 |
+ account, jid = param.get_strv()
|
|
| 154 |
+ if not jid:
|
|
| 155 |
+ jid = None
|
|
| 156 |
+ window = app.get_app_window(AddNewContactWindow, account)
|
|
| 149 | 157 |
if window is None:
|
| 150 |
- AddNewContactWindow(param.get_string())
|
|
| 158 |
+ AddNewContactWindow(account, jid)
|
|
| 151 | 159 |
else:
|
| 152 | 160 |
window.present()
|
| 153 | 161 |
|
| ... | ... | @@ -337,3 +345,25 @@ def show_next_pending_event(action, param): |
| 337 | 345 |
if not event:
|
| 338 | 346 |
return
|
| 339 | 347 |
app.interface.handle_event(account, jid, event.type_)
|
| 348 |
+ |
|
| 349 |
+ |
|
| 350 |
+def open_link(_action, param):
|
|
| 351 |
+ kind, link = param.get_strv()
|
|
| 352 |
+ helpers.launch_browser_mailer(kind, link)
|
|
| 353 |
+ |
|
| 354 |
+ |
|
| 355 |
+def copy_link(_action, param):
|
|
| 356 |
+ text = param.get_string()
|
|
| 357 |
+ clip = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
|
|
| 358 |
+ clip.set_text(text, -1)
|
|
| 359 |
+ |
|
| 360 |
+ |
|
| 361 |
+def start_chat(_action, param):
|
|
| 362 |
+ account, jid = param.get_strv()
|
|
| 363 |
+ app.interface.new_chat_from_jid(account, jid)
|
|
| 364 |
+ |
|
| 365 |
+ |
|
| 366 |
+def join_groupchat(_action, param):
|
|
| 367 |
+ account, jid = param.get_strv()
|
|
| 368 |
+ room_jid = jid.split('?')[0]
|
|
| 369 |
+ app.interface.join_gc_minimal(account, room_jid)
|
| ... | ... | @@ -363,6 +363,14 @@ class GajimApplication(Gtk.Application): |
| 363 | 363 |
act.connect("activate", app_actions.on_add_contact_jid)
|
| 364 | 364 |
self.add_action(act)
|
| 365 | 365 |
|
| 366 |
+ act = Gio.SimpleAction.new('copy-link', GLib.VariantType.new('s'))
|
|
| 367 |
+ act.connect("activate", app_actions.copy_link)
|
|
| 368 |
+ self.add_action(act)
|
|
| 369 |
+ |
|
| 370 |
+ act = Gio.SimpleAction.new('open-link', GLib.VariantType.new('as'))
|
|
| 371 |
+ act.connect("activate", app_actions.open_link)
|
|
| 372 |
+ self.add_action(act)
|
|
| 373 |
+ |
|
| 366 | 374 |
for action in general_actions:
|
| 367 | 375 |
action_name, func = action
|
| 368 | 376 |
act = Gio.SimpleAction.new(action_name, None)
|
| ... | ... | @@ -388,8 +396,9 @@ class GajimApplication(Gtk.Application): |
| 388 | 396 |
|
| 389 | 397 |
return [
|
| 390 | 398 |
('-start-single-chat', a.on_single_message, 'online', 's'),
|
| 391 |
- ('-join-groupchat', a.on_join_gc, 'online', 's'),
|
|
| 392 |
- ('-add-contact', a.on_add_contact, 'online', 's'),
|
|
| 399 |
+ ('-start-chat', a.start_chat, 'online', 'as'),
|
|
| 400 |
+ ('-join-groupchat', a.on_join_gc, 'online', 'as'),
|
|
| 401 |
+ ('-add-contact', a.on_add_contact, 'online', 'as'),
|
|
| 393 | 402 |
('-services', a.on_service_disco, 'online', 's'),
|
| 394 | 403 |
('-profile', a.on_profile, 'feature', 's'),
|
| 395 | 404 |
('-xml-console', a.on_xml_console, 'always', 's'),
|
| ... | ... | @@ -23,21 +23,20 @@ |
| 23 | 23 |
# You should have received a copy of the GNU General Public License
|
| 24 | 24 |
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
| 25 | 25 |
|
| 26 |
-from gi.repository import Gtk
|
|
| 27 |
-from gi.repository import Gdk
|
|
| 28 |
-from gi.repository import Pango
|
|
| 29 |
-from gi.repository import GObject
|
|
| 30 |
-from gi.repository import GLib
|
|
| 31 | 26 |
import time
|
| 32 | 27 |
import os
|
| 33 |
- |
|
| 34 | 28 |
import queue
|
| 35 | 29 |
import urllib
|
| 30 |
+import logging
|
|
| 31 |
+from calendar import timegm
|
|
| 32 |
+ |
|
| 33 |
+from gi.repository import Gtk
|
|
| 34 |
+from gi.repository import Pango
|
|
| 35 |
+from gi.repository import GObject
|
|
| 36 |
+from gi.repository import GLib
|
|
| 36 | 37 |
|
| 37 |
-from gajim.gtk import AddNewContactWindow
|
|
| 38 | 38 |
from gajim.gtk import util
|
| 39 | 39 |
from gajim.gtk.util import load_icon
|
| 40 |
-from gajim.gtk.util import get_builder
|
|
| 41 | 40 |
from gajim.gtk.util import get_cursor
|
| 42 | 41 |
from gajim.gtk.emoji_data import emoji_pixbufs
|
| 43 | 42 |
from gajim.gtk.emoji_data import is_emoji
|
| ... | ... | @@ -45,7 +44,7 @@ from gajim.gtk.emoji_data import get_emoji_pixbuf |
| 45 | 44 |
from gajim.common import app
|
| 46 | 45 |
from gajim.common import helpers
|
| 47 | 46 |
from gajim.common import i18n
|
| 48 |
-from calendar import timegm
|
|
| 47 |
+ |
|
| 49 | 48 |
from gajim.common.fuzzyclock import FuzzyClock
|
| 50 | 49 |
from gajim.common.const import StyleAttr
|
| 51 | 50 |
|
| ... | ... | @@ -55,7 +54,6 @@ NOT_SHOWN = 0 |
| 55 | 54 |
ALREADY_RECEIVED = 1
|
| 56 | 55 |
SHOWN = 2
|
| 57 | 56 |
|
| 58 |
-import logging
|
|
| 59 | 57 |
log = logging.getLogger('gajim.conversation_textview')
|
| 60 | 58 |
|
| 61 | 59 |
def is_selection_modified(mark):
|
| ... | ... | @@ -172,10 +170,7 @@ class ConversationTextview(GObject.GObject): |
| 172 | 170 |
self.fc = FuzzyClock()
|
| 173 | 171 |
|
| 174 | 172 |
# no need to inherit TextView, use it as atrribute is safer
|
| 175 |
- self.tv = HtmlTextView()
|
|
| 176 |
- # we have to override HtmlTextView Event handlers
|
|
| 177 |
- # because we don't inherit
|
|
| 178 |
- self.tv.hyperlink_handler = self.hyperlink_handler
|
|
| 173 |
+ self.tv = HtmlTextView(account)
|
|
| 179 | 174 |
self.tv.connect_tooltip(self.query_tooltip)
|
| 180 | 175 |
|
| 181 | 176 |
# set properties
|
| ... | ... | @@ -658,146 +653,6 @@ class ConversationTextview(GObject.GObject): |
| 658 | 653 |
finish_sel.forward_word_end()
|
| 659 | 654 |
self.selected_phrase = buffer_.get_text(start_sel, finish_sel, True)
|
| 660 | 655 |
|
| 661 |
- def on_open_link_activate(self, widget, kind, text):
|
|
| 662 |
- helpers.launch_browser_mailer(kind, text)
|
|
| 663 |
- |
|
| 664 |
- def on_copy_link_activate(self, widget, text):
|
|
| 665 |
- clip = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
|
|
| 666 |
- clip.set_text(text, -1)
|
|
| 667 |
- |
|
| 668 |
- def on_start_chat_activate(self, widget, jid):
|
|
| 669 |
- app.interface.new_chat_from_jid(self.account, jid)
|
|
| 670 |
- |
|
| 671 |
- def on_join_group_chat_menuitem_activate(self, widget, room_jid):
|
|
| 672 |
- # Remove ?join
|
|
| 673 |
- room_jid = room_jid.split('?')[0]
|
|
| 674 |
- app.interface.join_gc_minimal(self.account, room_jid)
|
|
| 675 |
- |
|
| 676 |
- def on_add_to_roster_activate(self, widget, jid):
|
|
| 677 |
- AddNewContactWindow(self.account, jid)
|
|
| 678 |
- |
|
| 679 |
- def make_link_menu(self, event, kind, text):
|
|
| 680 |
- xml = get_builder('chat_context_menu.ui')
|
|
| 681 |
- menu = xml.get_object('chat_context_menu')
|
|
| 682 |
- childs = menu.get_children()
|
|
| 683 |
- if kind == 'url':
|
|
| 684 |
- id_ = childs[0].connect('activate', self.on_copy_link_activate, text)
|
|
| 685 |
- self.handlers[id_] = childs[0]
|
|
| 686 |
- id_ = childs[1].connect('activate', self.on_open_link_activate, kind,
|
|
| 687 |
- text)
|
|
| 688 |
- self.handlers[id_] = childs[1]
|
|
| 689 |
- childs[2].hide() # copy mail/jid address
|
|
| 690 |
- childs[3].hide() # open mail composer
|
|
| 691 |
- childs[4].hide() # jid section separator
|
|
| 692 |
- childs[5].hide() # start chat
|
|
| 693 |
- childs[6].hide() # join group chat
|
|
| 694 |
- childs[7].hide() # add to roster
|
|
| 695 |
- else: # It's a mail or a JID
|
|
| 696 |
- text = text.lower()
|
|
| 697 |
- if text.startswith('xmpp:'):
|
|
| 698 |
- text = text[5:]
|
|
| 699 |
- id_ = childs[2].connect('activate', self.on_copy_link_activate, text)
|
|
| 700 |
- self.handlers[id_] = childs[2]
|
|
| 701 |
- id_ = childs[3].connect('activate', self.on_open_link_activate, kind,
|
|
| 702 |
- text)
|
|
| 703 |
- self.handlers[id_] = childs[3]
|
|
| 704 |
- id_ = childs[5].connect('activate', self.on_start_chat_activate, text)
|
|
| 705 |
- self.handlers[id_] = childs[5]
|
|
| 706 |
- id_ = childs[6].connect('activate',
|
|
| 707 |
- self.on_join_group_chat_menuitem_activate, text)
|
|
| 708 |
- self.handlers[id_] = childs[6]
|
|
| 709 |
- |
|
| 710 |
- if self.account and app.connections[self.account].\
|
|
| 711 |
- roster_supported:
|
|
| 712 |
- id_ = childs[7].connect('activate',
|
|
| 713 |
- self.on_add_to_roster_activate, text)
|
|
| 714 |
- self.handlers[id_] = childs[7]
|
|
| 715 |
- childs[7].show() # show add to roster menuitem
|
|
| 716 |
- else:
|
|
| 717 |
- childs[7].hide() # hide add to roster menuitem
|
|
| 718 |
- |
|
| 719 |
- if kind == 'xmpp':
|
|
| 720 |
- id_ = childs[0].connect('activate', self.on_copy_link_activate,
|
|
| 721 |
- 'xmpp:' + text)
|
|
| 722 |
- self.handlers[id_] = childs[0]
|
|
| 723 |
- childs[0].set_label(_('Copy JID'))
|
|
| 724 |
- childs[2].hide() # copy mail/jid address
|
|
| 725 |
- childs[3].hide() # open mail composer
|
|
| 726 |
- childs[4].hide() # jid section separator
|
|
| 727 |
- elif kind == 'mail':
|
|
| 728 |
- childs[2].set_label(_('Copy Email Address'))
|
|
| 729 |
- childs[4].hide() # jid section separator
|
|
| 730 |
- childs[5].hide() # start chat
|
|
| 731 |
- childs[6].hide() # join group chat
|
|
| 732 |
- childs[7].hide() # add to roster
|
|
| 733 |
- |
|
| 734 |
- if kind != 'xmpp':
|
|
| 735 |
- childs[0].hide() # copy link location
|
|
| 736 |
- childs[1].hide() # open link in browser
|
|
| 737 |
- |
|
| 738 |
- menu.attach_to_widget(self.tv, None)
|
|
| 739 |
- menu.popup(None, None, None, None, event.button.button, event.time)
|
|
| 740 |
- |
|
| 741 |
- def hyperlink_handler(self, texttag, widget, event, iter_, kind):
|
|
| 742 |
- if event.type == Gdk.EventType.BUTTON_PRESS:
|
|
| 743 |
- begin_iter = iter_.copy()
|
|
| 744 |
- # we get the beginning of the tag
|
|
| 745 |
- while not begin_iter.begins_tag(texttag):
|
|
| 746 |
- begin_iter.backward_char()
|
|
| 747 |
- end_iter = iter_.copy()
|
|
| 748 |
- # we get the end of the tag
|
|
| 749 |
- while not end_iter.ends_tag(texttag):
|
|
| 750 |
- end_iter.forward_char()
|
|
| 751 |
- |
|
| 752 |
- # Detect XHTML-IM link
|
|
| 753 |
- word = getattr(texttag, 'href', None)
|
|
| 754 |
- if word:
|
|
| 755 |
- if word.startswith('xmpp'):
|
|
| 756 |
- kind = 'xmpp'
|
|
| 757 |
- elif word.startswith('mailto:'):
|
|
| 758 |
- kind = 'mail'
|
|
| 759 |
- elif app.interface.sth_at_sth_dot_sth_re.match(word):
|
|
| 760 |
- # it's a JID or mail
|
|
| 761 |
- kind = 'sth_at_sth'
|
|
| 762 |
- else:
|
|
| 763 |
- word = self.tv.get_buffer().get_text(begin_iter, end_iter, True)
|
|
| 764 |
- |
|
| 765 |
- if event.button.button == 3: # right click
|
|
| 766 |
- self.make_link_menu(event, kind, word)
|
|
| 767 |
- return True
|
|
| 768 |
- |
|
| 769 |
- self.plugin_modified = False
|
|
| 770 |
- app.plugin_manager.extension_point(
|
|
| 771 |
- 'hyperlink_handler', word, kind, self,
|
|
| 772 |
- self.tv.get_toplevel())
|
|
| 773 |
- if self.plugin_modified:
|
|
| 774 |
- return
|
|
| 775 |
- |
|
| 776 |
- # we launch the correct application
|
|
| 777 |
- if kind == 'xmpp':
|
|
| 778 |
- word = word[5:]
|
|
| 779 |
- if '?' in word:
|
|
| 780 |
- (jid, action) = word.split('?')
|
|
| 781 |
- if action == 'join':
|
|
| 782 |
- app.interface.join_gc_minimal(self.account, jid)
|
|
| 783 |
- else:
|
|
| 784 |
- self.on_start_chat_activate(None, jid)
|
|
| 785 |
- else:
|
|
| 786 |
- self.on_start_chat_activate(None, word)
|
|
| 787 |
- # handle geo:-URIs
|
|
| 788 |
- elif word[:4] == 'geo:':
|
|
| 789 |
- location = word[4:]
|
|
| 790 |
- lat, _, lon = location.partition(',')
|
|
| 791 |
- if lon == '':
|
|
| 792 |
- return
|
|
| 793 |
- uri = 'https://www.openstreetmap.org/?' \
|
|
| 794 |
- 'mlat=%(lat)s&mlon=%(lon)s&zoom=16' % \
|
|
| 795 |
- {'lat': lat, 'lon': lon}
|
|
| 796 |
- helpers.launch_browser_mailer(kind, uri)
|
|
| 797 |
- # other URIs
|
|
| 798 |
- else:
|
|
| 799 |
- helpers.launch_browser_mailer(kind, word)
|
|
| 800 |
- |
|
| 801 | 656 |
def detect_and_print_special_text(self, otext, other_tags, graphics=True,
|
| 802 | 657 |
iter_=None, additional_data=None):
|
| 803 | 658 |
"""
|
| 1 |
-<?xml version="1.0" encoding="UTF-8"?>
|
|
| 2 |
-<!-- Generated with glade 3.18.3 -->
|
|
| 3 |
-<interface>
|
|
| 4 |
- <requires lib="gtk+" version="3.12"/>
|
|
| 5 |
- <object class="GtkMenu" id="chat_context_menu">
|
|
| 6 |
- <property name="can_focus">False</property>
|
|
| 7 |
- <child>
|
|
| 8 |
- <object class="GtkMenuItem" id="copy_link_location_menuitem">
|
|
| 9 |
- <property name="visible">True</property>
|
|
| 10 |
- <property name="can_focus">False</property>
|
|
| 11 |
- <property name="label" translatable="yes">_Copy Link Location</property>
|
|
| 12 |
- <property name="use_underline">True</property>
|
|
| 13 |
- </object>
|
|
| 14 |
- </child>
|
|
| 15 |
- <child>
|
|
| 16 |
- <object class="GtkMenuItem" id="open_link_in_browser_menuitem">
|
|
| 17 |
- <property name="visible">True</property>
|
|
| 18 |
- <property name="can_focus">False</property>
|
|
| 19 |
- <property name="label" translatable="yes">_Open Link in Browser</property>
|
|
| 20 |
- <property name="use_underline">True</property>
|
|
| 21 |
- </object>
|
|
| 22 |
- </child>
|
|
| 23 |
- <child>
|
|
| 24 |
- <object class="GtkMenuItem" id="copy_email_address_menuitem">
|
|
| 25 |
- <property name="visible">True</property>
|
|
| 26 |
- <property name="can_focus">False</property>
|
|
| 27 |
- <property name="label" translatable="yes">_Copy JID/Email Address</property>
|
|
| 28 |
- <property name="use_underline">True</property>
|
|
| 29 |
- </object>
|
|
| 30 |
- </child>
|
|
| 31 |
- <child>
|
|
| 32 |
- <object class="GtkMenuItem" id="open_email_composer_menuitem">
|
|
| 33 |
- <property name="visible">True</property>
|
|
| 34 |
- <property name="can_focus">False</property>
|
|
| 35 |
- <property name="label" translatable="yes">_Open Email Composer</property>
|
|
| 36 |
- <property name="use_underline">True</property>
|
|
| 37 |
- </object>
|
|
| 38 |
- </child>
|
|
| 39 |
- <child>
|
|
| 40 |
- <object class="GtkSeparatorMenuItem" id="jid_section_separator">
|
|
| 41 |
- <property name="visible">True</property>
|
|
| 42 |
- <property name="can_focus">False</property>
|
|
| 43 |
- </object>
|
|
| 44 |
- </child>
|
|
| 45 |
- <child>
|
|
| 46 |
- <object class="GtkMenuItem" id="start_chat_menuitem">
|
|
| 47 |
- <property name="visible">True</property>
|
|
| 48 |
- <property name="can_focus">False</property>
|
|
| 49 |
- <property name="label" translatable="yes">_Start Chat</property>
|
|
| 50 |
- <property name="use_underline">True</property>
|
|
| 51 |
- </object>
|
|
| 52 |
- </child>
|
|
| 53 |
- <child>
|
|
| 54 |
- <object class="GtkMenuItem" id="join_group_chat_menuitem">
|
|
| 55 |
- <property name="visible">True</property>
|
|
| 56 |
- <property name="can_focus">False</property>
|
|
| 57 |
- <property name="label" translatable="yes">Join _Group Chat</property>
|
|
| 58 |
- <property name="use_underline">True</property>
|
|
| 59 |
- <signal name="activate" handler="on_join_group_chat_menuitem_activate" swapped="no"/>
|
|
| 60 |
- </object>
|
|
| 61 |
- </child>
|
|
| 62 |
- <child>
|
|
| 63 |
- <object class="GtkMenuItem" id="add_to_roster_menuitem">
|
|
| 64 |
- <property name="visible">True</property>
|
|
| 65 |
- <property name="can_focus">False</property>
|
|
| 66 |
- <property name="label" translatable="yes">_Add to Roster...</property>
|
|
| 67 |
- <property name="use_underline">True</property>
|
|
| 68 |
- </object>
|
|
| 69 |
- </child>
|
|
| 70 |
- </object>
|
|
| 71 |
-</interface>
|
| ... | ... | @@ -675,7 +675,7 @@ def get_bookmarks_menu(account, rebuild=False): |
| 675 | 675 |
# Build Join Groupchat
|
| 676 | 676 |
action = 'app.{}-join-groupchat'.format(account)
|
| 677 | 677 |
menuitem = Gio.MenuItem.new(_('Join Group Chat'), action)
|
| 678 |
- variant = GLib.Variant('s', account)
|
|
| 678 |
+ variant = GLib.Variant('as', [account, ''])
|
|
| 679 | 679 |
menuitem.set_action_and_target_value(action, variant)
|
| 680 | 680 |
menu.append_item(menuitem)
|
| 681 | 681 |
|
| ... | ... | @@ -749,7 +749,10 @@ def get_account_menu(account): |
| 749 | 749 |
continue
|
| 750 | 750 |
action = 'app.{}{}'.format(account, action)
|
| 751 | 751 |
menuitem = Gio.MenuItem.new(label, action)
|
| 752 |
- variant = GLib.Variant('s', account)
|
|
| 752 |
+ if 'add_contact' in action:
|
|
| 753 |
+ variant = GLib.Variant('as', [account, ''])
|
|
| 754 |
+ else:
|
|
| 755 |
+ variant = GLib.Variant('s', account)
|
|
| 753 | 756 |
menuitem.set_action_and_target_value(action, variant)
|
| 754 | 757 |
menu.append_item(menuitem)
|
| 755 | 758 |
else:
|
| ... | ... | @@ -840,6 +843,75 @@ def get_encryption_menu(control_id, type_id, zeroconf=False): |
| 840 | 843 |
return menu
|
| 841 | 844 |
|
| 842 | 845 |
|
| 846 |
+def get_conv_context_menu(account, kind, text):
|
|
| 847 |
+ if kind == 'xmpp':
|
|
| 848 |
+ if '?join' in text:
|
|
| 849 |
+ context_menu = [
|
|
| 850 |
+ ('copy-link', _('Copy JID')),
|
|
| 851 |
+ ('-join-groupchat', _('Join Groupchat')),
|
|
| 852 |
+ ]
|
|
| 853 |
+ else:
|
|
| 854 |
+ context_menu = [
|
|
| 855 |
+ ('copy-link', _('Copy JID')),
|
|
| 856 |
+ ('-start-chat', _('Start Chat')),
|
|
| 857 |
+ ('-add-contact', _('Add to Roster…')),
|
|
| 858 |
+ ]
|
|
| 859 |
+ |
|
| 860 |
+ elif kind == 'url':
|
|
| 861 |
+ context_menu = [
|
|
| 862 |
+ ('copy-link', _('Copy Link Location')),
|
|
| 863 |
+ ('open-link', _('Open Link in Browser')),
|
|
| 864 |
+ ]
|
|
| 865 |
+ |
|
| 866 |
+ elif kind == 'mail':
|
|
| 867 |
+ context_menu = [
|
|
| 868 |
+ ('copy-link', _('Copy Email Address')),
|
|
| 869 |
+ ('open-link', _('Open Email Composer')),
|
|
| 870 |
+ ]
|
|
| 871 |
+ |
|
| 872 |
+ elif kind == 'sth_at_sth':
|
|
| 873 |
+ context_menu = [
|
|
| 874 |
+ ('copy-link', _('Copy JID/Email')),
|
|
| 875 |
+ ('open-link', _('Open Email Composer')),
|
|
| 876 |
+ ('-start-chat', _('Start Chat')),
|
|
| 877 |
+ ('-join-groupchat', _('Join Groupchat')),
|
|
| 878 |
+ ('-add-contact', _('Add to Roster…')),
|
|
| 879 |
+ ]
|
|
| 880 |
+ else:
|
|
| 881 |
+ return
|
|
| 882 |
+ |
|
| 883 |
+ menu = Gtk.Menu()
|
|
| 884 |
+ for item in context_menu:
|
|
| 885 |
+ action, label = item
|
|
| 886 |
+ menuitem = Gtk.MenuItem()
|
|
| 887 |
+ menuitem.set_label(label)
|
|
| 888 |
+ |
|
| 889 |
+ if action.startswith('-'):
|
|
| 890 |
+ action = 'app.%s%s' % (account, action)
|
|
| 891 |
+ else:
|
|
| 892 |
+ action = 'app.%s' % action
|
|
| 893 |
+ menuitem.set_action_name(action)
|
|
| 894 |
+ |
|
| 895 |
+ if 'join-groupchat' in action:
|
|
| 896 |
+ text = text.replace('xmpp:', '')
|
|
| 897 |
+ text = text.split('?')[0]
|
|
| 898 |
+ |
|
| 899 |
+ if 'add-contact' in action:
|
|
| 900 |
+ text = text.replace('xmpp:', '')
|
|
| 901 |
+ text = text.split('?')[0]
|
|
| 902 |
+ |
|
| 903 |
+ if action == 'app.open-link':
|
|
| 904 |
+ value = GLib.Variant.new_strv([kind, text])
|
|
| 905 |
+ elif action == 'app.copy-link':
|
|
| 906 |
+ value = GLib.Variant.new_string(text)
|
|
| 907 |
+ else:
|
|
| 908 |
+ value = GLib.Variant.new_strv([account, text])
|
|
| 909 |
+ menuitem.set_action_target_value(value)
|
|
| 910 |
+ menuitem.show()
|
|
| 911 |
+ menu.append(menuitem)
|
|
| 912 |
+ return menu
|
|
| 913 |
+ |
|
| 914 |
+ |
|
| 843 | 915 |
def escape_mnemonic(label):
|
| 844 | 916 |
if label is None:
|
| 845 | 917 |
return
|
| ... | ... | @@ -43,16 +43,16 @@ from gi.repository import Pango |
| 43 | 43 |
from gi.repository import Gtk
|
| 44 | 44 |
from gi.repository import Gdk
|
| 45 | 45 |
from gi.repository import GdkPixbuf
|
| 46 |
+from gi.repository import GLib
|
|
| 46 | 47 |
|
| 47 | 48 |
from gajim.common import app
|
| 48 | 49 |
from gajim.common import helpers
|
| 49 | 50 |
from gajim.common.i18n import _
|
| 50 | 51 |
from gajim.common.const import StyleAttr
|
| 51 |
-from gajim.gtk import JoinGroupchatWindow
|
|
| 52 |
-from gajim.gtk import AddNewContactWindow
|
|
| 53 | 52 |
from gajim.gtk.util import load_icon
|
| 54 | 53 |
from gajim.gtk.util import get_cursor
|
| 55 |
-from gajim.gtk.util import get_builder
|
|
| 54 |
+ |
|
| 55 |
+from gajim.gui_menu_builder import get_conv_context_menu
|
|
| 56 | 56 |
|
| 57 | 57 |
log = logging.getLogger('gajim.htmlview')
|
| 58 | 58 |
|
| ... | ... | @@ -825,7 +825,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler): |
| 825 | 825 |
|
| 826 | 826 |
class HtmlTextView(Gtk.TextView):
|
| 827 | 827 |
|
| 828 |
- def __init__(self):
|
|
| 828 |
+ def __init__(self, account=None):
|
|
| 829 | 829 |
Gtk.TextView.__init__(self)
|
| 830 | 830 |
self.set_wrap_mode(Gtk.WrapMode.CHAR)
|
| 831 | 831 |
self.set_editable(False)
|
| ... | ... | @@ -835,11 +835,12 @@ class HtmlTextView(Gtk.TextView): |
| 835 | 835 |
self.connect('unrealize', self.on_html_text_view_unrealized)
|
| 836 | 836 |
self.connect('copy-clipboard', self.on_html_text_view_copy_clipboard)
|
| 837 | 837 |
self.id_ = self.connect('button-release-event',
|
| 838 |
- self.on_left_mouse_button_release)
|
|
| 838 |
+ self.on_left_mouse_button_release)
|
|
| 839 | 839 |
self.get_buffer().eol_tag = self.get_buffer().create_tag('eol')
|
| 840 | 840 |
self.config = app.config
|
| 841 | 841 |
self.interface = app.interface
|
| 842 |
- # end big hack
|
|
| 842 |
+ self.account = account
|
|
| 843 |
+ self.plugin_modified = False
|
|
| 843 | 844 |
|
| 844 | 845 |
def connect_tooltip(self, func=None):
|
| 845 | 846 |
self.connect('query-tooltip', func or self.__query_tooltip)
|
| ... | ... | @@ -892,73 +893,21 @@ class HtmlTextView(Gtk.TextView): |
| 892 | 893 |
self._changed_cursor = False
|
| 893 | 894 |
return False
|
| 894 | 895 |
|
| 895 |
- def on_open_link_activate(self, widget, kind, text):
|
|
| 896 |
- helpers.launch_browser_mailer(kind, text)
|
|
| 897 |
- |
|
| 898 |
- def on_copy_link_activate(self, widget, text):
|
|
| 899 |
- clip = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
|
|
| 900 |
- clip.set_text(text, -1)
|
|
| 901 |
- |
|
| 902 |
-# def on_start_chat_activate(self, widget, jid):
|
|
| 903 |
-# app.interface.new_chat_from_jid(self.account, jid)
|
|
| 904 |
- |
|
| 905 |
- def on_join_group_chat_menuitem_activate(self, widget, room_jid):
|
|
| 906 |
- JoinGroupchatWindow(None, room_jid)
|
|
| 907 |
- |
|
| 908 |
- def on_add_to_roster_activate(self, widget, jid):
|
|
| 909 |
- AddNewContactWindow(self.account, jid)
|
|
| 910 |
- |
|
| 911 |
- def make_link_menu(self, event, kind, text):
|
|
| 912 |
- ui = get_builder('chat_context_menu.ui')
|
|
| 913 |
- menu = ui.get_object('chat_context_menu')
|
|
| 914 |
- childs = menu.get_children()
|
|
| 915 |
- if kind == 'url':
|
|
| 916 |
- childs[0].connect('activate', self.on_copy_link_activate, text)
|
|
| 917 |
- childs[1].connect('activate', self.on_open_link_activate, kind,
|
|
| 918 |
- text)
|
|
| 919 |
- childs[2].hide() # copy mail address
|
|
| 920 |
- childs[3].hide() # open mail composer
|
|
| 921 |
- childs[4].hide() # jid section separator
|
|
| 922 |
- childs[5].hide() # start chat
|
|
| 923 |
- childs[6].hide() # join group chat
|
|
| 924 |
- childs[7].hide() # add to roster
|
|
| 925 |
- else: # It's a mail or a JID
|
|
| 926 |
- text = text.lower()
|
|
| 927 |
- if text.startswith('xmpp:'):
|
|
| 928 |
- text = text[5:]
|
|
| 929 |
- childs[2].connect('activate', self.on_copy_link_activate, text)
|
|
| 930 |
- childs[3].connect('activate', self.on_open_link_activate, kind,
|
|
| 931 |
- text)
|
|
| 932 |
-# childs[5].connect('activate', self.on_start_chat_activate, text)
|
|
| 933 |
- childs[6].connect('activate',
|
|
| 934 |
- self.on_join_group_chat_menuitem_activate, text)
|
|
| 935 |
- |
|
| 936 |
-# if self.account and app.connections[self.account].\
|
|
| 937 |
-# roster_supported:
|
|
| 938 |
-# childs[7].connect('activate',
|
|
| 939 |
-# self.on_add_to_roster_activate, text)
|
|
| 940 |
-# childs[7].show() # show add to roster menuitem
|
|
| 941 |
-# else:
|
|
| 942 |
-# childs[7].hide() # hide add to roster menuitem
|
|
| 896 |
+ def show_context_menu(self, _event, kind, text):
|
|
| 897 |
+ menu = get_conv_context_menu(self.account, kind, text)
|
|
| 898 |
+ if menu is None:
|
|
| 899 |
+ return
|
|
| 900 |
+ |
|
| 901 |
+ def destroy(menu, pspec):
|
|
| 902 |
+ visible = menu.get_property('visible')
|
|
| 903 |
+ if not visible:
|
|
| 904 |
+ GLib.idle_add(menu.destroy)
|
|
| 943 | 905 |
|
| 944 |
- if kind == 'xmpp':
|
|
| 945 |
- childs[0].connect('activate', self.on_copy_link_activate,
|
|
| 946 |
- 'xmpp:' + text)
|
|
| 947 |
- childs[2].hide() # copy mail address
|
|
| 948 |
- childs[3].hide() # open mail composer
|
|
| 949 |
- elif kind == 'mail':
|
|
| 950 |
- childs[6].hide() # join group chat
|
|
| 951 |
- |
|
| 952 |
- if kind != 'xmpp':
|
|
| 953 |
- childs[0].hide() # copy link location
|
|
| 954 |
- childs[1].hide() # open link in browser
|
|
| 955 |
- childs[4].hide() # jid section separator
|
|
| 956 |
- childs[5].hide() # start chat
|
|
| 957 |
- childs[7].hide() # add to roster
|
|
| 958 |
- |
|
| 959 |
- menu.popup(None, None, None, event.button, event.time)
|
|
| 960 |
- |
|
| 961 |
- def hyperlink_handler(self, texttag, widget, event, iter_, kind):
|
|
| 906 |
+ menu.attach_to_widget(self, None)
|
|
| 907 |
+ menu.connect('notify::visible', destroy)
|
|
| 908 |
+ menu.popup_at_pointer()
|
|
| 909 |
+ |
|
| 910 |
+ def hyperlink_handler(self, texttag, _widget, event, iter_, kind):
|
|
| 962 | 911 |
if event.type == Gdk.EventType.BUTTON_PRESS:
|
| 963 | 912 |
begin_iter = iter_.copy()
|
| 964 | 913 |
# we get the beginning of the tag
|
| ... | ... | @@ -980,31 +929,45 @@ class HtmlTextView(Gtk.TextView): |
| 980 | 929 |
# it's a JID or mail
|
| 981 | 930 |
kind = 'sth_at_sth'
|
| 982 | 931 |
else:
|
| 983 |
- word = self.textview.get_buffer().get_text(begin_iter,
|
|
| 984 |
- end_iter)
|
|
| 932 |
+ word = self.get_buffer().get_text(begin_iter, end_iter, True)
|
|
| 985 | 933 |
|
| 986 |
- if event.button == 3: # right click
|
|
| 987 |
- self.make_link_menu(event, kind, word)
|
|
| 934 |
+ if event.button.button == 3: # right click
|
|
| 935 |
+ self.show_context_menu(event, kind, word)
|
|
| 988 | 936 |
return True
|
| 989 | 937 |
|
| 938 |
+ self.plugin_modified = False
|
|
| 939 |
+ app.plugin_manager.extension_point(
|
|
| 940 |
+ 'hyperlink_handler', word, kind, self,
|
|
| 941 |
+ self.get_toplevel())
|
|
| 942 |
+ if self.plugin_modified:
|
|
| 943 |
+ return
|
|
| 944 |
+ |
|
| 990 | 945 |
# we launch the correct application
|
| 991 | 946 |
if kind == 'xmpp':
|
| 992 | 947 |
word = word[5:]
|
| 993 | 948 |
if '?' in word:
|
| 994 | 949 |
(jid, action) = word.split('?')
|
| 995 | 950 |
if action == 'join':
|
| 996 |
- self.on_join_group_chat_menuitem_activate(None, jid)
|
|
| 951 |
+ app.interface.join_gc_minimal(self.account, jid)
|
|
| 997 | 952 |
else:
|
| 998 |
- self.on_start_chat_activate(None, jid)
|
|
| 953 |
+ app.interface.new_chat_from_jid(self.account, jid)
|
|
| 999 | 954 |
else:
|
| 1000 |
- self.on_start_chat_activate(None, word)
|
|
| 955 |
+ app.interface.new_chat_from_jid(self.account, word)
|
|
| 956 |
+ |
|
| 957 |
+ # handle geo:-URIs
|
|
| 958 |
+ elif word[:4] == 'geo:':
|
|
| 959 |
+ location = word[4:]
|
|
| 960 |
+ lat, _, lon = location.partition(',')
|
|
| 961 |
+ if lon == '':
|
|
| 962 |
+ return
|
|
| 963 |
+ uri = 'https://www.openstreetmap.org/?' \
|
|
| 964 |
+ 'mlat=%(lat)s&mlon=%(lon)s&zoom=16' % \
|
|
| 965 |
+ {'lat': lat, 'lon': lon}
|
|
| 966 |
+ helpers.launch_browser_mailer(kind, uri)
|
|
| 967 |
+ # other URIs
|
|
| 1001 | 968 |
else:
|
| 1002 | 969 |
helpers.launch_browser_mailer(kind, word)
|
| 1003 | 970 |
|
| 1004 |
- def _hyperlink_handler(self, texttag, widget, event, iter_, kind):
|
|
| 1005 |
- # self.hyperlink_handler can be overwritten, so call it when needed
|
|
| 1006 |
- self.hyperlink_handler(texttag, widget, event, iter_, kind)
|
|
| 1007 |
- |
|
| 1008 | 971 |
def display_html(self, html, textview, conv_textview, iter_=None):
|
| 1009 | 972 |
buffer_ = self.get_buffer()
|
| 1010 | 973 |
if iter_:
|
| ... | ... | @@ -3679,7 +3679,7 @@ class RosterWindow: |
| 3679 | 3679 |
When the join gc menuitem is clicked, show the join gc window
|
| 3680 | 3680 |
"""
|
| 3681 | 3681 |
app.app.activate_action('%s-join-groupchat' % account,
|
| 3682 |
- GLib.Variant('s', account))
|
|
| 3682 |
+ GLib.Variant('as', [account, '']))
|
|
| 3683 | 3683 |
|
| 3684 | 3684 |
def on_show_transports_action(self, action, param):
|
| 3685 | 3685 |
app.config.set('show_transports_group', param.get_boolean())
|