From 19d92c847ab87768104220e73cdd2d3ea4758033 Mon Sep 17 00:00:00 2001
From: Yann Leboulanger <asterix@lagaule.org>
Date: Sun, 8 Sep 2013 18:18:23 +0200
Subject: [PATCH] render the whole line when we use XEP-309 Last Message
 Correction. Fixes #7400, #7453

---
 .../32x32/categories/gajim-agent-twitter.png  | Bin 0 -> 1351 bytes
 src/conversation_textview.py                  |  99 +++++++++++-------
 src/htmltextview.py                           |  13 ++-
 3 files changed, 69 insertions(+), 43 deletions(-)
 create mode 100644 icons/hicolor/32x32/categories/gajim-agent-twitter.png

diff --git a/icons/hicolor/32x32/categories/gajim-agent-twitter.png b/icons/hicolor/32x32/categories/gajim-agent-twitter.png
new file mode 100644
index 0000000000000000000000000000000000000000..f7f862c40a56d6fd7f41f877976e61cabb2e3218
GIT binary patch
literal 1351
zcmV-N1-SZ&P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800004b3#c}2nYxW
zd<bNS00009a7bBm000fw000fw0YWI7cmMzZ8FWQhbW?9;ba!ELWdL_~cP?peYja~^
zaAhuUa%Y?FJQ@H11jI>1K~z|U#g|=dR7DiW|7Ygz-n;E?TWSHTQqUA5mhb>XOpQwL
zBjM4nXh2C!j1L-OFeXC$s11=+9>gfoga;!Kf-l4b9*JpqAb>WenxX+EN`*jC*+S{=
z{g|2K!@aw`-Og4UmpI8kle_ocJ-<EY%ztKynel%Pr``?fKhTo%xKEOJ&X4p0FC(vL
zHeZ%~>gT?V*Bb>uwhYkD&kIeQ{pr;;%R4r%=yq?*=P*_Zuy^=uu>0icKYg0);WuBt
z)(8M$`>+|_uD2gvwcz#M6|U>$a3N$kSr>2gu5jO3yK;Ur@*g!KcwGPh>z`P*By%w|
zC@KTrFpA3HLTK>RvL#s%9>1vozS5oTITt0(P>iZ3HDg}RMWA(OqX4W;C;(yrk)=Nv
z05RyM0#pJi%L+9B@>vJoz=3N36Eg?|0yD*r6FEYZ9YJHhQhTD%`;_~h3Fi!8>Hu7c
z48D8iX)w@206<96LDjUBl+OJ=QEuOJYGmNZ+4GA5Y?(6vGoUObIPYtSYS1`S)j7Fv
z1);6bjCa?qb`PI9|Ke-_^;SVO18GHx0t5Jof<&PKLXI_|85aYCd0rOU=mPck*Nrnv
z53scfYe#K25`e5Av^j)pp@JatRbQW(GeEr_=yD|%xdMXXGR3e{Gc(|8jZ2e0b`772
z93c<S_5-W{Okie^nsEc@%nIE9*&&QgmH{HB$}5y`FtHQ}9VxGB!w174+A((kW@VT&
zwk9+HA~q4U)6s}c$=V!3h%hu<^@6lQX0&>)0?_hbgVzNhP#9_h!?7Et6&gmH=Nd>;
zXas=WiUoqe7^@qG474`63~o#YtN;WG0&Tz$b^y<1NYl{>0J}jD{6HH348_xRH8OZ|
zd3W9w&H!!S+e0(0U{0fs5779yA0p#6&9LJiOA6~2-a>CZa^KyDemHw-WXHa&1JWQS
zFcBl3rJ$0O^0HFVK}Gn4w{7~%8p(Dflke}}zV*>H+g5dV$?qp;xB&{1ur%jjVMZWF
zweQE9(uC6Z^?C`%ejfGr51lRsOg+4HL-Ai_z_9-M*tyZy9=m5r!RCfV#rS3-0ua}b
zEJbJ*g!yg`&#%7M>nt>Nd@%U!#{gcaea_wktrI7PMlZYh<Zi7OO!tMU4JoawigBi_
zar}COwRhc~A<$Y|C@TPO-W&)aPoEpVfzGU$(TM+~v~P@SgH|_#P$}y%ZUz9wLx$zj
z?hglt%Bz|kv^k>g)@)PyxmGDK<|{}kZV-_qnqDwl1_*$o-+Sq+;on9F2L^|Nhw=gs
zwr0@N<Y192&>{)8C7PCDh9`jToW#f<MHYt7A?~?p0Mk}MLMH*_0JNdCW1-lzWpm5o
zJD*+Ovs5g*<JL@9TLJUE4BE2}gsuB3Wn{)g7-8f}k#`<F5ndV|+JG;19tBVapg9RV
zI{?rQpasj<EXK+Qdb3?id)f6C84@{WcBK&YPgKm2fVn|I`Im6`<Src9cN{=*R)7RT
z0LUf~c>qlSTmYE_E-jIylo9XLx<(2>0AMmv2|&oq)f18pfRZnkNze@9+Es#5YEEas
zq(CY#20)aOj*~ML)c)sms#7b!urec=3HCjJQ>t92!N4^E{|3sJ$#ERcIP3rb002ov
JPDHLkV1oGQSBC%q

literal 0
HcmV?d00001

diff --git a/src/conversation_textview.py b/src/conversation_textview.py
index d3918c19d9..6229426e1e 100644
--- a/src/conversation_textview.py
+++ b/src/conversation_textview.py
@@ -477,8 +477,8 @@ class ConversationTextview(gobject.GObject):
         buffer_.delete(i1, i2)
         tag = 'outgoingtxt'
         if message.startswith('/me'):
-           tag = 'outgoing'
-        i2 = self.print_real_text(message, text_tags=[tag], name=name,
+            tag = 'outgoing'
+        i2 = self.print_conversation_line(message, '', 'outgoing', name, None,
             xhtml=xhtml, iter_=i1)
         tt_txt = _('<b>Message was corrected. Last message was:</b>\n  %s') % \
             old_txt
@@ -496,7 +496,7 @@ class ConversationTextview(gobject.GObject):
         i2 = buffer_.get_iter_at_mark(m2)
         txt = buffer_.get_text(i1, i2)
         buffer_.delete(i1, i2)
-        i2 = self.print_real_text(message, text_tags=['incomingtxt'], name=name,
+        i2 = self.print_conversation_line(message, '', 'incoming', name, None,
             xhtml=xhtml, iter_=i1)
         tt_txt = _('<b>Message was corrected. Last message was:</b>\n  %s') % \
             old_txt
@@ -1243,12 +1243,14 @@ class ConversationTextview(gobject.GObject):
     def print_conversation_line(self, text, jid, kind, name, tim,
     other_tags_for_name=[], other_tags_for_time=[], other_tags_for_text=[],
     subject=None, old_kind=None, xhtml=None, simple=False, graphics=True,
-    displaymarking=None):
+    displaymarking=None, iter_=None):
         """
         Print 'chat' type messages
         """
         buffer_ = self.tv.get_buffer()
         buffer_.begin_user_action()
+        if iter_:
+            temp_mark = buffer_.create_mark(None, iter_, left_gravity=True)
         if self.marks_queue.full():
             # remove oldest line
             m1 = self.marks_queue.get()
@@ -1257,7 +1259,11 @@ class ConversationTextview(gobject.GObject):
             i2 = buffer_.get_iter_at_mark(m2)
             buffer_.delete(i1, i2)
             buffer_.delete_mark(m1)
-        end_iter = buffer_.get_end_iter()
+        if iter_:
+            end_iter = buffer_.get_iter_at_mark(temp_mark)
+            buffer_.delete_mark(temp_mark)
+        else:
+            end_iter = buffer_.get_end_iter()
         end_offset = end_iter.get_offset()
         at_the_end = self.at_the_end()
         move_selection = False
@@ -1265,21 +1271,22 @@ class ConversationTextview(gobject.GObject):
         get_offset() == end_offset:
             move_selection = True
 
-        # Create one mark and add it to queue once if it's the first line
-        # else twice (one for end bound, one for start bound)
-        mark = None
-        if buffer_.get_char_count() > 0:
-            if not simple:
-                buffer_.insert_with_tags_by_name(end_iter, '\n', 'eol')
-                if move_selection:
-                    sel_start, sel_end = buffer_.get_selection_bounds()
-                    sel_end.backward_char()
-                    buffer_.select_range(sel_start, sel_end)
-            mark = buffer_.create_mark(None, end_iter, left_gravity=True)
+        if not iter_:
+            # Create one mark and add it to queue once if it's the first line
+            # else twice (one for end bound, one for start bound)
+            mark = None
+            if buffer_.get_char_count() > 0:
+                if not simple and not iter_:
+                    buffer_.insert_with_tags_by_name(end_iter, '\n', 'eol')
+                    if move_selection:
+                        sel_start, sel_end = buffer_.get_selection_bounds()
+                        sel_end.backward_char()
+                        buffer_.select_range(sel_start, sel_end)
+                mark = buffer_.create_mark(None, end_iter, left_gravity=True)
+                self.marks_queue.put(mark)
+            if not mark:
+                mark = buffer_.create_mark(None, end_iter, left_gravity=True)
             self.marks_queue.put(mark)
-        if not mark:
-            mark = buffer_.create_mark(None, end_iter, left_gravity=True)
-        self.marks_queue.put(mark)
         if kind == 'incoming_queue':
             kind = 'incoming'
         if old_kind == 'incoming_queue':
@@ -1318,7 +1325,7 @@ class ConversationTextview(gobject.GObject):
                         'time_sometimes')
         # If there's a displaymarking, print it here.
         if displaymarking:
-            self.print_displaymarking(displaymarking)
+            self.print_displaymarking(displaymarking, iter_=end_iter)
         # kind = info, we print things as if it was a status: same color, ...
         if kind in ('error', 'info'):
             kind = 'status'
@@ -1328,36 +1335,43 @@ class ConversationTextview(gobject.GObject):
         if other_text_tag:
             # note that color of /me may be overwritten in gc_control
             text_tags.append(other_text_tag)
-            if text.startswith('/me'):
-                mark1 = buffer_.create_mark(None, buffer_.get_end_iter(),
-                    left_gravity=True)
+            if text.startswith('/me') and not iter_:
+                mark1 = mark
         else: # not status nor /me
             if gajim.config.get('chat_merge_consecutive_nickname'):
                 if kind != old_kind or self.just_cleared:
                     self.print_name(name, kind, other_tags_for_name,
-                        direction_mark=direction_mark)
+                        direction_mark=direction_mark, iter_=end_iter)
                 else:
                     self.print_real_text(gajim.config.get(
-                        'chat_merge_consecutive_nickname_indent'))
+                        'chat_merge_consecutive_nickname_indent'),
+                        iter_=end_iter)
             else:
                 self.print_name(name, kind, other_tags_for_name,
-                    direction_mark=direction_mark)
+                    direction_mark=direction_mark, iter_=end_iter)
             if kind == 'incoming':
                 text_tags.append('incomingtxt')
