Merge branch 'printline' into 'master'
print_conversation_line() refactoring See merge request !3
This commit is contained in:
		
						commit
						430c4b1536
					
				
					 7 changed files with 327 additions and 308 deletions
				
			
		| 
						 | 
				
			
			@ -341,7 +341,6 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
 | 
			
		|||
        self.was_at_the_end = True
 | 
			
		||||
        self.correcting = False
 | 
			
		||||
        self.last_sent_msg = None
 | 
			
		||||
        self.last_sent_txt = None
 | 
			
		||||
        self.last_received_txt = {} # one per name
 | 
			
		||||
        self.last_received_id = {} # one per name
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -785,7 +784,6 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
 | 
			
		|||
 | 
			
		||||
        def _cb(obj, msg, cb, *cb_args):
 | 
			
		||||
            self.last_sent_msg = msg
 | 
			
		||||
            self.last_sent_txt = cb_args[0]
 | 
			
		||||
            if cb:
 | 
			
		||||
                cb(obj, msg, *cb_args)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -841,7 +839,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
 | 
			
		|||
    other_tags_for_name=[], other_tags_for_time=[], other_tags_for_text=[],
 | 
			
		||||
    count_as_new=True, subject=None, old_kind=None, xhtml=None, simple=False,
 | 
			
		||||
    xep0184_id=None, graphics=True, displaymarking=None, msg_log_id=None,
 | 
			
		||||
    correct_id=None, additional_data={}):
 | 
			
		||||
    msg_stanza_id=None, correct_id=None, additional_data={}):
 | 
			
		||||
        """
 | 
			
		||||
        Print 'chat' type messages
 | 
			
		||||
        correct_id = (message_id, correct_id)
 | 
			
		||||
| 
						 | 
				
			
			@ -852,26 +850,12 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
 | 
			
		|||
        end = False
 | 
			
		||||
        if self.was_at_the_end or kind == 'outgoing':
 | 
			
		||||
            end = True
 | 
			
		||||
        old_txt = ''
 | 
			
		||||
        if name in self.last_received_txt:
 | 
			
		||||
            old_txt = self.last_received_txt[name]
 | 
			
		||||
        if correct_id and correct_id[1] and \
 | 
			
		||||
        name in self.conv_textview.last_received_message_marks and \
 | 
			
		||||
        correct_id[1] == self.last_received_id[name]:
 | 
			
		||||
            self.conv_textview.correct_last_received_message(text, xhtml,
 | 
			
		||||
                name, old_txt)
 | 
			
		||||
        elif correct_id and correct_id[1] and \
 | 
			
		||||
        self.conv_textview.last_sent_message_marks[0] and \
 | 
			
		||||
        correct_id[1] == self.last_received_id[name]:
 | 
			
		||||
            # this is for carbon copied messages that are sent from another
 | 
			
		||||
            # resource
 | 
			
		||||
            self.conv_textview.correct_last_sent_message(text, xhtml,
 | 
			
		||||
                self.get_our_nick(), old_txt, additional_data=additional_data)
 | 
			
		||||
        else:
 | 
			
		||||
            textview.print_conversation_line(text, jid, kind, name, tim,
 | 
			
		||||
                other_tags_for_name, other_tags_for_time, other_tags_for_text,
 | 
			
		||||
                subject, old_kind, xhtml, simple=simple, graphics=graphics,
 | 
			
		||||
                displaymarking=displaymarking, additional_data=additional_data)
 | 
			
		||||
 | 
			
		||||
        textview.print_conversation_line(text, jid, kind, name, tim,
 | 
			
		||||
            other_tags_for_name, other_tags_for_time, other_tags_for_text,
 | 
			
		||||
            subject, old_kind, xhtml, simple=simple, graphics=graphics,
 | 
			
		||||
            displaymarking=displaymarking, msg_stanza_id=msg_stanza_id,
 | 
			
		||||
            correct_id=correct_id, additional_data=additional_data)
 | 
			
		||||
 | 
			
		||||
        if xep0184_id is not None:
 | 
			
		||||
            textview.show_xep0184_warning(xep0184_id)
 | 
			
		||||
| 
						 | 
				
			
			@ -1364,6 +1348,7 @@ class ChatControl(ChatControlBase):
 | 
			
		|||
        self.gpg_is_active = False
 | 
			
		||||
        self.last_recv_message_id = None
 | 
			
		||||
        self.last_recv_message_marks = None
 | 
			
		||||
        self.last_message_timestamp = None
 | 
			
		||||
        # for muc use:
 | 
			
		||||
        # widget = self.xml.get_object('muc_window_actions_button')
 | 
			
		||||
        self.actions_button = self.xml.get_object('message_window_actions_button')
 | 
			
		||||
| 
						 | 
				
			
			@ -2282,7 +2267,7 @@ class ChatControl(ChatControlBase):
 | 
			
		|||
                GLib.source_remove(self.possible_inactive_timeout_id)
 | 
			
		||||
                self._schedule_activity_timers()
 | 
			
		||||
 | 
			
		||||
        def _on_sent(obj, msg_stanza, message, encrypted, xhtml, label, old_txt):
 | 
			
		||||
        def _on_sent(obj, msg_stanza, message, encrypted, xhtml, label):
 | 
			
		||||
            id_ = msg_stanza.getID()
 | 
			
		||||
            if self.contact.supports(NS_RECEIPTS) and gajim.config.get_per(
 | 
			
		||||
            'accounts', self.account, 'request_receipt'):
 | 
			
		||||
| 
						 | 
				
			
			@ -2293,22 +2278,21 @@ class ChatControl(ChatControlBase):
 | 
			
		|||
                displaymarking = label.getTag('displaymarking')
 | 
			
		||||
            else:
 | 
			
		||||
                displaymarking = None
 | 
			
		||||
            if self.correcting and \
 | 
			
		||||
            self.conv_textview.last_sent_message_marks[0]:
 | 
			
		||||
                self.conv_textview.correct_last_sent_message(message, xhtml,
 | 
			
		||||
                    self.get_our_nick(), old_txt, additional_data=obj.additional_data)
 | 
			
		||||
            if self.correcting:
 | 
			
		||||
                self.correcting = False
 | 
			
		||||
                self.msg_textview.override_background_color(
 | 
			
		||||
                    Gtk.StateType.NORMAL, self.old_message_tv_color)
 | 
			
		||||
                return
 | 
			
		||||
 | 
			
		||||
            self.print_conversation(message, self.contact.jid,
 | 
			
		||||
                encrypted=encrypted, xep0184_id=xep0184_id, xhtml=xhtml,
 | 
			
		||||
                displaymarking=displaymarking, additional_data=obj.additional_data)
 | 
			
		||||
                displaymarking=displaymarking, msg_stanza_id=id_,
 | 
			
		||||
                correct_id=msg_stanza.getTagAttr('replace', 'id'),
 | 
			
		||||
                additional_data=obj.additional_data)
 | 
			
		||||
 | 
			
		||||
        ChatControlBase.send_message(self, message, keyID, type_='chat',
 | 
			
		||||
            chatstate=chatstate_to_send, xhtml=xhtml, callback=_on_sent,
 | 
			
		||||
            callback_args=[message, encrypted, xhtml, self.get_seclabel(),
 | 
			
		||||
            self.last_sent_txt], process_commands=process_commands,
 | 
			
		||||
            callback_args=[message, encrypted, xhtml, self.get_seclabel()],
 | 
			
		||||
            process_commands=process_commands,
 | 
			
		||||
            attention=attention)
 | 
			
		||||
 | 
			
		||||
    def check_for_possible_paused_chatstate(self, arg):
 | 
			
		||||
| 
						 | 
				
			
			@ -2422,7 +2406,8 @@ class ChatControl(ChatControlBase):
 | 
			
		|||
 | 
			
		||||
    def print_conversation(self, text, frm='', tim=None, encrypted=False,
 | 
			
		||||
    subject=None, xhtml=None, simple=False, xep0184_id=None,
 | 
			
		||||
    displaymarking=None, msg_log_id=None, correct_id=None, additional_data={}):
 | 
			
		||||
    displaymarking=None, msg_log_id=None, correct_id=None,
 | 
			
		||||
    msg_stanza_id=None, additional_data={}):
 | 
			
		||||
        """
 | 
			
		||||
        Print a line in the conversation
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2487,7 +2472,8 @@ class ChatControl(ChatControlBase):
 | 
			
		|||
        ChatControlBase.print_conversation_line(self, text, kind, name, tim,
 | 
			
		||||
            subject=subject, old_kind=self.old_msg_kind, xhtml=xhtml,
 | 
			
		||||
            simple=simple, xep0184_id=xep0184_id, displaymarking=displaymarking,
 | 
			
		||||
            msg_log_id=msg_log_id, correct_id=correct_id, additional_data=additional_data)
 | 
			
		||||
            msg_log_id=msg_log_id, msg_stanza_id=msg_stanza_id,
 | 
			
		||||
            correct_id=correct_id, additional_data=additional_data)
 | 
			
		||||
        if text.startswith('/me ') or text.startswith('/me\n'):
 | 
			
		||||
            self.old_msg_kind = None
 | 
			
		||||
        else:
 | 
			
		||||
