use python-sexy if available to have clickable links in chat window banner. fixes #2962
This commit is contained in:
parent
3c936682dc
commit
aff3697f06
6 changed files with 871 additions and 1231 deletions
|
@ -38,6 +38,7 @@ Gajim is a GTK+ app that loves GNOME. You can do 'make' so you don't require gno
|
||||||
<li>notification-daemon or notify-python (and D-Bus) to get cooler popups</li>
|
<li>notification-daemon or notify-python (and D-Bus) to get cooler popups</li>
|
||||||
<li>D-Bus running to have gajim-remote working</li>
|
<li>D-Bus running to have gajim-remote working</li>
|
||||||
<li>python-dbus bindings</li>
|
<li>python-dbus bindings</li>
|
||||||
|
<li>python-sexy to have clickable URLs in chat windows</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -28,6 +28,7 @@ import message_control
|
||||||
import dialogs
|
import dialogs
|
||||||
import history_window
|
import history_window
|
||||||
import notify
|
import notify
|
||||||
|
import re
|
||||||
|
|
||||||
from common import gajim
|
from common import gajim
|
||||||
from common import helpers
|
from common import helpers
|
||||||
|
@ -46,7 +47,6 @@ try:
|
||||||
except:
|
except:
|
||||||
HAS_GTK_SPELL = False
|
HAS_GTK_SPELL = False
|
||||||
|
|
||||||
|
|
||||||
# the next script, executed in the "po" directory,
|
# the next script, executed in the "po" directory,
|
||||||
# generates the following list.
|
# generates the following list.
|
||||||
##!/bin/sh
|
##!/bin/sh
|
||||||
|
@ -54,11 +54,15 @@ except:
|
||||||
#echo "{_('en'):'en'",$LANG"}"
|
#echo "{_('en'):'en'",$LANG"}"
|
||||||
langs = {_('English'): 'en', _('Belarusian'): 'be', _('Bulgarian'): 'bg', _('Breton'): 'br', _('Czech'): 'cs', _('German'): 'de', _('Greek'): 'el', _('British'): 'en_GB', _('Esperanto'): 'eo', _('Spanish'): 'es', _('Basque'): 'eu', _('French'): 'fr', _('Croatian'): 'hr', _('Italian'): 'it', _('Norwegian (b)'): 'nb', _('Dutch'): 'nl', _('Norwegian'): 'no', _('Polish'): 'pl', _('Portuguese'): 'pt', _('Brazilian Portuguese'): 'pt_BR', _('Russian'): 'ru', _('Serbian'): 'sr', _('Slovak'): 'sk', _('Swedish'): 'sv', _('Chinese (Ch)'): 'zh_CN'}
|
langs = {_('English'): 'en', _('Belarusian'): 'be', _('Bulgarian'): 'bg', _('Breton'): 'br', _('Czech'): 'cs', _('German'): 'de', _('Greek'): 'el', _('British'): 'en_GB', _('Esperanto'): 'eo', _('Spanish'): 'es', _('Basque'): 'eu', _('French'): 'fr', _('Croatian'): 'hr', _('Italian'): 'it', _('Norwegian (b)'): 'nb', _('Dutch'): 'nl', _('Norwegian'): 'no', _('Polish'): 'pl', _('Portuguese'): 'pt', _('Brazilian Portuguese'): 'pt_BR', _('Russian'): 'ru', _('Serbian'): 'sr', _('Slovak'): 'sk', _('Swedish'): 'sv', _('Chinese (Ch)'): 'zh_CN'}
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
class ChatControlBase(MessageControl):
|
class ChatControlBase(MessageControl):
|
||||||
'''A base class containing a banner, ConversationTextview, MessageTextView
|
'''A base class containing a banner, ConversationTextview, MessageTextView
|
||||||
'''
|
'''
|
||||||
|
def make_href(self, match):
|
||||||
|
url_color = gajim.config.get('urlmsgcolor')
|
||||||
|
return '<a href="%s"><span color="%s">%s</span></a>' % (match.group(),
|
||||||
|
url_color, match.group())
|
||||||
|
|
||||||
def get_font_attrs(self):
|
def get_font_attrs(self):
|
||||||
''' get pango font attributes for banner from theme settings '''
|
''' get pango font attributes for banner from theme settings '''
|
||||||
theme = gajim.config.get('roster_theme')
|
theme = gajim.config.get('roster_theme')
|
||||||
|
@ -120,6 +124,9 @@ class ChatControlBase(MessageControl):
|
||||||
event_keymod):
|
event_keymod):
|
||||||
pass # Derived should implement this rather than connecting to the event itself.
|
pass # Derived should implement this rather than connecting to the event itself.
|
||||||
|
|
||||||
|
def status_url_clicked(self, widget, url):
|
||||||
|
helpers.launch_browser_mailer('url', url)
|
||||||
|
|
||||||
def __init__(self, type_id, parent_win, widget_name, contact, acct,
|
def __init__(self, type_id, parent_win, widget_name, contact, acct,
|
||||||
resource = None):
|
resource = None):
|
||||||
MessageControl.__init__(self, type_id, parent_win, widget_name,
|
MessageControl.__init__(self, type_id, parent_win, widget_name,
|
||||||
|
@ -138,6 +145,22 @@ class ChatControlBase(MessageControl):
|
||||||
id = widget.connect('button-press-event',
|
id = widget.connect('button-press-event',
|
||||||
self._on_banner_eventbox_button_press_event)
|
self._on_banner_eventbox_button_press_event)
|
||||||
self.handlers[id] = widget
|
self.handlers[id] = widget
|
||||||
|
|
||||||
|
self.urlfinder = re.compile("(https?://|www|ftp)[^ ]+")
|
||||||
|
|
||||||
|
if gajim.HAVE_PYSEXY:
|
||||||
|
import sexy
|
||||||
|
self.banner_status_label = sexy.UrlLabel()
|
||||||
|
self.banner_status_label.connect('url_activated', self.status_url_clicked)
|
||||||
|
else:
|
||||||
|
self.banner_status_label = gtk.Label()
|
||||||
|
self.banner_status_label.set_selectable(True)
|
||||||
|
self.banner_status_label.set_alignment(0,0.5)
|
||||||
|
|
||||||
|
banner_vbox = self.xml.get_widget('banner_vbox')
|
||||||
|
banner_vbox.pack_start(self.banner_status_label)
|
||||||
|
self.banner_status_label.show()
|
||||||
|
|
||||||
# Init DND
|
# Init DND
|
||||||
self.TARGET_TYPE_URI_LIST = 80
|
self.TARGET_TYPE_URI_LIST = 80
|
||||||
self.dnd_list = [ ( 'text/uri-list', 0, self.TARGET_TYPE_URI_LIST ),
|
self.dnd_list = [ ( 'text/uri-list', 0, self.TARGET_TYPE_URI_LIST ),
|
||||||
|
@ -247,7 +270,6 @@ class ChatControlBase(MessageControl):
|
||||||
spell.set_language(lang)
|
spell.set_language(lang)
|
||||||
except (gobject.GError, RuntimeError), msg:
|
except (gobject.GError, RuntimeError), msg:
|
||||||
dialogs.AspellDictError(lang)
|
dialogs.AspellDictError(lang)
|
||||||
self.style_event_id = 0
|
|
||||||
self.conv_textview.tv.show()
|
self.conv_textview.tv.show()
|
||||||
self._paint_banner()
|
self._paint_banner()
|
||||||
|
|
||||||
|
@ -324,6 +346,7 @@ class ChatControlBase(MessageControl):
|
||||||
banner_eventbox = self.xml.get_widget('banner_eventbox')
|
banner_eventbox = self.xml.get_widget('banner_eventbox')
|
||||||
banner_name_label = self.xml.get_widget('banner_name_label')
|
banner_name_label = self.xml.get_widget('banner_name_label')
|
||||||
self.disconnect_style_event(banner_name_label)
|
self.disconnect_style_event(banner_name_label)
|
||||||
|
self.disconnect_style_event(self.banner_status_label)
|
||||||
if bgcolor:
|
if bgcolor:
|
||||||
banner_eventbox.modify_bg(gtk.STATE_NORMAL,
|
banner_eventbox.modify_bg(gtk.STATE_NORMAL,
|
||||||
gtk.gdk.color_parse(bgcolor))
|
gtk.gdk.color_parse(bgcolor))
|
||||||
|
@ -333,24 +356,32 @@ class ChatControlBase(MessageControl):
|
||||||
if textcolor:
|
if textcolor:
|
||||||
banner_name_label.modify_fg(gtk.STATE_NORMAL,
|
banner_name_label.modify_fg(gtk.STATE_NORMAL,
|
||||||
gtk.gdk.color_parse(textcolor))
|
gtk.gdk.color_parse(textcolor))
|
||||||
|
self.banner_status_label.modify_fg(gtk.STATE_NORMAL,
|
||||||
|
gtk.gdk.color_parse(textcolor))
|
||||||
default_fg = False
|
default_fg = False
|
||||||
else:
|
else:
|
||||||
default_fg = True
|
default_fg = True
|
||||||
if default_bg or default_fg:
|
if default_bg or default_fg:
|
||||||
self._on_style_set_event(banner_name_label, None, default_fg,
|
self._on_style_set_event(banner_name_label, None, default_fg,
|
||||||
default_bg)
|
default_bg)
|
||||||
|
self._on_style_set_event(self.banner_status_label, None, default_fg,
|
||||||
|
default_bg)
|
||||||
|
|
||||||
def disconnect_style_event(self, widget):
|
def disconnect_style_event(self, widget):
|
||||||
if self.style_event_id:
|
# Try to find the event_id
|
||||||
widget.disconnect(self.style_event_id)
|
found = False
|
||||||
del self.handlers[self.style_event_id]
|
for id in self.handlers:
|
||||||
self.style_event_id = 0
|
if self.handlers[id] == widget:
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
if found:
|
||||||
|
widget.disconnect(id)
|
||||||
|
del self.handlers[id]
|
||||||
|
|
||||||
def connect_style_event(self, widget, set_fg = False, set_bg = False):
|
def connect_style_event(self, widget, set_fg = False, set_bg = False):
|
||||||
self.disconnect_style_event(widget)
|
self.disconnect_style_event(widget)
|
||||||
self.style_event_id = widget.connect('style-set',
|
id = widget.connect('style-set', self._on_style_set_event, set_fg, set_bg)
|
||||||
self._on_style_set_event, set_fg, set_bg)
|
self.handlers[id] = widget
|
||||||
self.handlers[self.style_event_id] = widget
|
|
||||||
|
|
||||||
def _on_style_set_event(self, widget, style, *opts):
|
def _on_style_set_event(self, widget, style, *opts):
|
||||||
'''set style of widget from style class *.Frame.Eventbox
|
'''set style of widget from style class *.Frame.Eventbox
|
||||||
|
@ -1162,6 +1193,7 @@ class ChatControl(ChatControlBase):
|
||||||
self.status_tooltip.set_tip(banner_eventbox, status)
|
self.status_tooltip.set_tip(banner_eventbox, status)
|
||||||
self.status_tooltip.enable()
|
self.status_tooltip.enable()
|
||||||
banner_name_label.set_ellipsize(pango.ELLIPSIZE_END)
|
banner_name_label.set_ellipsize(pango.ELLIPSIZE_END)
|
||||||
|
self.banner_status_label.set_ellipsize(pango.ELLIPSIZE_END)
|
||||||
status = helpers.reduce_chars_newlines(status, max_lines = 1)
|
status = helpers.reduce_chars_newlines(status, max_lines = 1)
|
||||||
status_escaped = gobject.markup_escape_text(status)
|
status_escaped = gobject.markup_escape_text(status)
|
||||||
|
|
||||||
|
@ -1192,9 +1224,15 @@ class ChatControl(ChatControlBase):
|
||||||
# weight="heavy" size="x-large"
|
# weight="heavy" size="x-large"
|
||||||
label_text = '<span %s>%s</span><span %s>%s</span>' % \
|
label_text = '<span %s>%s</span><span %s>%s</span>' % \
|
||||||
(font_attrs, name, font_attrs_small, acct_info)
|
(font_attrs, name, font_attrs_small, acct_info)
|
||||||
|
|
||||||
if status_escaped:
|
if status_escaped:
|
||||||
label_text += '\n<span %s>%s</span>' %\
|
if gajim.HAVE_PYSEXY:
|
||||||
(font_attrs_small, status_escaped)
|
status_text = self.urlfinder.sub(self.make_href, status_escaped)
|
||||||
|
status_text = '<span %s>%s</span>' % (font_attrs_small, status_text)
|
||||||
|
else:
|
||||||
|
status_text = '<span %s>%s</span>' % (font_attrs_small, status_escaped)
|
||||||
|
|
||||||
|
self.banner_status_label.set_markup(status_text)
|
||||||
else:
|
else:
|
||||||
self.status_tooltip.disable()
|
self.status_tooltip.disable()
|
||||||
# setup the label that holds name and jid
|
# setup the label that holds name and jid
|
||||||
|
|
|
@ -142,6 +142,12 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
HAVE_PYCRYPTO = False
|
HAVE_PYCRYPTO = False
|
||||||
|
|
||||||
|
HAVE_PYSEXY = True
|
||||||
|
try:
|
||||||
|
import sexy
|
||||||
|
except ImportError:
|
||||||
|
HAVE_PYSEXY = False
|
||||||
|
|
||||||
def get_nick_from_jid(jid):
|
def get_nick_from_jid(jid):
|
||||||
pos = jid.find('@')
|
pos = jid.find('@')
|
||||||
return jid[:pos]
|
return jid[:pos]
|
||||||
|
|
|
@ -98,6 +98,10 @@ class FeaturesWindow:
|
||||||
_('Generate XHTML output from RST code (see http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html).'),
|
_('Generate XHTML output from RST code (see http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html).'),
|
||||||
_('Requires python-docutils.'),
|
_('Requires python-docutils.'),
|
||||||
_('Requires python-docutils.')),
|
_('Requires python-docutils.')),
|
||||||
|
_('libsexy'): (self.pysexy_available,
|
||||||
|
_('Ability to have clickable URLs in chat window.'),
|
||||||
|
_('Requires python-sexy.'),
|
||||||
|
_('Requires python-sexy.')),
|
||||||
}
|
}
|
||||||
|
|
||||||
# name, supported
|
# name, supported
|
||||||
|
@ -294,3 +298,7 @@ class FeaturesWindow:
|
||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def pysexy_available(self):
|
||||||
|
from common import gajim
|
||||||
|
return gajim.HAVE_PYSEXY
|
||||||
|
|
|
@ -481,6 +481,7 @@ class GroupchatControl(ChatControlBase):
|
||||||
houses the room jid, subject.
|
houses the room jid, subject.
|
||||||
'''
|
'''
|
||||||
self.name_label.set_ellipsize(pango.ELLIPSIZE_END)
|
self.name_label.set_ellipsize(pango.ELLIPSIZE_END)
|
||||||
|
self.banner_status_label.set_ellipsize(pango.ELLIPSIZE_END)
|
||||||
font_attrs, font_attrs_small = self.get_font_attrs()
|
font_attrs, font_attrs_small = self.get_font_attrs()
|
||||||
if self.is_continued:
|
if self.is_continued:
|
||||||
nicks = []
|
nicks = []
|
||||||
|
@ -495,16 +496,22 @@ class GroupchatControl(ChatControlBase):
|
||||||
text = '<span %s>%s</span>' % (font_attrs, title)
|
text = '<span %s>%s</span>' % (font_attrs, title)
|
||||||
else:
|
else:
|
||||||
text = '<span %s>%s</span>' % (font_attrs, self.room_jid)
|
text = '<span %s>%s</span>' % (font_attrs, self.room_jid)
|
||||||
|
self.name_label.set_markup(text)
|
||||||
|
|
||||||
if self.subject:
|
if self.subject:
|
||||||
subject = helpers.reduce_chars_newlines(self.subject, max_lines = 2)
|
subject = helpers.reduce_chars_newlines(self.subject, max_lines = 2)
|
||||||
subject = gobject.markup_escape_text(subject)
|
subject = gobject.markup_escape_text(subject)
|
||||||
text += '\n<span %s>%s</span>' % (font_attrs_small, subject)
|
if gajim.HAVE_PYSEXY:
|
||||||
|
subject_text = self.urlfinder.sub(self.make_href, subject)
|
||||||
|
subject_text = '<span %s>%s</span>' % (font_attrs_small,
|
||||||
|
subject_text)
|
||||||
|
else:
|
||||||
|
subject_text = '<span %s>%s</span>' % (font_attrs_small, subject)
|
||||||
|
self.banner_status_label.set_markup(subject_text)
|
||||||
|
|
||||||
# tooltip must always hold ALL the subject
|
# tooltip must always hold ALL the subject
|
||||||
self.subject_tooltip.set_tip(self.event_box, self.subject)
|
self.subject_tooltip.set_tip(self.event_box, self.subject)
|
||||||
|
|
||||||
self.name_label.set_markup(text)
|
|
||||||
|
|
||||||
def prepare_context_menu(self):
|
def prepare_context_menu(self):
|
||||||
'''sets sensitivity state for configure_room'''
|
'''sets sensitivity state for configure_room'''
|
||||||
ag = gtk.accel_groups_from_object(self.parent_win.window)[0]
|
ag = gtk.accel_groups_from_object(self.parent_win.window)[0]
|
||||||
|
|
Loading…
Add table
Reference in a new issue