Logo Search packages:      
Sourcecode: sushi version File versions  Download package

history.py

import os
import gtk
import time
import calendar as mod_calendar

from gettext import gettext as _

from .. import gui
from .. import config
from ..com import sushi
from ..helper import history

def strip_date(text):
      new = []
      for line in text.split("\n"):
            match = history.DATEPATTERN.match(line)
            if match:
                  time_len = len(line[match.start():match.end()].split(" ")[-1])
                  new.append(line[match.end()-time_len:])
            else:
                  new.append(line)
      return "\n".join(new)

00024 class HistoryDialog(object):

      def __init__(self, history_tab):
            self.current_path = ()
            self.current_file = None
            self.current_offsets = {}

            # last search result position
            self.last_search_iter = None
            self.last_result = None
            self.search_in_progress = False

            # use log API despite remotely maki connection
            self.force_remote = False

            self.builder = gtk.Builder()

            path = config.get("uifiles","dialogs")
            self.builder.add_from_file(os.path.join(path, "history.ui"))

            self.builder.connect_signals(self)

            if not self.verify_remote():
                  return

            gui.mgmt.set_font(self.builder.get_object("history_view"),
                                      gui.mgmt.get_font())

            # jump to current date
            (year, month, day) = time.localtime(time.time())[0:3]
            self.builder.get_object("calendar").set_properties(
                  year=year, month=month-1, day=day)

            self.fill_target_tree()

            self.switch_to_target(history_tab.server.name, history_tab.name)

            self.load_current_day()

            bar = self.builder.get_object("searchbar")
            bar.autohide = False
            bar.default_buttons = False
            bar.search_button.connect("clicked", self.search)
            bar.search_entry.connect("activate", self.search)

00069       def verify_remote(self):
            """ ask user if he wants to try reading logs even if maki
                  is connected via sushi-remote. This is useful if maki
                  runs on the same host.
            """
            if not sushi.remote:
                  return True

            d = gui.builder.question_dialog(
                        _("Read history anyways?"),
                        _("maki is connected remotely. It's possible that "
                          "the history is not accessible. Do you want to "
                          "try anyways?"))

            id = d.run()
            d.destroy()

            if id == gtk.RESPONSE_YES:
                  self.force_remote = True
                  return True
            else:
                  self.builder.get_object("history_dialog").destroy()
                  return False


00094       def fill_target_tree(self):
            """ fill target tree store with server/targets """
            store = self.builder.get_object("target_tree")

            for server in history.get_available_servers(
                                                      force_remote=self.force_remote):
                  server_iter = store.append(None, (server,))

                  for conv in history.get_available_conversations(server,
                                                      force_remote=self.force_remote):
                        store.append(server_iter, (conv,))

00106       def switch_to_target(self, server, target):
            """ switch to combo box entry identified by server / target """
            cbox = self.builder.get_object("target_combobox")
            store = self.builder.get_object("target_tree")

            for srow in store:
                  if srow[0].lower() == server.lower():
                        for trow in srow.iterchildren():
                              if trow[0].lower() == target.lower():
                                    cbox.set_active_iter(trow.iter)
                                    d = self.builder.get_object("history_dialog")
                                    d.set_title(_("History for %(target)s") % {
                                                      "target": target})

00120       def get_current_names(self):
            """ return (server, target) of current selection
                  return (server, None) if no target is active
                  return (None, None) if no entry is active
            """
            if not self.current_path:
                  return (None, None)

            store = self.builder.get_object("target_tree")
            iter = store.get_iter(self.current_path)
            target = store.get_value(iter, 0)
            parent_iter = store.iter_parent(iter)

            if not parent_iter:
                  return (target, None)

            server = store.get_value(parent_iter, 0)
            return (server, target)

00139       def update_calendar(self, highlight=True):
            """ update the calendar markings if highlight is True and
                  the cache variables self.current_file and self.current_offsets
            """
            calendar = self.builder.get_object("calendar")
            calendar.clear_marks()

            (server, target) = self.get_current_names()

            if not server or not target:
                  return

            (year, month) = calendar.get_properties("year","month")
            month += 1 # 1-12 instead of 0-11

            for log in history.get_available_logs(server, target,
                                                            force_remote=self.force_remote):
                  (lyear, lmonth) = history.get_log_date(log)

                  if year == lyear and lmonth == month:
                        path = history.get_log_path(server, target, log)

                        try:
                              fd = file(path, "r")
                        except Exception,e:
                              print "Exception %s while open %s." % (e, path)
                              return

                        self.current_file = path
                        self.current_offsets = history.parse_day_offsets(fd)

                        if highlight:
                              for (year, month, day) in self.current_offsets.keys():
                                    calendar.mark_day(day)


      def search_calender_marks(self):
            needle = self.builder.get_object(
                              "searchbar").search_entry.get_text()

            if not self.current_file or not needle:
                  return

            calender = self.builder.get_object("calendar")
            calender.clear_marks()

            if not self.current_offsets:
                  return

            fd = file(self.current_file, "r")
            for ((year, month, day),
                  (start,end)) in self.current_offsets.items():

                  fd.seek(start)

                  if fd.read(end-start).find(needle) >= 0:
                        calender.mark_day(day)


