Source code for timelinelib.canvas.data.immutable

# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018  Rickard Lindberg, Roger Lindberg
#
# This file is part of Timeline.
#
# Timeline 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, either version 3 of the License, or
# (at your option) any later version.
#
# Timeline 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.
#
# You should have received a copy of the GNU General Public License
# along with Timeline.  If not, see <http://www.gnu.org/licenses/>.


from timelinelib.canvas.drawing.drawers import get_progress_color
from timelinelib.general.immutable import Field
from timelinelib.general.immutable import ImmutableDict
from timelinelib.general.immutable import ImmutableRecord


[docs]class ImmutableEvent(ImmutableRecord): text = Field(None) time_period = Field(None) category_id = Field(None) category_ids = Field(ImmutableDict()) fuzzy = Field(False) fuzzy_start = Field(False) fuzzy_end = Field(False) locked = Field(False) ends_today = Field(False) description = Field(None) labels = Field(None) icon = Field(None) hyperlink = Field(None) alert = Field(None) progress = Field(None) default_color = Field(None) container_id = Field(None) sort_order = Field(None)
[docs]class ImmutableMilestone(ImmutableRecord): text = Field(None) category_id = Field(None) category_ids = Field(ImmutableDict()) time_period = Field(None) description = Field(None) default_color = Field((255, 255, 128)) sort_order = Field(None)
[docs]class ImmutableEra(ImmutableRecord): name = Field(None) time_period = Field(None) color = Field((200, 200, 200)) ends_today = Field(False)
[docs]class ImmutableCategory(ImmutableRecord): name = Field("") color = Field((255, 0, 0)) progress_color = Field(get_progress_color((255, 0, 0))) done_color = Field(get_progress_color((255, 0, 0))) font_color = Field((0, 0, 0)) parent_id = Field(None)
[docs]class ImmutableContainer(ImmutableRecord): text = Field(None) category_id = Field(None) category_ids = Field(ImmutableDict()) time_period = Field(None) description = Field(None)
[docs]class ImmutableDB(ImmutableRecord): categories = Field(ImmutableDict()) containers = Field(ImmutableDict()) events = Field(ImmutableDict()) milestones = Field(ImmutableDict()) eras = Field(ImmutableDict())
[docs] def save_event(self, event, id_): self._ensure_non_none_category_exists(event.category_id) self._ensure_non_none_container_exists(event.container_id) return self.update( events=self.events.update({ id_: event, }) )
[docs] def delete_event(self, id_): self._ensure_event_exists(id_) return self.update( events=self.events.remove(id_) )
[docs] def save_milestone(self, milestone, id_): self._ensure_non_none_category_exists(milestone.category_id) return self.update( milestones=self.milestones.update({ id_: milestone }) )
[docs] def delete_milestone(self, id_): self._ensure_milestone_exists(id_) return self.update( milestones=self.milestones.remove(id_) )
[docs] def save_era(self, era, id_): return self.update( eras=self.eras.update({ id_: era, }) )
[docs] def delete_era(self, id_): self._ensure_era_exists(id_) return self.update( eras=self.eras.remove(id_) )
[docs] def save_category(self, category, id_): self._ensure_category_name_is_unique(id_, category.name) self._ensure_non_none_category_exists(category.parent_id) self._ensure_no_category_circular(id_, category.parent_id) return self.update( categories=self.categories.update({id_: category}) )
[docs] def delete_category(self, delete_id): self._ensure_category_exists(delete_id) new_parent_id = self.categories.get(delete_id).parent_id def update_parent_id(category): if category.parent_id == delete_id: return category.update(parent_id=new_parent_id) else: return category def update_category_id(thing): if thing.category_id == delete_id: return thing.update(category_id=new_parent_id) else: return thing return self.update( categories=self.categories.remove(delete_id).map(update_parent_id), events=self.events.map(update_category_id), milestones=self.milestones.map(update_category_id), containers=self.containers.map(update_category_id) )
[docs] def save_container(self, container, id_): self._ensure_non_none_category_exists(container.category_id) return self.update( containers=self.containers.update({id_: container}) )
[docs] def delete_container(self, delete_id): self._ensure_container_exists(delete_id) def update_container_id(event): if event.container_id == delete_id: return event.update(container_id=None) else: return event return self.update( containers=self.containers.remove(delete_id), events=self.events.map(update_container_id), )
def _ensure_event_exists(self, id_): if id_ not in self.events: raise InvalidOperationError( "Event with id {0!r} does not exist".format(id_) ) def _ensure_milestone_exists(self, id_): if id_ not in self.milestones: raise InvalidOperationError( "Milestone with id {0!r} does not exist".format(id_) ) def _ensure_era_exists(self, id_): if id_ not in self.eras: raise InvalidOperationError( "Era with id {0!r} does not exist".format(id_) ) def _ensure_category_name_is_unique(self, save_id, save_name): for id_, category in self.categories: if id_ != save_id and category.name == save_name: raise InvalidOperationError( "Category name {0!r} is not unique".format(save_name) ) def _ensure_non_none_category_exists(self, id_): if id_ is not None: self._ensure_category_exists(id_) def _ensure_category_exists(self, id_): if id_ not in self.categories: raise InvalidOperationError( "Category with id {0!r} does not exist".format(id_) ) def _ensure_no_category_circular(self, save_id, parent_id): while parent_id is not None: if parent_id == save_id: raise InvalidOperationError( "Circular category parent" ) else: parent_id = self.categories.get(parent_id).parent_id def _ensure_non_none_container_exists(self, id_): if id_ is not None: self._ensure_container_exists(id_) def _ensure_container_exists(self, id_): if id_ not in self.containers: raise InvalidOperationError( "Container with id {0!r} does not exist".format(id_) )
[docs]class InvalidOperationError(Exception): pass