| 
						 | 
				
			
			@ -2961,7 +2947,7 @@ class ChatControl(ChatControlBase):
 | 
			
		|||
                kind = 'status'
 | 
			
		||||
                name = self.contact.get_shown_name()
 | 
			
		||||
 | 
			
		||||
            tim = time.localtime(float(row[0]))
 | 
			
		||||
            tim = float(row[0])
 | 
			
		||||
 | 
			
		||||
            if gajim.config.get('restored_messages_small'):
 | 
			
		||||
                small_attr = ['small']
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1032,7 +1032,7 @@ class ConnectionHandlersBase:
 | 
			
		|||
            # Do not override assigned key
 | 
			
		||||
            obj.contact.keyID = obj.keyID
 | 
			
		||||
        if obj.timestamp:
 | 
			
		||||
            obj.contact.last_status_time = obj.timestamp
 | 
			
		||||
            obj.contact.last_status_time = localtime(obj.timestamp)
 | 
			
		||||
        elif not gajim.block_signed_in_notifications[account]:
 | 
			
		||||
            # We're connected since more that 30 seconds
 | 
			
		||||
            obj.contact.last_status_time = localtime()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -94,12 +94,16 @@ class HelperEvent:
 | 
			
		|||
            self.gc_control = minimized.get(self.jid)
 | 
			
		||||
 | 
			
		||||
    def _generate_timestamp(self, tag):
 | 
			
		||||
        # Make sure we use only int/float Epoch time
 | 
			
		||||
        if not isinstance(tag, str):
 | 
			
		||||
            self.timestamp = time_time()
 | 
			
		||||
            return
 | 
			
		||||
        try:
 | 
			
		||||
            tim = helpers.datetime_tuple(tag)
 | 
			
		||||
            self.timestamp = timegm(tim)
 | 
			
		||||
        except Exception:
 | 
			
		||||
            log.error('wrong timestamp, ignoring it: ' + tag)
 | 
			
		||||
            tim = localtime()
 | 
			
		||||
        self.timestamp = localtime(timegm(tim))
 | 
			
		||||
            self.timestamp = time_time()
 | 
			
		||||
 | 
			
		||||
    def get_chatstate(self):
 | 
			
		||||
        """
 | 
			
		||||
| 
						 | 
				
			
			@ -1059,7 +1063,7 @@ class MamMessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
 | 
			
		|||
            return
 | 
			
		||||
        tim = delay.getAttr('stamp')
 | 
			
		||||
        tim = helpers.datetime_tuple(tim)
 | 
			
		||||
        self.tim = localtime(timegm(tim))
 | 
			
		||||
        self.tim = timegm(tim)
 | 
			
		||||
        to_ = self.msg_.getAttr('to')
 | 
			
		||||
        if to_:
 | 
			
		||||
            to_ = gajim.get_jid_without_resource(to_)
 | 
			
		||||
| 
						 | 
				
			
			@ -1278,7 +1282,7 @@ class MessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
 | 
			
		|||
 | 
			
		||||
                if not form.getField('FORM_TYPE'):
 | 
			
		||||
                    return
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
                if form['FORM_TYPE'] == 'urn:xmpp:ssn':
 | 
			
		||||
                    self.session.handle_negotiation(form)
 | 
			
		||||
                else:
 | 
			
		||||
| 
						 | 
				
			
			@ -1302,6 +1306,7 @@ class MessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
 | 
			
		|||
 | 
			
		||||
        self._generate_timestamp(self.stanza.getTimestamp())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        self.encrypted = False
 | 
			
		||||
        xep_200_encrypted = self.stanza.getTag('c',
 | 
			
		||||
            namespace=nbxmpp.NS_STANZA_CRYPTO)
 | 
			
		||||
| 
						 | 
				
			
			@ -1522,6 +1527,7 @@ class GcMessageReceivedEvent(nec.NetworkIncomingEvent):
 | 
			
		|||
        self.stanza = self.msg_obj.stanza
 | 
			
		||||
        if not hasattr(self, 'additional_data'):
 | 
			
		||||
            self.additional_data = self.msg_obj.additional_data
 | 
			
		||||
        self.id_ = self.msg_obj.stanza.getID()
 | 
			
		||||
        self.fjid = self.msg_obj.fjid
 | 
			
		||||
        self.msgtxt = self.msg_obj.msgtxt
 | 
			
		||||
        self.jid = self.msg_obj.jid
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -523,9 +523,9 @@ class Logger:
 | 
			
		|||
        subject_col = subject
 | 
			
		||||
        additional_data_col = json.dumps(additional_data)
 | 
			
		||||
        if tim:
 | 
			
		||||
            time_col = int(float(time.mktime(tim)))
 | 
			
		||||
            time_col = float(tim)
 | 
			
		||||
        else:
 | 
			
		||||
            time_col = int(float(time.time()))
 | 
			
		||||
            time_col = float(time.time())
 | 
			
		||||
 | 
			
		||||
        kind_col, show_col = self.convert_human_values_to_db_api_values(kind,
 | 
			
		||||
                show)
 | 
			
		||||
| 
						 | 
				
			
			@ -1112,9 +1112,9 @@ class Logger:
 | 
			
		|||
 | 
			
		||||
    def save_if_not_exists(self, with_, direction, tim, msg='', nick=None, additional_data={}):
 | 
			
		||||
        if tim:
 | 
			
		||||
            time_col = int(float(time.mktime(tim)))
 | 
			
		||||
            time_col = float(tim)
 | 
			
		||||
        else:
 | 
			
		||||
            time_col = int(float(time.time()))
 | 
			
		||||
            time_col = float(time.time())
 | 
			
		||||
        if not msg:
 | 
			
		||||
            return
 | 
			
		||||
        if self.jid_is_from_pm(with_) or nick:
 | 
			
		||||
| 
						 | 
				
			
			@ -1157,7 +1157,7 @@ class Logger:
 | 
			
		|||
        self.write(type_, with_, message=msg, tim=tim, additional_data=additional_data)
 | 
			
		||||
 | 
			
		||||
    def _nec_gc_message_received(self, obj):
 | 
			
		||||
        tim_f = float(time.mktime(obj.timestamp))
 | 
			
		||||
        tim_f = float(obj.timestamp)
 | 
			
		||||
        tim_int = int(tim_f)
 | 
			
		||||
        if gajim.config.should_log(obj.conn.name, obj.jid) and not \
 | 
			
		||||
        tim_int < obj.conn.last_history_time[obj.jid] and obj.msgtxt and \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,6 +57,9 @@ NOT_SHOWN = 0
 | 
			
		|||
ALREADY_RECEIVED = 1
 | 
			
		||||
SHOWN = 2
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
log = logging.getLogger('gajim.conversation_textview')
 | 
			
		||||
 | 
			
		||||
def is_selection_modified(mark):
 | 
			
		||||
    name = mark.get_name()
 | 
			
		||||
    if name and name in ('selection_bound', 'insert'):
 | 
			
		||||
| 
						 | 
				
			
			@ -154,7 +157,6 @@ class TextViewImage(Gtk.Image):
 | 
			
		|||
        if is_selection_modified(mark):
 | 
			
		||||
            self._update_selected()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ConversationTextview(GObject.GObject):
 | 
			
		||||
    """
 | 
			
		||||
    Class for the conversation textview (where user reads already said messages)
 | 
			
		||||