00198       def search_local(self):
            """ search in the text loaded into history_buffer and highlight
                  the needle if found.
                  Returns True on success otherwise False
            """
            view = self.builder.get_object("history_view")
            buffer = self.builder.get_object("history_buffer")
            needle = self.builder.get_object(
                              "searchbar").search_entry.get_text()

            if not needle:
                  return False

            if (not self.last_search_iter or self.last_result != needle):
                  # new search
                  self.last_search_iter = buffer.get_start_iter()
                  self.search_calender_marks()

            result = self.last_search_iter.forward_search(needle,
                                                      gtk.TEXT_SEARCH_TEXT_ONLY)

            if not result or result == self.last_result:
                  return False

            self.last_search_iter = result[1]
            self.last_result = buffer.get_text(*result)

            buffer.select_range(*result)

            # scroll the textview to the result
            view.scroll_to_iter(result[0], 0.0)
            return True

00231       def load_next_month(self):
            """ find the next possible month with data in it and
                  jump to it. Return True on success, otherwise False
            """
            calendar = self.builder.get_object("calendar")

            (year, month) = calendar.get_properties("year","month")

            real_month = month + 1

            (server, target) = self.get_current_names()

            if not server and not target:
                  return False

            available_months = {}

            for log in history.get_available_logs(server, target,
                                                      force_remote=self.force_remote):

                  (dyear, dmonth) = history.get_log_date(log)

                  if dyear > year or (dyear == year and dmonth > real_month):
                        if not available_months.has_key(dyear):
                              available_months[dyear] = []
                        available_months[dyear].append(dmonth)

            if not available_months:
                  return False

            # get lowest possible year
            low_year = sorted(available_months.keys())[0]

            # get lowest month in year
            low_month = sorted(available_months[low_year])[0] - 1

            # get first day
            # XXX this mustnt be a day which has search results so it would
            # probably better to set the day to a day with search result
            day = mod_calendar.monthrange(low_year, low_month+1)[0]

            calendar.set_properties(year=low_year, month=low_month, day=day)
            return True

00275       def search(self,*x):
            """ search for a needle, mark all days where something
                  was found. On every hit, iterate further until no
                  further matches are found.
            """
            needle = self.builder.get_object(
                              "searchbar").search_entry.get_text()
            if not needle:
                  print "aborting search.."
                  self.abort_search()
                  return

            self.search_in_progress = True
            print "in search"

            if not self.search_local():
                  # no results at current day, search for the next one.
                  print "local didnt succeed..."
                  calendar = self.builder.get_object("calendar")
                  (cyear,cmonth,cday) = calendar.get_properties("year","month",
                                                                                      "day")
                  cmonth += 1
                  possible_days = []
                  for (year, month, day) in self.current_offsets:
                        if year == cyear and cmonth == month and day > cday:
                              possible_days.append(day)
                  if possible_days:
                        print "got possible days, %s" % (possible_days,)
                        # switch to smallest possible day
                        calendar.select_day(sorted(possible_days)[0])
                        self.search()
                  else:
                        # no days with data this month. load next month (if avail)
                        if self.load_next_month():
                              print "loading next month"
                              return self.search()
                        else:
                              # no next month, abort search
                              self.reset_search()
                              print "SEARCH ENDED!"
                              return

00317       def reset_search(self):
            """ reset search variables """
            self.search_in_progress = False
            self.last_search_iter = None

00322       def abort_search(self):
            """ clear the search markup and reset variables """
            self.reset_search()
            self.update_calendar()

      def load_current_day(self):
            calendar = self.builder.get_object("calendar")
            if not self.current_file:
                  return False
            (year, month, day) = calendar.get_properties("year", "month",
                                                                              "day")
            month += 1 # we work with 1-12 not 0-11 like the calendar widget
            if not self.current_offsets.has_key((year, month, day)):
                  return False

            (start, end) = self.current_offsets[(year, month, day)]

            buffer = self.builder.get_object("history_buffer")

            fd = file(self.current_file, "r")
            fd.seek(start)
            buffer.set_text(strip_date(fd.read(end - start)))
            return True

      def calendar_date_changed(self, calendar):
            if not self.search_in_progress:
                  self.update_calendar()
            else:
                  self.update_calendar(highlight=False)
                  self.search_calender_marks()

      def calendar_day_selected(self, calendar):
            if not self.load_current_day():
                  self.builder.get_object("history_buffer").set_text("")

      def target_combobox_changed(self, box):
            self.current_path = box.get_model().get_path(box.get_active_iter())
            self.update_calendar()
            self.search_in_progress = False

      def history_dialog_response(self, dialog, id):
            dialog.destroy()

      def history_buffer_changed(self, buffer, *x):
            if self.search_in_progress:
                  self.last_search_iter = buffer.get_start_iter()



def run(tab):
      d = HistoryDialog(tab)

      dwin = d.builder.get_object("history_dialog")
      dwin.show_all()


def setup():
      pass

Generated by  Doxygen 1.6.0   Back to index