Merge branch 'history-highlighting' into 'master'

Highlight all paragraphs of a message in the history window

See merge request !46
This commit is contained in:
Philipp Hörist 2017-03-03 23:45:06 +01:00
commit 1b975172d6
3 changed files with 72 additions and 73 deletions

View File

@ -628,7 +628,7 @@ class Logger:
def get_conversation_for_date(self, jid, year, month, day, account): def get_conversation_for_date(self, jid, year, month, day, account):
""" """
Return contact_name, time, kind, show, message, subject Return contact_name, time, kind, show, message, subject, additional_data, log_line_id
For each row in a list of tupples, returns list with empty tupple if we For each row in a list of tupples, returns list with empty tupple if we
found nothing to meet our demands found nothing to meet our demands
@ -645,7 +645,9 @@ class Logger:
last_second_of_day = start_of_day + seconds_in_a_day - 1 last_second_of_day = start_of_day + seconds_in_a_day - 1
self.cur.execute(''' self.cur.execute('''
SELECT contact_name, time, kind, show, message, subject, additional_data FROM logs SELECT contact_name, time, kind, show, message, subject,
additional_data, log_line_id
FROM logs
WHERE (%s) WHERE (%s)
AND time BETWEEN %d AND %d AND time BETWEEN %d AND %d
ORDER BY time ORDER BY time
@ -660,7 +662,7 @@ class Logger:
def get_search_results_for_query(self, jid, query, account, year=False, def get_search_results_for_query(self, jid, query, account, year=False,
month=False, day=False): month=False, day=False):
""" """
Returns contact_name, time, kind, show, message Returns contact_name, time, kind, show, message, subject, log_line_id
For each row in a list of tupples, returns list with empty tupple if we For each row in a list of tupples, returns list with empty tupple if we
found nothing to meet our demands found nothing to meet our demands
@ -671,33 +673,25 @@ class Logger:
# Error trying to create a new jid_id. This means there is no log # Error trying to create a new jid_id. This means there is no log
return [] return []
if False: # query.startswith('SELECT '): # it's SQL query (FIXME) where_sql, jid_tuple = self._build_contact_where(account, jid)
try: like_sql = '%' + query.replace("'", "''") + '%'
self.cur.execute(query) if year:
except sqlite.OperationalError as e: start_of_day = self.get_unix_time_from_date(year, month, day)
results = [('', '', '', '', str(e))] seconds_in_a_day = 86400 # 60 * 60 * 24
return results last_second_of_day = start_of_day + seconds_in_a_day - 1
self.cur.execute('''
else: # user just typed something, we search in message column SELECT contact_name, time, kind, show, message, subject, log_line_id FROM logs
where_sql, jid_tuple = self._build_contact_where(account, jid) WHERE (%s) AND message LIKE '%s'
like_sql = '%' + query.replace("'", "''") + '%' AND time BETWEEN %d AND %d
if year: ORDER BY time
start_of_day = self.get_unix_time_from_date(year, month, day) ''' % (where_sql, like_sql, start_of_day, last_second_of_day),
seconds_in_a_day = 86400 # 60 * 60 * 24 jid_tuple)
last_second_of_day = start_of_day + seconds_in_a_day - 1 else:
self.cur.execute(''' self.cur.execute('''
SELECT contact_name, time, kind, show, message, subject FROM logs SELECT contact_name, time, kind, show, message, subject, log_line_id FROM logs
WHERE (%s) AND message LIKE '%s' WHERE (%s) AND message LIKE '%s'
AND time BETWEEN %d AND %d ORDER BY time
ORDER BY time ''' % (where_sql, like_sql), jid_tuple)
''' % (where_sql, like_sql, start_of_day, last_second_of_day),
jid_tuple)
else:
self.cur.execute('''
SELECT contact_name, time, kind, show, message, subject FROM logs
WHERE (%s) AND message LIKE '%s'
ORDER BY time
''' % (where_sql, like_sql), jid_tuple)
results = self.cur.fetchall() results = self.cur.fetchall()
return results return results

View File

@ -56,6 +56,7 @@ class Column(IntEnum):
UNIXTIME = 2 UNIXTIME = 2
MESSAGE = 3 MESSAGE = 3
TIME = 4 TIME = 4
LOG_LINE_ID = 5
class HistoryWindow: class HistoryWindow:
""" """
@ -85,8 +86,8 @@ class HistoryWindow:
self.results_window = xml.get_object('results_scrolledwindow') self.results_window = xml.get_object('results_scrolledwindow')
self.search_in_date = xml.get_object('search_in_date') self.search_in_date = xml.get_object('search_in_date')
# contact_name, date, message, time # jid, contact_name, date, message, time, log_line_id
model = Gtk.ListStore(str, str, str, str, str) model = Gtk.ListStore(str, str, str, str, str, int)
self.results_treeview.set_model(model) self.results_treeview.set_model(model)
col = Gtk.TreeViewColumn(_('Name')) col = Gtk.TreeViewColumn(_('Name'))
self.results_treeview.append_column(col) self.results_treeview.append_column(col)
@ -393,28 +394,31 @@ class HistoryWindow:
show_status = self.show_status_checkbutton.get_active() show_status = self.show_status_checkbutton.get_active()
lines = gajim.logger.get_conversation_for_date(self.jid, year, month, day, self.account) lines = gajim.logger.get_conversation_for_date(self.jid, year, month, day, self.account)
# lines holds list with tupples that have:
# contact_name, time, kind, show, message
for line in lines: for line in lines:
# line[0] is contact_name, line[1] is time of message # line[0] is contact_name, line[1] is time of message
# line[2] is kind, line[3] is show, line[4] is message, line[5] is subject # line[2] is kind, line[3] is show, line[4] is message, line[5] is subject
# line[6] is additional_data # line[6] is additional_data, line[7] is log_line_id
if not show_status and line[2] in (KindConstant.GCSTATUS, if not show_status and line[2] in (KindConstant.GCSTATUS,
KindConstant.STATUS): KindConstant.STATUS):
continue continue
self._add_new_line(line[0], line[1], line[2], line[3], line[4], self._add_new_line(line[0], line[1], line[2], line[3], line[4],
line[5], line[6]) line[5], line[6], line[7])
def _add_new_line(self, contact_name, tim, kind, show, message, subject, additional_data): def _add_new_line(self, contact_name, tim, kind, show, message, subject,
additional_data, log_line_id):
""" """
Add a new line in textbuffer Add a new line in textbuffer
""" """
if not message and kind not in (KindConstant.STATUS, if not message and kind not in (KindConstant.STATUS,
KindConstant.GCSTATUS): KindConstant.GCSTATUS):
return return
buf = self.history_buffer buf = self.history_buffer
end_iter = buf.get_end_iter() end_iter = buf.get_end_iter()
# Make the beginning of every message searchable by its log_line_id
buf.create_mark(str(log_line_id), end_iter, left_gravity=True)
if gajim.config.get('print_time') == 'always': if gajim.config.get('print_time') == 'always':
timestamp_str = gajim.config.get('time_stamp') timestamp_str = gajim.config.get('time_stamp')
timestamp_str = helpers.from_one_line(timestamp_str) timestamp_str = helpers.from_one_line(timestamp_str)
@ -429,12 +433,6 @@ class HistoryWindow:
tim = time.strftime('%X ', time.localtime(float(tim))) tim = time.strftime('%X ', time.localtime(float(tim)))
buf.insert_with_tags_by_name(end_iter, tim + '\n', buf.insert_with_tags_by_name(end_iter, tim + '\n',
'time_sometimes') 'time_sometimes')
else: # don't print time. So we print it as invisible to be able to
# search for it
timestamp_str = gajim.config.get('time_stamp')
timestamp_str = helpers.from_one_line(timestamp_str)
tim = time.strftime(timestamp_str, time.localtime(float(tim)))
buf.insert_with_tags_by_name(end_iter, tim, 'invisible')
tag_name = '' tag_name = ''
tag_msg = '' tag_msg = ''
@ -512,9 +510,7 @@ class HistoryWindow:
else: else:
self.history_textview.print_real_text(message, name=contact_name, self.history_textview.print_real_text(message, name=contact_name,
xhtml=xhtml, additional_data=additional_data) xhtml=xhtml, additional_data=additional_data)
buffer_ = self.history_textview.tv.get_buffer() self.history_textview.print_real_text('\n', text_tags=['eol'])
eob = buffer_.get_end_iter()
buffer_.insert_with_tags_by_name(eob, '\n', 'eol')
def on_search_entry_activate(self, widget): def on_search_entry_activate(self, widget):
text = self.search_entry.get_text() text = self.search_entry.get_text()
@ -563,12 +559,13 @@ class HistoryWindow:
contact_name = self.completion_dict[jid][InfoColumn.NAME] contact_name = self.completion_dict[jid][InfoColumn.NAME]
tim = row[1] tim = row[1]
message = row[4] message = row[4]
log_line_id = row[6]
local_time = time.localtime(tim) local_time = time.localtime(tim)
date = time.strftime('%Y-%m-%d', local_time) date = time.strftime('%Y-%m-%d', local_time)
# jid (to which log is assigned to), name, date, message, # jid (to which log is assigned to), name, date, message,
# time (full unix time) # time (full unix time)
model.append((jid, contact_name, date, message, str(tim))) model.append((jid, contact_name, date, message, str(tim), log_line_id))
def on_results_treeview_row_activated(self, widget, path, column): def on_results_treeview_row_activated(self, widget, path, column):
""" """
@ -576,7 +573,7 @@ class HistoryWindow:
which results to showing conversation logs for that date which results to showing conversation logs for that date
""" """
# get currently selected date # get currently selected date
cur_year, cur_month = self.calendar.get_date()[0:2] cur_year, cur_month, cur_day = self.calendar.get_date()
cur_month = gtkgui_helpers.make_gtk_month_python_month(cur_month) cur_month = gtkgui_helpers.make_gtk_month_python_month(cur_month)
model = widget.get_model() model = widget.get_model()
# make it a tupple (Y, M, D, 0, 0, 0...) # make it a tupple (Y, M, D, 0, 0, 0...)
@ -595,33 +592,41 @@ class HistoryWindow:
if year != cur_year or gtk_month != cur_month: if year != cur_year or gtk_month != cur_month:
self.calendar.select_month(month, year) self.calendar.select_month(month, year)
self.calendar.select_day(day) if year != cur_year or gtk_month != cur_month or day != cur_day:
unix_time = model[path][Column.TIME] self.calendar.select_day(day)
self._scroll_to_result(unix_time)
#FIXME: one day do not search just for unix_time but the whole and user
# specific format of the textbuffer line [time] nick: message
# and highlight all that
def _scroll_to_result(self, unix_time): self._scroll_to_message_and_highlight(model[path][Column.LOG_LINE_ID])
def _scroll_to_message_and_highlight(self, log_line_id):
""" """
Scroll to the result using unix_time and highlight line Scroll to a message and highlight it
""" """
start_iter = self.history_buffer.get_start_iter()
local_time = time.localtime(float(unix_time)) def iterator_has_mark(iterator, mark_name):
timestamp_str = gajim.config.get('time_stamp') for mark in iterator.get_marks():
timestamp_str = helpers.from_one_line(timestamp_str) if mark.get_name() == mark_name:
tim = time.strftime(timestamp_str, local_time) return True
result = start_iter.forward_search(tim, Gtk.TextSearchFlags.TEXT_ONLY, return False
None)
if result is not None: # Clear previous search result by removing the highlighting. The scroll
match_start_iter, match_end_iter = result # mark is automatically removed when the new one is set.
match_start_iter.backward_char() # include '[' or other character before time start = self.history_buffer.get_start_iter()
match_end_iter.forward_line() # highlight all message not just time end = self.history_buffer.get_end_iter()
self.history_buffer.apply_tag_by_name('highlight', match_start_iter, self.history_buffer.remove_tag_by_name('highlight', start, end)
match_end_iter)
mark = self.history_buffer.create_mark('match', match_start_iter, True) log_line_id = str(log_line_id)
GLib.idle_add(self.history_textview.tv.scroll_to_mark, mark, line = start
0, True, 0.0, 0.5) while not iterator_has_mark(line, log_line_id):
if not line.forward_line():
return
match_start = line
match_end = match_start.copy()
match_end.forward_to_tag_toggle(self.history_buffer.eol_tag)
self.history_buffer.apply_tag_by_name('highlight', match_start, match_end)
mark = self.history_buffer.create_mark('match', match_start, True)
GLib.idle_add(self.history_textview.tv.scroll_to_mark, mark, 0, True, 0.0, 0.5)
def on_log_history_checkbutton_toggled(self, widget): def on_log_history_checkbutton_toggled(self, widget):
# log conversation history? # log conversation history?

View File

@ -850,7 +850,7 @@ class HtmlTextView(Gtk.TextView):
self.connect('copy-clipboard', self.on_html_text_view_copy_clipboard) self.connect('copy-clipboard', self.on_html_text_view_copy_clipboard)
self.id_ = self.connect('button-release-event', self.id_ = self.connect('button-release-event',
self.on_left_mouse_button_release) self.on_left_mouse_button_release)
self.get_buffer().create_tag('eol') self.get_buffer().eol_tag = self.get_buffer().create_tag('eol')
self.tooltip = tooltips.BaseTooltip() self.tooltip = tooltips.BaseTooltip()
self.config = gajim.config self.config = gajim.config
self.interface = gajim.interface self.interface = gajim.interface