| 
						 | 
				
			
			@ -185,14 +187,17 @@ class ConversationTextview(GObject.GObject):
 | 
			
		|||
        """
 | 
			
		||||
        GObject.GObject.__init__(self)
 | 
			
		||||
        self.used_in_history_window = used_in_history_window
 | 
			
		||||
 | 
			
		||||
        self.line = 0
 | 
			
		||||
        self.message_list = []
 | 
			
		||||
        self.corrected_text_list = {}
 | 
			
		||||
        self.fc = FuzzyClock()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        # no need to inherit TextView, use it as atrribute is safer
 | 
			
		||||
        self.tv = HtmlTextView()
 | 
			
		||||
        self.tv.hyperlink_handler = self.hyperlink_handler
 | 
			
		||||
 | 
			
		||||
        self.tv.set_has_tooltip(True)
 | 
			
		||||
 | 
			
		||||
        # set properties
 | 
			
		||||
        self.tv.set_border_width(1)
 | 
			
		||||
        self.tv.set_accepts_tab(True)
 | 
			
		||||
| 
						 | 
				
			
			@ -206,9 +211,10 @@ class ConversationTextview(GObject.GObject):
 | 
			
		|||
        self.image_cache = {}
 | 
			
		||||
        self.xep0184_marks = {}
 | 
			
		||||
        self.xep0184_shown = {}
 | 
			
		||||
        self.last_sent_message_marks = [None, None]
 | 
			
		||||
        # A pair per occupant. Key is '' in normal chat
 | 
			
		||||
        self.last_received_message_marks = {}
 | 
			
		||||
        # self.last_sent_message_id = msg_stanza_id
 | 
			
		||||
        self.last_sent_message_id = None
 | 
			
		||||
        # last_received_message_id[name] = (msg_stanza_id, line_start_mark)
 | 
			
		||||
        self.last_received_message_id = {}
 | 
			
		||||
 | 
			
		||||
        # It's True when we scroll in the code, so we can detect scroll from user
 | 
			
		||||
        self.auto_scrolling = False
 | 
			
		||||
| 
						 | 
				
			
			@ -225,6 +231,8 @@ class ConversationTextview(GObject.GObject):
 | 
			
		|||
 | 
			
		||||
        id_ = self.tv.connect('draw', self.on_textview_draw)
 | 
			
		||||
        self.handlers[id_] = self.tv
 | 
			
		||||
        id_ = self.tv.connect('query-tooltip', self.query_tooltip)
 | 
			
		||||
        self.handlers[id_] = self.tv
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        self.account = account
 | 
			
		||||
| 
						 | 
				
			
			@ -326,18 +334,39 @@ class ConversationTextview(GObject.GObject):
 | 
			
		|||
 | 
			
		||||
        self.xep0184_warning_tooltip = tooltips.BaseTooltip()
 | 
			
		||||
 | 
			
		||||
        self.line_tooltip = tooltips.BaseTooltip()
 | 
			
		||||
        self.smooth_id = None
 | 
			
		||||
        self.just_cleared = False
 | 
			
		||||
 | 
			
		||||
    def query_tooltip(self, widget, x_pos, y_pos, keyboard_mode, tooltip):
 | 
			
		||||
        x_pos, y_pos = self.tv.window_to_buffer_coords(
 | 
			
		||||
            Gtk.TextWindowType.TEXT, x_pos, y_pos)
 | 
			
		||||
        if Gtk.MINOR_VERSION > 18:
 | 
			
		||||
            iter_ = self.tv.get_iter_at_position(x_pos, y_pos)[1]
 | 
			
		||||
        else:
 | 
			
		||||
            iter_ = self.tv.get_iter_at_position(x_pos, y_pos)[0]
 | 
			
		||||
        for tag in iter_.get_tags():
 | 
			
		||||
            tag_name = tag.get_property('name')
 | 
			
		||||
            if tag_name == 'focus-out-line':
 | 
			
		||||
                tooltip.set_text(_(
 | 
			
		||||
                    'Text below this line is what has '
 | 
			
		||||
                    'been said since the\nlast time you paid attention to this '
 | 
			
		||||
                    'group chat'))
 | 
			
		||||
                return True
 | 
			
		||||
 | 
			
		||||
            try:
 | 
			
		||||
                text = self.corrected_text_list[tag_name]
 | 
			
		||||
                tooltip.set_markup(text)
 | 
			
		||||
                return True
 | 
			
		||||
            except KeyError:
 | 
			
		||||
                pass
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    def del_handlers(self):
 | 
			
		||||
        for i in self.handlers.keys():
 | 
			
		||||
            if self.handlers[i].handler_is_connected(i):
 | 
			
		||||
                self.handlers[i].disconnect(i)
 | 
			
		||||
        del self.handlers
 | 
			
		||||
        self.tv.destroy()
 | 
			
		||||
        #FIXME:
 | 
			
		||||
        # self.line_tooltip.destroy()
 | 
			
		||||
 | 
			
		||||
    def update_tags(self):
 | 
			
		||||
        self.tagIn.set_property('foreground', gajim.config.get('inmsgcolor'))
 | 
			
		||||
| 
						 | 
				
			
			@ -398,7 +427,7 @@ class ConversationTextview(GObject.GObject):
 | 
			
		|||
            self.auto_scrolling = False
 | 
			
		||||
 | 
			
		||||
    def smooth_scroll_to_end(self):
 | 
			
		||||
        if None != self.smooth_id: # already scrolling
 | 
			
		||||
        if self.smooth_id is not None:  # already scrolling
 | 
			
		||||
            return False
 | 
			
		||||
        self.smooth_id = GLib.timeout_add(self.SCROLL_DELAY,
 | 
			
		||||
                self.smooth_scroll)
 | 
			
		||||
| 
						 | 
				
			
			@ -448,55 +477,46 @@ class ConversationTextview(GObject.GObject):
 | 
			
		|||
            self.smooth_id = None
 | 
			
		||||
            self.smooth_scroll_timer.cancel()
 | 
			
		||||
 | 
			
		||||
    def show_corrected_message_warning(self, iter_, text=''):
 | 
			
		||||
        buffer_ = self.tv.get_buffer()
 | 
			
		||||
        buffer_.begin_user_action()
 | 
			
		||||
        buffer_.insert(iter_, ' ')
 | 
			
		||||
        anchor = buffer_.create_child_anchor(iter_)
 | 
			
		||||
        img = TextViewImage(anchor, text)
 | 
			
		||||
        img.set_from_pixbuf(ConversationTextview.MESSAGE_CORRECTED_PIXBUF)
 | 
			
		||||
        img.show()
 | 
			
		||||
        self.tv.add_child_at_anchor(img, anchor)
 | 
			
		||||
        buffer_.end_user_action()
 | 
			
		||||
    def correct_message(self, correct_id, kind, name):
 | 
			
		||||
        allowed = True
 | 
			
		||||
        if kind == 'incoming':
 | 
			
		||||
            try:
 | 
			
		||||
                if correct_id in self.last_received_message_id[name]:
 | 
			
		||||
                    start_mark = self.last_received_message_id[name][1]
 | 
			
		||||
                else:
 | 
			
		||||
                    allowed = False
 | 
			
		||||
            except KeyError:
 | 
			
		||||
                allowed = False
 | 
			
		||||
        elif kind == 'outgoing':
 | 
			
		||||
            if self.last_sent_message_id[0] == correct_id:
 | 
			
		||||
                start_mark = self.last_sent_message_id[1]
 | 
			
		||||
            else:
 | 
			
		||||
                allowed = False
 | 
			
		||||
        else:
 | 
			
		||||
            allowed = False
 | 
			
		||||
 | 
			
		||||
    def correct_last_sent_message(self, message, xhtml, name, old_txt, additional_data={}):
 | 
			
		||||
        m1 = self.last_sent_message_marks[0]
 | 
			
		||||
        m2 = self.last_sent_message_marks[1]
 | 
			
		||||
        buffer_ = self.tv.get_buffer()
 | 
			
		||||
        i1 = buffer_.get_iter_at_mark(m1)
 | 
			
		||||
        i2 = buffer_.get_iter_at_mark(m2)
 | 
			
		||||
        txt = buffer_.get_text(i1, i2, True)
 | 
			
		||||
        buffer_.delete(i1, i2)
 | 
			
		||||
        tag = 'outgoingtxt'
 | 
			
		||||
        if message.startswith('/me'):
 | 
			
		||||
            tag = 'outgoing'
 | 
			
		||||
        i2 = self.print_conversation_line(message, '', 'outgoing', name, None,
 | 
			
		||||
            xhtml=xhtml, iter_=i1, additional_data=additional_data)
 | 
			
		||||
        tt_txt = _('<b>Message was corrected. Last message was:</b>\n  %s') % \
 | 
			
		||||
            GLib.markup_escape_text(old_txt)
 | 
			
		||||
        self.show_corrected_message_warning(i2, tt_txt)
 | 
			
		||||
        self.last_sent_message_marks[1] = buffer_.create_mark(None, i2,
 | 
			
		||||
            left_gravity=True)
 | 
			
		||||
        if not allowed:
 | 
			
		||||
            log.debug('Message correctiong not allowed')
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
        end_mark, index = self.get_end_mark(correct_id, start_mark)
 | 
			
		||||
        if not index:
 | 
			
		||||
            log.debug('Could not find line to correct')
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
    def correct_last_received_message(self, message, xhtml, name, old_txt,
 | 
			
		||||
    other_tags_for_name=[], other_tags_for_text=[], additional_data={}):
 | 
			
		||||
        if name not in self.last_received_message_marks:
 | 
			
		||||
            return
 | 
			
		||||
        m1 = self.last_received_message_marks[name][0]
 | 
			
		||||
        m2 = self.last_received_message_marks[name][1]
 | 
			
		||||
        buffer_ = self.tv.get_buffer()
 | 
			
		||||
        i1 = buffer_.get_iter_at_mark(m1)
 | 
			
		||||
        i2 = buffer_.get_iter_at_mark(m2)
 | 
			
		||||
        txt = buffer_.get_text(i1, i2, True)
 | 
			
		||||
        buffer_.delete(i1, i2)
 | 
			
		||||
        i2 = self.print_conversation_line(message, '', 'incoming', name, None,
 | 
			
		||||
            other_tags_for_name=other_tags_for_name,
 | 
			
		||||
            other_tags_for_text=other_tags_for_text, xhtml=xhtml, iter_=i1, additional_data=additional_data)
 | 
			
		||||
        tt_txt = _('<b>Message was corrected. Last message was:</b>\n  %s') % \
 | 
			
		||||
            GLib.markup_escape_text(old_txt)
 | 
			
		||||
        self.show_corrected_message_warning(i2, tt_txt)
 | 
			
		||||
        self.last_received_message_marks[name][1] = buffer_.create_mark(None, i2,
 | 
			
		||||
            left_gravity=True)
 | 
			
		||||
        if not end_mark:
 | 
			
		||||
            end_iter = self.tv.get_buffer().get_end_iter()
 | 
			
		||||
        else:
 | 
			
		||||
            end_iter = buffer_.get_iter_at_mark(end_mark)
 | 
			
		||||
 | 
			
		||||
        start_iter = buffer_.get_iter_at_mark(start_mark)
 | 
			
		||||
 | 
			
		||||
        old_txt = buffer_.get_text(start_iter, end_iter, True)
 | 
			
		||||
        buffer_.delete(start_iter, end_iter)
 | 
			
		||||
        buffer_.delete_mark(start_mark)
 | 
			
		||||
 | 
			
		||||
        return index, end_mark, old_txt
 | 
			
		||||
 | 
			
		||||
    def show_xep0184_warning(self, id_):
 | 
			
		||||
        if id_ in self.xep0184_marks:
 | 
			
		||||
| 
						 | 
				
			
			@ -639,30 +659,6 @@ class ConversationTextview(GObject.GObject):
 | 
			
		|||
                "end. If this icon stays\nfor a long time, it's likely the "
 | 
			
		||||
                'message got lost.'), 8, position[1] + y)
 | 
			
		||||
 | 
			
		||||
    def show_line_tooltip(self):
 | 
			
		||||
        self.line_tooltip.timeout = 0
 | 
			
		||||
        w = self.tv.get_window(Gtk.TextWindowType.TEXT)
 | 
			
		||||
        device = w.get_display().get_device_manager().get_client_pointer()
 | 
			
		||||
        pointer = w.get_device_position(device)
 | 
			
		||||
        x = pointer[1]
 | 
			
		||||
        y = pointer[2]
 | 
			
		||||
        iter_ = self.tv.get_iter_at_location(x, y)
 | 
			
		||||
        if isinstance(iter_, tuple):
 | 
			
		||||
            iter_ = iter_[1]
 | 
			
		||||
        tags = iter_.get_tags()
 | 
			
		||||
        tag_table = self.tv.get_buffer().get_tag_table()
 | 
			
		||||
        over_line = False
 | 
			
		||||
        for tag in tags:
 | 
			
		||||
            if tag == tag_table.lookup('focus-out-line'):
 | 
			
		||||
                over_line = True
 | 
			
		||||
                break
 | 
			
		||||
        if over_line and not self.line_tooltip.win:
 | 
			
		||||
            # check if the current pointer is still over the line
 | 
			
		||||
            position = w.get_origin()[1:]
 | 
			
		||||
            self.line_tooltip.show_tooltip(_('Text below this line is what has '
 | 
			
		||||
                'been said since the\nlast time you paid attention to this '
 | 
			
		||||
                'group chat'), 8, position[1] + y)
 | 
			
		||||
 | 
			
		||||
    def on_textview_draw(self, widget, ctx):
 | 
			
		||||
        return
 | 
			
		||||
        #TODO
 | 
			
		||||
| 
						 | 
				
			
			@ -708,7 +704,6 @@ class ConversationTextview(GObject.GObject):
 | 
			
		|||
            w.set_cursor(Gdk.Cursor.new(Gdk.CursorType.XTERM))
 | 
			
		||||
            self.change_cursor = False
 | 
			
		||||
        tag_table = self.tv.get_buffer().get_tag_table()
 | 
			
		||||
        over_line = False
 | 
			
		||||
        xep0184_warning = False
 | 
			
		||||
 | 
			
		||||
        for tag in tags:
 | 
			
		||||
| 
						 | 
				
			
			@ -716,25 +711,15 @@ class ConversationTextview(GObject.GObject):
 | 
			
		|||
            tag_table.lookup('xmpp'), tag_table.lookup('sth_at_sth')):
 | 
			
		||||
                w.set_cursor(Gdk.Cursor.new(Gdk.CursorType.HAND2))
 | 
			
		||||
                self.change_cursor = True
 | 
			
		||||
            elif tag == tag_table.lookup('focus-out-line'):
 | 
			
		||||
                over_line = True
 | 
			
		||||
            elif tag == tag_table.lookup('xep0184-warning'):
 | 
			
		||||
                xep0184_warning = True
 | 
			
		||||
 | 
			
		||||
        if self.line_tooltip.timeout != 0 or self.line_tooltip.shown:
 | 
			
		||||
            # Check if we should hide the line tooltip
 | 
			
		||||
            if not over_line:
 | 
			
		||||
                self.line_tooltip.hide_tooltip()
 | 
			
		||||
        if self.xep0184_warning_tooltip.timeout != 0 or \
 | 
			
		||||
        self.xep0184_warning_tooltip.shown:
 | 
			
		||||
            # Check if we should hide the XEP-184 warning tooltip
 | 
			
		||||
            if not xep0184_warning:
 | 
			
		||||
                self.xep0184_warning_tooltip.hide_tooltip()
 | 
			
		||||
        if over_line and not self.line_tooltip.win:
 | 
			
		||||
            self.line_tooltip.timeout = GLib.timeout_add(500,
 | 
			
		||||
                    self.show_line_tooltip)
 | 
			
		||||
            w.set_cursor(Gdk.Cursor.new(Gdk.CursorType.LEFT_PTR))
 | 
			
		||||
            self.change_cursor = True
 | 
			
		||||
 | 
			
		||||
        if xep0184_warning and not self.xep0184_warning_tooltip.win:
 | 
			
		||||
            self.xep0184_warning_tooltip.timeout = GLib.timeout_add(500,
 | 
			
		||||
                    self.show_xep0184_warning_tooltip)
 | 
			
		||||
| 
						 | 
				
			
			@ -1244,62 +1229,105 @@ class ConversationTextview(GObject.GObject):
 | 
			
		|||
        buffer_.insert_with_tags_by_name(iter_, '\n', 'eol')
 | 
			
		||||
        self.just_cleared = False
 | 
			
		||||
 | 
			
		||||
    def get_end_mark(self, msg_stanza_id, start_mark):
 | 
			
		||||
        for index, msg in enumerate(self.message_list):
 | 
			
		||||
            if msg[2] == msg_stanza_id and msg[1] == start_mark:
 | 
			
		||||
                try:
 | 
			
		||||
                    end_mark = self.message_list[index + 1][1]
 | 
			
		||||
                    end_mark_name = end_mark.get_name()
 | 
			
		||||
                except IndexError:
 | 
			
		||||
                    # We are at the last message
 | 
			
		||||
                    end_mark = None
 | 
			
		||||
                    end_mark_name = None
 | 
			
		||||
 | 
			
		||||
                log.debug('start mark: %s, end mark: %s, '
 | 
			
		||||
                          'replace message-list index: %s',
 | 
			
		||||
                          start_mark.get_name(), end_mark_name, index)
 | 
			
		||||
 | 
			
		||||
                return end_mark, index
 | 
			
		||||
        log.debug('stanza-id not in message list')
 | 
			
		||||
        return None, None
 | 
			
		||||
 | 
			
		||||
    def get_insert_mark(self, timestamp):
 | 
			
		||||
        # message_list = [(timestamp, line_start_mark, msg_stanza_id)]
 | 
			
		||||
        # We check if this is a new Message
 | 
			
		||||
        try:
 | 
			
		||||
            if self.message_list[-1][0] <= timestamp:
 | 
			
		||||
                return None, None
 | 
			
		||||
        except IndexError:
 | 
			
		||||
            # We have no Messages in the TextView
 | 
			
		||||
            return None, None
 | 
			
		||||
 | 
			
		||||
        # Not a new Message
 | 
			
		||||
        # Search for insertion point
 | 
			
		||||
        for index, msg in enumerate(self.message_list):
 | 
			
		||||
            if msg[0] > timestamp:
 | 
			
		||||
                return msg[1], index
 | 
			
		||||
 | 
			
		||||
        # Should not happen, but who knows
 | 
			
		||||
        return None, None
 | 
			
		||||
 | 
			
		||||
    def print_conversation_line(self, text, jid, kind, name, tim,
 | 
			
		||||
    other_tags_for_name=[], other_tags_for_time=[], other_tags_for_text=[],
 | 
			
		||||
    other_tags_for_name=None, other_tags_for_time=None, other_tags_for_text=None,
 | 
			
		||||
    subject=None, old_kind=None, xhtml=None, simple=False, graphics=True,
 | 
			
		||||
    displaymarking=None, iter_=None, additional_data={}):
 | 
			
		||||
    displaymarking=None, msg_stanza_id=None, correct_id=None, additional_data=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()
 | 
			
		||||
            m2 = self.marks_queue.get()
 | 
			
		||||
            i1 = buffer_.get_iter_at_mark(m1)
 | 
			
		||||
            i2 = buffer_.get_iter_at_mark(m2)
 | 
			
		||||
            buffer_.delete(i1, i2)
 | 
			
		||||
            buffer_.delete_mark(m1)
 | 
			
		||||
        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
 | 
			
		||||
        if buffer_.get_has_selection() and buffer_.get_selection_bounds()[1].\
 | 
			
		||||
        get_offset() == end_offset:
 | 
			
		||||
            move_selection = True
 | 
			
		||||
        insert_mark = None
 | 
			
		||||
        insert_mark_name = None
 | 
			
		||||
 | 
			
		||||
        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 kind == 'incoming_queue':
 | 
			
		||||
            kind = 'incoming'
 | 
			
		||||
        if old_kind == 'incoming_queue':
 | 
			
		||||
            old_kind = 'incoming'
 | 
			
		||||
        # print the time stamp
 | 
			
		||||
 | 
			
		||||
        if not tim:
 | 
			
		||||
            # We don't have tim for outgoing messages...
 | 
			
		||||
            tim = time.localtime()
 | 
			
		||||
        current_print_time = gajim.config.get('print_time')
 | 
			
		||||
            # For outgoing Messages and Status prints
 | 
			
		||||
            tim = time.time()
 | 
			
		||||
 | 
			
		||||
        corrected = False
 | 
			
		||||
        if correct_id:
 | 
			
		||||
            try:
 | 
			
		||||
                index, insert_mark, old_txt = \
 | 
			
		||||
                    self.correct_message(correct_id, kind, name)
 | 
			
		||||
                self.corrected_text_list[msg_stanza_id] = \
 | 
			
		||||
                    '<b>Message was corrected. Last message was:</b>\n{}' \
 | 
			
		||||
                    .format(GLib.markup_escape_text(old_txt))
 | 
			
		||||
                corrected = True
 | 
			
		||||
            except TypeError:
 | 
			
		||||
                log.debug('Message was not corrected !')
 | 
			
		||||
 | 
			
		||||
        if not corrected:
 | 
			
		||||
            # Get insertion point into TextView
 | 
			
		||||
            insert_mark, index = self.get_insert_mark(tim)
 | 
			
		||||
 | 
			
		||||
        if insert_mark:
 | 
			
		||||
            insert_mark_name = insert_mark.get_name()
 | 
			
		||||
 | 
			
		||||
        log.debug(
 | 
			
		||||
            'Printed Line: %s, %s, %s, inserted after: %s'
 | 
			
		||||
            ', stanza-id: %s, correct-id: %s',
 | 
			
		||||
            self.line, text, tim, insert_mark_name,
 | 
			
		||||
            msg_stanza_id, correct_id)
 | 
			
		||||
 | 
			
		||||
        if not insert_mark:  # Texview is empty or Message is new
 | 
			
		||||
            iter_ = buffer_.get_end_iter()
 | 
			
		||||
            # Insert new Line if Textview is not empty
 | 
			
		||||
            if buffer_.get_char_count() > 0 and not corrected:
 | 
			
		||||
                buffer_.insert_with_tags_by_name(iter_, '\n', 'eol')
 | 
			
		||||
        else:
 | 
			
		||||
            iter_ = buffer_.get_iter_at_mark(insert_mark)
 | 
			
		||||
 | 
			
		||||
        # Create a temporary mark at the start of the line
 | 
			
		||||
        # with gravity=Left, so it will not move
 | 
			
		||||
        # even if we insert directly at the mark iter
 | 
			
		||||
        temp_mark = buffer_.create_mark('temp', iter_, left_gravity=True)
 | 
			
		||||
 | 
			
		||||
        at_the_end = self.at_the_end()
 | 
			
		||||
 | 
			
		||||
        if text.startswith('/me '):
 | 
			
		||||
            direction_mark = i18n.paragraph_direction_mark(str(text[3:]))
 | 
			
		||||
        else:
 | 
			
		||||
| 
						 | 
				
			
			@ -1307,90 +1335,96 @@ class ConversationTextview(GObject.GObject):
 | 
			
		|||
        # don't apply direction mark if it's status message
 | 
			
		||||
        if kind == 'status':
 | 
			
		||||
            direction_mark = i18n.direction_mark
 | 
			
		||||
        if current_print_time == 'always' and kind != 'info' and not simple:
 | 
			
		||||
            timestamp_str = self.get_time_to_show(tim, direction_mark)
 | 
			
		||||
            timestamp = time.strftime(timestamp_str, tim)
 | 
			
		||||
            timestamp = direction_mark + timestamp + direction_mark
 | 
			
		||||
            if other_tags_for_time:
 | 
			
		||||
                buffer_.insert_with_tags_by_name(end_iter, timestamp,
 | 
			
		||||
                    *other_tags_for_time)
 | 
			
		||||
            else:
 | 
			
		||||
                buffer_.insert (end_iter, timestamp)
 | 
			
		||||
        elif current_print_time == 'sometimes' and kind != 'info' and not simple:
 | 
			
		||||
            every_foo_seconds = 60 * gajim.config.get(
 | 
			
		||||
                'print_ichat_every_foo_minutes')
 | 
			
		||||
            seconds_passed = time.mktime(tim) - self.last_time_printout
 | 
			
		||||
            if seconds_passed > every_foo_seconds:
 | 
			
		||||
                self.last_time_printout = time.mktime(tim)
 | 
			
		||||
                end_iter = buffer_.get_end_iter()
 | 
			
		||||
                if gajim.config.get('print_time_fuzzy') > 0:
 | 
			
		||||
                    tim_format = self.fc.fuzzy_time(gajim.config.get('print_time_fuzzy'), tim)
 | 
			
		||||
                else:
 | 
			
		||||
                    tim_format = self.get_time_to_show(tim, direction_mark)
 | 
			
		||||
                buffer_.insert_with_tags_by_name(end_iter, tim_format + '\n',
 | 
			
		||||
                    'time_sometimes')
 | 
			
		||||
 | 
			
		||||
        # print the time stamp
 | 
			
		||||
        self.print_time(text, kind, tim, simple, direction_mark,
 | 
			
		||||
            other_tags_for_time, iter_)
 | 
			
		||||
 | 
			
		||||
        # If there's a displaymarking, print it here.
 | 
			
		||||
        if displaymarking:
 | 
			
		||||
            self.print_displaymarking(displaymarking, iter_=end_iter)
 | 
			
		||||
            self.print_displaymarking(displaymarking, iter_=iter_)
 | 
			
		||||
 | 
			
		||||
        # kind = info, we print things as if it was a status: same color, ...
 | 
			
		||||
        if kind in ('error', 'info'):
 | 
			
		||||
            kind = 'status'
 | 
			
		||||
        other_text_tag = self.detect_other_text_tag(text, kind)
 | 
			
		||||
        text_tags = other_tags_for_text[:] # create a new list
 | 
			
		||||
        mark1 = None
 | 
			
		||||
        text_tags = []
 | 
			
		||||
        if other_tags_for_text:
 | 
			
		||||
            text_tags = other_tags_for_text[:]  # create a new list
 | 
			
		||||
        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') and not iter_:
 | 
			
		||||
                mark1 = mark
 | 
			
		||||
        else: # not status nor /me
 | 
			
		||||
 | 
			
		||||
        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, iter_=end_iter)
 | 
			
		||||
                        direction_mark=direction_mark, iter_=iter_)
 | 
			
		||||
                else:
 | 
			
		||||
                    self.print_real_text(gajim.config.get(
 | 
			
		||||
                        'chat_merge_consecutive_nickname_indent'),
 | 
			
		||||
                        iter_=end_iter, additional_data=additional_data)
 | 
			
		||||
                        mark=insert_mark, additional_data=additional_data)
 | 
			
		||||
            else:
 | 
			
		||||
                self.print_name(name, kind, other_tags_for_name,
 | 
			
		||||
                    direction_mark=direction_mark, iter_=end_iter)
 | 
			
		||||
                    direction_mark=direction_mark, iter_=iter_)
 | 
			
		||||
            if kind == 'incoming':
 | 
			
		||||
                text_tags.append('incomingtxt')
 | 
			
		||||
                if not iter_:
 | 
			
		||||
                    mark1 = mark
 | 
			
		||||
            elif kind == 'outgoing':
 | 
			
		||||
                text_tags.append('outgoingtxt')
 | 
			
		||||
                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, additional_data=additional_data)
 | 
			
		||||
        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':
 | 
			
		||||
            # we are at the end or we are sending something
 | 
			
		||||
            # scroll to the end (via idle in case the scrollbar has appeared)
 | 
			
		||||
            if gajim.config.get('use_smooth_scrolling'):
 | 
			
		||||
                GLib.idle_add(self.smooth_scroll_to_end)
 | 
			
		||||
            else:
 | 
			
		||||
                GLib.idle_add(self.scroll_to_end)
 | 
			
		||||
 | 
			
		||||
        self.print_subject(subject, iter_=iter_)
 | 
			
		||||
        
 | 
			
		||||
        iter_ = self.print_real_text(text, text_tags, name, xhtml, graphics=graphics,
 | 
			
		||||
            mark=insert_mark, additional_data=additional_data)
 | 
			
		||||
 | 
			
		||||
        if corrected:
 | 
			
		||||
            # Show Correction Icon
 | 
			
		||||
            buffer_.create_tag(tag_name=msg_stanza_id)
 | 
			
		||||
            buffer_.insert(iter_, ' ')
 | 
			
		||||
            buffer_.insert_pixbuf(
 | 
			
		||||
                iter_, ConversationTextview.MESSAGE_CORRECTED_PIXBUF)
 | 
			
		||||
            tag_start_iter = iter_.copy()
 | 
			
		||||
            tag_start_iter.backward_chars(2)
 | 
			
		||||
            buffer_.apply_tag_by_name(msg_stanza_id, tag_start_iter, iter_)
 | 
			
		||||
 | 
			
		||||
        # If we inserted a Line we add a new line at the end
 | 
			
		||||
        if insert_mark:
 | 
			
		||||
            buffer_.insert_with_tags_by_name(iter_, '\n', 'eol')
 | 
			
		||||
        # We delete the temp mark and replace it with a mark
 | 
			
		||||
        # that has gravity=right
 | 
			
		||||
        temp_iter = buffer_.get_iter_at_mark(temp_mark)
 | 
			
		||||
        buffer_.delete_mark(temp_mark)
 | 
			
		||||
        new_mark = buffer_.create_mark(
 | 
			
		||||
            str(self.line), temp_iter, left_gravity=False)
 | 
			
		||||
 | 
			
		||||
        if not index:
 | 
			
		||||
            # New Message
 | 
			
		||||
            self.message_list.append((tim, new_mark, msg_stanza_id))
 | 
			
		||||
        elif corrected:
 | 
			
		||||
            # Replace the corrected message
 | 
			
		||||
            self.message_list[index] = (tim, new_mark, msg_stanza_id)
 | 
			
		||||
        else:
 | 
			
		||||
            # We insert the message at index
 | 
			
		||||
            self.message_list.insert(index, (tim, new_mark, msg_stanza_id))
 | 
			
		||||
 | 
			
		||||
        if kind == 'incoming':
 | 
			
		||||
            self.last_received_message_id[name] = (msg_stanza_id, new_mark)
 | 
			
		||||
        elif kind == 'outgoing':
 | 
			
		||||
            self.last_sent_message_id = (msg_stanza_id, new_mark)
 | 
			
		||||
 | 
			
		||||
        if not insert_mark:
 | 
			
		||||
            if at_the_end or kind == 'outgoing':
 | 
			
		||||
                # we are at the end or we are sending something
 | 
			
		||||
                # scroll to the end (via idle in case the scrollbar has appeared)
 | 
			
		||||
                if gajim.config.get('use_smooth_scrolling'):
 | 
			
		||||
                    GLib.idle_add(self.smooth_scroll_to_end)
 | 
			
		||||
                else:
 | 
			
		||||
                    GLib.idle_add(self.scroll_to_end)
 | 
			
		||||
 | 
			
		||||
        self.just_cleared = False
 | 
			
		||||
        buffer_.end_user_action()
 | 
			
		||||
        return end_iter
 | 
			
		||||
 | 
			
		||||
        self.line += 1
 | 
			
		||||
        return iter_
 | 
			
		||||
 | 
			
		||||
    def get_time_to_show(self, tim, direction_mark=''):
 | 
			
		||||
        """
 | 
			
		||||
