From ca31a7f67a0d1e6a96b00ec4c8760b405c3107de Mon Sep 17 00:00:00 2001 From: Nikos Kouremenos Date: Sun, 20 Nov 2005 21:58:08 +0000 Subject: [PATCH] history window now has a calendar; tons of cleanups, comments, better varnames and in general better quality of code; also a fixme for another day --- src/common/logger.py | 89 +++++++++-- src/gtkgui.glade | 305 +------------------------------------- src/gtkgui_helpers.py | 6 + src/history_window.py | 144 +++++------------- src/tabbed_chat_window.py | 25 ++-- 5 files changed, 137 insertions(+), 432 deletions(-) diff --git a/src/common/logger.py b/src/common/logger.py index 839e14123..417abfa1f 100644 --- a/src/common/logger.py +++ b/src/common/logger.py @@ -129,31 +129,90 @@ class Logger: path_to_file = self.__get_path_to_file(fjid) if not os.path.isfile(path_to_file): return 0 - fil = open(path_to_file, 'r') - no_of_lines = 0 # number of lines - while fil.readline(): - no_of_lines += 1 - fil.close() - return no_of_lines + f = open(path_to_file, 'r') + return len(f.readlines()) # number of lines - def read(self, fjid, begin_line, end_line): - '''returns number of lines read and the text in the lines - returns 0 and empty string respectively if log file does not exist''' + # FIXME: remove me when refactor in TC is done + def read_from_line_to_line(self, fjid, begin_from_line, end_line): + '''returns the text in the lines (list), + returns empty list if log file does not exist''' fjid = fjid.lower() path_to_file = self.__get_path_to_file(fjid) if not os.path.isfile(path_to_file): - return 0, [] - fil = open(path_to_file, 'r') - no_of_lines = 0 # number of lines + return [] + lines = [] - while (no_of_lines < begin_line and fil.readline()): + + fil = open(path_to_file, 'r') + #fil.readlines(begin_from_line) # skip the previous lines + no_of_lines = begin_from_line # number of lines between being and end + while (no_of_lines < begin_from_line and fil.readline()): no_of_lines += 1 + + print begin_from_line, end_line while no_of_lines < end_line: line = fil.readline().decode('utf-8') + print `line`, '@', no_of_lines if line: line = helpers.from_one_line(line) lineSplited = line.split(':') if len(lineSplited) > 2: lines.append(lineSplited) - no_of_lines += 1 - return no_of_lines, lines + no_of_lines += 1 + else: # emplty line (we are at the end of file) + break + return lines + + def get_last_conversation_lines(self, jid, how_many_lines, timeout): + '''accepts how many lines to restore and when to time them out + (mark them as too old), returns the lines (list), empty list if log file + does not exist''' + fjid = fjid.lower() + path_to_file = self.__get_path_to_file(fjid) + if not os.path.isfile(path_to_file): + return [] + + + def get_conversation_for_date(self, fjid, year, month, day): + '''returns the text in the lines (list), + returns empty list if log file does not exist''' + fjid = fjid.lower() + path_to_file = self.__get_path_to_file(fjid) + if not os.path.isfile(path_to_file): + return [] + + lines = [] + f = open(path_to_file, 'r') + done = False + found_first_line_that_matches = False + while not done: + line = f.readline().decode('utf-8') + if line: + line = helpers.from_one_line(line) + splitted_line = line.split(':') + if len(splitted_line) > 2: + if splitted_line: + # line[0] is date, line[1] is type of message + # line[2:] is message + date = splitted_line[0] + # eg. 2005 + line_year = int(time.strftime('%Y', time.localtime(float(date)))) + # (01 - 12) + line_month = int(time.strftime('%m', time.localtime(float(date)))) + # (01 - 31) + line_day = int(time.strftime('%d', time.localtime(float(date)))) + + # now check if that line is one of the lines we want + # (if it is in the date we want) + if line_year == year and line_month == month and line_day == day: + if found_first_line_that_matches is False: + found_first_line_that_matches = True + lines.append(splitted_line) + else: + if found_first_line_that_matches: + done = True + + else: + done = True + + return lines diff --git a/src/gtkgui.glade b/src/gtkgui.glade index 7c7c24014..d7fddad5c 100644 --- a/src/gtkgui.glade +++ b/src/gtkgui.glade @@ -9082,10 +9082,11 @@ Custom 150 - + True True GTK_CALENDAR_SHOW_HEADING|GTK_CALENDAR_SHOW_DAY_NAMES + True @@ -9139,307 +9140,7 @@ Custom True GTK_BUTTONBOX_END - 6 - - - - True - True - True - GTK_RELIEF_NORMAL - True - - - - - True - 0.5 - 0.5 - 0 - 0 - 0 - 0 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-goto-first - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - REMOVEME - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - - - - - - - True - True - True - GTK_RELIEF_NORMAL - True - - - - - True - 0.5 - 0.5 - 0 - 0 - 0 - 0 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-go-back - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - REMOVEME - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - - - - - - - True - True - True - GTK_RELIEF_NORMAL - True - - - - - True - 0.5 - 0.5 - 0 - 0 - 0 - 0 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-media-forward - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - REMOVEME - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - - - - - - - True - True - True - GTK_RELIEF_NORMAL - True - - - - - True - 0.5 - 0.5 - 0 - 0 - 0 - 0 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-goto-last - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - REMOVEME - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - - - + 0 diff --git a/src/gtkgui_helpers.py b/src/gtkgui_helpers.py index b6e3bd520..0f03f3715 100644 --- a/src/gtkgui_helpers.py +++ b/src/gtkgui_helpers.py @@ -436,3 +436,9 @@ def get_avatar_pixbuf_from_cache(jid): return None pixbuf = vcard.get_avatar_pixbuf_encoded_mime(vcard_dict['PHOTO'])[0] return pixbuf + +def make_gtk_month_python_month(month): + '''gtk start counting months from 0, so January is 0 + but python's time start from 1, so align to python + month MUST be integer''' + return month + 1 diff --git a/src/history_window.py b/src/history_window.py index f6d1d6987..fa9559a87 100644 --- a/src/history_window.py +++ b/src/history_window.py @@ -22,7 +22,7 @@ import gtk.glade import time import os -import dialogs +import gtkgui_helpers from common import gajim from common import helpers @@ -41,7 +41,6 @@ class HistoryWindow: def __init__(self, jid, account): self.jid = jid self.account = account - self.no_of_lines = gajim.logger.get_no_of_lines(jid) xml = gtk.glade.XML(GTKGUI_GLADE, 'history_window', APP) self.window = xml.get_widget('history_window') if account and gajim.contacts[account].has_key(jid): @@ -51,10 +50,6 @@ class HistoryWindow: title = _('Conversation History with %s') % jid self.window.set_title(title) self.history_buffer = xml.get_widget('history_textview').get_buffer() - self.earliest_button = xml.get_widget('earliest_button') - self.previous_button = xml.get_widget('previous_button') - self.forward_button = xml.get_widget('forward_button') - self.latest_button = xml.get_widget('latest_button') xml.signal_autoconnect(self) @@ -70,17 +65,10 @@ class HistoryWindow: color = gajim.config.get('statusmsgcolor') tag.set_property('foreground', color) - begin = 0 - #FIXME: 50 is very bad. find a way to always fill size of window - #or come up with something better in general. - #investigate how other clients do this window - if self.no_of_lines > 50: - begin = self.no_of_lines - 50 - nb, lines = gajim.logger.read(self.jid, begin, self.no_of_lines) - self.set_buttons_sensitivity(nb) - for line in lines: - self.new_line(line[0], line[1], line[2:]) - self.num_begin = begin + date = time.localtime() + y, m, d = date[0], date[1], date[2] + self.add_lines_for_date(y, m, d) + self.window.show_all() def on_history_window_destroy(self, widget): @@ -89,90 +77,27 @@ class HistoryWindow: def on_close_button_clicked(self, widget): self.window.destroy() - def on_earliest_button_clicked(self, widget): - start, end = self.history_buffer.get_bounds() - self.history_buffer.delete(start, end) - self.earliest_button.set_sensitive(False) - self.previous_button.set_sensitive(False) - self.forward_button.set_sensitive(True) - self.latest_button.set_sensitive(True) - end = 50 - if end > self.no_of_lines: - end = self.no_of_lines - nb, lines = gajim.logger.read(self.jid, 0, end) - self.set_buttons_sensitivity(nb) + def on_calendar_day_selected(self, widget): + year, month, day = widget.get_date() # integers + month = gtkgui_helpers.make_gtk_month_python_month(month) + self.add_lines_for_date(year, month, day) + + def add_lines_for_date(self, year, month, day): + '''adds all the lines for given date in textbuffer''' + self.history_buffer.set_text('') # clear the buffer first + lines = gajim.logger.get_conversation_for_date(self.jid, year, month, day) for line in lines: - self.new_line(line[0], line[1], line[2:]) - self.num_begin = 0 - - def on_previous_button_clicked(self, widget): - start, end = self.history_buffer.get_bounds() - self.history_buffer.delete(start, end) - self.earliest_button.set_sensitive(True) - self.previous_button.set_sensitive(True) - self.forward_button.set_sensitive(True) - self.latest_button.set_sensitive(True) - begin = self.num_begin - 50 - if begin < 0: - begin = 0 - end = begin + 50 - if end > self.no_of_lines: - end = self.no_of_lines - nb, lines = gajim.logger.read(self.jid, begin, end) - self.set_buttons_sensitivity(nb) - for line in lines: - self.new_line(line[0], line[1], line[2:]) - self.num_begin = begin - - def on_forward_button_clicked(self, widget): - start, end = self.history_buffer.get_bounds() - self.history_buffer.delete(start, end) - self.earliest_button.set_sensitive(True) - self.previous_button.set_sensitive(True) - self.forward_button.set_sensitive(True) - self.latest_button.set_sensitive(True) - begin = self.num_begin + 50 - if begin > self.no_of_lines: - begin = self.no_of_lines - end = begin + 50 - if end > self.no_of_lines: - end = self.no_of_lines - nb, lines = gajim.logger.read(self.jid, begin, end) - self.set_buttons_sensitivity(nb) - for line in lines: - self.new_line(line[0], line[1], line[2:]) - self.num_begin = begin - - def on_latest_button_clicked(self, widget): - start, end = self.history_buffer.get_bounds() - self.history_buffer.delete(start, end) - self.earliest_button.set_sensitive(True) - self.previous_button.set_sensitive(True) - self.forward_button.set_sensitive(False) - self.latest_button.set_sensitive(False) - begin = self.no_of_lines - 50 - if begin < 0: - begin = 0 - nb, lines = gajim.logger.read(self.jid, begin, self.no_of_lines) - self.set_buttons_sensitivity(nb) - for line in lines: - self.new_line(line[0], line[1], line[2:]) - self.num_begin = begin - - def set_buttons_sensitivity(self, nb): - if nb == 50: - self.earliest_button.set_sensitive(False) - self.previous_button.set_sensitive(False) - if nb == self.no_of_lines: - self.forward_button.set_sensitive(False) - self.latest_button.set_sensitive(False) - - def new_line(self, date, type, data): + # line[0] is date, line[1] is type of message + # line[2:] is message + date = line[0] + self.add_new_line(date, line[1], line[2:]) + + def add_new_line(self, date, type, data): '''add a new line in textbuffer''' - buff = self.history_buffer - end_iter = buff.get_end_iter() - tim = time.strftime('[%x %X] ', time.localtime(float(date))) - buff.insert(end_iter, tim) + buf = self.history_buffer + end_iter = buf.get_end_iter() + tim = time.strftime('[%X] ', time.localtime(float(date))) + buf.insert(end_iter, tim) name = None tag_name = '' tag_msg = '' @@ -184,7 +109,12 @@ class HistoryWindow: nick = data[0] show = data[1] status_msg = ':'.join(data[2:]) - msg = _('%s is now %s: %s') % (nick, show, status_msg) + if status_msg: + msg = _('%(nick)s is now %(status)s: %(status_msg)s') % {'nick': nick, + 'status': show, 'status_msg': status_msg } + else: + msg = _('%(nick)s is now %(status)s') % {'nick': nick, + 'status': show } tag_msg = 'status' elif type == 'recv': try: @@ -199,17 +129,21 @@ class HistoryWindow: name = gajim.nicks[self.account] msg = ':'.join(data[0:]) tag_name = 'outgoing' - else: + else: # status status_msg = ':'.join(data[1:]) - msg = _('Status is now: %s: %s') % (data[0], status_msg) + if status_msg: + msg = _('Status is now: %(status)s: %(status_msg)s') % \ + {'status': data[0], 'status_msg': status_msg} + else: + msg = _('Status is now: %(status)s') % { 'status': data[0] } tag_msg = 'status' if name: before_str = gajim.config.get('before_nickname') after_str = gajim.config.get('after_nickname') format = before_str + name + after_str + ' ' - buff.insert_with_tags_by_name(end_iter, format, tag_name) + buf.insert_with_tags_by_name(end_iter, format, tag_name) if tag_msg: - buff.insert_with_tags_by_name(end_iter, msg, tag_msg) + buf.insert_with_tags_by_name(end_iter, msg, tag_msg) else: - buff.insert(end_iter, msg) + buf.insert(end_iter, msg) diff --git a/src/tabbed_chat_window.py b/src/tabbed_chat_window.py index bc6372187..a3f7d4c8f 100644 --- a/src/tabbed_chat_window.py +++ b/src/tabbed_chat_window.py @@ -890,12 +890,16 @@ class TabbedChatWindow(chat.Chat): # don't restore lines if it's a transport if gajim.jid_is_transport(jid): return + + return # FIXME: clean up logic, make most of it a func for logger.py + # see get_last_conversation_lines + # good to review to avoid dup last line (still happens) # How many lines to restore and when to time them out restore = gajim.config.get('restore_lines') - time_out = gajim.config.get('restore_timeout') + timeout = gajim.config.get('restore_timeout') # in minutes pos = 0 # position, while reading from history - size = 0 # how many lines we alreay retreived + size = 0 # how many lines we already retreived lines = [] # we'll need to reverse the lines from history count = gajim.logger.get_no_of_lines(jid) @@ -910,17 +914,17 @@ class TabbedChatWindow(chat.Chat): now = time.time() while size <= restore: if pos == count or size > restore - 1: - # don't try to read beyond history, not read more than required + # don't try to read beyond history, nor read more than required break - nb, line = gajim.logger.read(jid, count - 1 - pos, count - pos) + line = gajim.logger.read_from_line_to_line(jid, count - 1 - pos, count - pos) pos = pos + 1 # line is [] if log file for jid is not a file (does not exist or dir) if line == []: break - if (now - float(line[0][0]))/60 >= time_out: + if (now - float(line[0][0])) / 60 >= time_out: # stop looking for messages if we found something too old break @@ -934,17 +938,18 @@ class TabbedChatWindow(chat.Chat): if lines != []: lines.reverse() - for msg in lines: - if msg[1] == 'sent': + print lines + for line in lines: # line[0] time, line[1] type, line[2:] the message + if line[1] == 'sent': kind = 'outgoing' name = gajim.nicks[self.account] - elif msg[1] == 'recv': + elif line[1] == 'recv': kind = 'incoming' name = self.contacts[jid].name - tim = time.localtime(float(msg[0])) + tim = time.localtime(float(line[0])) - text = ':'.join(msg[2:])[:-1] #remove the latest \n + text = ':'.join(line[2:])[:-1] #remove the latest \n self.print_conversation_line(text, jid, kind, name, tim, ['small'], ['small', 'grey'], ['small', 'grey'], False)