| ... |
... |
@@ -45,7 +45,6 @@ from gajim.common.fuzzyclock import FuzzyClock |
|
45
|
45
|
from gajim.common.const import StyleAttr, Trust
|
|
46
|
46
|
|
|
47
|
47
|
from gajim.gtk import util
|
|
48
|
|
-from gajim.gtk.util import load_icon
|
|
49
|
48
|
from gajim.gtk.util import get_cursor
|
|
50
|
49
|
from gajim.gtk.util import format_fingerprint
|
|
51
|
50
|
from gajim.gtk.util import text_to_color
|
| ... |
... |
@@ -185,7 +184,7 @@ class ConversationTextview(GObject.GObject): |
|
185
|
184
|
GObject.GObject.__init__(self)
|
|
186
|
185
|
self.used_in_history_window = used_in_history_window
|
|
187
|
186
|
self.line = 0
|
|
188
|
|
- self.message_list = []
|
|
|
187
|
+ self._message_list = []
|
|
189
|
188
|
self.corrected_text_list = {}
|
|
190
|
189
|
self.fc = FuzzyClock()
|
|
191
|
190
|
|
| ... |
... |
@@ -204,7 +203,6 @@ class ConversationTextview(GObject.GObject): |
|
204
|
203
|
self._buffer = self.tv.get_buffer()
|
|
205
|
204
|
self.handlers = {}
|
|
206
|
205
|
self.image_cache = {}
|
|
207
|
|
- self.xep0184_marks = {}
|
|
208
|
206
|
# self.last_sent_message_id = message_id
|
|
209
|
207
|
self.last_sent_message_id = None
|
|
210
|
208
|
# last_received_message_id[name] = (message_id, line_start_mark)
|
| ... |
... |
@@ -298,9 +296,6 @@ class ConversationTextview(GObject.GObject): |
|
298
|
296
|
buffer_.create_tag('focus-out-line', justification=Gtk.Justification.CENTER)
|
|
299
|
297
|
self.displaymarking_tags = {}
|
|
300
|
298
|
|
|
301
|
|
- tag = buffer_.create_tag('xep0184-received')
|
|
302
|
|
- tag.set_property('foreground', '#73d216')
|
|
303
|
|
-
|
|
304
|
299
|
# One mark at the begining then 2 marks between each lines
|
|
305
|
300
|
size = app.config.get('max_conversation_lines')
|
|
306
|
301
|
size = 2 * size - 1
|
| ... |
... |
@@ -339,12 +334,7 @@ class ConversationTextview(GObject.GObject): |
|
339
|
334
|
window.set_cursor(get_cursor('pointer'))
|
|
340
|
335
|
self._cursor_changed = True
|
|
341
|
336
|
return False
|
|
342
|
|
- try:
|
|
343
|
|
- text = self.corrected_text_list[tag_name]
|
|
344
|
|
- tooltip.set_markup(text)
|
|
345
|
|
- return True
|
|
346
|
|
- except KeyError:
|
|
347
|
|
- pass
|
|
|
337
|
+
|
|
348
|
338
|
if self._cursor_changed:
|
|
349
|
339
|
window.set_cursor(get_cursor('text'))
|
|
350
|
340
|
self._cursor_changed = False
|
| ... |
... |
@@ -411,30 +401,11 @@ class ConversationTextview(GObject.GObject): |
|
411
|
401
|
|
|
412
|
402
|
return index, end_mark, old_txt
|
|
413
|
403
|
|
|
414
|
|
- def add_xep0184_mark(self, id_):
|
|
415
|
|
- if id_ in self.xep0184_marks:
|
|
|
404
|
+ def show_receipt_icon(self, id_):
|
|
|
405
|
+ line = self._get_message_line(id_)
|
|
|
406
|
+ if line is None:
|
|
416
|
407
|
return
|
|
417
|
|
-
|
|
418
|
|
- buffer_ = self.tv.get_buffer()
|
|
419
|
|
- buffer_.begin_user_action()
|
|
420
|
|
-
|
|
421
|
|
- self.xep0184_marks[id_] = buffer_.create_mark(
|
|
422
|
|
- None, buffer_.get_end_iter(), left_gravity=True)
|
|
423
|
|
-
|
|
424
|
|
- buffer_.end_user_action()
|
|
425
|
|
-
|
|
426
|
|
- def show_xep0184_ack(self, id_):
|
|
427
|
|
- if id_ not in self.xep0184_marks:
|
|
428
|
|
- return
|
|
429
|
|
-
|
|
430
|
|
- buffer_ = self.tv.get_buffer()
|
|
431
|
|
-
|
|
432
|
|
- if app.config.get('positive_184_ack'):
|
|
433
|
|
- begin_iter = buffer_.get_iter_at_mark(self.xep0184_marks[id_])
|
|
434
|
|
- buffer_.insert_with_tags_by_name(begin_iter, ' ✓',
|
|
435
|
|
- 'xep0184-received')
|
|
436
|
|
-
|
|
437
|
|
- del self.xep0184_marks[id_]
|
|
|
408
|
+ line.show_receipt_icon()
|
|
438
|
409
|
|
|
439
|
410
|
def show_focus_out_line(self):
|
|
440
|
411
|
if not self.allow_focus_out_line:
|
| ... |
... |
@@ -892,10 +863,10 @@ class ConversationTextview(GObject.GObject): |
|
892
|
863
|
self.just_cleared = False
|
|
893
|
864
|
|
|
894
|
865
|
def get_end_mark(self, message_id, start_mark):
|
|
895
|
|
- for index, msg in enumerate(self.message_list):
|
|
896
|
|
- if msg[2] == message_id and msg[1] == start_mark:
|
|
|
866
|
+ for index, line in enumerate(self._message_list):
|
|
|
867
|
+ if line.id == message_id and line.start_mark == start_mark:
|
|
897
|
868
|
try:
|
|
898
|
|
- end_mark = self.message_list[index + 1][1]
|
|
|
869
|
+ end_mark = self._message_list[index + 1].start_mark
|
|
899
|
870
|
end_mark_name = end_mark.get_name()
|
|
900
|
871
|
except IndexError:
|
|
901
|
872
|
# We are at the last message
|
| ... |
... |
@@ -914,7 +885,7 @@ class ConversationTextview(GObject.GObject): |
|
914
|
885
|
# message_list = [(timestamp, line_start_mark, message_id)]
|
|
915
|
886
|
# We check if this is a new Message
|
|
916
|
887
|
try:
|
|
917
|
|
- if self.message_list[-1][0] <= timestamp:
|
|
|
888
|
+ if self._message_list[-1].timestamp <= timestamp:
|
|
918
|
889
|
return None, None
|
|
919
|
890
|
except IndexError:
|
|
920
|
891
|
# We have no Messages in the TextView
|
| ... |
... |
@@ -922,13 +893,18 @@ class ConversationTextview(GObject.GObject): |
|
922
|
893
|
|
|
923
|
894
|
# Not a new Message
|
|
924
|
895
|
# Search for insertion point
|
|
925
|
|
- for index, msg in enumerate(self.message_list):
|
|
926
|
|
- if msg[0] > timestamp:
|
|
927
|
|
- return msg[1], index
|
|
|
896
|
+ for index, line in enumerate(self._message_list):
|
|
|
897
|
+ if line.timestamp > timestamp:
|
|
|
898
|
+ return line.start_mark, index
|
|
928
|
899
|
|
|
929
|
900
|
# Should not happen, but who knows
|
|
930
|
901
|
return None, None
|
|
931
|
902
|
|
|
|
903
|
+ def _get_message_line(self, id_):
|
|
|
904
|
+ for message_line in reversed(self._message_list):
|
|
|
905
|
+ if message_line.id == id_:
|
|
|
906
|
+ return message_line
|
|
|
907
|
+
|
|
932
|
908
|
def print_conversation_line(self, text, kind, name, tim,
|
|
933
|
909
|
other_tags_for_name=None, other_tags_for_time=None, other_tags_for_text=None,
|
|
934
|
910
|
subject=None, old_kind=None, xhtml=None, graphics=True,
|
| ... |
... |
@@ -1049,16 +1025,8 @@ class ConversationTextview(GObject.GObject): |
|
1049
|
1025
|
iter_ = self.print_real_text(text, text_tags, name, xhtml, graphics=graphics,
|
|
1050
|
1026
|
mark=insert_mark, additional_data=additional_data)
|
|
1051
|
1027
|
|
|
1052
|
|
- if corrected:
|
|
1053
|
|
- # Show Correction Icon
|
|
1054
|
|
- buffer_.create_tag(tag_name=message_id)
|
|
1055
|
|
- buffer_.insert(iter_, ' ')
|
|
1056
|
|
- icon = load_icon('document-edit-symbolic', self.tv, pixbuf=True)
|
|
1057
|
|
- buffer_.insert_pixbuf(
|
|
1058
|
|
- iter_, icon)
|
|
1059
|
|
- tag_start_iter = iter_.copy()
|
|
1060
|
|
- tag_start_iter.backward_chars(2)
|
|
1061
|
|
- buffer_.apply_tag_by_name(message_id, tag_start_iter, iter_)
|
|
|
1028
|
+ message_icons = MessageIcons()
|
|
|
1029
|
+ self._insert_message_icons(iter_, message_icons)
|
|
1062
|
1030
|
|
|
1063
|
1031
|
# If we inserted a Line we add a new line at the end
|
|
1064
|
1032
|
if insert_mark:
|
| ... |
... |
@@ -1070,15 +1038,21 @@ class ConversationTextview(GObject.GObject): |
|
1070
|
1038
|
new_mark = buffer_.create_mark(
|
|
1071
|
1039
|
str(self.line), temp_iter, left_gravity=False)
|
|
1072
|
1040
|
|
|
|
1041
|
+ message_line = MessageLine(message_id, tim, message_icons, new_mark)
|
|
|
1042
|
+
|
|
|
1043
|
+ if corrected:
|
|
|
1044
|
+ message_line.show_correction_icon(
|
|
|
1045
|
+ self.corrected_text_list[message_id])
|
|
|
1046
|
+
|
|
1073
|
1047
|
if index is None:
|
|
1074
|
1048
|
# New Message
|
|
1075
|
|
- self.message_list.append((tim, new_mark, message_id))
|
|
|
1049
|
+ self._message_list.append(message_line)
|
|
1076
|
1050
|
elif corrected:
|
|
1077
|
1051
|
# Replace the corrected message
|
|
1078
|
|
- self.message_list[index] = (tim, new_mark, message_id)
|
|
|
1052
|
+ self._message_list[index] = message_line
|
|
1079
|
1053
|
else:
|
|
1080
|
1054
|
# We insert the message at index
|
|
1081
|
|
- self.message_list.insert(index, (tim, new_mark, message_id))
|
|
|
1055
|
+ self._message_list.insert(index, message_line)
|
|
1082
|
1056
|
|
|
1083
|
1057
|
if kind == 'incoming':
|
|
1084
|
1058
|
self.last_received_message_id[name] = (message_id, new_mark)
|
| ... |
... |
@@ -1095,9 +1069,6 @@ class ConversationTextview(GObject.GObject): |
|
1095
|
1069
|
|
|
1096
|
1070
|
self.line += 1
|
|
1097
|
1071
|
|
|
1098
|
|
- if kind == 'outgoing' and message_id is not None:
|
|
1099
|
|
- self.add_xep0184_mark(message_id)
|
|
1100
|
|
-
|
|
1101
|
1072
|
def get_time_to_show(self, tim, direction_mark=''):
|
|
1102
|
1073
|
"""
|
|
1103
|
1074
|
Get the time, with the day before if needed and return it. It DOESN'T
|
| ... |
... |
@@ -1135,6 +1106,18 @@ class ConversationTextview(GObject.GObject): |
|
1135
|
1106
|
if text.startswith('/me ') or text.startswith('/me\n'):
|
|
1136
|
1107
|
return kind
|
|
1137
|
1108
|
|
|
|
1109
|
+ def _insert_message_icons(self, iter_, message_icons):
|
|
|
1110
|
+ temp_mark = self._buffer.create_mark(None, iter_, True)
|
|
|
1111
|
+ self._buffer.insert(iter_, ' ')
|
|
|
1112
|
+ anchor = self._buffer.create_child_anchor(iter_)
|
|
|
1113
|
+ anchor.plaintext = ''
|
|
|
1114
|
+ self._buffer.insert(iter_, ' ')
|
|
|
1115
|
+
|
|
|
1116
|
+ # Apply mark to vertically center the icon
|
|
|
1117
|
+ start = self._buffer.get_iter_at_mark(temp_mark)
|
|
|
1118
|
+ self._buffer.apply_tag_by_name('textview-icon', start, iter_)
|
|
|
1119
|
+ self.tv.add_child_at_anchor(message_icons, anchor)
|
|
|
1120
|
+
|
|
1138
|
1121
|
def print_encryption_status(self, iter_, additional_data):
|
|
1139
|
1122
|
details = self._get_encryption_details(additional_data)
|
|
1140
|
1123
|
if details is None:
|
| ... |
... |
@@ -1312,3 +1295,50 @@ class ConversationTextview(GObject.GObject): |
|
1312
|
1295
|
# detect urls formatting and if the user has it on emoticons
|
|
1313
|
1296
|
return self.detect_and_print_special_text(text, text_tags, graphics=graphics,
|
|
1314
|
1297
|
iter_=iter_, additional_data=additional_data)
|
|
|
1298
|
+
|
|
|
1299
|
+
|
|
|
1300
|
+class MessageLine:
|
|
|
1301
|
+ def __init__(self, id_, timestamp, message_icons, start_mark):
|
|
|
1302
|
+ self.id = id_
|
|
|
1303
|
+ self.timestamp = timestamp
|
|
|
1304
|
+ self.start_mark = start_mark
|
|
|
1305
|
+ self._message_icons = message_icons
|
|
|
1306
|
+
|
|
|
1307
|
+ def show_receipt_icon(self):
|
|
|
1308
|
+ self._message_icons.set_receipt_icon_visible(True)
|
|
|
1309
|
+
|
|
|
1310
|
+ def show_correction_icon(self, tooltip):
|
|
|
1311
|
+ self._message_icons.set_correction_icon_visible(True)
|
|
|
1312
|
+ self._message_icons.set_correction_tooltip(tooltip)
|
|
|
1313
|
+
|
|
|
1314
|
+
|
|
|
1315
|
+class MessageIcons(Gtk.Box):
|
|
|
1316
|
+ def __init__(self):
|
|
|
1317
|
+ Gtk.Box.__init__(self,
|
|
|
1318
|
+ orientation=Gtk.Orientation.HORIZONTAL)
|
|
|
1319
|
+
|
|
|
1320
|
+ self._correction_image = Gtk.Image.new_from_icon_name(
|
|
|
1321
|
+ 'document-edit-symbolic', Gtk.IconSize.MENU)
|
|
|
1322
|
+ self._correction_image.set_no_show_all(True)
|
|
|
1323
|
+
|
|
|
1324
|
+ self._receipt_image = Gtk.Image.new_from_icon_name(
|
|
|
1325
|
+ 'emblem-ok-symbolic', Gtk.IconSize.MENU)
|
|
|
1326
|
+ self._receipt_image.get_style_context().add_class(
|
|
|
1327
|
+ 'receipt-received-color')
|
|
|
1328
|
+ self._receipt_image.set_tooltip_text(_('Received'))
|
|
|
1329
|
+ self._receipt_image.set_no_show_all(True)
|
|
|
1330
|
+
|
|
|
1331
|
+ self.add(self._correction_image)
|
|
|
1332
|
+ self.add(self._receipt_image)
|
|
|
1333
|
+ self.show_all()
|
|
|
1334
|
+
|
|
|
1335
|
+ def set_receipt_icon_visible(self, visible):
|
|
|
1336
|
+ if not app.config.get('positive_184_ack'):
|
|
|
1337
|
+ return
|
|
|
1338
|
+ self._receipt_image.set_visible(visible)
|
|
|
1339
|
+
|
|
|
1340
|
+ def set_correction_icon_visible(self, visible):
|
|
|
1341
|
+ self._correction_image.set_visible(visible)
|
|
|
1342
|
+
|
|
|
1343
|
+ def set_correction_tooltip(self, text):
|
|
|
1344
|
+ self._correction_image.set_tooltip_markup(text)
|