Package Gnumed :: Package timelinelib :: Package db |
[frames] | no frames]

# Source Code for Package Gnumed.timelinelib.db

      1  # Copyright (C) 2009, 2010, 2011  Rickard Lindberg, Roger Lindberg
      2  #
      3  # This file is part of Timeline.
      4  #
      5  # Timeline is free software: you can redistribute it and/or modify
      6  # it under the terms of the GNU General Public License as published by
      7  # the Free Software Foundation, either version 3 of the License, or
      8  # (at your option) any later version.
      9  #
     10  # Timeline is distributed in the hope that it will be useful,
     11  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  # GNU General Public License for more details.
     14  #
     15  # You should have received a copy of the GNU General Public License
     16  # along with Timeline.  If not, see <http://www.gnu.org/licenses/>.
     17
     18
     19  import os.path
     20
     21  from timelinelib.db.backends.memory import MemoryDB
     22  from timelinelib.db.backends.tutorial import create_in_memory_tutorial_db
     23  from timelinelib.db.exceptions import TimelineIOError
     24  from timelinelib.db.objects import Category
     25  from timelinelib.db.objects import Event
     26  from timelinelib.db.objects import TimePeriod
     27  from timelinelib.drawing.viewproperties import ViewProperties
     28
     29
     30 -def db_open(path, use_wide_date_range=False):
     31      """
     32      Create timeline database that can read and write timeline data from and to
     33      persistent storage identified by path.
     34
     35      Throw a TimelineIOError exception if not able to read from the given path.
     36
     37      Valid values for path:
     38
     39        - special string ":tutorial:"
     40        - string with suffix .timeline
     41        - string with suffix .ics
     42        - string denoting a directory
     43      """
     44      if path == ":tutorial:":
     45          return create_in_memory_tutorial_db()
     46      elif os.path.isdir(path):
     47          from timelinelib.db.backends.dir import DirTimeline
     48          return DirTimeline(path)
     49      elif path.endswith(".timeline"):
     50          if (os.path.exists(path) and
     51              file_starts_with(path, "# Written by Timeline ")):
     52              # Convert file db to xml db
     53              from timelinelib.db.backends.file import FileTimeline
     54              from timelinelib.db.backends.xmlfile import XmlTimeline
     55              file_db = FileTimeline(path)
     56              xml_db = XmlTimeline(path, load=False,
     57                                   use_wide_date_range=use_wide_date_range)
     58              copy_db(file_db, xml_db)
     59              return xml_db
     60          else:
     61              from timelinelib.db.backends.xmlfile import XmlTimeline
     62              return XmlTimeline(path, use_wide_date_range=use_wide_date_range)
     63      elif path.endswith(".ics"):
     64          try:
     65              import icalendar
     66          except ImportError:
     67              raise TimelineIOError(_("Could not find iCalendar Python package. It is required for working with ICS files. See the Timeline website or the INSTALL file for instructions how to install it."))
     68          else:
     69              from timelinelib.db.backends.ics import IcsTimeline
     70              return IcsTimeline(path)
     71      else:
     72          msg_template = (_("Unable to open timeline '%s'.") + "\n\n" +
     73                          _("Unknown format."))
     74          raise TimelineIOError(msg_template % path)
     75
     76
     77 -def file_starts_with(path, start):
     78      return read_first_line(path).startswith(start)
     79
     80
     81 -def read_first_line(path):
     82      try:
     83          f = open(path)
     84          try:
     85              line = f.readline()
     86              return line
     87          finally:
     88              f.close()
     89      except IOError:
     90          raise TimelineIOError("Unable to read data from '%s'." % path)
     91
     92
     93 -def copy_db(from_db, to_db):
     94      """
     95      Copy all content from one db to another.
     96
     97      to_db is assumed to have no categories (conflicting category names are not
     98      handled).
     99      """
    100      if isinstance(to_db, MemoryDB):
    101          to_db.disable_save()
    102      # Copy categories (parent attribute fixed later)
    103      cat_map = {}
    104      for cat in from_db.get_categories():
    105          # name, color, and visible all immutable so safe to copy
    106          new_cat = Category(cat.name, cat.color, None, cat.visible)
    107          cat_map[cat.name] = new_cat
    108          to_db.save_category(new_cat)
    109      # Fix parent attribute
    110      for cat in from_db.get_categories():
    111          if cat.parent is not None:
    112              cat_map[cat.name].parent = cat_map[cat.parent.name]
    113      # Copy events
    114      for event in from_db.get_all_events():
    115          cat = None
    116          if event.category is not None:
    117              cat = cat_map[event.category.name]
    118          # start_time, end_time, and text all immutable so safe to copy
    119          new_event = Event(to_db.get_time_type(), event.time_period.start_time,
    120                            event.time_period.end_time,
    121                            event.text,
    122                            cat)
    123          # description immutable so safe to copy
    124          if event.get_data("description") is not None:
    125              new_event.set_data("description", event.get_data("description"))
    126          # icon immutable in practice (since never modified) so safe to copy
    127          if event.get_data("icon") is not None:
    128              new_event.set_data("icon", event.get_data("icon"))
    129          to_db.save_event(new_event)
    130      # Copy view properties (ViewProperties is specific to db so we need to copy
    131      # like this instead of just using load/save_view_properties in db).
    132      from_vp = ViewProperties()
    133      from_db.load_view_properties(from_vp)
    134      to_vp = ViewProperties()
    135      for from_cat in from_db.get_categories():
    136          cat = cat_map[from_cat.name]
    137          visible = from_vp.category_visible(from_cat)
    138          to_vp.set_category_visible(cat, visible)
    139      if from_vp.displayed_period is not None:
    140          # start_time and end_time immutable so safe to copy
    141          start = from_vp.displayed_period.start_time
    142          end = from_vp.displayed_period.end_time
    143          to_vp.displayed_period = TimePeriod(to_db.get_time_type(), start, end)
    144      to_db.save_view_properties(to_vp)
    145      # Save
    146      if isinstance(to_db, MemoryDB):
    147          to_db.enable_save()
    148