Merge branch 'printline' into 'master'

print_conversation_line() refactoring

See merge request !3
This commit is contained in:
Philipp Hörist 2017-01-03 21:20:32 +01:00
commit 430c4b1536
7 changed files with 327 additions and 308 deletions

View File

@ -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']

View File

@ -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()

View File

@ -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

View File

@ -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 \

View File

@ -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)

View File

@ -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,

View File

@ -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