Пример #1
0
 def save_event(self, event):
     if (event.category is not None
             and event.category not in self.categories):
         raise TimelineIOError("Event's category not in db.")
     if event not in self.events:
         if event.has_id():
             raise TimelineIOError("Event with id %s not found in db." %
                                   event.id)
         self.events.append(event)
         event.set_id(self.event_id_counter.get_next())
         if event.is_subevent():
             self._register_subevent(event)
     self._save_if_not_disabled()
     self._notify(STATE_CHANGE_ANY)
Пример #2
0
 def _ensure_no_circular_parent(self, cat):
     parent = cat.parent
     while parent is not None:
         if parent == cat:
             raise TimelineIOError("Circular category parent.")
         else:
             parent = parent.parent
Пример #3
0
def db_open(path, timetype=None):
    """
    Create timeline database that can read and write timeline data from and to
    persistent storage identified by path.

    Throw a TimelineIOError exception if not able to read from the given path.

    Valid values for path:

      - special string ":tutorial:"
      - string with suffix .timeline
      - string with suffix .ics
      - string denoting a directory
    """
    if path == ":tutorial:":
        return open_tutorial_timeline(path)
    elif os.path.isdir(path):
        return open_directory_timeline(path)
    elif path.endswith(".timeline"):
        return db_open_timeline(path, timetype)
    elif path.endswith(".ics"):
        return db_open_ics(path)
    else:
        msg_template = (_("Unable to open timeline '%s'.") + "\n\n" +
                        _("Unknown format."))
        raise TimelineIOError(msg_template % path)
Пример #4
0
    def _load(self):
        """
        Load timeline data from the file that this timeline points to.

        This should only be done once when this class is created.

        The data is stored internally until we do a save.

        If a read error occurs a TimelineIOError will be raised.
        """
        if not os.path.exists(self.path):
            # Nothing to load. Will create a new timeline on save.
            return
        try:
            # _parse_version will create the rest of the schema dynamically
            partial_schema = Tag("timeline", SINGLE, None,
                                 [Tag("version", SINGLE, self._parse_version)])
            tmp_dict = {
                "partial_schema": partial_schema,
                "category_map": {},
                "hidden_categories": [],
            }
            self.disable_save()
            parse(self.path, partial_schema, tmp_dict)
            self.enable_save(call_save=False)
        except Exception, e:
            msg = _("Unable to read timeline data from '%s'.")
            whole_msg = (msg + "\n\n%s") % (abspath(self.path), ex_msg(e))
            raise TimelineIOError(whole_msg)
Пример #5
0
def _load(db, dir_path):
    """
    Load timeline data from the given directory.

    Each filename inside the directory (at any level) becomes an event where
    the text is the filename name and the time is the modification time for
    the filename.

    For each sub-directory a category is created and all events (files)
    belong the category (directory) in which they are.
    """
    if not os.path.exists(dir_path):
        # Nothing to load
        return
    if not os.path.isdir(dir_path):
        # Nothing to load
        return
    try:
        db.disable_save()
        color_ranges = {}  # Used to color categories
        color_ranges[dir_path] = (0.0, 1.0, 1.0)
        all_cats = []
        parents = {}
        for (dirpath, dirnames, filenames) in os.walk(dir_path):
            # Assign color ranges
            (rstart, rend, b) = color_ranges[dirpath]
            step = (rend - rstart) / (len(dirnames) + 1)
            next_start = rstart + step
            new_b = b - 0.2
            if new_b < 0:
                new_b = 0
            for dirname in dirnames:
                next_end = next_start + step
                color_ranges[os.path.join(dirpath,
                                          dirname)] = (next_start, next_end,
                                                       new_b)
                next_start = next_end
            # Create the stuff
            p = parents.get(os.path.normpath(os.path.join(dirpath, "..")),
                            None)
            cat = Category(dirpath, (233, 233, 233), None, parent=p)
            parents[os.path.normpath(dirpath)] = cat
            all_cats.append(cat)
            db.save_category(cat)
            for filename in filenames:
                path_inner = os.path.join(dirpath, filename)
                evt = _event_from_path(db, path_inner)
                db.save_event(evt)
        # Hide all categories but the first
        db.set_hidden_categories(all_cats[1:])
        # Set colors and change names
        for cat in db.get_categories():
            cat.color = _color_from_range(color_ranges[cat.name])
            cat.name = os.path.basename(cat.name)
            db.save_category(cat)
    except Exception, e:
        msg = _("Unable to read from filename '%s'.") % dir_path
        whole_msg = "%s\n\n%s" % (msg, e)
        raise TimelineIOError(whole_msg)
Пример #6
0
def convert_to_datetime(d):
    if isinstance(d, datetime):
        return Gregorian(d.year, d.month, d.day, d.hour, d.minute,
                         d.second).to_time()
    elif isinstance(d, date):
        return gregorian.from_date(d.year, d.month, d.day).to_time()
    else:
        raise TimelineIOError("Unknown date.")
Пример #7
0
def db_open_timeline(path, timetype=None):
    if (os.path.exists(path)
            and file_starts_with(path, "# Written by Timeline ")):
        raise TimelineIOError(
            _("You are trying to open an old file with a new version of timeline. Please install version 0.21.1 of timeline to convert it to the new format."
              ))
    else:
        return db_open_newtype_timeline(path, timetype)
