Very basic integration of xHtml GUI
This commit is contained in:
parent
0641beb5d4
commit
5a31ba2ef0
6 changed files with 367 additions and 33 deletions
|
@ -230,6 +230,27 @@
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkButton" id="formattings_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="tooltip" translatable="yes">Show a list of formattings</property>
|
||||||
|
<property name="relief">GTK_RELIEF_NONE</property>
|
||||||
|
<property name="focus_on_click">False</property>
|
||||||
|
<property name="response_id">0</property>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImage" id="image10">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="stock">gtk-bold</property>
|
||||||
|
<property name="icon_size">1</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkVSeparator" id="vseparator1">
|
<widget class="GtkVSeparator" id="vseparator1">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -237,7 +258,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="position">1</property>
|
<property name="position">2</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -261,7 +282,7 @@
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="fill">False</property>
|
<property name="fill">False</property>
|
||||||
<property name="position">2</property>
|
<property name="position">3</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -282,7 +303,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="position">3</property>
|
<property name="position">4</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -304,7 +325,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="position">4</property>
|
<property name="position">5</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -326,7 +347,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="position">5</property>
|
<property name="position">6</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -348,7 +369,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="position">6</property>
|
<property name="position">7</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -358,7 +379,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="position">7</property>
|
<property name="position">8</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -380,7 +401,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="position">8</property>
|
<property name="position">9</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -392,7 +413,7 @@
|
||||||
</child>
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">9</property>
|
<property name="position">10</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -438,7 +459,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="position">10</property>
|
<property name="position">11</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
|
@ -678,6 +699,27 @@
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkButton" id="formattings_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="tooltip" translatable="yes">Show a list of formattings</property>
|
||||||
|
<property name="relief">GTK_RELIEF_NONE</property>
|
||||||
|
<property name="focus_on_click">False</property>
|
||||||
|
<property name="response_id">0</property>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImage" id="image11">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="stock">gtk-bold</property>
|
||||||
|
<property name="icon_size">1</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkVSeparator" id="vseparator2">
|
<widget class="GtkVSeparator" id="vseparator2">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -685,7 +727,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="position">1</property>
|
<property name="position">2</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -707,7 +749,7 @@
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="fill">False</property>
|
<property name="fill">False</property>
|
||||||
<property name="position">2</property>
|
<property name="position">3</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -729,7 +771,7 @@
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="fill">False</property>
|
<property name="fill">False</property>
|
||||||
<property name="position">3</property>
|
<property name="position">4</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -752,7 +794,7 @@
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="fill">False</property>
|
<property name="fill">False</property>
|
||||||
<property name="position">4</property>
|
<property name="position">5</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -774,7 +816,7 @@
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="fill">False</property>
|
<property name="fill">False</property>
|
||||||
<property name="position">5</property>
|
<property name="position">6</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -784,7 +826,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="position">6</property>
|
<property name="position">7</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -813,7 +855,7 @@
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="fill">False</property>
|
<property name="fill">False</property>
|
||||||
<property name="position">7</property>
|
<property name="position">8</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -825,7 +867,7 @@
|
||||||
</child>
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">8</property>
|
<property name="position">9</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -872,7 +914,7 @@
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="fill">False</property>
|
<property name="fill">False</property>
|
||||||
<property name="position">9</property>
|
<property name="position">10</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
|
@ -258,6 +258,10 @@ class ChatControlBase(MessageControl):
|
||||||
id = widget.connect('clicked', self._on_send_button_clicked)
|
id = widget.connect('clicked', self._on_send_button_clicked)
|
||||||
self.handlers[id] = widget
|
self.handlers[id] = widget
|
||||||
|
|
||||||
|
widget = self.xml.get_widget('formattings_button')
|
||||||
|
id = widget.connect('clicked', self.on_formattings_button_clicked)
|
||||||
|
self.handlers[id] = widget
|
||||||
|
|
||||||
# the following vars are used to keep history of user's messages
|
# the following vars are used to keep history of user's messages
|
||||||
self.sent_history = []
|
self.sent_history = []
|
||||||
self.sent_history_pos = 0
|
self.sent_history_pos = 0
|
||||||
|
@ -359,9 +363,10 @@ class ChatControlBase(MessageControl):
|
||||||
start_iter = message_buffer.get_start_iter()
|
start_iter = message_buffer.get_start_iter()
|
||||||
end_iter = message_buffer.get_end_iter()
|
end_iter = message_buffer.get_end_iter()
|
||||||
message = message_buffer.get_text(start_iter, end_iter, 0).decode('utf-8')
|
message = message_buffer.get_text(start_iter, end_iter, 0).decode('utf-8')
|
||||||
|
xhtml = self.msg_textview.get_xhtml()
|
||||||
|
|
||||||
# send the message
|
# send the message
|
||||||
self.send_message(message)
|
self.send_message(message, xhtml=xhtml)
|
||||||
|
|
||||||
def _paint_banner(self):
|
def _paint_banner(self):
|
||||||
'''Repaint banner with theme color'''
|
'''Repaint banner with theme color'''
|
||||||
|
@ -508,6 +513,7 @@ class ChatControlBase(MessageControl):
|
||||||
start_iter, end_iter = message_buffer.get_bounds()
|
start_iter, end_iter = message_buffer.get_bounds()
|
||||||
message = message_buffer.get_text(start_iter, end_iter, False).decode(
|
message = message_buffer.get_text(start_iter, end_iter, False).decode(
|
||||||
'utf-8')
|
'utf-8')
|
||||||
|
xhtml = self.msg_textview.get_xhtml()
|
||||||
|
|
||||||
# construct event instance from binding
|
# construct event instance from binding
|
||||||
event = gtk.gdk.Event(gtk.gdk.KEY_PRESS) # it's always a key-press here
|
event = gtk.gdk.Event(gtk.gdk.KEY_PRESS) # it's always a key-press here
|
||||||
|
@ -551,7 +557,7 @@ class ChatControlBase(MessageControl):
|
||||||
send_message = False
|
send_message = False
|
||||||
|
|
||||||
if send_message:
|
if send_message:
|
||||||
self.send_message(message) # send the message
|
self.send_message(message, xhtml=xhtml) # send the message
|
||||||
else:
|
else:
|
||||||
# Give the control itself a chance to process
|
# Give the control itself a chance to process
|
||||||
self.handle_message_textview_mykey_press(widget, event_keyval,
|
self.handle_message_textview_mykey_press(widget, event_keyval,
|
||||||
|
@ -595,7 +601,7 @@ class ChatControlBase(MessageControl):
|
||||||
|
|
||||||
def send_message(self, message, keyID = '', type_ = 'chat', chatstate = None,
|
def send_message(self, message, keyID = '', type_ = 'chat', chatstate = None,
|
||||||
msg_id = None, composing_xep = None, resource = None,
|
msg_id = None, composing_xep = None, resource = None,
|
||||||
process_command = True):
|
process_command = True, xhtml = None):
|
||||||
'''Send the given message to the active tab. Doesn't return None if error
|
'''Send the given message to the active tab. Doesn't return None if error
|
||||||
'''
|
'''
|
||||||
if not message or message == '\n':
|
if not message or message == '\n':
|
||||||
|
@ -607,7 +613,7 @@ class ChatControlBase(MessageControl):
|
||||||
ret = MessageControl.send_message(self, message, keyID, type_ = type_,
|
ret = MessageControl.send_message(self, message, keyID, type_ = type_,
|
||||||
chatstate = chatstate, msg_id = msg_id,
|
chatstate = chatstate, msg_id = msg_id,
|
||||||
composing_xep = composing_xep, resource = resource,
|
composing_xep = composing_xep, resource = resource,
|
||||||
user_nick = self.user_nick)
|
user_nick = self.user_nick, xhtml = xhtml)
|
||||||
|
|
||||||
# Record message history
|
# Record message history
|
||||||
self.save_sent_message(message)
|
self.save_sent_message(message)
|
||||||
|
@ -739,6 +745,68 @@ class ChatControlBase(MessageControl):
|
||||||
gajim.interface.emoticon_menuitem_clicked = self.append_emoticon
|
gajim.interface.emoticon_menuitem_clicked = self.append_emoticon
|
||||||
gajim.interface.popup_emoticons_under_button(widget, self.parent_win)
|
gajim.interface.popup_emoticons_under_button(widget, self.parent_win)
|
||||||
|
|
||||||
|
def on_formattings_button_clicked(self, widget):
|
||||||
|
'''popup formattings menu'''
|
||||||
|
menu = gtk.Menu()
|
||||||
|
|
||||||
|
menuitems = ((_('Bold'), 'bold'),
|
||||||
|
(_('Italic'), 'italic'),
|
||||||
|
(_('Underline'), 'underline'),
|
||||||
|
(_('Strike'), 'strike'))
|
||||||
|
|
||||||
|
active_tags = self.msg_textview.get_active_tags()
|
||||||
|
|
||||||
|
for menuitem in menuitems:
|
||||||
|
item = gtk.CheckMenuItem(menuitem[0])
|
||||||
|
if menuitem[1] in active_tags:
|
||||||
|
item.set_active(True)
|
||||||
|
else:
|
||||||
|
item.set_active(False)
|
||||||
|
item.connect('activate', self.msg_textview.set_tag,
|
||||||
|
menuitem[1])
|
||||||
|
menu.append(item)
|
||||||
|
|
||||||
|
item = gtk.SeparatorMenuItem() # separator
|
||||||
|
menu.append(item)
|
||||||
|
|
||||||
|
item = gtk.ImageMenuItem(_('Color'))
|
||||||
|
icon = gtk.image_new_from_stock(gtk.STOCK_SELECT_COLOR, gtk.ICON_SIZE_MENU)
|
||||||
|
item.set_image(icon)
|
||||||
|
item.connect('activate', self.on_color_menuitem_activale)
|
||||||
|
menu.append(item)
|
||||||
|
|
||||||
|
item = gtk.ImageMenuItem(_('Font'))
|
||||||
|
icon = gtk.image_new_from_stock(gtk.STOCK_SELECT_FONT, gtk.ICON_SIZE_MENU)
|
||||||
|
item.set_image(icon)
|
||||||
|
item.connect('activate', self.on_font_menuitem_activale)
|
||||||
|
menu.append(item)
|
||||||
|
|
||||||
|
item = gtk.SeparatorMenuItem() # separator
|
||||||
|
menu.append(item)
|
||||||
|
|
||||||
|
item = gtk.ImageMenuItem(_('Clear formating'))
|
||||||
|
icon = gtk.image_new_from_stock(gtk.STOCK_CLEAR, gtk.ICON_SIZE_MENU)
|
||||||
|
item.set_image(icon)
|
||||||
|
item.connect('activate', self.msg_textview.clear_tags)
|
||||||
|
menu.append(item)
|
||||||
|
|
||||||
|
menu.show_all()
|
||||||
|
gtkgui_helpers.popup_emoticons_under_button(menu, widget,
|
||||||
|
self.parent_win)
|
||||||
|
|
||||||
|
def on_color_menuitem_activale(self, widget):
|
||||||
|
color_dialog = gtk.ColorSelectionDialog('Select a color')
|
||||||
|
color_dialog.connect('response', self.msg_textview.color_set,
|
||||||
|
color_dialog.colorsel)
|
||||||
|
color_dialog.show_all()
|
||||||
|
|
||||||
|
def on_font_menuitem_activale(self, widget):
|
||||||
|
font_dialog = gtk.FontSelectionDialog('Select a font')
|
||||||
|
font_dialog.connect('response', self.msg_textview.font_set,
|
||||||
|
font_dialog.fontsel)
|
||||||
|
font_dialog.show_all()
|
||||||
|
|
||||||
|
|
||||||
def on_actions_button_clicked(self, widget):
|
def on_actions_button_clicked(self, widget):
|
||||||
'''popup action menu'''
|
'''popup action menu'''
|
||||||
menu = self.prepare_context_menu(True)
|
menu = self.prepare_context_menu(True)
|
||||||
|
@ -1668,7 +1736,8 @@ class ChatControl(ChatControlBase):
|
||||||
else:
|
else:
|
||||||
self.print_conversation(_('No help info for /%s') % command, 'info')
|
self.print_conversation(_('No help info for /%s') % command, 'info')
|
||||||
|
|
||||||
def send_message(self, message, keyID = '', chatstate = None):
|
def send_message(self, message, keyID = '', chatstate = None,
|
||||||
|
xhtml = None):
|
||||||
'''Send a message to contact'''
|
'''Send a message to contact'''
|
||||||
if message in ('', None, '\n') or self._process_command(message):
|
if message in ('', None, '\n') or self._process_command(message):
|
||||||
return None
|
return None
|
||||||
|
@ -1725,7 +1794,7 @@ class ChatControl(ChatControlBase):
|
||||||
id = ChatControlBase.send_message(self, message, keyID,
|
id = ChatControlBase.send_message(self, message, keyID,
|
||||||
type_ = 'chat', chatstate = chatstate_to_send,
|
type_ = 'chat', chatstate = chatstate_to_send,
|
||||||
composing_xep = composing_xep,
|
composing_xep = composing_xep,
|
||||||
process_command = process_command)
|
process_command = process_command, xhtml = xhtml)
|
||||||
if id:
|
if id:
|
||||||
# XXX: Once we have fallback to disco, remove
|
# XXX: Once we have fallback to disco, remove
|
||||||
# notexistant check
|
# notexistant check
|
||||||
|
@ -1738,7 +1807,8 @@ class ChatControl(ChatControlBase):
|
||||||
xep0184_id = None
|
xep0184_id = None
|
||||||
|
|
||||||
self.print_conversation(message, self.contact.jid,
|
self.print_conversation(message, self.contact.jid,
|
||||||
encrypted = encrypted, xep0184_id = xep0184_id)
|
encrypted = encrypted, xep0184_id = xep0184_id,
|
||||||
|
xhtml = xhtml)
|
||||||
|
|
||||||
def check_for_possible_paused_chatstate(self, arg):
|
def check_for_possible_paused_chatstate(self, arg):
|
||||||
''' did we move mouse of that window or write something in message
|
''' did we move mouse of that window or write something in message
|
||||||
|
|
|
@ -2454,6 +2454,9 @@ class Interface:
|
||||||
|
|
||||||
basic_pattern = links + '|' + mail + '|' + legacy_prefixes
|
basic_pattern = links + '|' + mail + '|' + legacy_prefixes
|
||||||
|
|
||||||
|
link_pattern = basic_pattern
|
||||||
|
self.link_pattern_re = re.compile(link_pattern, re.IGNORECASE)
|
||||||
|
|
||||||
if gajim.config.get('use_latex'):
|
if gajim.config.get('use_latex'):
|
||||||
basic_pattern += latex
|
basic_pattern += latex
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,7 @@ class PrivateChatControl(ChatControl):
|
||||||
ChatControl.__init__(self, parent_win, contact, account, session)
|
ChatControl.__init__(self, parent_win, contact, account, session)
|
||||||
self.TYPE_ID = 'pm'
|
self.TYPE_ID = 'pm'
|
||||||
|
|
||||||
def send_message(self, message):
|
def send_message(self, message, xhtml=None):
|
||||||
'''call this function to send our message'''
|
'''call this function to send our message'''
|
||||||
if not message:
|
if not message:
|
||||||
return
|
return
|
||||||
|
@ -153,7 +153,7 @@ class PrivateChatControl(ChatControl):
|
||||||
'left.') % {'room': room, 'nick': nick})
|
'left.') % {'room': room, 'nick': nick})
|
||||||
return
|
return
|
||||||
|
|
||||||
ChatControl.send_message(self, message)
|
ChatControl.send_message(self, message, xhtml=xhtml)
|
||||||
|
|
||||||
def update_ui(self):
|
def update_ui(self):
|
||||||
if self.contact.show == 'offline':
|
if self.contact.show == 'offline':
|
||||||
|
@ -1628,7 +1628,7 @@ class GroupchatControl(ChatControlBase):
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def send_message(self, message):
|
def send_message(self, message, xhtml=None):
|
||||||
'''call this function to send our message'''
|
'''call this function to send our message'''
|
||||||
if not message:
|
if not message:
|
||||||
return
|
return
|
||||||
|
@ -1644,7 +1644,7 @@ class GroupchatControl(ChatControlBase):
|
||||||
if not self._process_command(message):
|
if not self._process_command(message):
|
||||||
# Send the message
|
# Send the message
|
||||||
gajim.connections[self.account].send_gc_message(self.room_jid,
|
gajim.connections[self.account].send_gc_message(self.room_jid,
|
||||||
message)
|
message, xhtml=xhtml)
|
||||||
self.msg_textview.get_buffer().set_text('')
|
self.msg_textview.get_buffer().set_text('')
|
||||||
self.msg_textview.grab_focus()
|
self.msg_textview.grab_focus()
|
||||||
|
|
||||||
|
|
|
@ -162,7 +162,7 @@ class MessageControl:
|
||||||
|
|
||||||
def send_message(self, message, keyID = '', type_ = 'chat',
|
def send_message(self, message, keyID = '', type_ = 'chat',
|
||||||
chatstate = None, msg_id = None, composing_xep = None, resource = None,
|
chatstate = None, msg_id = None, composing_xep = None, resource = None,
|
||||||
user_nick = None):
|
user_nick = None, xhtml = None):
|
||||||
# Send the given message to the active tab.
|
# Send the given message to the active tab.
|
||||||
# Doesn't return None if error
|
# Doesn't return None if error
|
||||||
jid = self.contact.jid
|
jid = self.contact.jid
|
||||||
|
@ -189,6 +189,6 @@ class MessageControl:
|
||||||
composing_xep = composing_xep,
|
composing_xep = composing_xep,
|
||||||
resource = self.resource, user_nick = user_nick,
|
resource = self.resource, user_nick = user_nick,
|
||||||
session = self.session,
|
session = self.session,
|
||||||
original_message = original_message)
|
original_message = original_message, xhtml = xhtml)
|
||||||
|
|
||||||
# vim: se ts=3:
|
# vim: se ts=3:
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
|
|
||||||
import gtk
|
import gtk
|
||||||
import gobject
|
import gobject
|
||||||
|
import pango
|
||||||
|
import gtkgui_helpers
|
||||||
|
from common import gajim
|
||||||
|
|
||||||
class MessageTextView(gtk.TextView):
|
class MessageTextView(gtk.TextView):
|
||||||
'''Class for the message textview (where user writes new messages)
|
'''Class for the message textview (where user writes new messages)
|
||||||
|
@ -48,6 +51,222 @@ class MessageTextView(gtk.TextView):
|
||||||
self.set_pixels_below_lines(2)
|
self.set_pixels_below_lines(2)
|
||||||
|
|
||||||
self.lang = None # Lang used for spell checking
|
self.lang = None # Lang used for spell checking
|
||||||
|
buffer = self.get_buffer()
|
||||||
|
self.begin_tags = {}
|
||||||
|
self.end_tags = {}
|
||||||
|
self.color_tags = []
|
||||||
|
self.fonts_tags = []
|
||||||
|
self.other_tags = {}
|
||||||
|
self.other_tags['bold'] = buffer.create_tag('bold')
|
||||||
|
self.other_tags['bold'].set_property('weight', pango.WEIGHT_BOLD)
|
||||||
|
self.begin_tags['bold'] = '<strong>'
|
||||||
|
self.end_tags['bold'] = '</strong>'
|
||||||
|
self.other_tags['italic'] = buffer.create_tag('italic')
|
||||||
|
self.other_tags['italic'].set_property('style', pango.STYLE_ITALIC)
|
||||||
|
self.begin_tags['italic'] = '<em>'
|
||||||
|
self.end_tags['italic'] = '</em>'
|
||||||
|
self.other_tags['underline'] = buffer.create_tag('underline')
|
||||||
|
self.other_tags['underline'].set_property('underline', pango.UNDERLINE_SINGLE)
|
||||||
|
self.begin_tags['underline'] = '<span style="text-decoration: underline;">'
|
||||||
|
self.end_tags['underline'] = '</span>'
|
||||||
|
self.other_tags['strike'] = buffer.create_tag('strike')
|
||||||
|
self.other_tags['strike'].set_property('strikethrough', True)
|
||||||
|
self.begin_tags['strike'] = '<span style="text-decoration: line-through;">'
|
||||||
|
self.end_tags['strike'] = '</span>'
|
||||||
|
|
||||||
|
def make_clickable_urls(self, text):
|
||||||
|
buffer = self.get_buffer()
|
||||||
|
|
||||||
|
start = 0
|
||||||
|
end = 0
|
||||||
|
index = 0
|
||||||
|
|
||||||
|
new_text = ''
|
||||||
|
iterator = gajim.interface.link_pattern_re.finditer(text)
|
||||||
|
for match in iterator:
|
||||||
|
start, end = match.span()
|
||||||
|
url = text[start:end]
|
||||||
|
if start != 0:
|
||||||
|
text_before_special_text = text[index:start]
|
||||||
|
else:
|
||||||
|
text_before_special_text = ''
|
||||||
|
end_iter = buffer.get_end_iter()
|
||||||
|
# we insert normal text
|
||||||
|
new_text += text_before_special_text + \
|
||||||
|
'<a href="'+ url +'">' + url + '</a>'
|
||||||
|
|
||||||
|
index = end # update index
|
||||||
|
|
||||||
|
if end < len(text):
|
||||||
|
new_text += text[end:]
|
||||||
|
|
||||||
|
return new_text # the position after *last* special text
|
||||||
|
|
||||||
|
def get_active_tags(self):
|
||||||
|
buffer = self.get_buffer()
|
||||||
|
return_val = buffer.get_selection_bounds()
|
||||||
|
if return_val: # if sth was selected
|
||||||
|
start, finish = return_val[0], return_val[1]
|
||||||
|
else:
|
||||||
|
start, finish = buffer.get_bounds()
|
||||||
|
active_tags = []
|
||||||
|
for tag in start.get_tags():
|
||||||
|
active_tags.append(tag.get_property('name'))
|
||||||
|
return active_tags
|
||||||
|
|
||||||
|
def set_tag(self, widget, tag):
|
||||||
|
buffer = self.get_buffer()
|
||||||
|
return_val = buffer.get_selection_bounds()
|
||||||
|
if return_val: # if sth was selected
|
||||||
|
start, finish = return_val[0], return_val[1]
|
||||||
|
else:
|
||||||
|
start, finish = buffer.get_bounds()
|
||||||
|
if start.has_tag(self.other_tags[tag]):
|
||||||
|
buffer.remove_tag_by_name(tag, start, finish)
|
||||||
|
else:
|
||||||
|
if tag == 'underline':
|
||||||
|
buffer.remove_tag_by_name('strike', start, finish)
|
||||||
|
elif tag == 'strike':
|
||||||
|
buffer.remove_tag_by_name('underline', start, finish)
|
||||||
|
buffer.apply_tag_by_name(tag, start, finish)
|
||||||
|
|
||||||
|
def clear_tags(self, widget):
|
||||||
|
buffer = self.get_buffer()
|
||||||
|
return_val = buffer.get_selection_bounds()
|
||||||
|
if return_val: # if sth was selected
|
||||||
|
start, finish = return_val[0], return_val[1]
|
||||||
|
else:
|
||||||
|
start, finish = buffer.get_bounds()
|
||||||
|
buffer.remove_all_tags(start, finish)
|
||||||
|
|
||||||
|
def color_set(self, widget, response, color):
|
||||||
|
if response == -6:
|
||||||
|
widget.destroy()
|
||||||
|
return
|
||||||
|
buffer = self.get_buffer()
|
||||||
|
color = color.get_current_color()
|
||||||
|
widget.destroy()
|
||||||
|
color_string = gtkgui_helpers.make_color_string(color)
|
||||||
|
tag_name = 'color' + color_string
|
||||||
|
if not tag_name in self.color_tags:
|
||||||
|
tagColor = buffer.create_tag(tag_name)
|
||||||
|
tagColor.set_property('foreground', color_string)
|
||||||
|
self.begin_tags[tag_name] = '<span style="color: ' + color_string + ';">'
|
||||||
|
self.end_tags[tag_name] = '</span>'
|
||||||
|
self.color_tags.append(tag_name)
|
||||||
|
|
||||||
|
return_val = buffer.get_selection_bounds()
|
||||||
|
if return_val: # if sth was selected
|
||||||
|
start, finish = return_val[0], return_val[1]
|
||||||
|
else:
|
||||||
|
start, finish = buffer.get_bounds()
|
||||||
|
|
||||||
|
for tag in self.color_tags:
|
||||||
|
buffer.remove_tag_by_name(tag, start, finish)
|
||||||
|
|
||||||
|
buffer.apply_tag_by_name(tag_name, start, finish)
|
||||||
|
|
||||||
|
def font_set(self, widget, response, font):
|
||||||
|
if response == -6:
|
||||||
|
widget.destroy()
|
||||||
|
return
|
||||||
|
|
||||||
|
buffer = self.get_buffer()
|
||||||
|
|
||||||
|
font = font.get_font_name()
|
||||||
|
font_desc = pango.FontDescription(font)
|
||||||
|
family = font_desc.get_family()
|
||||||
|
size = font_desc.get_size()
|
||||||
|
size = size / pango.SCALE
|
||||||
|
weight = font_desc.get_weight()
|
||||||
|
style = font_desc.get_style()
|
||||||
|
|
||||||
|
widget.destroy()
|
||||||
|
|
||||||
|
tag_name = 'font' + font
|
||||||
|
if not tag_name in self.fonts_tags:
|
||||||
|
tagFont = buffer.create_tag(tag_name)
|
||||||
|
tagFont.set_property('font', family + ' ' + str(size))
|
||||||
|
self.begin_tags[tag_name] = \
|
||||||
|
'<span style="font-family: ' + family + '; ' + \
|
||||||
|
'font-size: ' + str(size) + 'px">'
|
||||||
|
self.end_tags[tag_name] = '</span>'
|
||||||
|
self.fonts_tags.append(tag_name)
|
||||||
|
|
||||||
|
return_val = buffer.get_selection_bounds()
|
||||||
|
if return_val: # if sth was selected
|
||||||
|
start, finish = return_val[0], return_val[1]
|
||||||
|
else:
|
||||||
|
start, finish = buffer.get_bounds()
|
||||||
|
|
||||||
|
for tag in self.fonts_tags:
|
||||||
|
buffer.remove_tag_by_name(tag, start, finish)
|
||||||
|
|
||||||
|
buffer.apply_tag_by_name(tag_name, start, finish)
|
||||||
|
|
||||||
|
if weight == pango.WEIGHT_BOLD:
|
||||||
|
buffer.apply_tag_by_name('bold', start, finish)
|
||||||
|
else:
|
||||||
|
buffer.remove_tag_by_name('bold', start, finish)
|
||||||
|
|
||||||
|
if style == pango.STYLE_ITALIC:
|
||||||
|
buffer.apply_tag_by_name('italic', start, finish)
|
||||||
|
else:
|
||||||
|
buffer.remove_tag_by_name('italic', start, finish)
|
||||||
|
|
||||||
|
def get_xhtml(self):
|
||||||
|
buffer = self.get_buffer()
|
||||||
|
old = buffer.get_start_iter()
|
||||||
|
tags = {}
|
||||||
|
tags['bold'] = False
|
||||||
|
iter = buffer.get_start_iter()
|
||||||
|
old = buffer.get_start_iter()
|
||||||
|
texte = ''
|
||||||
|
modified = False
|
||||||
|
def xhtml_special(text):
|
||||||
|
text = text.replace('<', '<')
|
||||||
|
text = text.replace('>', '>')
|
||||||
|
text = text.replace('\n', '<br />')
|
||||||
|
return text
|
||||||
|
|
||||||
|
for tag in iter.get_toggled_tags(True):
|
||||||
|
texte += self.begin_tags[tag.get_property('name')]
|
||||||
|
modified = True
|
||||||
|
while (iter.forward_to_tag_toggle(None) and not iter.is_end()):
|
||||||
|
modified = True
|
||||||
|
texte += xhtml_special(buffer.get_text(old, iter))
|
||||||
|
old.forward_to_tag_toggle(None)
|
||||||
|
new_tags = []
|
||||||
|
old_tags = []
|
||||||
|
end_tags = []
|
||||||
|
for tag in iter.get_toggled_tags(True):
|
||||||
|
new_tags.append(tag.get_property('name'))
|
||||||
|
|
||||||
|
for tag in iter.get_tags():
|
||||||
|
if tag.get_property('name') not in new_tags:
|
||||||
|
old_tags.append(tag.get_property('name'))
|
||||||
|
|
||||||
|
for tag in iter.get_toggled_tags(False):
|
||||||
|
end_tags.append(tag.get_property('name'))
|
||||||
|
|
||||||
|
for tag in old_tags:
|
||||||
|
texte += self.end_tags[tag]
|
||||||
|
for tag in end_tags:
|
||||||
|
texte += self.end_tags[tag]
|
||||||
|
for tag in new_tags:
|
||||||
|
texte += self.begin_tags[tag]
|
||||||
|
for tag in old_tags:
|
||||||
|
texte += self.begin_tags[tag]
|
||||||
|
|
||||||
|
texte += xhtml_special(buffer.get_text(old, buffer.get_end_iter()))
|
||||||
|
for tag in iter.get_toggled_tags(False):
|
||||||
|
texte += self.end_tags[tag.get_property('name')]
|
||||||
|
|
||||||
|
if modified:
|
||||||
|
return '<p>' + self.make_clickable_urls(texte) + '</p>'
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def destroy(self):
|
def destroy(self):
|
||||||
import gc
|
import gc
|
||||||
|
|
Loading…
Add table
Reference in a new issue