Philipp Hörist pushed to branch master at gajim / gajim
Commits:
-
39216af2
by Philipp Hörist at 2017-01-02T19:09:06+01:00
-
430c4b15
by Philipp Hörist at 2017-01-03T21:20:32+01:00
7 changed files:
- src/chat_control.py
- src/common/connection_handlers.py
- src/common/connection_handlers_events.py
- src/common/logger.py
- src/conversation_textview.py
- src/groupchat_control.py
- src/roster_window.py
Changes:
| ... | ... | @@ -341,7 +341,6 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools): |
| 341 | 341 |
self.was_at_the_end = True
|
| 342 | 342 |
self.correcting = False
|
| 343 | 343 |
self.last_sent_msg = None
|
| 344 |
- self.last_sent_txt = None
|
|
| 345 | 344 |
self.last_received_txt = {} # one per name
|
| 346 | 345 |
self.last_received_id = {} # one per name
|
| 347 | 346 |
|
| ... | ... | @@ -785,7 +784,6 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools): |
| 785 | 784 |
|
| 786 | 785 |
def _cb(obj, msg, cb, *cb_args):
|
| 787 | 786 |
self.last_sent_msg = msg
|
| 788 |
- self.last_sent_txt = cb_args[0]
|
|
| 789 | 787 |
if cb:
|
| 790 | 788 |
cb(obj, msg, *cb_args)
|
| 791 | 789 |
|
| ... | ... | @@ -841,7 +839,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools): |
| 841 | 839 |
other_tags_for_name=[], other_tags_for_time=[], other_tags_for_text=[],
|
| 842 | 840 |
count_as_new=True, subject=None, old_kind=None, xhtml=None, simple=False,
|
| 843 | 841 |
xep0184_id=None, graphics=True, displaymarking=None, msg_log_id=None,
|
| 844 |
- correct_id=None, additional_data={}):
|
|
| 842 |
+ msg_stanza_id=None, correct_id=None, additional_data={}):
|
|
| 845 | 843 |
"""
|
| 846 | 844 |
Print 'chat' type messages
|
| 847 | 845 |
correct_id = (message_id, correct_id)
|
| ... | ... | @@ -852,26 +850,12 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools): |
| 852 | 850 |
end = False
|
| 853 | 851 |
if self.was_at_the_end or kind == 'outgoing':
|
| 854 | 852 |
end = True
|
| 855 |
- old_txt = ''
|
|
| 856 |
- if name in self.last_received_txt:
|
|
| 857 |
- old_txt = self.last_received_txt[name]
|
|
| 858 |
- if correct_id and correct_id[1] and \
|
|
| 859 |
- name in self.conv_textview.last_received_message_marks and \
|
|
| 860 |
- correct_id[1] == self.last_received_id[name]:
|
|
| 861 |
- self.conv_textview.correct_last_received_message(text, xhtml,
|
|
| 862 |
- name, old_txt)
|
|
| 863 |
- elif correct_id and correct_id[1] and \
|
|
| 864 |
- self.conv_textview.last_sent_message_marks[0] and \
|
|
| 865 |
- correct_id[1] == self.last_received_id[name]:
|
|
| 866 |
- # this is for carbon copied messages that are sent from another
|
|
| 867 |
- # resource
|
|
| 868 |
- self.conv_textview.correct_last_sent_message(text, xhtml,
|
|
| 869 |
- self.get_our_nick(), old_txt, additional_data=additional_data)
|
|
| 870 |
- else:
|
|
| 871 |
- textview.print_conversation_line(text, jid, kind, name, tim,
|
|
| 872 |
- other_tags_for_name, other_tags_for_time, other_tags_for_text,
|
|
| 873 |
- subject, old_kind, xhtml, simple=simple, graphics=graphics,
|
|
| 874 |
- displaymarking=displaymarking, additional_data=additional_data)
|
|
| 853 |
+ |
|
| 854 |
+ textview.print_conversation_line(text, jid, kind, name, tim,
|
|
| 855 |
+ other_tags_for_name, other_tags_for_time, other_tags_for_text,
|
|
| 856 |
+ subject, old_kind, xhtml, simple=simple, graphics=graphics,
|
|
| 857 |
+ displaymarking=displaymarking, msg_stanza_id=msg_stanza_id,
|
|
| 858 |
+ correct_id=correct_id, additional_data=additional_data)
|
|
| 875 | 859 |
|
| 876 | 860 |
if xep0184_id is not None:
|
| 877 | 861 |
textview.show_xep0184_warning(xep0184_id)
|
| ... | ... | @@ -1364,6 +1348,7 @@ class ChatControl(ChatControlBase): |
| 1364 | 1348 |
self.gpg_is_active = False
|
| 1365 | 1349 |
self.last_recv_message_id = None
|
| 1366 | 1350 |
self.last_recv_message_marks = None
|
| 1351 |
+ self.last_message_timestamp = None
|
|
| 1367 | 1352 |
# for muc use:
|
| 1368 | 1353 |
# widget = self.xml.get_object('muc_window_actions_button')
|
| 1369 | 1354 |
self.actions_button = self.xml.get_object('message_window_actions_button')
|
| ... | ... | @@ -2282,7 +2267,7 @@ class ChatControl(ChatControlBase): |
| 2282 | 2267 |
GLib.source_remove(self.possible_inactive_timeout_id)
|
| 2283 | 2268 |
self._schedule_activity_timers()
|
| 2284 | 2269 |
|
| 2285 |
- def _on_sent(obj, msg_stanza, message, encrypted, xhtml, label, old_txt):
|
|
| 2270 |
+ def _on_sent(obj, msg_stanza, message, encrypted, xhtml, label):
|
|
| 2286 | 2271 |
id_ = msg_stanza.getID()
|
| 2287 | 2272 |
if self.contact.supports(NS_RECEIPTS) and gajim.config.get_per(
|
| 2288 | 2273 |
'accounts', self.account, 'request_receipt'):
|
| ... | ... | @@ -2293,22 +2278,21 @@ class ChatControl(ChatControlBase): |
| 2293 | 2278 |
displaymarking = label.getTag('displaymarking')
|
| 2294 | 2279 |
else:
|
| 2295 | 2280 |
displaymarking = None
|
| 2296 |
- if self.correcting and \
|
|
| 2297 |
- self.conv_textview.last_sent_message_marks[0]:
|
|
| 2298 |
- self.conv_textview.correct_last_sent_message(message, xhtml,
|
|
| 2299 |
- self.get_our_nick(), old_txt, additional_data=obj.additional_data)
|
|
| 2281 |
+ if self.correcting:
|
|
| 2300 | 2282 |
self.correcting = False
|
| 2301 | 2283 |
self.msg_textview.override_background_color(
|
| 2302 | 2284 |
Gtk.StateType.NORMAL, self.old_message_tv_color)
|
| 2303 |
- return
|
|
| 2285 |
+ |
|
| 2304 | 2286 |
self.print_conversation(message, self.contact.jid,
|
| 2305 | 2287 |
encrypted=encrypted, xep0184_id=xep0184_id, xhtml=xhtml,
|
| 2306 |
- displaymarking=displaymarking, additional_data=obj.additional_data)
|
|
| 2288 |
+ displaymarking=displaymarking, msg_stanza_id=id_,
|
|
| 2289 |
+ correct_id=msg_stanza.getTagAttr('replace', 'id'),
|
|
| 2290 |
+ additional_data=obj.additional_data)
|
|
| 2307 | 2291 |
|
| 2308 | 2292 |
ChatControlBase.send_message(self, message, keyID, type_='chat',
|
| 2309 | 2293 |
chatstate=chatstate_to_send, xhtml=xhtml, callback=_on_sent,
|
| 2310 |
- callback_args=[message, encrypted, xhtml, self.get_seclabel(),
|
|
| 2311 |
- self.last_sent_txt], process_commands=process_commands,
|
|
| 2294 |
+ callback_args=[message, encrypted, xhtml, self.get_seclabel()],
|
|
| 2295 |
+ process_commands=process_commands,
|
|
| 2312 | 2296 |
attention=attention)
|
| 2313 | 2297 |
|
| 2314 | 2298 |
def check_for_possible_paused_chatstate(self, arg):
|
| ... | ... | @@ -2422,7 +2406,8 @@ class ChatControl(ChatControlBase): |
| 2422 | 2406 |
|
| 2423 | 2407 |
def print_conversation(self, text, frm='', tim=None, encrypted=False,
|
| 2424 | 2408 |
subject=None, xhtml=None, simple=False, xep0184_id=None,
|
| 2425 |
- displaymarking=None, msg_log_id=None, correct_id=None, additional_data={}):
|
|
| 2409 |
+ displaymarking=None, msg_log_id=None, correct_id=None,
|
|
| 2410 |
+ msg_stanza_id=None, additional_data={}):
|
|
| 2426 | 2411 |
"""
|
| 2427 | 2412 |
Print a line in the conversation
|
| 2428 | 2413 |
|
| ... | ... | @@ -2487,7 +2472,8 @@ class ChatControl(ChatControlBase): |
| 2487 | 2472 |
ChatControlBase.print_conversation_line(self, text, kind, name, tim,
|
| 2488 | 2473 |
subject=subject, old_kind=self.old_msg_kind, xhtml=xhtml,
|
| 2489 | 2474 |
simple=simple, xep0184_id=xep0184_id, displaymarking=displaymarking,
|
| 2490 |
- msg_log_id=msg_log_id, correct_id=correct_id, additional_data=additional_data)
|
|
| 2475 |
+ msg_log_id=msg_log_id, msg_stanza_id=msg_stanza_id,
|
|
| 2476 |
+ correct_id=correct_id, additional_data=additional_data)
|
|
| 2491 | 2477 |
if text.startswith('/me ') or text.startswith('/me\n'):
|
| 2492 | 2478 |
self.old_msg_kind = None
|
| 2493 | 2479 |
else:
|
| ... | ... | @@ -2961,7 +2947,7 @@ class ChatControl(ChatControlBase): |
| 2961 | 2947 |
kind = 'status'
|
| 2962 | 2948 |
name = self.contact.get_shown_name()
|
| 2963 | 2949 |
|
| 2964 |
- tim = time.localtime(float(row[0]))
|
|
| 2950 |
+ tim = float(row[0])
|
|
| 2965 | 2951 |
|
| 2966 | 2952 |
if gajim.config.get('restored_messages_small'):
|
| 2967 | 2953 |
small_attr = ['small']
|
| ... | ... | @@ -1032,7 +1032,7 @@ class ConnectionHandlersBase: |
| 1032 | 1032 |
# Do not override assigned key
|
| 1033 | 1033 |
obj.contact.keyID = obj.keyID
|
| 1034 | 1034 |
if obj.timestamp:
|
| 1035 |
- obj.contact.last_status_time = obj.timestamp
|
|
| 1035 |
+ obj.contact.last_status_time = localtime(obj.timestamp)
|
|
| 1036 | 1036 |
elif not gajim.block_signed_in_notifications[account]:
|
| 1037 | 1037 |
# We're connected since more that 30 seconds
|
| 1038 | 1038 |
obj.contact.last_status_time = localtime()
|
| ... | ... | @@ -94,12 +94,16 @@ class HelperEvent: |
| 94 | 94 |
self.gc_control = minimized.get(self.jid)
|
| 95 | 95 |
|
| 96 | 96 |
def _generate_timestamp(self, tag):
|
| 97 |
+ # Make sure we use only int/float Epoch time
|
|
| 98 |
+ if not isinstance(tag, str):
|
|
| 99 |
+ self.timestamp = time_time()
|
|
| 100 |
+ return
|
|
| 97 | 101 |
try:
|
| 98 | 102 |
tim = helpers.datetime_tuple(tag)
|
| 103 |
+ self.timestamp = timegm(tim)
|
|
| 99 | 104 |
except Exception:
|
| 100 | 105 |
log.error('wrong timestamp, ignoring it: ' + tag)
|
| 101 |
- tim = localtime()
|
|
| 102 |
- self.timestamp = localtime(timegm(tim))
|
|
| 106 |
+ self.timestamp = time_time()
|
|
| 103 | 107 |
|
| 104 | 108 |
def get_chatstate(self):
|
| 105 | 109 |
"""
|
| ... | ... | @@ -1059,7 +1063,7 @@ class MamMessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): |
| 1059 | 1063 |
return
|
| 1060 | 1064 |
tim = delay.getAttr('stamp')
|
| 1061 | 1065 |
tim = helpers.datetime_tuple(tim)
|
| 1062 |
- self.tim = localtime(timegm(tim))
|
|
| 1066 |
+ self.tim = timegm(tim)
|
|
| 1063 | 1067 |
to_ = self.msg_.getAttr('to')
|
| 1064 | 1068 |
if to_:
|
| 1065 | 1069 |
to_ = gajim.get_jid_without_resource(to_)
|
| ... | ... | @@ -1278,7 +1282,7 @@ class MessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): |
| 1278 | 1282 |
|
| 1279 | 1283 |
if not form.getField('FORM_TYPE'):
|
| 1280 | 1284 |
return
|
| 1281 |
-
|
|
| 1285 |
+ |
|
| 1282 | 1286 |
if form['FORM_TYPE'] == 'urn:xmpp:ssn':
|
| 1283 | 1287 |
self.session.handle_negotiation(form)
|
| 1284 | 1288 |
else:
|
| ... | ... | @@ -1302,6 +1306,7 @@ class MessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): |
| 1302 | 1306 |
|
| 1303 | 1307 |
self._generate_timestamp(self.stanza.getTimestamp())
|
| 1304 | 1308 |
|
| 1309 |
+ |
|
| 1305 | 1310 |
self.encrypted = False
|
| 1306 | 1311 |
xep_200_encrypted = self.stanza.getTag('c',
|
| 1307 | 1312 |
namespace=nbxmpp.NS_STANZA_CRYPTO)
|
| ... | ... | @@ -1522,6 +1527,7 @@ class GcMessageReceivedEvent(nec.NetworkIncomingEvent): |
| 1522 | 1527 |
self.stanza = self.msg_obj.stanza
|
| 1523 | 1528 |
if not hasattr(self, 'additional_data'):
|
| 1524 | 1529 |
self.additional_data = self.msg_obj.additional_data
|
| 1530 |
+ self.id_ = self.msg_obj.stanza.getID()
|
|
| 1525 | 1531 |
self.fjid = self.msg_obj.fjid
|
| 1526 | 1532 |
self.msgtxt = self.msg_obj.msgtxt
|
| 1527 | 1533 |
self.jid = self.msg_obj.jid
|
| ... | ... | @@ -523,9 +523,9 @@ class Logger: |
| 523 | 523 |
subject_col = subject
|
| 524 | 524 |
additional_data_col = json.dumps(additional_data)
|
| 525 | 525 |
if tim:
|
| 526 |
- time_col = int(float(time.mktime(tim)))
|
|
| 526 |
+ time_col = float(tim)
|
|
| 527 | 527 |
else:
|
| 528 |
- time_col = int(float(time.time()))
|
|
| 528 |
+ time_col = float(time.time())
|
|
| 529 | 529 |
|
| 530 | 530 |
kind_col, show_col = self.convert_human_values_to_db_api_values(kind,
|
| 531 | 531 |
show)
|
| ... | ... | @@ -1112,9 +1112,9 @@ class Logger: |
| 1112 | 1112 |
|
| 1113 | 1113 |
def save_if_not_exists(self, with_, direction, tim, msg='', nick=None, additional_data={}):
|
| 1114 | 1114 |
if tim:
|
| 1115 |
- time_col = int(float(time.mktime(tim)))
|
|
| 1115 |
+ time_col = float(tim)
|
|
| 1116 | 1116 |
else:
|
| 1117 |
- time_col = int(float(time.time()))
|
|
| 1117 |
+ time_col = float(time.time())
|
|
| 1118 | 1118 |
if not msg:
|
| 1119 | 1119 |
return
|
| 1120 | 1120 |
if self.jid_is_from_pm(with_) or nick:
|
| ... | ... | @@ -1157,7 +1157,7 @@ class Logger: |
| 1157 | 1157 |
self.write(type_, with_, message=msg, tim=tim, additional_data=additional_data)
|
| 1158 | 1158 |
|
| 1159 | 1159 |
def _nec_gc_message_received(self, obj):
|
| 1160 |
- tim_f = float(time.mktime(obj.timestamp))
|
|
| 1160 |
+ tim_f = float(obj.timestamp)
|
|
| 1161 | 1161 |
tim_int = int(tim_f)
|
| 1162 | 1162 |
if gajim.config.should_log(obj.conn.name, obj.jid) and not \
|
| 1163 | 1163 |
tim_int < obj.conn.last_history_time[obj.jid] and obj.msgtxt and \
|
| ... | ... | @@ -57,6 +57,9 @@ NOT_SHOWN = 0 |
| 57 | 57 |
ALREADY_RECEIVED = 1
|
| 58 | 58 |
SHOWN = 2
|
| 59 | 59 |
|
| 60 |
+import logging
|
|
| 61 |
+log = logging.getLogger('gajim.conversation_textview')
|
|
| 62 |
+ |
|
| 60 | 63 |
def is_selection_modified(mark):
|
| 61 | 64 |
name = mark.get_name()
|
| 62 | 65 |
if name and name in ('selection_bound', 'insert'):
|
| ... | ... | @@ -154,7 +157,6 @@ class TextViewImage(Gtk.Image): |
| 154 | 157 |
if is_selection_modified(mark):
|
| 155 | 158 |
self._update_selected()
|
| 156 | 159 |
|
| 157 |
- |
|
| 158 | 160 |
class ConversationTextview(GObject.GObject):
|
| 159 | 161 |
"""
|
| 160 | 162 |
Class for the conversation textview (where user reads already said messages)
|
| ... | ... | @@ -185,14 +187,17 @@ class ConversationTextview(GObject.GObject): |
| 185 | 187 |
"""
|
| 186 | 188 |
GObject.GObject.__init__(self)
|
| 187 | 189 |
self.used_in_history_window = used_in_history_window
|
| 188 |
- |
|
| 190 |
+ self.line = 0
|
|
| 191 |
+ self.message_list = []
|
|
| 192 |
+ self.corrected_text_list = {}
|
|
| 189 | 193 |
self.fc = FuzzyClock()
|
| 190 | 194 |
|
| 191 |
- |
|
| 192 | 195 |
# no need to inherit TextView, use it as atrribute is safer
|
| 193 | 196 |
self.tv = HtmlTextView()
|
| 194 | 197 |
self.tv.hyperlink_handler = self.hyperlink_handler
|
| 195 | 198 |
|
| 199 |
+ self.tv.set_has_tooltip(True)
|
|
| 200 |
+ |
|
| 196 | 201 |
# set properties
|
| 197 | 202 |
self.tv.set_border_width(1)
|
| 198 | 203 |
self.tv.set_accepts_tab(True)
|
| ... | ... | @@ -206,9 +211,10 @@ class ConversationTextview(GObject.GObject): |
| 206 | 211 |
self.image_cache = {}
|
| 207 | 212 |
self.xep0184_marks = {}
|
| 208 | 213 |
self.xep0184_shown = {}
|
| 209 |
- self.last_sent_message_marks = [None, None]
|
|
| 210 |
- # A pair per occupant. Key is '' in normal chat
|
|
| 211 |
- self.last_received_message_marks = {}
|
|
| 214 |
+ # self.last_sent_message_id = msg_stanza_id
|
|
| 215 |
+ self.last_sent_message_id = None
|
|
| 216 |
+ # last_received_message_id[name] = (msg_stanza_id, line_start_mark)
|
|
| 217 |
+ self.last_received_message_id = {}
|
|
| 212 | 218 |
|
| 213 | 219 |
# It's True when we scroll in the code, so we can detect scroll from user
|
| 214 | 220 |
self.auto_scrolling = False
|
| ... | ... | @@ -225,6 +231,8 @@ class ConversationTextview(GObject.GObject): |
| 225 | 231 |
|
| 226 | 232 |
id_ = self.tv.connect('draw', self.on_textview_draw)
|
| 227 | 233 |
self.handlers[id_] = self.tv
|
| 234 |
+ id_ = self.tv.connect('query-tooltip', self.query_tooltip)
|
|
| 235 |
+ self.handlers[id_] = self.tv
|
|
| 228 | 236 |
|
| 229 | 237 |
|
| 230 | 238 |
self.account = account
|
| ... | ... | @@ -326,18 +334,39 @@ class ConversationTextview(GObject.GObject): |
| 326 | 334 |
|
| 327 | 335 |
self.xep0184_warning_tooltip = tooltips.BaseTooltip()
|
| 328 | 336 |
|
| 329 |
- self.line_tooltip = tooltips.BaseTooltip()
|
|
| 330 | 337 |
self.smooth_id = None
|
| 331 | 338 |
self.just_cleared = False
|
| 332 | 339 |
|
| 340 |
+ def query_tooltip(self, widget, x_pos, y_pos, keyboard_mode, tooltip):
|
|
| 341 |
+ x_pos, y_pos = self.tv.window_to_buffer_coords(
|
|
| 342 |
+ Gtk.TextWindowType.TEXT, x_pos, y_pos)
|
|
| 343 |
+ if Gtk.MINOR_VERSION > 18:
|
|
| 344 |
+ iter_ = self.tv.get_iter_at_position(x_pos, y_pos)[1]
|
|
| 345 |
+ else:
|
|
| 346 |
+ iter_ = self.tv.get_iter_at_position(x_pos, y_pos)[0]
|
|
| 347 |
+ for tag in iter_.get_tags():
|
|
| 348 |
+ tag_name = tag.get_property('name')
|
|
| 349 |
+ if tag_name == 'focus-out-line':
|
|
| 350 |
+ tooltip.set_text(_(
|
|
| 351 |
+ 'Text below this line is what has '
|
|
| 352 |
+ 'been said since the\nlast time you paid attention to this '
|
|
| 353 |
+ 'group chat'))
|
|
| 354 |
+ return True
|
|
| 355 |
+ |
|
| 356 |
+ try:
|
|
| 357 |
+ text = self.corrected_text_list[tag_name]
|
|
| 358 |
+ tooltip.set_markup(text)
|
|
| 359 |
+ return True
|
|
| 360 |
+ except KeyError:
|
|
| 361 |
+ pass
|
|
| 362 |
+ return False
|
|
| 363 |
+ |
|
| 333 | 364 |
def del_handlers(self):
|
| 334 | 365 |
for i in self.handlers.keys():
|
| 335 | 366 |
if self.handlers[i].handler_is_connected(i):
|
| 336 | 367 |
self.handlers[i].disconnect(i)
|
| 337 | 368 |
del self.handlers
|
| 338 | 369 |
self.tv.destroy()
|
| 339 |
- #FIXME:
|
|
| 340 |
- # self.line_tooltip.destroy()
|
|
| 341 | 370 |
|
| 342 | 371 |
def update_tags(self):
|
| 343 | 372 |
self.tagIn.set_property('foreground', gajim.config.get('inmsgcolor'))
|
| ... | ... | @@ -398,7 +427,7 @@ class ConversationTextview(GObject.GObject): |
| 398 | 427 |
self.auto_scrolling = False
|
| 399 | 428 |
|
| 400 | 429 |
def smooth_scroll_to_end(self):
|
| 401 |
- if None != self.smooth_id: # already scrolling
|
|
| 430 |
+ if self.smooth_id is not None: # already scrolling
|
|
| 402 | 431 |
return False
|
| 403 | 432 |
self.smooth_id = GLib.timeout_add(self.SCROLL_DELAY,
|
| 404 | 433 |
self.smooth_scroll)
|
| ... | ... | @@ -448,55 +477,46 @@ class ConversationTextview(GObject.GObject): |
| 448 | 477 |
self.smooth_id = None
|
| 449 | 478 |
self.smooth_scroll_timer.cancel()
|
| 450 | 479 |
|
| 451 |
- def show_corrected_message_warning(self, iter_, text=''):
|
|
| 452 |
- buffer_ = self.tv.get_buffer()
|
|
| 453 |
- buffer_.begin_user_action()
|
|
| 454 |
- buffer_.insert(iter_, ' ')
|
|
| 455 |
- anchor = buffer_.create_child_anchor(iter_)
|
|
| 456 |
- img = TextViewImage(anchor, text)
|
|
| 457 |
- img.set_from_pixbuf(ConversationTextview.MESSAGE_CORRECTED_PIXBUF)
|
|
| 458 |
- img.show()
|
|
| 459 |
- self.tv.add_child_at_anchor(img, anchor)
|
|
| 460 |
- buffer_.end_user_action()
|
|
| 480 |
+ def correct_message(self, correct_id, kind, name):
|
|
| 481 |
+ allowed = True
|
|
| 482 |
+ if kind == 'incoming':
|
|
| 483 |
+ try:
|
|
| 484 |
+ if correct_id in self.last_received_message_id[name]:
|
|
| 485 |
+ start_mark = self.last_received_message_id[name][1]
|
|
| 486 |
+ else:
|
|
| 487 |
+ allowed = False
|
|
| 488 |
+ except KeyError:
|
|
| 489 |
+ allowed = False
|
|
| 490 |
+ elif kind == 'outgoing':
|
|
| 491 |
+ if self.last_sent_message_id[0] == correct_id:
|
|
| 492 |
+ start_mark = self.last_sent_message_id[1]
|
|
| 493 |
+ else:
|
|
| 494 |
+ allowed = False
|
|
| 495 |
+ else:
|
|
| 496 |
+ allowed = False
|
|
| 497 |
+ |
|
| 498 |
+ if not allowed:
|
|
| 499 |
+ log.debug('Message correctiong not allowed')
|
|
| 500 |
+ return None
|
|
| 501 |
+ |
|
| 502 |
+ end_mark, index = self.get_end_mark(correct_id, start_mark)
|
|
| 503 |
+ if not index:
|
|
| 504 |
+ log.debug('Could not find line to correct')
|
|
| 505 |
+ return None
|
|
| 461 | 506 |
|
| 462 |
- def correct_last_sent_message(self, message, xhtml, name, old_txt, additional_data={}):
|
|
| 463 |
- m1 = self.last_sent_message_marks[0]
|
|
| 464 |
- m2 = self.last_sent_message_marks[1]
|
|
| 465 |
- buffer_ = self.tv.get_buffer()
|
|
| 466 |
- i1 = buffer_.get_iter_at_mark(m1)
|
|
| 467 |
- i2 = buffer_.get_iter_at_mark(m2)
|
|
| 468 |
- txt = buffer_.get_text(i1, i2, True)
|
|
| 469 |
- buffer_.delete(i1, i2)
|
|
| 470 |
- tag = 'outgoingtxt'
|
|
| 471 |
- if message.startswith('/me'):
|
|
| 472 |
- tag = 'outgoing'
|
|
| 473 |
- i2 = self.print_conversation_line(message, '', 'outgoing', name, None,
|
|
| 474 |
- xhtml=xhtml, iter_=i1, additional_data=additional_data)
|
|
| 475 |
- tt_txt = _('<b>Message was corrected. Last message was:</b>\n %s') % \
|
|
| 476 |
- GLib.markup_escape_text(old_txt)
|
|
| 477 |
- self.show_corrected_message_warning(i2, tt_txt)
|
|
| 478 |
- self.last_sent_message_marks[1] = buffer_.create_mark(None, i2,
|
|
| 479 |
- left_gravity=True)
|
|
| 480 |
- |
|
| 481 |
- def correct_last_received_message(self, message, xhtml, name, old_txt,
|
|
| 482 |
- other_tags_for_name=[], other_tags_for_text=[], additional_data={}):
|
|
| 483 |
- if name not in self.last_received_message_marks:
|
|
| 484 |
- return
|
|
| 485 |
- m1 = self.last_received_message_marks[name][0]
|
|
| 486 |
- m2 = self.last_received_message_marks[name][1]
|
|
| 487 | 507 |
buffer_ = self.tv.get_buffer()
|
| 488 |
- i1 = buffer_.get_iter_at_mark(m1)
|
|
| 489 |
- i2 = buffer_.get_iter_at_mark(m2)
|
|
| 490 |
- txt = buffer_.get_text(i1, i2, True)
|
|
| 491 |
- buffer_.delete(i1, i2)
|
|
| 492 |
- i2 = self.print_conversation_line(message, '', 'incoming', name, None,
|
|
| 493 |
- other_tags_for_name=other_tags_for_name,
|
|
| 494 |
- other_tags_for_text=other_tags_for_text, xhtml=xhtml, iter_=i1, additional_data=additional_data)
|
|
| 495 |
- tt_txt = _('<b>Message was corrected. Last message was:</b>\n %s') % \
|
|
| 496 |
- GLib.markup_escape_text(old_txt)
|
|
| 497 |
- self.show_corrected_message_warning(i2, tt_txt)
|
|
| 498 |
- self.last_received_message_marks[name][1] = buffer_.create_mark(None, i2,
|
|
| 499 |
- left_gravity=True)
|
|
| 508 |
+ if not end_mark:
|
|
| 509 |
+ end_iter = self.tv.get_buffer().get_end_iter()
|
|
| 510 |
+ else:
|
|
| 511 |
+ end_iter = buffer_.get_iter_at_mark(end_mark)
|
|
| 512 |
+ |
|
| 513 |
+ start_iter = buffer_.get_iter_at_mark(start_mark)
|
|
| 514 |
+ |
|
| 515 |
+ old_txt = buffer_.get_text(start_iter, end_iter, True)
|
|
| 516 |
+ buffer_.delete(start_iter, end_iter)
|
|
| 517 |
+ buffer_.delete_mark(start_mark)
|
|
| 518 |
+ |
|
| 519 |
+ return index, end_mark, old_txt
|
|
| 500 | 520 |
|
| 501 | 521 |
def show_xep0184_warning(self, id_):
|
| 502 | 522 |
if id_ in self.xep0184_marks:
|
| ... | ... | @@ -639,30 +659,6 @@ class ConversationTextview(GObject.GObject): |
| 639 | 659 |
"end. If this icon stays\nfor a long time, it's likely the "
|
| 640 | 660 |
'message got lost.'), 8, position[1] + y)
|
| 641 | 661 |
|
| 642 |
- def show_line_tooltip(self):
|
|
| 643 |
- self.line_tooltip.timeout = 0
|
|
| 644 |
- w = self.tv.get_window(Gtk.TextWindowType.TEXT)
|
|
| 645 |
- device = w.get_display().get_device_manager().get_client_pointer()
|
|
| 646 |
- pointer = w.get_device_position(device)
|
|
| 647 |
- x = pointer[1]
|
|
| 648 |
- y = pointer[2]
|
|
| 649 |
- iter_ = self.tv.get_iter_at_location(x, y)
|
|
| 650 |
- if isinstance(iter_, tuple):
|
|
| 651 |
- iter_ = iter_[1]
|
|
| 652 |
- tags = iter_.get_tags()
|
|
| 653 |
- tag_table = self.tv.get_buffer().get_tag_table()
|
|
| 654 |
- over_line = False
|
|
| 655 |
- for tag in tags:
|
|
| 656 |
- if tag == tag_table.lookup('focus-out-line'):
|
|
| 657 |
- over_line = True
|
|
| 658 |
- break
|
|
| 659 |
- if over_line and not self.line_tooltip.win:
|
|
| 660 |
- # check if the current pointer is still over the line
|
|
| 661 |
- position = w.get_origin()[1:]
|
|
| 662 |
- self.line_tooltip.show_tooltip(_('Text below this line is what has '
|
|
| 663 |
- 'been said since the\nlast time you paid attention to this '
|
|
| 664 |
- 'group chat'), 8, position[1] + y)
|
|
| 665 |
- |
|
| 666 | 662 |
def on_textview_draw(self, widget, ctx):
|
| 667 | 663 |
return
|
| 668 | 664 |
#TODO
|
| ... | ... | @@ -708,7 +704,6 @@ class ConversationTextview(GObject.GObject): |
| 708 | 704 |
w.set_cursor(Gdk.Cursor.new(Gdk.CursorType.XTERM))
|
| 709 | 705 |
self.change_cursor = False
|
| 710 | 706 |
tag_table = self.tv.get_buffer().get_tag_table()
|
| 711 |
- over_line = False
|
|
| 712 | 707 |
xep0184_warning = False
|
| 713 | 708 |
|
| 714 | 709 |
for tag in tags:
|
| ... | ... | @@ -716,25 +711,15 @@ class ConversationTextview(GObject.GObject): |
| 716 | 711 |
tag_table.lookup('xmpp'), tag_table.lookup('sth_at_sth')):
|
| 717 | 712 |
w.set_cursor(Gdk.Cursor.new(Gdk.CursorType.HAND2))
|
| 718 | 713 |
self.change_cursor = True
|
| 719 |
- elif tag == tag_table.lookup('focus-out-line'):
|
|
| 720 |
- over_line = True
|
|
| 721 | 714 |
elif tag == tag_table.lookup('xep0184-warning'):
|
| 722 | 715 |
xep0184_warning = True
|
| 723 | 716 |
|
| 724 |
- if self.line_tooltip.timeout != 0 or self.line_tooltip.shown:
|
|
| 725 |
- # Check if we should hide the line tooltip
|
|
| 726 |
- if not over_line:
|
|
| 727 |
- self.line_tooltip.hide_tooltip()
|
|
| 728 | 717 |
if self.xep0184_warning_tooltip.timeout != 0 or \
|
| 729 | 718 |
self.xep0184_warning_tooltip.shown:
|
| 730 | 719 |
# Check if we should hide the XEP-184 warning tooltip
|
| 731 | 720 |
if not xep0184_warning:
|
| 732 | 721 |
self.xep0184_warning_tooltip.hide_tooltip()
|
| 733 |
- if over_line and not self.line_tooltip.win:
|
|
| 734 |
- self.line_tooltip.timeout = GLib.timeout_add(500,
|
|
| 735 |
- self.show_line_tooltip)
|
|
| 736 |
- w.set_cursor(Gdk.Cursor.new(Gdk.CursorType.LEFT_PTR))
|
|
| 737 |
- self.change_cursor = True
|
|
| 722 |
+ |
|
| 738 | 723 |
if xep0184_warning and not self.xep0184_warning_tooltip.win:
|
| 739 | 724 |
self.xep0184_warning_tooltip.timeout = GLib.timeout_add(500,
|
| 740 | 725 |
self.show_xep0184_warning_tooltip)
|
| ... | ... | @@ -1244,62 +1229,105 @@ class ConversationTextview(GObject.GObject): |
| 1244 | 1229 |
buffer_.insert_with_tags_by_name(iter_, '\n', 'eol')
|
| 1245 | 1230 |
self.just_cleared = False
|
| 1246 | 1231 |
|
| 1232 |
+ def get_end_mark(self, msg_stanza_id, start_mark):
|
|
| 1233 |
+ for index, msg in enumerate(self.message_list):
|
|
| 1234 |
+ if msg[2] == msg_stanza_id and msg[1] == start_mark:
|
|
| 1235 |
+ try:
|
|
| 1236 |
+ end_mark = self.message_list[index + 1][1]
|
|
| 1237 |
+ end_mark_name = end_mark.get_name()
|
|
| 1238 |
+ except IndexError:
|
|
| 1239 |
+ # We are at the last message
|
|
| 1240 |
+ end_mark = None
|
|
| 1241 |
+ end_mark_name = None
|
|
| 1242 |
+ |
|
| 1243 |
+ log.debug('start mark: %s, end mark: %s, '
|
|
| 1244 |
+ 'replace message-list index: %s',
|
|
| 1245 |
+ start_mark.get_name(), end_mark_name, index)
|
|
| 1246 |
+ |
|
| 1247 |
+ return end_mark, index
|
|
| 1248 |
+ log.debug('stanza-id not in message list')
|
|
| 1249 |
+ return None, None
|
|
| 1250 |
+ |
|
| 1251 |
+ def get_insert_mark(self, timestamp):
|
|
| 1252 |
+ # message_list = [(timestamp, line_start_mark, msg_stanza_id)]
|
|
| 1253 |
+ # We check if this is a new Message
|
|
| 1254 |
+ try:
|
|
| 1255 |
+ if self.message_list[-1][0] <= timestamp:
|
|
| 1256 |
+ return None, None
|
|
| 1257 |
+ except IndexError:
|
|
| 1258 |
+ # We have no Messages in the TextView
|
|
| 1259 |
+ return None, None
|
|
| 1260 |
+ |
|
| 1261 |
+ # Not a new Message
|
|
| 1262 |
+ # Search for insertion point
|
|
| 1263 |
+ for index, msg in enumerate(self.message_list):
|
|
| 1264 |
+ if msg[0] > timestamp:
|
|
| 1265 |
+ return msg[1], index
|
|
| 1266 |
+ |
|
| 1267 |
+ # Should not happen, but who knows
|
|
| 1268 |
+ return None, None
|
|
| 1269 |
+ |
|
| 1247 | 1270 |
def print_conversation_line(self, text, jid, kind, name, tim,
|
| 1248 |
- other_tags_for_name=[], other_tags_for_time=[], other_tags_for_text=[],
|
|
| 1271 |
+ other_tags_for_name=None, other_tags_for_time=None, other_tags_for_text=None,
|
|
| 1249 | 1272 |
subject=None, old_kind=None, xhtml=None, simple=False, graphics=True,
|
| 1250 |
- displaymarking=None, iter_=None, additional_data={}):
|
|
| 1273 |
+ displaymarking=None, msg_stanza_id=None, correct_id=None, additional_data=None):
|
|
| 1251 | 1274 |
"""
|
| 1252 | 1275 |
Print 'chat' type messages
|
| 1253 | 1276 |
"""
|
| 1254 | 1277 |
buffer_ = self.tv.get_buffer()
|
| 1255 | 1278 |
buffer_.begin_user_action()
|
| 1256 |
- if iter_:
|
|
| 1257 |
- temp_mark = buffer_.create_mark(None, iter_, left_gravity=True)
|
|
| 1258 |
- if self.marks_queue.full():
|
|
| 1259 |
- # remove oldest line
|
|
| 1260 |
- m1 = self.marks_queue.get()
|
|
| 1261 |
- m2 = self.marks_queue.get()
|
|
| 1262 |
- i1 = buffer_.get_iter_at_mark(m1)
|
|
| 1263 |
- i2 = buffer_.get_iter_at_mark(m2)
|
|
| 1264 |
- buffer_.delete(i1, i2)
|
|
| 1265 |
- buffer_.delete_mark(m1)
|
|
| 1266 |
- if iter_:
|
|
| 1267 |
- end_iter = buffer_.get_iter_at_mark(temp_mark)
|
|
| 1268 |
- buffer_.delete_mark(temp_mark)
|
|
| 1269 |
- else:
|
|
| 1270 |
- end_iter = buffer_.get_end_iter()
|
|
| 1271 |
- end_offset = end_iter.get_offset()
|
|
| 1272 |
- at_the_end = self.at_the_end()
|
|
| 1273 |
- move_selection = False
|
|
| 1274 |
- if buffer_.get_has_selection() and buffer_.get_selection_bounds()[1].\
|
|
| 1275 |
- get_offset() == end_offset:
|
|
| 1276 |
- move_selection = True
|
|
| 1279 |
+ insert_mark = None
|
|
| 1280 |
+ insert_mark_name = None
|
|
| 1277 | 1281 |
|
| 1278 |
- if not iter_:
|
|
| 1279 |
- # Create one mark and add it to queue once if it's the first line
|
|
| 1280 |
- # else twice (one for end bound, one for start bound)
|
|
| 1281 |
- mark = None
|
|
| 1282 |
- if buffer_.get_char_count() > 0:
|
|
| 1283 |
- if not simple and not iter_:
|
|
| 1284 |
- buffer_.insert_with_tags_by_name(end_iter, '\n', 'eol')
|
|
| 1285 |
- if move_selection:
|
|
| 1286 |
- sel_start, sel_end = buffer_.get_selection_bounds()
|
|
| 1287 |
- sel_end.backward_char()
|
|
| 1288 |
- buffer_.select_range(sel_start, sel_end)
|
|
| 1289 |
- mark = buffer_.create_mark(None, end_iter, left_gravity=True)
|
|
| 1290 |
- self.marks_queue.put(mark)
|
|
| 1291 |
- if not mark:
|
|
| 1292 |
- mark = buffer_.create_mark(None, end_iter, left_gravity=True)
|
|
| 1293 |
- self.marks_queue.put(mark)
|
|
| 1294 | 1282 |
if kind == 'incoming_queue':
|
| 1295 | 1283 |
kind = 'incoming'
|
| 1296 | 1284 |
if old_kind == 'incoming_queue':
|
| 1297 | 1285 |
old_kind = 'incoming'
|
| 1298 |
- # print the time stamp
|
|
| 1286 |
+ |
|
| 1299 | 1287 |
if not tim:
|
| 1300 |
- # We don't have tim for outgoing messages...
|
|
| 1301 |
- tim = time.localtime()
|
|
| 1302 |
- current_print_time = gajim.config.get('print_time')
|
|
| 1288 |
+ # For outgoing Messages and Status prints
|
|
| 1289 |
+ tim = time.time()
|
|
| 1290 |
+ |
|
| 1291 |
+ corrected = False
|
|
| 1292 |
+ if correct_id:
|
|
| 1293 |
+ try:
|
|
| 1294 |
+ index, insert_mark, old_txt = \
|
|
| 1295 |
+ self.correct_message(correct_id, kind, name)
|
|
| 1296 |
+ self.corrected_text_list[msg_stanza_id] = \
|
|
| 1297 |
+ '<b>Message was corrected. Last message was:</b>\n{}' \
|
|
| 1298 |
+ .format(GLib.markup_escape_text(old_txt))
|
|
| 1299 |
+ corrected = True
|
|
| 1300 |
+ except TypeError:
|
|
| 1301 |
+ log.debug('Message was not corrected !')
|
|
| 1302 |
+ |
|
| 1303 |
+ if not corrected:
|
|
| 1304 |
+ # Get insertion point into TextView
|
|
| 1305 |
+ insert_mark, index = self.get_insert_mark(tim)
|
|
| 1306 |
+ |
|
| 1307 |
+ if insert_mark:
|
|
| 1308 |
+ insert_mark_name = insert_mark.get_name()
|
|
| 1309 |
+ |
|
| 1310 |
+ log.debug(
|
|
| 1311 |
+ 'Printed Line: %s, %s, %s, inserted after: %s'
|
|
| 1312 |
+ ', stanza-id: %s, correct-id: %s',
|
|
| 1313 |
+ self.line, text, tim, insert_mark_name,
|
|
| 1314 |
+ msg_stanza_id, correct_id)
|
|
| 1315 |
+ |
|
| 1316 |
+ if not insert_mark: # Texview is empty or Message is new
|
|
| 1317 |
+ iter_ = buffer_.get_end_iter()
|
|
| 1318 |
+ # Insert new Line if Textview is not empty
|
|
| 1319 |
+ if buffer_.get_char_count() > 0 and not corrected:
|
|
| 1320 |
+ buffer_.insert_with_tags_by_name(iter_, '\n', 'eol')
|
|
| 1321 |
+ else:
|
|
| 1322 |
+ iter_ = buffer_.get_iter_at_mark(insert_mark)
|
|
| 1323 |
+ |
|
| 1324 |
+ # Create a temporary mark at the start of the line
|
|
| 1325 |
+ # with gravity=Left, so it will not move
|
|
| 1326 |
+ # even if we insert directly at the mark iter
|
|
| 1327 |
+ temp_mark = buffer_.create_mark('temp', iter_, left_gravity=True)
|
|
| 1328 |
+ |
|
| 1329 |
+ at_the_end = self.at_the_end()
|
|
| 1330 |
+ |
|
| 1303 | 1331 |
if text.startswith('/me '):
|
| 1304 | 1332 |
direction_mark = i18n.paragraph_direction_mark(str(text[3:]))
|
| 1305 | 1333 |
else:
|
| ... | ... | @@ -1307,90 +1335,96 @@ class ConversationTextview(GObject.GObject): |
| 1307 | 1335 |
# don't apply direction mark if it's status message
|
| 1308 | 1336 |
if kind == 'status':
|
| 1309 | 1337 |
direction_mark = i18n.direction_mark
|
| 1310 |
- if current_print_time == 'always' and kind != 'info' and not simple:
|
|
| 1311 |
- timestamp_str = self.get_time_to_show(tim, direction_mark)
|
|
| 1312 |
- timestamp = time.strftime(timestamp_str, tim)
|
|
| 1313 |
- timestamp = direction_mark + timestamp + direction_mark
|
|
| 1314 |
- if other_tags_for_time:
|
|
| 1315 |
- buffer_.insert_with_tags_by_name(end_iter, timestamp,
|
|
| 1316 |
- *other_tags_for_time)
|
|
| 1317 |
- else:
|
|
| 1318 |
- buffer_.insert (end_iter, timestamp)
|
|
| 1319 |
- elif current_print_time == 'sometimes' and kind != 'info' and not simple:
|
|
| 1320 |
- every_foo_seconds = 60 * gajim.config.get(
|
|
| 1321 |
- 'print_ichat_every_foo_minutes')
|
|
| 1322 |
- seconds_passed = time.mktime(tim) - self.last_time_printout
|
|
| 1323 |
- if seconds_passed > every_foo_seconds:
|
|
| 1324 |
- self.last_time_printout = time.mktime(tim)
|
|
| 1325 |
- end_iter = buffer_.get_end_iter()
|
|
| 1326 |
- if gajim.config.get('print_time_fuzzy') > 0:
|
|
| 1327 |
- tim_format = self.fc.fuzzy_time(gajim.config.get('print_time_fuzzy'), tim)
|
|
| 1328 |
- else:
|
|
| 1329 |
- tim_format = self.get_time_to_show(tim, direction_mark)
|
|
| 1330 |
- buffer_.insert_with_tags_by_name(end_iter, tim_format + '\n',
|
|
| 1331 |
- 'time_sometimes')
|
|
| 1338 |
+ |
|
| 1339 |
+ # print the time stamp
|
|
| 1340 |
+ self.print_time(text, kind, tim, simple, direction_mark,
|
|
| 1341 |
+ other_tags_for_time, iter_)
|
|
| 1342 |
+ |
|
| 1332 | 1343 |
# If there's a displaymarking, print it here.
|
| 1333 | 1344 |
if displaymarking:
|
| 1334 |
- self.print_displaymarking(displaymarking, iter_=end_iter)
|
|
| 1345 |
+ self.print_displaymarking(displaymarking, iter_=iter_)
|
|
| 1346 |
+ |
|
| 1335 | 1347 |
# kind = info, we print things as if it was a status: same color, ...
|
| 1336 | 1348 |
if kind in ('error', 'info'):
|
| 1337 | 1349 |
kind = 'status'
|
| 1338 | 1350 |
other_text_tag = self.detect_other_text_tag(text, kind)
|
| 1339 |
- text_tags = other_tags_for_text[:] # create a new list
|
|
| 1340 |
- mark1 = None
|
|
| 1351 |
+ text_tags = []
|
|
| 1352 |
+ if other_tags_for_text:
|
|
| 1353 |
+ text_tags = other_tags_for_text[:] # create a new list
|
|
| 1341 | 1354 |
if other_text_tag:
|
| 1342 |
- # note that color of /me may be overwritten in gc_control
|
|
| 1343 | 1355 |
text_tags.append(other_text_tag)
|
| 1344 |
- if text.startswith('/me') and not iter_:
|
|
| 1345 |
- mark1 = mark
|
|
| 1346 |
- else: # not status nor /me
|
|
| 1356 |
+ |
|
| 1357 |
+ else: # not status nor /me
|
|
| 1347 | 1358 |
if gajim.config.get('chat_merge_consecutive_nickname'):
|
| 1348 | 1359 |
if kind != old_kind or self.just_cleared:
|
| 1349 | 1360 |
self.print_name(name, kind, other_tags_for_name,
|
| 1350 |
- direction_mark=direction_mark, iter_=end_iter)
|
|
| 1361 |
+ direction_mark=direction_mark, iter_=iter_)
|
|
| 1351 | 1362 |
else:
|
| 1352 | 1363 |
self.print_real_text(gajim.config.get(
|
| 1353 | 1364 |
'chat_merge_consecutive_nickname_indent'),
|
| 1354 |
- iter_=end_iter, additional_data=additional_data)
|
|
| 1365 |
+ mark=insert_mark, additional_data=additional_data)
|
|
| 1355 | 1366 |
else:
|
| 1356 | 1367 |
self.print_name(name, kind, other_tags_for_name,
|
| 1357 |
- direction_mark=direction_mark, iter_=end_iter)
|
|
| 1368 |
+ direction_mark=direction_mark, iter_=iter_)
|
|
| 1358 | 1369 |
if kind == 'incoming':
|
| 1359 | 1370 |
text_tags.append('incomingtxt')
|
| 1360 |
- if not iter_:
|
|
| 1361 |
- mark1 = mark
|
|
| 1362 | 1371 |
elif kind == 'outgoing':
|
| 1363 | 1372 |
text_tags.append('outgoingtxt')
|
| 1364 |
- if not iter_:
|
|
| 1365 |
- mark1 = mark
|
|
| 1366 |
- self.print_subject(subject, iter_=end_iter)
|
|
| 1367 |
- self.print_real_text(text, text_tags, name, xhtml, graphics=graphics,
|
|
| 1368 |
- iter_=end_iter, additional_data=additional_data)
|
|
| 1369 |
- if not iter_ and mark1:
|
|
| 1370 |
- mark2 = buffer_.create_mark(None, buffer_.get_end_iter(),
|
|
| 1371 |
- left_gravity=True)
|
|
| 1372 |
- if kind == 'incoming':
|
|
| 1373 |
- if name in self.last_received_message_marks:
|
|
| 1374 |
- m = self.last_received_message_marks[name][1]
|
|
| 1375 |
- buffer_.delete_mark(m)
|
|
| 1376 |
- self.last_received_message_marks[name] = [mark1, mark2]
|
|
| 1377 |
- elif kind == 'outgoing':
|
|
| 1378 |
- m = self.last_sent_message_marks[1]
|
|
| 1379 |
- if m:
|
|
| 1380 |
- buffer_.delete_mark(m)
|
|
| 1381 |
- self.last_sent_message_marks = [mark1, mark2]
|
|
| 1382 |
- # scroll to the end of the textview
|
|
| 1383 |
- if at_the_end or kind == 'outgoing':
|
|
| 1384 |
- # we are at the end or we are sending something
|
|
| 1385 |
- # scroll to the end (via idle in case the scrollbar has appeared)
|
|
| 1386 |
- if gajim.config.get('use_smooth_scrolling'):
|
|
| 1387 |
- GLib.idle_add(self.smooth_scroll_to_end)
|
|
| 1388 |
- else:
|
|
| 1389 |
- GLib.idle_add(self.scroll_to_end)
|
|
| 1373 |
+ |
|
| 1374 |
+ self.print_subject(subject, iter_=iter_)
|
|
| 1375 |
+
|
|
| 1376 |
+ iter_ = self.print_real_text(text, text_tags, name, xhtml, graphics=graphics,
|
|
| 1377 |
+ mark=insert_mark, additional_data=additional_data)
|
|
| 1378 |
+ |
|
| 1379 |
+ if corrected:
|
|
| 1380 |
+ # Show Correction Icon
|
|
| 1381 |
+ buffer_.create_tag(tag_name=msg_stanza_id)
|
|
| 1382 |
+ buffer_.insert(iter_, ' ')
|
|
| 1383 |
+ buffer_.insert_pixbuf(
|
|
| 1384 |
+ iter_, ConversationTextview.MESSAGE_CORRECTED_PIXBUF)
|
|
| 1385 |
+ tag_start_iter = iter_.copy()
|
|
| 1386 |
+ tag_start_iter.backward_chars(2)
|
|
| 1387 |
+ buffer_.apply_tag_by_name(msg_stanza_id, tag_start_iter, iter_)
|
|
| 1388 |
+ |
|
| 1389 |
+ # If we inserted a Line we add a new line at the end
|
|
| 1390 |
+ if insert_mark:
|
|
| 1391 |
+ buffer_.insert_with_tags_by_name(iter_, '\n', 'eol')
|
|
| 1392 |
+ # We delete the temp mark and replace it with a mark
|
|
| 1393 |
+ # that has gravity=right
|
|
| 1394 |
+ temp_iter = buffer_.get_iter_at_mark(temp_mark)
|
|
| 1395 |
+ buffer_.delete_mark(temp_mark)
|
|
| 1396 |
+ new_mark = buffer_.create_mark(
|
|
| 1397 |
+ str(self.line), temp_iter, left_gravity=False)
|
|
| 1398 |
+ |
|
| 1399 |
+ if not index:
|
|
| 1400 |
+ # New Message
|
|
| 1401 |
+ self.message_list.append((tim, new_mark, msg_stanza_id))
|
|
| 1402 |
+ elif corrected:
|
|
| 1403 |
+ # Replace the corrected message
|
|
| 1404 |
+ self.message_list[index] = (tim, new_mark, msg_stanza_id)
|
|
| 1405 |
+ else:
|
|
| 1406 |
+ # We insert the message at index
|
|
| 1407 |
+ self.message_list.insert(index, (tim, new_mark, msg_stanza_id))
|
|
| 1408 |
+ |
|
| 1409 |
+ if kind == 'incoming':
|
|
| 1410 |
+ self.last_received_message_id[name] = (msg_stanza_id, new_mark)
|
|
| 1411 |
+ elif kind == 'outgoing':
|
|
| 1412 |
+ self.last_sent_message_id = (msg_stanza_id, new_mark)
|
|
| 1413 |
+ |
|
| 1414 |
+ if not insert_mark:
|
|
| 1415 |
+ if at_the_end or kind == 'outgoing':
|
|
| 1416 |
+ # we are at the end or we are sending something
|
|
| 1417 |
+ # scroll to the end (via idle in case the scrollbar has appeared)
|
|
| 1418 |
+ if gajim.config.get('use_smooth_scrolling'):
|
|
| 1419 |
+ GLib.idle_add(self.smooth_scroll_to_end)
|
|
| 1420 |
+ else:
|
|
| 1421 |
+ GLib.idle_add(self.scroll_to_end)
|
|
| 1390 | 1422 |
|
| 1391 | 1423 |
self.just_cleared = False
|
| 1392 | 1424 |
buffer_.end_user_action()
|
| 1393 |
- return end_iter
|
|
| 1425 |
+ |
|
| 1426 |
+ self.line += 1
|
|
| 1427 |
+ return iter_
|
|
| 1394 | 1428 |
|
| 1395 | 1429 |
def get_time_to_show(self, tim, direction_mark=''):
|
| 1396 | 1430 |
"""
|
| ... | ... | @@ -1429,6 +1463,34 @@ class ConversationTextview(GObject.GObject): |
| 1429 | 1463 |
elif text.startswith('/me ') or text.startswith('/me\n'):
|
| 1430 | 1464 |
return kind
|
| 1431 | 1465 |
|
| 1466 |
+ def print_time(self, text, kind, tim, simple, direction_mark, other_tags_for_time, iter_):
|
|
| 1467 |
+ local_tim = time.localtime(tim)
|
|
| 1468 |
+ buffer_ = self.tv.get_buffer()
|
|
| 1469 |
+ current_print_time = gajim.config.get('print_time')
|
|
| 1470 |
+ |
|
| 1471 |
+ if current_print_time == 'always' and kind != 'info' and not simple:
|
|
| 1472 |
+ timestamp_str = self.get_time_to_show(local_tim, direction_mark)
|
|
| 1473 |
+ timestamp = time.strftime(timestamp_str, local_tim)
|
|
| 1474 |
+ timestamp = direction_mark + timestamp + direction_mark
|
|
| 1475 |
+ if other_tags_for_time:
|
|
| 1476 |
+ buffer_.insert_with_tags_by_name(iter_, timestamp,
|
|
| 1477 |
+ *other_tags_for_time)
|
|
| 1478 |
+ else:
|
|
| 1479 |
+ buffer_.insert(iter_, timestamp)
|
|
| 1480 |
+ elif current_print_time == 'sometimes' and kind != 'info' and not simple:
|
|
| 1481 |
+ every_foo_seconds = 60 * gajim.config.get(
|
|
| 1482 |
+ 'print_ichat_every_foo_minutes')
|
|
| 1483 |
+ seconds_passed = tim - self.last_time_printout
|
|
| 1484 |
+ if seconds_passed > every_foo_seconds:
|
|
| 1485 |
+ self.last_time_printout = tim
|
|
| 1486 |
+ if gajim.config.get('print_time_fuzzy') > 0:
|
|
| 1487 |
+ tim_format = self.fc.fuzzy_time(
|
|
| 1488 |
+ gajim.config.get('print_time_fuzzy'), tim)
|
|
| 1489 |
+ else:
|
|
| 1490 |
+ tim_format = self.get_time_to_show(local_tim, direction_mark)
|
|
| 1491 |
+ buffer_.insert_with_tags_by_name(iter_, tim_format + '\n',
|
|
| 1492 |
+ 'time_sometimes')
|
|
| 1493 |
+ |
|
| 1432 | 1494 |
def print_displaymarking(self, displaymarking, iter_=None):
|
| 1433 | 1495 |
bgcolor = displaymarking.getAttr('bgcolor') or '#FFF'
|
| 1434 | 1496 |
fgcolor = displaymarking.getAttr('fgcolor') or '#000'
|
| ... | ... | @@ -1448,12 +1510,15 @@ class ConversationTextview(GObject.GObject): |
| 1448 | 1510 |
def print_name(self, name, kind, other_tags_for_name, direction_mark='',
|
| 1449 | 1511 |
iter_=None):
|
| 1450 | 1512 |
if name:
|
| 1513 |
+ name_tags = []
|
|
| 1451 | 1514 |
buffer_ = self.tv.get_buffer()
|
| 1452 | 1515 |
if iter_:
|
| 1453 | 1516 |
end_iter = iter_
|
| 1454 | 1517 |
else:
|
| 1455 | 1518 |
end_iter = buffer_.get_end_iter()
|
| 1456 |
- name_tags = other_tags_for_name[:] # create a new list
|
|
| 1519 |
+ |
|
| 1520 |
+ if other_tags_for_name:
|
|
| 1521 |
+ name_tags = other_tags_for_name[:] # create a new list
|
|
| 1457 | 1522 |
name_tags.append(kind)
|
| 1458 | 1523 |
before_str = gajim.config.get('before_nickname')
|
| 1459 | 1524 |
before_str = helpers.from_one_line(before_str)
|
| ... | ... | @@ -1474,10 +1539,15 @@ class ConversationTextview(GObject.GObject): |
| 1474 | 1539 |
self.print_empty_line(end_iter)
|
| 1475 | 1540 |
|
| 1476 | 1541 |
def print_real_text(self, text, text_tags=[], name=None, xhtml=None,
|
| 1477 |
- graphics=True, iter_=None, additional_data={}):
|
|
| 1542 |
+ graphics=True, mark=None, additional_data={}):
|
|
| 1478 | 1543 |
"""
|
| 1479 | 1544 |
Add normal and special text. call this to add text
|
| 1480 | 1545 |
"""
|
| 1546 |
+ buffer_ = self.tv.get_buffer()
|
|
| 1547 |
+ if not mark:
|
|
| 1548 |
+ iter_ = buffer_.get_end_iter()
|
|
| 1549 |
+ else:
|
|
| 1550 |
+ iter_ = buffer_.get_iter_at_mark(mark)
|
|
| 1481 | 1551 |
if xhtml:
|
| 1482 | 1552 |
try:
|
| 1483 | 1553 |
if name and (text.startswith('/me ') or text.startswith('/me\n')):
|
| ... | ... | @@ -1492,16 +1562,23 @@ class ConversationTextview(GObject.GObject): |
| 1492 | 1562 |
if name and (text.startswith('/me ') or text.startswith('/me\n')):
|
| 1493 | 1563 |
text = '* ' + name + text[3:]
|
| 1494 | 1564 |
text_tags.append('italic')
|
| 1495 |
-
|
|
| 1565 |
+ |
|
| 1496 | 1566 |
# PluginSystem: adding GUI extension point for ConversationTextview
|
| 1497 | 1567 |
self.plugin_modified = False
|
| 1498 | 1568 |
gajim.plugin_manager.gui_extension_point('print_real_text', self,
|
| 1499 | 1569 |
text, text_tags, graphics, iter_, additional_data)
|
| 1570 |
+ |
|
| 1500 | 1571 |
if self.plugin_modified:
|
| 1501 |
- return self.tv.get_buffer().get_end_iter()
|
|
| 1502 |
- #needed, if buffer is manipulated by plugins without setting plugin_modified to True
|
|
| 1503 |
- iter_ = self.tv.get_buffer().get_end_iter()
|
|
| 1504 |
-
|
|
| 1572 |
+ if not mark:
|
|
| 1573 |
+ return buffer_.get_end_iter()
|
|
| 1574 |
+ else:
|
|
| 1575 |
+ return buffer_.get_iter_at_mark(mark)
|
|
| 1576 |
+ |
|
| 1577 |
+ if not mark:
|
|
| 1578 |
+ iter_ = buffer_.get_end_iter()
|
|
| 1579 |
+ else:
|
|
| 1580 |
+ iter_ = buffer_.get_iter_at_mark(mark)
|
|
| 1581 |
+ |
|
| 1505 | 1582 |
# detect urls formatting and if the user has it on emoticons
|
| 1506 | 1583 |
return self.detect_and_print_special_text(text, text_tags, graphics=graphics,
|
| 1507 | 1584 |
iter_=iter_, additional_data=additional_data)
|
| ... | ... | @@ -1069,64 +1069,14 @@ class GroupchatControl(ChatControlBase): |
| 1069 | 1069 |
# Like that xhtml messages are grayed too.
|
| 1070 | 1070 |
self.print_old_conversation(obj.msgtxt, contact=obj.nick,
|
| 1071 | 1071 |
tim=obj.timestamp, xhtml=None,
|
| 1072 |
- displaymarking=obj.displaymarking)
|
|
| 1072 |
+ displaymarking=obj.displaymarking, msg_stanza_id=obj.id_)
|
|
| 1073 | 1073 |
else:
|
| 1074 |
- if obj.nick in self.last_received_txt and obj.correct_id and \
|
|
| 1075 |
- obj.correct_id == self.last_received_id[obj.nick]:
|
|
| 1076 |
- if obj.nick == self.nick:
|
|
| 1077 |
- old_txt = self.last_sent_txt
|
|
| 1078 |
- self.last_sent_txt = obj.msgtxt
|
|
| 1079 |
- self.conv_textview.correct_last_sent_message(obj.msgtxt,
|
|
| 1080 |
- obj.xhtml_msgtxt, obj.nick, old_txt)
|
|
| 1081 |
- else:
|
|
| 1082 |
- old_txt = self.last_received_txt[obj.nick]
|
|
| 1083 |
- (highlight, sound) = self.highlighting_for_message(obj.msgtxt, obj.timestamp)
|
|
| 1084 |
- other_tags_for_name = []
|
|
| 1085 |
- other_tags_for_text = []
|
|
| 1086 |
- if obj.nick in self.gc_custom_colors:
|
|
| 1087 |
- other_tags_for_name.append('gc_nickname_color_' + \
|
|
| 1088 |
- str(self.gc_custom_colors[obj.nick]))
|
|
| 1089 |
- else:
|
|
| 1090 |
- self.gc_count_nicknames_colors += 1
|
|
| 1091 |
- if self.gc_count_nicknames_colors == \
|
|
| 1092 |
- self.number_of_colors:
|
|
| 1093 |
- self.gc_count_nicknames_colors = 0
|
|
| 1094 |
- self.gc_custom_colors[obj.nick] = \
|
|
| 1095 |
- self.gc_count_nicknames_colors
|
|
| 1096 |
- other_tags_for_name.append('gc_nickname_color_' + \
|
|
| 1097 |
- str(self.gc_count_nicknames_colors))
|
|
| 1098 |
- if highlight:
|
|
| 1099 |
- # muc-specific chatstate
|
|
| 1100 |
- if self.parent_win:
|
|
| 1101 |
- self.parent_win.redraw_tab(self, 'attention')
|
|
| 1102 |
- else:
|
|
| 1103 |
- self.attention_flag = True
|
|
| 1104 |
- other_tags_for_name.append('bold')
|
|
| 1105 |
- other_tags_for_text.append('marked')
|
|
| 1106 |
- |
|
| 1107 |
- if obj.nick in self.attention_list:
|
|
| 1108 |
- self.attention_list.remove(obj.nick)
|
|
| 1109 |
- elif len(self.attention_list) > 6:
|
|
| 1110 |
- self.attention_list.pop(0) # remove older
|
|
| 1111 |
- self.attention_list.append(obj.nick)
|
|
| 1112 |
- |
|
| 1113 |
- if obj.msgtxt.startswith('/me ') or \
|
|
| 1114 |
- obj.msgtxt.startswith('/me\n'):
|
|
| 1115 |
- other_tags_for_text.append('gc_nickname_color_' + \
|
|
| 1116 |
- str(self.gc_custom_colors[obj.nick]))
|
|
| 1117 |
- self.conv_textview.correct_last_received_message(
|
|
| 1118 |
- obj.msgtxt, obj.xhtml_msgtxt, obj.nick, old_txt,
|
|
| 1119 |
- other_tags_for_name=other_tags_for_name,
|
|
| 1120 |
- other_tags_for_text=other_tags_for_text)
|
|
| 1121 |
- self.last_received_txt[obj.nick] = obj.msgtxt
|
|
| 1122 |
- self.last_received_id[obj.nick] = obj.stanza.getID()
|
|
| 1123 |
- return
|
|
| 1124 | 1074 |
if obj.nick == self.nick:
|
| 1125 | 1075 |
self.last_sent_txt = obj.msgtxt
|
| 1126 | 1076 |
self.print_conversation(obj.msgtxt, contact=obj.nick,
|
| 1127 | 1077 |
tim=obj.timestamp, xhtml=obj.xhtml_msgtxt,
|
| 1128 | 1078 |
displaymarking=obj.displaymarking,
|
| 1129 |
- correct_id=(obj.stanza.getID(), None))
|
|
| 1079 |
+ correct_id=obj.correct_id, msg_stanza_id=obj.id_)
|
|
| 1130 | 1080 |
obj.needs_highlight = self.needs_visual_notification(obj.msgtxt)
|
| 1131 | 1081 |
|
| 1132 | 1082 |
def on_private_message(self, nick, msg, tim, xhtml, session, msg_log_id=None,
|
| ... | ... | @@ -1181,7 +1131,7 @@ class GroupchatControl(ChatControlBase): |
| 1181 | 1131 |
return None
|
| 1182 | 1132 |
|
| 1183 | 1133 |
def print_old_conversation(self, text, contact='', tim=None, xhtml = None,
|
| 1184 |
- displaymarking=None):
|
|
| 1134 |
+ displaymarking=None, msg_stanza_id=None):
|
|
| 1185 | 1135 |
if contact:
|
| 1186 | 1136 |
if contact == self.nick: # it's us
|
| 1187 | 1137 |
kind = 'outgoing'
|
| ... | ... | @@ -1196,10 +1146,10 @@ class GroupchatControl(ChatControlBase): |
| 1196 | 1146 |
ChatControlBase.print_conversation_line(self, text, kind, contact, tim,
|
| 1197 | 1147 |
small_attr, small_attr + ['restored_message'],
|
| 1198 | 1148 |
small_attr + ['restored_message'], count_as_new=False, xhtml=xhtml,
|
| 1199 |
- displaymarking=displaymarking)
|
|
| 1149 |
+ displaymarking=displaymarking, msg_stanza_id=msg_stanza_id)
|
|
| 1200 | 1150 |
|
| 1201 | 1151 |
def print_conversation(self, text, contact='', tim=None, xhtml=None,
|
| 1202 |
- graphics=True, displaymarking=None, correct_id=None):
|
|
| 1152 |
+ graphics=True, displaymarking=None, correct_id=None, msg_stanza_id=None):
|
|
| 1203 | 1153 |
"""
|
| 1204 | 1154 |
Print a line in the conversation
|
| 1205 | 1155 |
|
| ... | ... | @@ -1261,7 +1211,7 @@ class GroupchatControl(ChatControlBase): |
| 1261 | 1211 |
ChatControlBase.print_conversation_line(self, text, kind, contact, tim,
|
| 1262 | 1212 |
other_tags_for_name, [], other_tags_for_text, xhtml=xhtml,
|
| 1263 | 1213 |
graphics=graphics, displaymarking=displaymarking,
|
| 1264 |
- correct_id=correct_id)
|
|
| 1214 |
+ correct_id=correct_id, msg_stanza_id=msg_stanza_id)
|
|
| 1265 | 1215 |
|
| 1266 | 1216 |
def get_nb_unread(self):
|
| 1267 | 1217 |
type_events = ['printed_marked_gc_msg']
|
| ... | ... | @@ -1422,8 +1372,8 @@ class GroupchatControl(ChatControlBase): |
| 1422 | 1372 |
# print if a control is open
|
| 1423 | 1373 |
obj.session.control.print_conversation(obj.msgtxt,
|
| 1424 | 1374 |
tim=obj.timestamp, xhtml=obj.xhtml, encrypted=obj.encrypted,
|
| 1425 |
- displaymarking=obj.displaymarking, correct_id=(obj.id_,
|
|
| 1426 |
- obj.correct_id))
|
|
| 1375 |
+ displaymarking=obj.displaymarking, msg_stanza_id=obj.id_,
|
|
| 1376 |
+ correct_id=obj.correct_id)
|
|
| 1427 | 1377 |
else:
|
| 1428 | 1378 |
# otherwise pass it off to the control to be queued
|
| 1429 | 1379 |
self.on_private_message(nick, obj.msgtxt, obj.timestamp,
|
| ... | ... | @@ -1858,7 +1858,7 @@ class RosterWindow: |
| 1858 | 1858 |
# with them
|
| 1859 | 1859 |
session = gajim.connections[account].make_new_session(jid)
|
| 1860 | 1860 |
|
| 1861 |
- tim = time.localtime(float(result[2]))
|
|
| 1861 |
+ tim = float(result[2])
|
|
| 1862 | 1862 |
session.roster_message(jid, result[1], tim, msg_type='chat',
|
| 1863 | 1863 |
msg_log_id=result[0], additional_data=additional_data)
|
| 1864 | 1864 |
gajim.logger.set_shown_unread_msgs(result[0])
|
| ... | ... | @@ -2744,7 +2744,7 @@ class RosterWindow: |
| 2744 | 2744 |
obj.session.control.print_conversation(obj.msgtxt, typ,
|
| 2745 | 2745 |
tim=obj.timestamp, encrypted=obj.encrypted, subject=obj.subject,
|
| 2746 | 2746 |
xhtml=obj.xhtml, displaymarking=obj.displaymarking,
|
| 2747 |
- msg_log_id=obj.msg_log_id, correct_id=(obj.id_, obj.correct_id),
|
|
| 2747 |
+ msg_log_id=obj.msg_log_id, msg_stanza_id=obj.id_, correct_id=obj.correct_id,
|
|
| 2748 | 2748 |
xep0184_id=xep0184_id)
|
| 2749 | 2749 |
if obj.msg_log_id:
|
| 2750 | 2750 |
pw = obj.session.control.parent_win
|