| 
						 | 
				
			
			@ -1429,6 +1463,34 @@ class ConversationTextview(GObject.GObject):
 | 
			
		|||
        elif text.startswith('/me ') or text.startswith('/me\n'):
 | 
			
		||||
            return kind
 | 
			
		||||
 | 
			
		||||
    def print_time(self, text, kind, tim, simple, direction_mark, other_tags_for_time, iter_):
 | 
			
		||||
        local_tim = time.localtime(tim)
 | 
			
		||||
        buffer_ = self.tv.get_buffer()
 | 
			
		||||
        current_print_time = gajim.config.get('print_time')
 | 
			
		||||
 | 
			
		||||
        if current_print_time == 'always' and kind != 'info' and not simple:
 | 
			
		||||
            timestamp_str = self.get_time_to_show(local_tim, direction_mark)
 | 
			
		||||
            timestamp = time.strftime(timestamp_str, local_tim)
 | 
			
		||||
            timestamp = direction_mark + timestamp + direction_mark
 | 
			
		||||
            if other_tags_for_time:
 | 
			
		||||
                buffer_.insert_with_tags_by_name(iter_, timestamp,
 | 
			
		||||
                    *other_tags_for_time)
 | 
			
		||||
            else:
 | 
			
		||||
                buffer_.insert(iter_, timestamp)
 | 
			
		||||
        elif current_print_time == 'sometimes' and kind != 'info' and not simple:
 | 
			
		||||
            every_foo_seconds = 60 * gajim.config.get(
 | 
			
		||||
                'print_ichat_every_foo_minutes')
 | 
			
		||||
            seconds_passed = tim - self.last_time_printout
 | 
			
		||||
            if seconds_passed > every_foo_seconds:
 | 
			
		||||
                self.last_time_printout = tim
 | 
			
		||||
                if gajim.config.get('print_time_fuzzy') > 0:
 | 
			
		||||
                    tim_format = self.fc.fuzzy_time(
 | 
			
		||||
                        gajim.config.get('print_time_fuzzy'), tim)
 | 
			
		||||
                else:
 | 
			
		||||
                    tim_format = self.get_time_to_show(local_tim, direction_mark)
 | 
			
		||||
                buffer_.insert_with_tags_by_name(iter_, tim_format + '\n',
 | 
			
		||||
                    'time_sometimes')
 | 
			
		||||
 | 
			
		||||
    def print_displaymarking(self, displaymarking, iter_=None):
 | 
			
		||||
        bgcolor = displaymarking.getAttr('bgcolor') or '#FFF'
 | 
			
		||||
        fgcolor = displaymarking.getAttr('fgcolor') or '#000'
 | 
			
		||||