-                mark1 = buffer_.create_mark(None, buffer_.get_end_iter(),
-                    left_gravity=True)
+                if not iter_:
+                    mark1 = mark
             elif kind == 'outgoing':
                 text_tags.append('outgoingtxt')
-                mark1 = buffer_.create_mark(None, buffer_.get_end_iter(),
-                    left_gravity=True)
-        self.print_subject(subject)
-        self.print_real_text(text, text_tags, name, xhtml, graphics=graphics)
-        if mark1:
+                if not iter_:
+                    mark1 = mark
+        self.print_subject(subject, iter_=end_iter)
+        self.print_real_text(text, text_tags, name, xhtml, graphics=graphics,
+            iter_=end_iter)
+        if not iter_ and mark1:
             mark2 = buffer_.create_mark(None, buffer_.get_end_iter(),
                 left_gravity=True)
             if kind == 'incoming':
+                if name in self.last_received_message_marks:
+                    m = self.last_received_message_marks[name][1]
+                    buffer_.delete_mark(m)
                 self.last_received_message_marks[name] = [mark1, mark2]
             elif kind == 'outgoing':
+                m = self.last_sent_message_marks[1]
+                if m:
+                    buffer_.delete_mark(m)
                 self.last_sent_message_marks = [mark1, mark2]
         # scroll to the end of the textview
         if at_the_end or kind == 'outgoing':
