def testSaveCategoryWithParentChange(self): # Start with this hierarchy: # c1 # c11 # c111 # c12 c1 = Category("c1", (255, 0, 0), None, True, parent=None) c11 = Category("c11", (255, 0, 0), None, True, parent=c1) c111 = Category("c111", (255, 0, 0), None, True, parent=c11) c12 = Category("c12", (255, 0, 0), None, True, parent=c1) self.db.save_category(c1) self.db.save_category(c11) self.db.save_category(c111) self.db.save_category(c12) # Changing c11's parent to c12 should create the following tree: # c1 # c12 # c11 # c111 c11.parent = c12 self.db.save_category(c11) self.assertEquals(c1.parent, None) self.assertEquals(c12.parent, c1) self.assertEquals(c11.parent, c12) self.assertEquals(c111.parent, c11) # Changing c11's parent to c111 should raise exception since that would # create a circular parent link. c11.parent = c111 self.assertRaises(TimelineIOError, self.db.save_category, c11)
def setUp(self): # Category configuration: # foo # foofoo # bar self.category_repository = Mock(CategoryRepository) self.foo = Category("foo", (255, 0, 0), None, True, parent=None) self.foofoo = Category("foofoo", (255, 0, 0), (0, 255, 0), True, parent=self.foo) self.bar = Category("bar", (255, 0, 0), None, True, parent=None) self.category_repository.get_all.return_value = [ self.foo, self.foofoo, self.bar ] def get_tree_mock(remove): if remove is None: return [(self.bar, []), (self.foo, [(self.foofoo, [])])] elif remove is self.foofoo: return [(self.bar, []), (self.foo, [])] else: return [] self.category_repository.get_tree.side_effect = get_tree_mock self.view = Mock(WxCategoryEdtiorDialog)
def _load(self, dir_path): """ Load timeline data from the given directory. Each file inside the directory (at any level) becomes an event where the text is the file name and the time is the modification time for the file. 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: self.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 range = (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 dir in dirnames: next_end = next_start + step color_ranges[os.path.join(dirpath, dir)] = (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, False, parent=p) parents[os.path.normpath(dirpath)] = cat all_cats.append(cat) self.save_category(cat) for file in filenames: path_inner = os.path.join(dirpath, file) evt = self._event_from_path(path_inner) self.save_event(evt) # Hide all categories but the first self._set_hidden_categories(all_cats[1:]) # Set colors and change names for cat in self.get_categories(): cat.color = self._color_from_range(color_ranges[cat.name]) cat.name = os.path.basename(cat.name) self.save_category(cat) except Exception, e: msg = _("Unable to read from file '%s'.") % dir_path whole_msg = "%s\n\n%s" % (msg, e) raise TimelineIOError(whole_msg)
def setUp(self): self.db = MemoryDB() self.db._save = Mock() self.db_listener = Mock() self.c1 = Category("work", (255, 0, 0), None, True) self.c2 = Category("private", (0, 255, 0), None, True) self.e1 = Event(self.db.get_time_type(), datetime(2010, 2, 13), datetime(2010, 2, 13), "holiday") self.e2 = Event(self.db.get_time_type(), datetime(2010, 2, 14), datetime(2010, 2, 14), "work starts") self.e3 = Event(self.db.get_time_type(), datetime(2010, 2, 15), datetime(2010, 2, 16), "period") self.db.register(self.db_listener)
def setUp(self): self.db = Mock(MemoryDB) self.foo = Category("foo", (255, 0, 0), None, True, parent=None) self.foofoo = Category("foofoo", (255, 0, 0), None, True, parent=self.foo) self.bar = Category("bar", (255, 0, 0), None, True, parent=None) self.db.get_categories.return_value = [self.foo, self.foofoo, self.bar] self.view = Mock(CategoriesTree) self.timeline_view = Mock(DrawingAreaPanel) self.timeline_view.get_timeline.return_value = self.db self.timeline_view.get_view_properties.return_value = Mock() self.controller = CategoriesTreeController(self.view, None)
def add_category(self, name, color, font_color, make_last_added_parent=False): if make_last_added_parent: parent = self.last_cat else: parent = None self.prev_cat = self.last_cat self.last_cat = Category(name, color, font_color, True, parent) self.db.save_category(self.last_cat)
def testDelteCategoryWithEvent(self): # Create hierarchy: # c1 # c11 c1 = Category("c1", (255, 0, 0), None, True, parent=None) c11 = Category("c11", (255, 0, 0), None, True, parent=c1) self.db.save_category(c1) self.db.save_category(c11) # Create event belonging to c11 self.e1.category = c11 self.db.save_event(self.e1) # Delete c11 should cause e1 to get c1 as category self.db.delete_category(c11) self.assertEquals(self.e1.category, c1) # Delete c1 should cause e1 to have no category self.db.delete_category(c1) self.assertEquals(self.e1.category, None)
def given_event_at(self, start_time, end_time=None, visible=True): category = Category("category", (0, 0, 0), None, visible) if end_time is None: end_time = start_time event = Event(self.db.get_time_type(), human_time_to_py(start_time), human_time_to_py(end_time), "event-text", category) self.db.save_category(category) self.db.save_event(event) self.view_properties.set_category_visible(category, visible)
def testDeleteCategoryWithParent(self): # Create hierarchy: # c1 # c11 # c12 # c121 c1 = Category("c1", (255, 0, 0), None, True, parent=None) c11 = Category("c11", (255, 0, 0), None, True, parent=c1) c12 = Category("c12", (255, 0, 0), None, True, parent=c1) c121 = Category("c121", (255, 0, 0), None, True, parent=c12) self.db.save_category(c1) self.db.save_category(c11) self.db.save_category(c12) self.db.save_category(c121) # Delete c12 should cause c121 to get c1 as parent self.db.delete_category(c12) self.assertEquals(c121.parent, c1) # Delete c1 should cause c11, and c121 to be parentless self.db.delete_category(c1) self.assertEquals(c11.parent, None) self.assertEquals(c121.parent, None)
def copy_db(from_db, to_db): """ Copy all content from one db to another. to_db is assumed to have no categories (conflicting category names are not handled). """ if isinstance(to_db, MemoryDB): to_db.disable_save() # Copy categories (parent attribute fixed later) cat_map = {} for cat in from_db.get_categories(): # name, color, and visible all immutable so safe to copy new_cat = Category(cat.name, cat.color, None, cat.visible) cat_map[cat.name] = new_cat to_db.save_category(new_cat) # Fix parent attribute for cat in from_db.get_categories(): if cat.parent is not None: cat_map[cat.name].parent = cat_map[cat.parent.name] # Copy events for event in from_db.get_all_events(): cat = None if event.category is not None: cat = cat_map[event.category.name] # start_time, end_time, and text all immutable so safe to copy new_event = Event(to_db.get_time_type(), event.time_period.start_time, event.time_period.end_time, event.text, cat) # description immutable so safe to copy if event.get_data("description") is not None: new_event.set_data("description", event.get_data("description")) # icon immutable in practice (since never modified) so safe to copy if event.get_data("icon") is not None: new_event.set_data("icon", event.get_data("icon")) to_db.save_event(new_event) # Copy view properties (ViewProperties is specific to db so we need to copy # like this instead of just using load/save_view_properties in db). from_vp = ViewProperties() from_db.load_view_properties(from_vp) to_vp = ViewProperties() for from_cat in from_db.get_categories(): cat = cat_map[from_cat.name] visible = from_vp.is_category_visible(from_cat) to_vp.set_category_visible(cat, visible) if from_vp.displayed_period is not None: # start_time and end_time immutable so safe to copy start = from_vp.displayed_period.start_time end = from_vp.displayed_period.end_time to_vp.displayed_period = TimePeriod(to_db.get_time_type(), start, end) to_db.save_view_properties(to_vp) # Save if isinstance(to_db, MemoryDB): to_db.enable_save()
def _create_db(self): db = XmlTimeline(self.tmp_path) # Create categories cat1 = Category("Category 1", (255, 0, 0), (0, 0, 255), True) db.save_category(cat1) cat2 = Category("Category 2", (0, 255, 0), None, True, parent=cat1) db.save_category(cat2) cat3 = Category("Category 3", (0, 0, 255), None, True, parent=cat2) db.save_category(cat3) # Create events ev1 = Event(db.get_time_type(), datetime(2010, 3, 3), datetime(2010, 3, 6), "Event 1", cat1) ev1.set_data("description", u"The <b>first</b> event åäö.") ev1.set_data("alert", (datetime(2012, 12, 31), "Time to go")) db.save_event(ev1) # Create view properties vp = ViewProperties() start = datetime(2010, 3, 1) end = datetime(2010, 4, 1) vp.displayed_period = TimePeriod(db.get_time_type(), start, end) vp.set_category_visible(cat3, False) db.save_view_properties(vp)
def _parse_category(self, text, tmp_dict): name = tmp_dict.pop("tmp_name") color = parse_color(tmp_dict.pop("tmp_color")) font_color = self._parse_optional_color(tmp_dict, "tmp_font_color") parent_name = tmp_dict.pop("tmp_parent", None) if parent_name: parent = tmp_dict["category_map"].get(parent_name, None) if parent is None: raise ParseException("Parent category '%s' not found." % parent_name) else: parent = None category = Category(name, color, font_color, True, parent=parent) old_category = self._get_category_by_name(category) if old_category is not None: category = old_category if not tmp_dict["category_map"].has_key(name): tmp_dict["category_map"][name] = category self.save_category(category)
def an_event_with(start=None, end=None, time=ANY_TIME, text="foo", fuzzy=False, locked=False, ends_today=False): if start and end: start = human_time_to_py(start) end = human_time_to_py(end) else: start = human_time_to_py(time) end = human_time_to_py(time) return Event(PyTimeType(), start, end, text, Category("bar", None, None, True), fuzzy=fuzzy, locked=locked, ends_today=ends_today)
def testNameAndCategoryCanBeUpdated(self): self.given_default_container() new_name = "new text" new_category = Category("cat", (255, 0, 0), (255, 0, 0), True) self.container.update_properties(new_name, new_category) self.assertEqual(new_category, self.container.category)
def setUp(self): self.c1 = Category("c1", (255, 0, 0), None, True, parent=None) self.c11 = Category("c11", (255, 0, 0), None, True, parent=self.c1) self.c2 = Category("c2", (255, 0, 0), None, True, parent=None)
def category_named(self, name): return Category(name, (0, 0, 0), None, True)