2005-05-12 20:52:37 +02:00
|
|
|
## history_window.py
|
2005-03-11 18:57:35 +01:00
|
|
|
##
|
|
|
|
## Gajim Team:
|
|
|
|
## - Yann Le Boulanger <asterix@lagaule.org>
|
|
|
|
## - Vincent Hanquez <tab@snarc.org>
|
|
|
|
## - Nikos Kouremenos <kourem@gmail.com>
|
|
|
|
##
|
|
|
|
## Copyright (C) 2003-2005 Gajim Team
|
|
|
|
##
|
|
|
|
## This program is free software; you can redistribute it and/or modify
|
|
|
|
## it under the terms of the GNU General Public License as published
|
|
|
|
## by the Free Software Foundation; version 2 only.
|
|
|
|
##
|
|
|
|
## This program is distributed in the hope that it will be useful,
|
|
|
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
## GNU General Public License for more details.
|
|
|
|
##
|
|
|
|
|
|
|
|
import gtk
|
|
|
|
import gtk.glade
|
2005-11-27 01:22:26 +01:00
|
|
|
import gobject
|
2005-03-11 18:57:35 +01:00
|
|
|
import time
|
2005-11-24 02:39:47 +01:00
|
|
|
import calendar
|
2005-10-31 21:55:45 +01:00
|
|
|
import os
|
|
|
|
|
2005-11-20 22:58:08 +01:00
|
|
|
import gtkgui_helpers
|
2005-03-11 18:57:35 +01:00
|
|
|
|
2005-04-14 09:05:10 +02:00
|
|
|
from common import gajim
|
2005-10-31 21:55:45 +01:00
|
|
|
from common import helpers
|
2005-03-11 18:57:35 +01:00
|
|
|
from common import i18n
|
|
|
|
|
2005-11-26 00:23:25 +01:00
|
|
|
from common.logger import Constants
|
|
|
|
|
|
|
|
constants = Constants()
|
|
|
|
|
2005-03-11 18:57:35 +01:00
|
|
|
_ = i18n._
|
|
|
|
APP = i18n.APP
|
|
|
|
gtk.glade.bindtextdomain(APP, i18n.DIR)
|
|
|
|
gtk.glade.textdomain(APP)
|
|
|
|
|
2005-04-22 01:20:18 +02:00
|
|
|
GTKGUI_GLADE = 'gtkgui.glade'
|
2005-03-11 18:57:35 +01:00
|
|
|
|
2005-11-29 15:41:01 +01:00
|
|
|
# contact_name, time, kind, show, message
|
|
|
|
(
|
|
|
|
C_CONTACT_NAME,
|
|
|
|
C_TIME,
|
|
|
|
C_KIND,
|
|
|
|
C_SHOW,
|
|
|
|
C_MESSAGE
|
|
|
|
) = range(5)
|
|
|
|
|
2005-06-11 00:45:50 +02:00
|
|
|
class HistoryWindow:
|
2005-10-09 19:07:29 +02:00
|
|
|
'''Class for browsing logs of conversations with contacts'''
|
|
|
|
|
2005-10-20 13:17:17 +02:00
|
|
|
def __init__(self, jid, account):
|
2005-10-09 19:07:29 +02:00
|
|
|
self.jid = jid
|
|
|
|
self.account = account
|
2005-11-27 01:22:26 +01:00
|
|
|
self.mark_days_idle_call_id = None
|
|
|
|
|
2005-10-09 19:07:29 +02:00
|
|
|
xml = gtk.glade.XML(GTKGUI_GLADE, 'history_window', APP)
|
|
|
|
self.window = xml.get_widget('history_window')
|
2005-11-29 15:41:01 +01:00
|
|
|
self.query_entry = xml.get_widget('query_entry')
|
|
|
|
self.expander_vbox = xml.get_widget('expander_vbox')
|
|
|
|
self.results_treeview = xml.get_widget('results_treeview')
|
|
|
|
# contact_name, time, kind, show, message
|
|
|
|
model = gtk.ListStore(str, str, str, str, str)
|
|
|
|
self.results_treeview.set_model(model)
|
|
|
|
|
|
|
|
col = gtk.TreeViewColumn(_('Name'))
|
|
|
|
self.results_treeview.append_column(col)
|
|
|
|
renderer = gtk.CellRendererText()
|
|
|
|
col.pack_start(renderer)
|
|
|
|
col.set_attributes(renderer, text = C_CONTACT_NAME)
|
|
|
|
|
|
|
|
col = gtk.TreeViewColumn(_('Date'))
|
|
|
|
self.results_treeview.append_column(col)
|
|
|
|
renderer = gtk.CellRendererText()
|
|
|
|
col.pack_start(renderer)
|
|
|
|
col.set_attributes(renderer, text = C_TIME)
|
|
|
|
|
|
|
|
col = gtk.TreeViewColumn(_('Kind'))
|
|
|
|
self.results_treeview.append_column(col)
|
|
|
|
renderer = gtk.CellRendererText()
|
|
|
|
col.pack_start(renderer)
|
|
|
|
col.set_attributes(renderer, text = C_KIND)
|
|
|
|
|
|
|
|
col = gtk.TreeViewColumn(_('Status'))
|
|
|
|
self.results_treeview.append_column(col)
|
|
|
|
renderer = gtk.CellRendererText()
|
|
|
|
col.pack_start(renderer)
|
|
|
|
col.set_attributes(renderer, text = C_SHOW)
|
|
|
|
|
|
|
|
col = gtk.TreeViewColumn(_('Message'))
|
|
|
|
self.results_treeview.append_column(col)
|
|
|
|
renderer = gtk.CellRendererText()
|
|
|
|
col.pack_start(renderer)
|
|
|
|
col.set_attributes(renderer, text = C_MESSAGE)
|
2005-11-27 01:22:26 +01:00
|
|
|
|
2005-10-09 19:07:29 +02:00
|
|
|
if account and gajim.contacts[account].has_key(jid):
|
|
|
|
contact = gajim.get_first_contact_instance_from_jid(account, jid)
|
|
|
|
title = _('Conversation History with %s') % contact.name
|
|
|
|
else:
|
|
|
|
title = _('Conversation History with %s') % jid
|
|
|
|
self.window.set_title(title)
|
|
|
|
self.history_buffer = xml.get_widget('history_textview').get_buffer()
|
2005-10-31 22:28:39 +01:00
|
|
|
|
2005-10-09 19:07:29 +02:00
|
|
|
xml.signal_autoconnect(self)
|
2005-11-27 01:22:26 +01:00
|
|
|
|
|
|
|
calendar = xml.get_widget('calendar')
|
2005-11-27 01:24:46 +01:00
|
|
|
# fake event so we start mark days procedure for selected month
|
|
|
|
# selected month is current month as calendar defaults to selecting
|
|
|
|
# current date
|
|
|
|
calendar.emit('month-changed')
|
2005-11-27 01:22:26 +01:00
|
|
|
|
2005-10-09 19:07:29 +02:00
|
|
|
|
|
|
|
tag = self.history_buffer.create_tag('incoming')
|
|
|
|
color = gajim.config.get('inmsgcolor')
|
|
|
|
tag.set_property('foreground', color)
|
|
|
|
|
|
|
|
tag = self.history_buffer.create_tag('outgoing')
|
|
|
|
color = gajim.config.get('outmsgcolor')
|
|
|
|
tag.set_property('foreground', color)
|
|
|
|
|
|
|
|
tag = self.history_buffer.create_tag('status')
|
|
|
|
color = gajim.config.get('statusmsgcolor')
|
|
|
|
tag.set_property('foreground', color)
|
|
|
|
|
2005-11-29 20:41:08 +01:00
|
|
|
tag = self.history_buffer.create_tag('time_sometimes')
|
|
|
|
tag.set_property('foreground', '#9e9e9e')
|
|
|
|
tag.set_property('justification', gtk.JUSTIFY_CENTER)
|
|
|
|
|
2005-11-20 22:58:08 +01:00
|
|
|
date = time.localtime()
|
|
|
|
y, m, d = date[0], date[1], date[2]
|
|
|
|
self.add_lines_for_date(y, m, d)
|
|
|
|
|
2005-10-09 19:07:29 +02:00
|
|
|
self.window.show_all()
|
|
|
|
|
2005-03-11 18:57:35 +01:00
|
|
|
def on_history_window_destroy(self, widget):
|
2005-11-27 17:11:55 +01:00
|
|
|
if self.mark_days_idle_call_id:
|
|
|
|
# if user destroys the window, and we have a generator filling mark days
|
|
|
|
# stop him!
|
|
|
|
gobject.source_remove(self.mark_days_idle_call_id)
|
2005-11-13 16:08:47 +01:00
|
|
|
del gajim.interface.instances['logs'][self.jid]
|
2005-03-11 18:57:35 +01:00
|
|
|
|
|
|
|
def on_close_button_clicked(self, widget):
|
2005-05-12 20:52:37 +02:00
|
|
|
self.window.destroy()
|
2005-03-11 18:57:35 +01:00
|
|
|
|
2005-11-20 22:58:08 +01:00
|
|
|
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)
|
2005-11-24 02:39:47 +01:00
|
|
|
|
2005-11-27 01:22:26 +01:00
|
|
|
def do_possible_mark_for_days_in_this_month(self, widget, year, month):
|
|
|
|
'''this is a generator and does pseudo-threading via idle_add()
|
|
|
|
so it runs progressively! yea :)
|
|
|
|
asks for days in this month if they have logs it bolds them (marks them)'''
|
2005-11-24 02:39:47 +01:00
|
|
|
weekday, days_in_this_month = calendar.monthrange(year, month)
|
2005-11-27 01:22:26 +01:00
|
|
|
# count from 1 (gtk counts from 1), so add 1 more
|
|
|
|
for day in xrange(1, days_in_this_month + 1):
|
|
|
|
#print 'ask for logs for date:', year, month, day
|
2005-11-24 02:39:47 +01:00
|
|
|
if gajim.logger.date_has_logs(self.jid, year, month, day):
|
|
|
|
widget.mark_day(day)
|
2005-11-27 01:22:26 +01:00
|
|
|
yield True # we have more work to do
|
|
|
|
yield False # we're done with this work
|
|
|
|
|
|
|
|
def on_calendar_month_changed(self, widget):
|
|
|
|
year, month, day = widget.get_date() # integers
|
|
|
|
# in gtk January is 1, in python January is 0,
|
|
|
|
# I want the second
|
|
|
|
# first day of month is 1 not 0
|
|
|
|
if self.mark_days_idle_call_id:
|
|
|
|
# if user changed month, and we have a generator filling mark days
|
|
|
|
# stop him from marking dates for the previously selected month
|
|
|
|
gobject.source_remove(self.mark_days_idle_call_id)
|
|
|
|
widget.clear_marks()
|
|
|
|
month = gtkgui_helpers.make_gtk_month_python_month(month)
|
|
|
|
self.mark_days_idle_call_id = gobject.idle_add(
|
|
|
|
self.do_possible_mark_for_days_in_this_month(widget, year, month).next)
|
2005-11-20 22:58:08 +01:00
|
|
|
|
2005-11-26 00:23:25 +01:00
|
|
|
def get_string_show_from_constant_int(self, show):
|
|
|
|
if show == constants.SHOW_ONLINE:
|
|
|
|
show = 'online'
|
|
|
|
elif show == constants.SHOW_CHAT:
|
|
|
|
show = 'chat'
|
|
|
|
elif show == constants.SHOW_AWAY:
|
|
|
|
show = 'away'
|
|
|
|
elif show == constants.SHOW_XA:
|
|
|
|
show = 'xa'
|
|
|
|
elif show == constants.SHOW_DND:
|
|
|
|
show = 'dnd'
|
|
|
|
elif show == constants.SHOW_OFFLINE:
|
|
|
|
show = 'offline'
|
|
|
|
|
|
|
|
return show
|
|
|
|
|
2005-11-20 22:58:08 +01:00
|
|
|
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
|
2005-11-29 20:41:08 +01:00
|
|
|
self.last_time_printout = 0
|
2005-11-20 22:58:08 +01:00
|
|
|
lines = gajim.logger.get_conversation_for_date(self.jid, year, month, day)
|
2005-11-23 20:12:52 +01:00
|
|
|
# lines holds list with tupples that have:
|
|
|
|
# contact_name, time, kind, show, message
|
2005-04-16 00:02:13 +02:00
|
|
|
for line in lines:
|
2005-11-23 20:12:52 +01:00
|
|
|
# line[0] is contact_name, line[1] is time of message
|
|
|
|
# line[2] is kind, line[3] is show, line[4] is message
|
|
|
|
self.add_new_line(line[0], line[1], line[2], line[3], line[4])
|
2005-11-20 22:58:08 +01:00
|
|
|
|
2005-11-23 20:12:52 +01:00
|
|
|
def add_new_line(self, contact_name, tim, kind, show, message):
|
2005-10-31 21:55:45 +01:00
|
|
|
'''add a new line in textbuffer'''
|
2005-11-20 22:58:08 +01:00
|
|
|
buf = self.history_buffer
|
|
|
|
end_iter = buf.get_end_iter()
|
2005-11-29 20:41:08 +01:00
|
|
|
|
|
|
|
if gajim.config.get('print_time') == 'always':
|
|
|
|
before_str = gajim.config.get('before_time')
|
|
|
|
after_str = gajim.config.get('after_time')
|
|
|
|
format = before_str + '%X' + after_str + ' '
|
|
|
|
tim = time.strftime(format, time.localtime(float(tim)))
|
|
|
|
buf.insert(end_iter, tim) # add time
|
|
|
|
elif gajim.config.get('print_time') == 'sometimes':
|
|
|
|
every_foo_seconds = 60 * gajim.config.get(
|
|
|
|
'print_ichat_every_foo_minutes')
|
|
|
|
seconds_passed = tim - self.last_time_printout
|
|
|
|
if seconds_passed > every_foo_seconds:
|
|
|
|
self.last_time_printout = tim
|
|
|
|
tim = time.strftime('%X ', time.localtime(float(tim)))
|
|
|
|
buf.insert_with_tags_by_name(end_iter, tim + '\n',
|
|
|
|
'time_sometimes')
|
|
|
|
|
2005-06-30 08:17:56 +02:00
|
|
|
tag_name = ''
|
|
|
|
tag_msg = ''
|
2005-11-23 20:12:52 +01:00
|
|
|
|
2005-11-26 00:23:25 +01:00
|
|
|
show = self.get_string_show_from_constant_int(show)
|
|
|
|
|
|
|
|
if kind == constants.KIND_GC_MSG:
|
2005-06-30 08:17:56 +02:00
|
|
|
tag_name = 'incoming'
|
2005-11-26 00:23:25 +01:00
|
|
|
elif kind in (constants.KIND_SINGLE_MSG_RECV, constants.KIND_CHAT_MSG_RECV):
|
2005-06-30 08:17:56 +02:00
|
|
|
try:
|
2005-11-23 20:12:52 +01:00
|
|
|
contact_name = gajim.contacts[self.account][self.jid][0].name
|
2005-06-30 08:17:56 +02:00
|
|
|
except:
|
2005-11-23 20:12:52 +01:00
|
|
|
contact_name = self.jid.split('@')[0]
|
2005-06-30 08:17:56 +02:00
|
|
|
tag_name = 'incoming'
|
2005-11-26 00:23:25 +01:00
|
|
|
elif kind in (constants.KIND_SINGLE_MSG_SENT, constants.KIND_CHAT_MSG_SENT):
|
2005-11-23 20:12:52 +01:00
|
|
|
contact_name = gajim.nicks[self.account]
|
2005-06-30 08:17:56 +02:00
|
|
|
tag_name = 'outgoing'
|
2005-11-26 00:23:25 +01:00
|
|
|
elif kind == constants.KIND_GCSTATUS:
|
2005-11-23 20:12:52 +01:00
|
|
|
# message here (if not None) is status message
|
|
|
|
if message:
|
|
|
|
message = _('%(nick)s is now %(status)s: %(status_msg)s') %\
|
|
|
|
{'nick': contact_name, 'status': helpers.get_uf_show(show),
|
|
|
|
'status_msg': message }
|
2005-11-20 22:58:08 +01:00
|
|
|
else:
|
2005-11-23 20:12:52 +01:00
|
|
|
message = _('%(nick)s is now %(status)s') % {'nick': contact_name,
|
|
|
|
'status': helpers.get_uf_show(show) }
|
|
|
|
tag_msg = 'status'
|
|
|
|
else: # 'status'
|
|
|
|
# message here (if not None) is status message
|
|
|
|
if message:
|
|
|
|
message = _('Status is now: %(status)s: %(status_msg)s') % \
|
|
|
|
{'status': helpers.get_uf_show(show), 'status_msg': message}
|
|
|
|
else:
|
|
|
|
message = _('Status is now: %(status)s') % { 'status':
|
|
|
|
helpers.get_uf_show(show) }
|
2005-06-30 08:17:56 +02:00
|
|
|
tag_msg = 'status'
|
|
|
|
|
2005-11-23 20:12:52 +01:00
|
|
|
# do not do this if gcstats, avoid dupping contact_name
|
|
|
|
# eg. nkour: nkour is now Offline
|
2005-11-26 00:23:25 +01:00
|
|
|
if contact_name and kind != constants.KIND_GCSTATUS:
|
2005-11-23 20:12:52 +01:00
|
|
|
# add stuff before and after contact name
|
2005-06-30 08:17:56 +02:00
|
|
|
before_str = gajim.config.get('before_nickname')
|
|
|
|
after_str = gajim.config.get('after_nickname')
|
2005-11-23 20:12:52 +01:00
|
|
|
format = before_str + contact_name + after_str + ' '
|
2005-11-20 22:58:08 +01:00
|
|
|
buf.insert_with_tags_by_name(end_iter, format, tag_name)
|
2005-11-23 20:12:52 +01:00
|
|
|
|
|
|
|
message = message + '\n'
|
2005-06-30 08:17:56 +02:00
|
|
|
if tag_msg:
|
2005-11-23 20:12:52 +01:00
|
|
|
buf.insert_with_tags_by_name(end_iter, message, tag_msg)
|
2005-06-30 08:17:56 +02:00
|
|
|
else:
|
2005-11-23 20:12:52 +01:00
|
|
|
buf.insert(end_iter, message)
|
2005-11-29 15:41:01 +01:00
|
|
|
|
|
|
|
def set_unset_expand_on_expander(self, widget):
|
|
|
|
'''expander has to have expand to TRUE so scrolledwindow resizes properly
|
|
|
|
and does not have a static size. when expander is not expanded we set
|
|
|
|
expand property (note the Box one) to FALSE
|
|
|
|
to do this, we first get the box and then apply to expander widget
|
|
|
|
the True/False thingy depending if it's expanded or not
|
|
|
|
this function is called in a timeout just after expanded state changes'''
|
|
|
|
parent = widget.get_parent() # vbox
|
|
|
|
parent.child_set_property(widget, 'expand', widget.get_expanded())
|
|
|
|
|
|
|
|
def on_search_expander_activate(self, widget):
|
|
|
|
if widget.get_expanded(): # it's the OPPOSITE!, it's not expanded
|
|
|
|
gobject.timeout_add(200, self.set_unset_expand_on_expander, widget)
|
|
|
|
else:
|
|
|
|
gobject.timeout_add(200, self.set_unset_expand_on_expander, widget)
|
|
|
|
|
|
|
|
def on_search_button_clicked(self, widget):
|
|
|
|
text = self.query_entry.get_text()
|
|
|
|
model = self.results_treeview.get_model()
|
|
|
|
model.clear()
|
2005-11-29 20:41:08 +01:00
|
|
|
if text == '':
|
|
|
|
return
|
|
|
|
# contact_name, time, kind, show, message
|
|
|
|
results = gajim.logger.get_search_results_for_query(self.jid, text)
|
2005-11-29 15:41:01 +01:00
|
|
|
for row in results:
|
|
|
|
iter = model.append((row[0], row[1], row[2], row[3], row[4]))
|
|
|
|
|
|
|
|
|