| 
						 | 
				
			
			@ -1448,12 +1510,15 @@ class ConversationTextview(GObject.GObject):
 | 
			
		|||
    def print_name(self, name, kind, other_tags_for_name, direction_mark='',
 | 
			
		||||
    iter_=None):
 | 
			
		||||
        if name:
 | 
			
		||||
            name_tags = []
 | 
			
		||||
            buffer_ = self.tv.get_buffer()
 | 
			
		||||
            if iter_:
 | 
			
		||||
                end_iter = iter_
 | 
			
		||||
            else:
 | 
			
		||||
                end_iter = buffer_.get_end_iter()
 | 
			
		||||
            name_tags = other_tags_for_name[:] # create a new list
 | 
			
		||||
 | 
			
		||||
            if other_tags_for_name:
 | 
			
		||||
                name_tags = other_tags_for_name[:]  # create a new list
 | 
			
		||||
            name_tags.append(kind)
 | 
			
		||||
            before_str = gajim.config.get('before_nickname')
 | 
			
		||||
            before_str = helpers.from_one_line(before_str)
 | 
			
		||||
| 
						 | 
				
			
			@ -1474,10 +1539,15 @@ class ConversationTextview(GObject.GObject):
 | 
			
		|||
            self.print_empty_line(end_iter)
 | 
			
		||||
 | 
			
		||||
    def print_real_text(self, text, text_tags=[], name=None, xhtml=None,
 | 
			
		||||
    graphics=True, iter_=None, additional_data={}):
 | 
			
		||||
    graphics=True, mark=None, additional_data={}):
 | 
			
		||||
        """
 | 
			
		||||
        Add normal and special text. call this to add text
 | 
			
		||||
        """
 | 
			
		||||
        buffer_ = self.tv.get_buffer()
 | 
			
		||||
        if not mark:
 | 
			
		||||
            iter_ = buffer_.get_end_iter()
 | 
			
		||||
        else:
 | 
			
		||||
            iter_ = buffer_.get_iter_at_mark(mark)
 | 
			
		||||
        if xhtml:
 | 
			
		||||
            try:
 | 
			
		||||
                if name and (text.startswith('/me ') or text.startswith('/me\n')):
 | 
			
		||||