Пример #8
0
 def save_view_properties(self, view_properties):
     if view_properties.displayed_period is not None:
         if not view_properties.displayed_period.is_period():
             raise TimelineIOError(_("Displayed period must be > 0."))
         self.displayed_period = view_properties.displayed_period
     self.hidden_categories = []
     for cat in self.categories:
         if not view_properties.is_category_visible(cat):
             self.hidden_categories.append(cat)
     self._save_if_not_disabled()
Пример #9
0
def read_first_line(path):
    try:
        f = open(path)
        try:
            line = f.readline()
            return line
        finally:
            f.close()
    except IOError:
        raise TimelineIOError("Unable to read data from '%s'." % path)
Пример #10
0
def db_open_ics(path):
    try:
        import icalendar
    except ImportError:
        raise TimelineIOError(
            _("Could not find iCalendar Python package. It is required for working with ICS files."
              ))
    else:
        from timelinelib.dataimport.ics import import_db_from_ics
        return import_db_from_ics(path)
Пример #11
0
 def import_timeline(self, path):
     try:
         ics_file = open(path, "rb")
         try:
             file_contents = ics_file.read()
             try:
                 cal = Calendar.from_ical(file_contents)
                 for event in cal.walk("VEVENT"):
                     event["timeline_id"] = self.event_id_counter.get_next()
                 self.cals.append(cal)
             except Exception, pe:
                 msg1 = _("Unable to read timeline data from '%s'.")
                 msg2 = "\n\n" + ex_msg(pe)
                 raise TimelineIOError((msg1 % abspath(path)) + msg2)
         finally:
             ics_file.close()
     except IOError, e:
         msg = _("Unable to read from file '%s'.")
         whole_msg = (msg + "\n\n%s") % (abspath(self.path), e)
         raise TimelineIOError(whole_msg)
Пример #12
0
 def save_category(self, category):
     if (category.parent is not None
             and category.parent not in self.categories):
         raise TimelineIOError("Parent category not in db.")
     self._ensure_no_circular_parent(category)
     if not category in self.categories:
         if self.importing:
             if not self._category_name_exists(category):
                 self._append_category(category)
         else:
             self._append_category(category)
     self._save_if_not_disabled()
     self._notify(STATE_CHANGE_CATEGORY)
Пример #13
0
 def delete_event(self, event_or_id):
     if isinstance(event_or_id, Event):
         event = event_or_id
     else:
         event = self.find_event_with_id(event_or_id)
     if event in self.events:
         if event.is_subevent():
             self._unregister_subevent(event)
         if event.is_container():
             for subevent in event.events:
                 self.events.remove(subevent)
         self.events.remove(event)
         event.set_id(None)
         self._save_if_not_disabled()
         self._notify(STATE_CHANGE_ANY)
     else:
         raise TimelineIOError("Event not in db.")
Пример #14
0
 def _load(self):
     try:
         # _parse_version will create the rest of the schema dynamically
         partial_schema = Tag("timeline", SINGLE, None,
                              [Tag("version", SINGLE, self._parse_version)])
         tmp_dict = {
             "partial_schema": partial_schema,
             "category_map": {},
             "hidden_categories": [],
         }
         self.db.disable_save()
         parse(self.path, partial_schema, tmp_dict)
         self.db.enable_save(call_save=False)
     except Exception, e:
         msg = _("Unable to read timeline data from '%s'.")
         whole_msg = (msg + "\n\n%s") % (abspath(self.path), ex_msg(e))
         raise TimelineIOError(whole_msg)
Пример #15
0
def db_open_ics(path, import_timeline=False):
    global current_timeline
    try:
        import icalendar
    except ImportError:
        raise TimelineIOError(
            _("Could not find iCalendar Python package. It is required for working with ICS files. See the Timeline website or the doc/installing.rst file for instructions how to install it."
              ))
    else:
        from timelinelib.db.backends.ics import IcsTimeline
        if import_timeline and current_timeline:
            extension = current_timeline.path.rsplit(".", 1)[1]
            if extension != "ics":
                display_warning_message(
                    _("Only %s files can be imported") % extension)
                return current_timeline
            current_timeline.import_timeline(path)
        else:
            current_timeline = IcsTimeline(path)
        return current_timeline
Пример #16
0
 def delete_category(self, category_or_id):
     if isinstance(category_or_id, Category):
         category = category_or_id
     else:
         category = self._find_category_with_id(category_or_id)
     if category in self.categories:
         if category in self.hidden_categories:
             self.hidden_categories.remove(category)
         self.categories.remove(category)
         category.set_id(None)
         # Loop to update parent attribute on children
         for cat in self.categories:
             if cat.parent == category:
                 cat.parent = category.parent
         # Loop to update category for events
         for event in self.events:
             if event.category == category:
                 event.category = category.parent
         self._save_if_not_disabled()
         self._notify(STATE_CHANGE_CATEGORY)
     else:
         raise TimelineIOError("Category not in db.")
Пример #17
0
 def _append_category(self, category):
     if category.has_id():
         raise TimelineIOError("Category with id %s not found in db." %
                               category.id)
     self.categories.append(category)
     category.set_id(self.event_id_counter.get_next())
Пример #18
0
 def raise_error(specific_msg, cause_exception):
     err_general = _("Unable to save timeline data to '%s'. File left unmodified.") % path
     err_template = "%s\n\n%%s\n\n%%s" % err_general
     raise TimelineIOError(err_template % (specific_msg, cause_exception))
 def test_handles_open_timeline_failure(self):
     error = TimelineIOError("")
     self.given_opening_fails_with_error(error)
     self.when_timeline_is_opened()
     self.main_frame.handle_db_error.assert_called_with(error)