@@ -1370,6 +1384,7 @@ class ConversationTextview(gobject.GObject):
 
         self.just_cleared = False
         buffer_.end_user_action()
+        return end_iter
 
     def get_time_to_show(self, tim, direction_mark=''):
         """
@@ -1407,23 +1422,30 @@ class ConversationTextview(gobject.GObject):
         elif text.startswith('/me ') or text.startswith('/me\n'):
             return kind
 
-    def print_displaymarking(self, displaymarking):
+    def print_displaymarking(self, displaymarking, iter_=None):
         bgcolor = displaymarking.getAttr('bgcolor') or '#FFF'
         fgcolor = displaymarking.getAttr('fgcolor') or '#000'
         text = displaymarking.getData()
         if text:
             buffer_ = self.tv.get_buffer()
-            end_iter = buffer_.get_end_iter()
+            if iter_:
+                end_iter = iter_
+            else:
+                end_iter = buffer_.get_end_iter()
             tag = self.displaymarking_tags.setdefault(bgcolor + '/' + fgcolor,
                 buffer_.create_tag(None, background=bgcolor, foreground=fgcolor))
             buffer_.insert_with_tags(end_iter, '[' + text + ']', tag)
             end_iter = buffer_.get_end_iter()
             buffer_.insert_with_tags(end_iter, ' ')
 
-    def print_name(self, name, kind, other_tags_for_name, direction_mark=''):
+    def print_name(self, name, kind, other_tags_for_name, direction_mark='',
+    iter_=None):
         if name:
             buffer_ = self.tv.get_buffer()
-            end_iter = buffer_.get_end_iter()
+            if iter_:
+                end_iter = iter_
+            else:
+                end_iter = buffer_.get_end_iter()
             name_tags = other_tags_for_name[:] # create a new list
             name_tags.append(kind)
             before_str = gajim.config.get('before_nickname')
@@ -1453,7 +1475,8 @@ class ConversationTextview(gobject.GObject):
             try:
                 if name and (text.startswith('/me ') or text.startswith('/me\n')):
                     xhtml = xhtml.replace('/me', '<i>* %s</i>' % (name,), 1)
-                self.tv.display_html(xhtml.encode('utf-8'), self.tv, self)
+                self.tv.display_html(xhtml.encode('utf-8'), self.tv, self,
+                    iter_=iter_)
                 return
             except Exception, e:
                 gajim.log.debug('Error processing xhtml' + str(e))
diff --git a/src/htmltextview.py b/src/htmltextview.py
index 5fb028f690..25ecf1261d 100644
--- a/src/htmltextview.py
+++ b/src/htmltextview.py
@@ -656,7 +656,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
     def handle_specials(self, text):
         if self.conv_textview:
             self.iter = self.conv_textview.detect_and_print_special_text(text,
-                self._get_style_tags())
+                self._get_style_tags(), iter_=self.iter)
         else:
             self._insert_text(text)
 
@@ -815,8 +815,8 @@ class HtmlTextView(gtk.TextView):
         self.id_ = self.connect('button-release-event',
             self.on_left_mouse_button_release)
         buffer_ = self.get_buffer()
-        buffer_.create_tag('eol', scale = pango.SCALE_XX_SMALL)
-        
+        buffer_.create_tag('eol')
+
         self.tooltip = tooltips.BaseTooltip()
         self.config = gajim.config
         self.interface = gajim.interface
@@ -1018,9 +1018,12 @@ class HtmlTextView(gtk.TextView):
         # 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):
+    def display_html(self, html, textview, conv_textview, iter_=None):
         buffer_ = self.get_buffer()
-        eob = buffer_.get_end_iter()
+        if iter_:
+            eob = iter_
+        else:
+            eob = buffer_.get_end_iter()
         ## this works too if libxml2 is not available
         # parser = xml.sax.make_parser(['drv_libxml2'])
         # parser.setFeature(xml.sax.handler.feature_validation, True)
-- 
GitLab