| 
						 | 
				
			
			@ -1492,16 +1562,23 @@ class ConversationTextview(GObject.GObject):
 | 
			
		|||
        if name and (text.startswith('/me ') or text.startswith('/me\n')):
 | 
			
		||||
            text = '* ' + name + text[3:]
 | 
			
		||||
            text_tags.append('italic')
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        # PluginSystem: adding GUI extension point for ConversationTextview
 | 
			
		||||
        self.plugin_modified = False
 | 
			
		||||
        gajim.plugin_manager.gui_extension_point('print_real_text', self,
 | 
			
		||||
            text, text_tags, graphics, iter_, additional_data)
 | 
			
		||||
 | 
			
		||||
        if self.plugin_modified:
 | 
			
		||||
            return self.tv.get_buffer().get_end_iter()
 | 
			
		||||
        #needed, if buffer is manipulated by plugins without setting plugin_modified to True
 | 
			
		||||
        iter_ = self.tv.get_buffer().get_end_iter()
 | 
			
		||||
        
 | 
			
		||||
            if not mark:
 | 
			
		||||
                return buffer_.get_end_iter()
 | 
			
		||||
            else:
 | 
			
		||||
                return buffer_.get_iter_at_mark(mark)
 | 
			
		||||
 | 
			
		||||
        if not mark:
 | 
			
		||||
            iter_ = buffer_.get_end_iter()
 | 
			
		||||
        else:
 | 
			
		||||
            iter_ = buffer_.get_iter_at_mark(mark)
 | 
			
		||||
 | 
			
		||||
        # detect urls formatting and if the user has it on emoticons
 | 
			
		||||
        return self.detect_and_print_special_text(text, text_tags, graphics=graphics,
 | 
			
		||||
            iter_=iter_, additional_data=additional_data)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1069,64 +1069,14 @@ class GroupchatControl(ChatControlBase):
 | 
			
		|||
                # Like that xhtml messages are grayed too.
 | 
			
		||||
                self.print_old_conversation(obj.msgtxt, contact=obj.nick,
 | 
			
		||||
                    tim=obj.timestamp, xhtml=None,
 | 
			
		||||
                    displaymarking=obj.displaymarking)
 | 
			
		||||
                    displaymarking=obj.displaymarking, msg_stanza_id=obj.id_)
 | 
			
		||||
            else:
 | 
			
		||||
                if obj.nick in self.last_received_txt and obj.correct_id and \
 | 
			
		||||
                obj.correct_id == self.last_received_id[obj.nick]:
 | 
			
		||||
                    if obj.nick == self.nick:
 | 
			
		||||
                        old_txt = self.last_sent_txt
 | 
			
		||||
                        self.last_sent_txt = obj.msgtxt
 | 
			
		||||
                        self.conv_textview.correct_last_sent_message(obj.msgtxt,
 | 
			
		||||
                            obj.xhtml_msgtxt, obj.nick, old_txt)
 | 
			
		||||
                    else:
 | 
			
		||||
                        old_txt = self.last_received_txt[obj.nick]
 | 
			
		||||
                        (highlight, sound) = self.highlighting_for_message(obj.msgtxt, obj.timestamp)
 | 
			
		||||
                        other_tags_for_name = []
 | 
			
		||||
                        other_tags_for_text = []
 | 
			
		||||
                        if obj.nick in self.gc_custom_colors:
 | 
			
		||||
                            other_tags_for_name.append('gc_nickname_color_' + \
 | 
			
		||||
                                str(self.gc_custom_colors[obj.nick]))
 | 
			
		||||
                        else:
 | 
			
		||||
                            self.gc_count_nicknames_colors += 1
 | 
			
		||||
                            if self.gc_count_nicknames_colors == \
 | 
			
		||||
                            self.number_of_colors:
 | 
			
		||||
                                self.gc_count_nicknames_colors = 0
 | 
			
		||||
                            self.gc_custom_colors[obj.nick] = \
 | 
			
		||||
                                self.gc_count_nicknames_colors
 | 
			
		||||
                            other_tags_for_name.append('gc_nickname_color_' + \
 | 
			
		||||
                                str(self.gc_count_nicknames_colors))
 | 
			
		||||
                        if highlight:
 | 
			
		||||
                            # muc-specific chatstate
 | 
			
		||||
                            if self.parent_win:
 | 
			
		||||
                                self.parent_win.redraw_tab(self, 'attention')
 | 
			
		||||
                            else:
 | 
			
		||||
                                self.attention_flag = True
 | 
			
		||||
                            other_tags_for_name.append('bold')
 | 
			
		||||
                            other_tags_for_text.append('marked')
 | 
			
		||||
 | 
			
		||||
                            if obj.nick in self.attention_list:
 | 
			
		||||
                                self.attention_list.remove(obj.nick)
 | 
			
		||||
                            elif len(self.attention_list) > 6:
 | 
			
		||||
                                self.attention_list.pop(0) # remove older
 | 
			
		||||
                            self.attention_list.append(obj.nick)
 | 
			
		||||
 | 
			
		||||
                        if obj.msgtxt.startswith('/me ') or \
 | 
			
		||||
                        obj.msgtxt.startswith('/me\n'):
 | 
			
		||||
                            other_tags_for_text.append('gc_nickname_color_' + \
 | 
			
		||||
                                str(self.gc_custom_colors[obj.nick]))
 | 
			
		||||
                        self.conv_textview.correct_last_received_message(
 | 
			
		||||
                            obj.msgtxt, obj.xhtml_msgtxt, obj.nick, old_txt,
 | 
			
		||||
                            other_tags_for_name=other_tags_for_name,
 | 
			
		||||
                            other_tags_for_text=other_tags_for_text)
 | 
			
		||||
                    self.last_received_txt[obj.nick] = obj.msgtxt
 | 
			
		||||
                    self.last_received_id[obj.nick] = obj.stanza.getID()
 | 
			
		||||
                    return
 | 
			
		||||
                if obj.nick == self.nick:
 | 
			
		||||
                    self.last_sent_txt = obj.msgtxt
 | 
			
		||||
                self.print_conversation(obj.msgtxt, contact=obj.nick,
 | 
			
		||||
                    tim=obj.timestamp, xhtml=obj.xhtml_msgtxt,
 | 
			
		||||
                    displaymarking=obj.displaymarking,
 | 
			
		||||
                    correct_id=(obj.stanza.getID(), None))
 | 
			
		||||
                    correct_id=obj.correct_id, msg_stanza_id=obj.id_)
 | 
			
		||||
        obj.needs_highlight = self.needs_visual_notification(obj.msgtxt)
 | 
			
		||||
 | 
			
		||||
    def on_private_message(self, nick, msg, tim, xhtml, session, msg_log_id=None,
 | 
			
		||||
| 
						 | 
				
			
			@ -1181,7 +1131,7 @@ class GroupchatControl(ChatControlBase):
 | 
			
		|||
        return None
 | 
			
		||||
 | 
			
		||||
    def print_old_conversation(self, text, contact='', tim=None, xhtml = None,
 | 
			
		||||
    displaymarking=None):
 | 
			
		||||
    displaymarking=None, msg_stanza_id=None):
 | 
			
		||||
        if contact:
 | 
			
		||||
            if contact == self.nick: # it's us
 | 
			
		||||
                kind = 'outgoing'
 | 
			
		||||
| 
						 | 
				
			
			@ -1196,10 +1146,10 @@ class GroupchatControl(ChatControlBase):
 | 
			
		|||
        ChatControlBase.print_conversation_line(self, text, kind, contact, tim,
 | 
			
		||||
            small_attr, small_attr + ['restored_message'],
 | 
			
		||||
            small_attr + ['restored_message'], count_as_new=False, xhtml=xhtml,
 | 
			
		||||
            displaymarking=displaymarking)
 | 
			
		||||
            displaymarking=displaymarking, msg_stanza_id=msg_stanza_id)
 | 
			
		||||
 | 
			
		||||
    def print_conversation(self, text, contact='', tim=None, xhtml=None,
 | 
			
		||||
    graphics=True, displaymarking=None, correct_id=None):
 | 
			
		||||
    graphics=True, displaymarking=None, correct_id=None, msg_stanza_id=None):
 | 
			
		||||
        """
 | 
			
		||||
        Print a line in the conversation
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1261,7 +1211,7 @@ class GroupchatControl(ChatControlBase):
 | 
			
		|||
        ChatControlBase.print_conversation_line(self, text, kind, contact, tim,
 | 
			
		||||
            other_tags_for_name, [], other_tags_for_text, xhtml=xhtml,
 | 
			
		||||
            graphics=graphics, displaymarking=displaymarking,
 | 
			
		||||
            correct_id=correct_id)
 | 
			
		||||
            correct_id=correct_id, msg_stanza_id=msg_stanza_id)
 | 
			
		||||
 | 
			
		||||
    def get_nb_unread(self):
 | 
			
		||||
        type_events = ['printed_marked_gc_msg']
 | 
			
		||||
| 
						 | 
				
			
			@ -1422,8 +1372,8 @@ class GroupchatControl(ChatControlBase):
 | 
			
		|||
                # print if a control is open
 | 
			
		||||
                obj.session.control.print_conversation(obj.msgtxt,
 | 
			
		||||
                    tim=obj.timestamp, xhtml=obj.xhtml, encrypted=obj.encrypted,
 | 
			
		||||
                    displaymarking=obj.displaymarking, correct_id=(obj.id_,
 | 
			
		||||
                    obj.correct_id))
 | 
			
		||||
                    displaymarking=obj.displaymarking, msg_stanza_id=obj.id_,
 | 
			
		||||
                    correct_id=obj.correct_id)
 | 
			
		||||
            else:
 | 
			
		||||
                # otherwise pass it off to the control to be queued
 | 
			
		||||
                self.on_private_message(nick, obj.msgtxt, obj.timestamp,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1858,7 +1858,7 @@ class RosterWindow:
 | 
			
		|||
                # with them
 | 
			
		||||
                session = gajim.connections[account].make_new_session(jid)
 | 
			
		||||
 | 
			
		||||
                tim = time.localtime(float(result[2]))
 | 
			
		||||
                tim = float(result[2])
 | 
			
		||||
                session.roster_message(jid, result[1], tim, msg_type='chat',
 | 
			
		||||
                    msg_log_id=result[0], additional_data=additional_data)
 | 
			
		||||
                gajim.logger.set_shown_unread_msgs(result[0])
 | 
			
		||||
| 
						 | 
				
			
			@ -2744,7 +2744,7 @@ class RosterWindow:
 | 
			
		|||
            obj.session.control.print_conversation(obj.msgtxt, typ,
 | 
			
		||||
                tim=obj.timestamp, encrypted=obj.encrypted, subject=obj.subject,
 | 
			
		||||
                xhtml=obj.xhtml, displaymarking=obj.displaymarking,
 | 
			
		||||
                msg_log_id=obj.msg_log_id, correct_id=(obj.id_, obj.correct_id),
 | 
			
		||||
                msg_log_id=obj.msg_log_id, msg_stanza_id=obj.id_, correct_id=obj.correct_id,
 | 
			
		||||
                xep0184_id=xep0184_id)
 | 
			
		||||
            if obj.msg_log_id:
 | 
			
		||||
                pw = obj.session.control.parent_win
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue