예제 #1
0
    def test_OrderedSiblingsListNormal(self):
        """
			test that the tree works if the walk is done parents last.
		"""
        graph = NestedTree()
        (leaf_node, end_node) = self.build_simple_tree(graph)

        # paint the tree.
        painted_list = graph.walkTree(self.all_nodes_level_function,
                                      NestedTreeNode.TREE_WALK_NORMAL)

        # we are only using the next function for this rest.
        for item in painted_list:
            found = graph.child_node.findItemWithColour(
                item[2], NestedTreeNode.TREE_WALK_NORMAL, True)
            self.assertIsNotNone(found)
            self.assertEqual(found.payload, item[1])
            self.assertEqual(found.colour, item[2])

        # paint the tree.
        painted_list = graph.walkTree(self.all_nodes_level_function,
                                      NestedTreeNode.TREE_WALK_PARENTS_FIRST)

        # we are only using the next function for this rest.
        for item in painted_list:
            found = graph.walkTree(self.find_colours_function,
                                   NestedTreeNode.TREE_WALK_PARENTS_FIRST,
                                   item[2])
            self.assertIsNotNone(found)
            self.assertEqual(found.payload, item[1])
            self.assertEqual(found.colour, item[2])
예제 #2
0
    def test_5NodeWalk(self):
        """ 5 Node Walk - with insert before.

			This test adds three nodes in a row to see if the graph code works
			it also inserts two more nodes before node 2 and node 3.

			It then will walk the tree to see if the it finds all the nodes.
		"""
        node1 = NestedTreeNode(1)
        node2 = NestedTreeNode(2)
        node3 = NestedTreeNode(3)
        node4 = NestedTreeNode(4)
        node5 = NestedTreeNode(5)

        graph = NestedTree()

        # insert the three nodes
        graph.addNodeAfter(node1)
        node1.addNodeAfter(node2)
        node2.addNodeAfter(node3)

        # now insert the two extra nodes
        node2.addNodeBefore(node4)
        node3.addNodeBefore(node5)

        # we are only using the next function for this rest.
        count = 0
        count = graph.walkTree(self.count_function)
        self.assertTrue(count == 5)
예제 #3
0
    def test_TraceSimpleTree(self):
        """ Trace A Simple Tree

			The simple tree is used for this test.
			It should be a walk this tree and return the nodes in the correct order.
		"""
        graph = NestedTree()

        # now build the tree
        self.build_simple_tree(graph)

        # we are only using the next function for this rest.
        value = graph.walkTree(self.collect_function)
        self.assertTrue(value == list(range(1, 19)))
예제 #4
0
	def __init__(self):
		self.name				= 'Project'
		self.filename			= None
		self.start_time			= int((time.mktime(time.gmtime()) / (60 * 60 * 24))) * (60 * 60 * 24)	# now
		self.days_per_week 		= 5									# 5 days
		self.minutes_per_day	= 450								# 7.5 hours
		self.first_day_of_week	= 0									# Monday
		self.last_task_id		= 0									# task_id's start at 1
		self.tasks				= {}								# dictionary of tasks

		self.plan_tree			= NestedTree()						# Create the node tree

		self.calcuateTheWeek()

		self.initialised		= False								# project plan state
예제 #5
0
    def test_ParentsLasttTest(self):
        """
			test that the tree works if the walk is done parents last.
		"""
        graph = NestedTree()
        self.build_simple_tree(graph)

        # we are only using the next function for this rest.
        value = graph.walkTree(self.all_nodes_level_function,
                               NestedTreeNode.TREE_WALK_PARENTS_LAST)

        self.assertEqual(value, [(1, 1, 1), (1, 17, 2), (1, 18, 3), (1, 2, 4),
                                 (2, 3, 5), (2, 4, 6), (2, 9, 7), (2, 10, 8),
                                 (2, 5, 9), (3, 6, 10), (3, 7, 11), (3, 8, 12),
                                 (1, 11, 13), (2, 12, 14), (2, 13, 15),
                                 (2, 14, 16), (2, 15, 17), (2, 16, 18)])
예제 #6
0
    def test_SingleChildNode(self):
        """ Single Child Node with Walk.

			This test will add a single child node.

			It then will walk the tree to see if the it finds all the nodes.
		"""
        node1 = NestedTreeNode(1)
        graph = NestedTree()

        # insert the child node
        graph.addChildNode(node1)

        # we are only using the next function for this rest.
        count = 0
        count = graph.walkTree(self.count_function)
        self.assertTrue(count == 1)
예제 #7
0
    def test_ParentsFirstTest(self):
        """
			test that the tree works if the walk is done parents first.
		"""
        graph = NestedTree()
        self.build_simple_tree(graph)

        # we are only using the next function for this rest.
        value = graph.walkTree(self.all_nodes_level_function,
                               NestedTreeNode.TREE_WALK_PARENTS_FIRST)

        # Has the order been returned correctly.
        self.assertEqual(value, [(1, 2, 1), (2, 5, 2), (3, 6, 3), (3, 7, 4),
                                 (3, 8, 5), (2, 3, 6), (2, 4, 7), (2, 9, 8),
                                 (2, 10, 9), (1, 11, 10), (2, 12, 11),
                                 (2, 13, 12), (2, 14, 13), (2, 15, 14),
                                 (2, 16, 15), (1, 1, 16), (1, 17, 17),
                                 (1, 18, 18), (0, None, 19)])
예제 #8
0
    def test_addNodes(self):
        """ Add Nodes.

			This test adds three nodes in a row to see if the graph code works.
			This is an exploding test to see if the code works.
		"""
        node1 = NestedTreeNode(1)
        node2 = NestedTreeNode(2)
        node3 = NestedTreeNode(3)

        graph = NestedTree()

        graph.addNodeAfter(node1)
        node1.addNodeAfter(node2)
        node2.addNodeAfter(node3)

        self.assertTrue(graph.hasSibling())
        self.assertTrue(node1.hasSibling())
        self.assertTrue(node2.hasSibling())
예제 #9
0
    def test_createTree(self):
        """ Create Object Test

			This is a simple test that checks that the tree object can be created
			correctly.

			This is an exploding tests, to see if the code functions.`
		"""
        graph = NestedTree()
        self.assertTrue(True)
예제 #10
0
    def test_3NodeWalk(self):
        """ 3 Node Walk.

			This test adds three nodes in a row to see if the graph code works.

			It then will walk the tree to see if the it finds all the nodes.
		"""
        node1 = NestedTreeNode(1)
        node2 = NestedTreeNode(2)
        node3 = NestedTreeNode(3)

        graph = NestedTree()

        graph.addNodeAfter(node1)
        node1.addNodeAfter(node2)
        node2.addNodeAfter(node3)

        # we are only using the next function for this rest.
        count = 0
        count = graph.walkTree(self.count_function)
        self.assertTrue(count == 3)
예제 #11
0
    def test_OrderedSiblingsListFirst(self):
        graph = NestedTree()
        (leaf_node, end_node) = self.build_simple_tree(graph)
        leaf_node.addChildNode(NestedTreeNode(98))
        leaf_node.addChildNode(NestedTreeNode(99))

        leaf_node.setLeaf(True)

        # paint the tree - now with it's new leafy-ness
        painted_list = graph.walkTree(self.all_nodes_level_function,
                                      NestedTreeNode.TREE_WALK_PARENTS_FIRST)

        # we are only using the next function for this rest.
        for item in painted_list:
            found = graph.findItemWithColour(
                item[2], NestedTreeNode.TREE_WALK_PARENTS_FIRST, True)
            self.assertIsNotNone(found)
            self.assertEqual(found.payload, item[1])
            self.assertEqual(found.colour, item[2])

        next_node = leaf_node.next_node
        next_node.addChildNode(NestedTreeNode(108))
        next_node.addChildNode(NestedTreeNode(109))
        next_node.setLeaf(True)

        end_node.setLeaf(True)
        end_node.addChildNode(NestedTreeNode(209))
        end_node.addChildNode(NestedTreeNode(210))
        end_node.addChildNode(NestedTreeNode(211))

        # paint the tree - now with it's new leafy-ness
        painted_list = graph.walkTree(self.all_nodes_level_function,
                                      NestedTreeNode.TREE_WALK_PARENTS_FIRST)

        # we are only using the next function for this rest.
        for item in painted_list:
            found = graph.findItemWithColour(
                item[2], NestedTreeNode.TREE_WALK_PARENTS_FIRST, True)
            self.assertIsNotNone(found)
            self.assertEqual(found.payload, item[1])
            self.assertEqual(found.colour, item[2])
예제 #12
0
    def build_tree(self, use_id=True, mark_no_walk=False):
        """
			This function will create the following tree:

			{} this indicate sub-tree nodes that have been created.

			[root]
             |
             v
			[1] -> [2] -> [24] -> [40] -> [41] -> [42] -> [43] -> [44] -> [46]
                    |      |                                       |       |
					|      v                                       v       v
					|     {25} -> [26] -> [27] -> [28] -> [29]    [45]    [47] -> [48]
                    |      |
					|      v
					|     {30} -> [31] -> [32] -> [33] -> [34]
                    |      |
					|      v
					|     {35} -> [36] -> [37] -> [38] -> [39]
					|
					v
				   {3} -> [4] -> [5] -> [12] -> [13] -> [14] -> [15] -> [22] -> [23]
                                  |                              |
								  v                              v
                                 {6} -> [7] -> [8]              {16} -> [17] -> [18]
                                  |                              |
								  v                              v
                                 {9} -> [10] -> [11]            {19} -> [20] -> [21]

			It should be a walk this tree and return the nodes in the correct order.

			If no walk is set, then nodes 3,15,34,41 and 46 a marked as no walk, so that
			only the nodes 16-21 and 47,48 will be skipped as they are no walkers.
		"""
        graph = NestedTree()

        # create the nodes
        nodes = []

        if (use_id):
            for i in range(49):
                nodes.append(NestedTreeNode(i))
        else:
            nodes.append(NestedTreeNode(TestPayload(True)))
            for i in range(1, 49):
                nodes.append(NestedTreeNode(TestPayload()))

        #	[1] -> [2] -> [24] -> [40] -> [41] -> [42] -> [43] -> [44] -> [46]
        graph.addChildNode(nodes[1])
        nodes[1].addNodeAfter(nodes[2])
        nodes[2].addNodeAfter(nodes[24])
        nodes[24].addNodeAfter(nodes[40])
        nodes[40].addNodeAfter(nodes[41])
        nodes[41].addNodeAfter(nodes[42])
        nodes[42].addNodeAfter(nodes[43])
        nodes[43].addNodeAfter(nodes[44])
        nodes[44].addNodeAfter(nodes[46])

        # [25] -> [26] -> [27] -> [28] -> [29]
        nodes[24].addSubTreeNode(nodes[25])
        nodes[25].addNodeAfter(nodes[26])
        nodes[26].addNodeAfter(nodes[27])
        nodes[27].addNodeAfter(nodes[28])
        nodes[28].addNodeAfter(nodes[29])

        # subgraph of 24 - added from 24
        # [30] -> [31] -> [32] -> [33] -> [34]
        nodes[24].addSubTreeNode(nodes[30])
        nodes[30].addNodeAfter(nodes[31])
        nodes[31].addNodeAfter(nodes[32])
        nodes[32].addNodeAfter(nodes[33])
        nodes[33].addNodeAfter(nodes[34])

        # subtree of 24 - added from 24
        # [35] -> [36] -> [37] -> [38] -> [39]
        nodes[24].addSubTreeNode(nodes[35])
        nodes[35].addNodeAfter(nodes[36])
        nodes[36].addNodeAfter(nodes[37])
        nodes[37].addNodeAfter(nodes[38])
        nodes[38].addNodeAfter(nodes[39])

        # child of 44 - single
        nodes[44].addChildNode(nodes[45])

        # child of 46 - pair and end tree on an up.
        nodes[46].addChildNode(nodes[47])
        nodes[47].addNodeAfter(nodes[48])

        # subtree of 2
        #  [3] -> [4] -> [5] -> [12] -> [13] -> [14] -> [15] -> [22] -> [23]
        nodes[2].addSubTreeNode(nodes[3])
        nodes[3].addNodeAfter(nodes[4])
        nodes[4].addNodeAfter(nodes[5])
        nodes[5].addNodeAfter(nodes[12])
        nodes[12].addNodeAfter(nodes[13])
        nodes[13].addNodeAfter(nodes[14])
        nodes[14].addNodeAfter(nodes[15])
        nodes[15].addNodeAfter(nodes[22])
        nodes[22].addNodeAfter(nodes[23])

        # subtree of 5
        # [6] -> [7] -> [8]
        nodes[5].addSubTreeNode(nodes[6])
        nodes[6].addNodeAfter(nodes[7])
        nodes[7].addNodeAfter(nodes[8])

        # subtree of 5
        # [9] -> [10] -> [11]
        nodes[5].addSubTreeNode(nodes[9])
        nodes[9].addNodeAfter(nodes[10])
        nodes[10].addNodeAfter(nodes[11])

        # subtree of 15
        # [16] -> [17] -> [18]
        nodes[15].addSubTreeNode(nodes[16])
        nodes[16].addNodeAfter(nodes[17])
        nodes[17].addNodeAfter(nodes[18])

        # subtree of 15
        # [19] -> [20] -> [21]
        nodes[15].addSubTreeNode(nodes[19])
        nodes[19].addNodeAfter(nodes[20])
        nodes[20].addNodeAfter(nodes[21])

        # Ok, need to make a couple of nodes as no-walk nodes to test that the
        # short walk code works.
        # So 3, 15, 34, and 41 as this are all different in the tree and should prove that
        # the code works.
        if not use_id and mark_no_walk:
            nodes[3].payload.no_walk = True
            nodes[15].payload.no_walk = True
            nodes[34].payload.no_walk = True
            nodes[41].payload.no_walk = True
            nodes[46].payload.no_walk = True

        return graph
예제 #13
0
    def test_ChildNodeInsertionDecending(self):
        """
			This tests that the child node insertions work as expected.
			It will also check to see if they can be walked as expected.
		"""
        # test descending insertion - empty list
        graph = NestedTree()
        graph.addChildNode(NestedTreeNode(1), NestedTreeNode.INSERT_DESCENDING)
        graph.addChildNode(NestedTreeNode(4), NestedTreeNode.INSERT_DESCENDING)
        graph.addChildNode(NestedTreeNode(5), NestedTreeNode.INSERT_DESCENDING)
        graph.addChildNode(NestedTreeNode(6), NestedTreeNode.INSERT_DESCENDING)
        graph.addChildNode(NestedTreeNode(7), NestedTreeNode.INSERT_DESCENDING)
        graph.addChildNode(NestedTreeNode(3), NestedTreeNode.INSERT_DESCENDING)
        graph.addChildNode(NestedTreeNode(8), NestedTreeNode.INSERT_DESCENDING)
        graph.addChildNode(NestedTreeNode(2), NestedTreeNode.INSERT_DESCENDING)
        graph.addChildNode(NestedTreeNode(5), NestedTreeNode.INSERT_DESCENDING)
        self.assertEqual(graph.walkTree(self.all_nodes_function),
                         [8, 7, 6, 5, 5, 4, 3, 2, 1],
                         "Basic descending insert")

        # test normal insertion - empty list
        nodes = []
        nodes.append(NestedTreeNode(TestPayload(True)))
        for i in range(1, 10):
            nodes.append(NestedTreeNode(TestPayload()))

        graph = NestedTree()
        graph.addChildNode(nodes[1], NestedTreeNode.INSERT_DESCENDING)
        graph.addChildNode(nodes[4], NestedTreeNode.INSERT_DESCENDING)
        graph.addChildNode(nodes[5], NestedTreeNode.INSERT_DESCENDING)
        graph.addChildNode(nodes[6], NestedTreeNode.INSERT_DESCENDING)
        graph.addChildNode(nodes[7], NestedTreeNode.INSERT_DESCENDING)
        graph.addChildNode(nodes[3], NestedTreeNode.INSERT_DESCENDING)
        graph.addChildNode(nodes[8], NestedTreeNode.INSERT_DESCENDING)
        graph.addChildNode(nodes[2], NestedTreeNode.INSERT_DESCENDING)
        graph.addChildNode(nodes[5], NestedTreeNode.INSERT_DESCENDING)

        nodes[7].addChildNode(nodes[9])

        self.assertEqual((1, [(1, 8, 2), (1, 7, 3), (2, 9, 2), (1, 6, 1),
                              (1, 5, 3), (1, 4, 3), (1, 3, 3), (1, 2, 3),
                              (1, 1, 3)]),
                         graph.walkTree(self.levels_function))
예제 #14
0
    def test_OrderedSiblingsListLast(self):
        graph = NestedTree()
        (leaf_node, end_node) = self.build_simple_tree(graph)

        leaf_node.addChildNode(NestedTreeNode(98))
        leaf_node.addChildNode(NestedTreeNode(99))

        # paint the tree.
        painted_list = graph.walkTree(self.all_nodes_level_function,
                                      NestedTreeNode.TREE_WALK_PARENTS_LAST)
        for item in painted_list:
            found = graph.findItemWithColour(
                item[2], NestedTreeNode.TREE_WALK_PARENTS_LAST, True)
            self.assertIsNotNone(found)
            self.assertEqual(found.payload, item[1])
            self.assertEqual(found.colour, item[2])

        # corner case graphs
        nodes = []

        for count in range(1, 6):
            nodes.append(NestedTreeNode(count))

        graph = NestedTree()

        # the empty graph.
        found = graph.findItemWithColour(1, NestedTreeNode.TREE_WALK_NORMAL,
                                         True)
        self.assertIsNone(found)
        found = graph.findItemWithColour(
            1, NestedTreeNode.TREE_WALK_PARENTS_FIRST, True)
        self.assertIsNone(found)
        found = graph.findItemWithColour(1,
                                         NestedTreeNode.TREE_WALK_PARENTS_LAST,
                                         True)
        self.assertIsNone(found)

        # single node
        graph.addNodeAfter(nodes[1])
        # unpainted
        found = graph.findItemWithColour(1, NestedTreeNode.TREE_WALK_NORMAL,
                                         True)
        self.assertIsNone(found)
        found = graph.findItemWithColour(
            1, NestedTreeNode.TREE_WALK_PARENTS_FIRST, True)
        self.assertIsNone(found)
        found = graph.findItemWithColour(1,
                                         NestedTreeNode.TREE_WALK_PARENTS_LAST,
                                         True)
        self.assertIsNone(found)

        # painted
        nodes[1].colour = 1
        found = graph.findItemWithColour(1, NestedTreeNode.TREE_WALK_NORMAL,
                                         True)
        self.assertIsNotNone(found)
        found = graph.findItemWithColour(
            1, NestedTreeNode.TREE_WALK_PARENTS_FIRST, True)
        self.assertIsNotNone(found)
        found = graph.findItemWithColour(1,
                                         NestedTreeNode.TREE_WALK_PARENTS_LAST,
                                         True)
        self.assertIsNotNone(found)

        # One child - only need to test painted.
        graph = NestedTree()
        graph.colour = 99  # colour the route or it won't search down.
        graph.addChildNode(nodes[1])
        found = graph.findItemWithColour(1, NestedTreeNode.TREE_WALK_NORMAL,
                                         True)
        self.assertIsNotNone(found)
        found = graph.findItemWithColour(
            1, NestedTreeNode.TREE_WALK_PARENTS_FIRST, True)
        self.assertIsNotNone(found)
        found = graph.findItemWithColour(1,
                                         NestedTreeNode.TREE_WALK_PARENTS_LAST,
                                         True)
        self.assertIsNotNone(found)

        graph.addChildNode(nodes[2])
        graph.addChildNode(nodes[3])

        painted_list = graph.walkTree(self.all_nodes_level_function,
                                      NestedTreeNode.TREE_WALK_NORMAL)
        for item in range(1, 4):
            found = graph.findItemWithColour(item,
                                             NestedTreeNode.TREE_WALK_NORMAL,
                                             True)
            self.assertIsNotNone(found)

        painted_list = graph.walkTree(self.all_nodes_level_function,
                                      NestedTreeNode.TREE_WALK_PARENTS_FIRST)
        for item in range(1, 4):
            found = graph.findItemWithColour(
                1, NestedTreeNode.TREE_WALK_PARENTS_FIRST, True)
            self.assertIsNotNone(found)

        painted_list = graph.walkTree(self.all_nodes_level_function,
                                      NestedTreeNode.TREE_WALK_PARENTS_LAST)
        for item in range(1, 4):
            found = graph.findItemWithColour(
                1, NestedTreeNode.TREE_WALK_PARENTS_FIRST, True)
            self.assertIsNotNone(found)
예제 #15
0
    def test_ChildNodeInsertion(self):
        """
			This tests that the child node insertions work as expected.
			It will also check to see if they can be walked as expected.
		"""
        # test normal insertion - empty list
        graph = NestedTree()
        graph.addChildNode(NestedTreeNode(1))
        self.assertEqual(graph.walkTree(self.all_nodes_function), [1],
                         "Basic insert failed")

        # test normal insertion - empty list - this is the same as above as is the default
        graph = NestedTree()
        graph.addChildNode(NestedTreeNode(1), NestedTreeNode.INSERT_END)
        graph.addChildNode(NestedTreeNode(2), NestedTreeNode.INSERT_END)
        graph.addChildNode(NestedTreeNode(3), NestedTreeNode.INSERT_END)
        self.assertEqual(graph.walkTree(self.all_nodes_function), [1, 2, 3],
                         "Basic append insert")

        # test front insertion - empty list
        graph = NestedTree()
        graph.addChildNode(NestedTreeNode(3), NestedTreeNode.INSERT_FRONT)
        graph.addChildNode(NestedTreeNode(2), NestedTreeNode.INSERT_FRONT)
        graph.addChildNode(NestedTreeNode(1), NestedTreeNode.INSERT_FRONT)
        self.assertEqual(graph.walkTree(self.all_nodes_function), [1, 2, 3],
                         "Basic in front insert")

        # test ascending insertion - empty list
        graph = NestedTree()
        graph.addChildNode(NestedTreeNode(8), NestedTreeNode.INSERT_ASCENDING)
        graph.addChildNode(NestedTreeNode(2), NestedTreeNode.INSERT_ASCENDING)
        graph.addChildNode(NestedTreeNode(3), NestedTreeNode.INSERT_ASCENDING)
        graph.addChildNode(NestedTreeNode(7), NestedTreeNode.INSERT_ASCENDING)
        graph.addChildNode(NestedTreeNode(6), NestedTreeNode.INSERT_ASCENDING)
        graph.addChildNode(NestedTreeNode(5), NestedTreeNode.INSERT_ASCENDING)
        graph.addChildNode(NestedTreeNode(1), NestedTreeNode.INSERT_ASCENDING)
        graph.addChildNode(NestedTreeNode(4), NestedTreeNode.INSERT_ASCENDING)
        graph.addChildNode(NestedTreeNode(5), NestedTreeNode.INSERT_ASCENDING)
        self.assertEqual(graph.walkTree(self.all_nodes_function),
                         [1, 2, 3, 4, 5, 5, 6, 7, 8], "Basic in front insert")
예제 #16
0
    def test_MakeTree(self):
        """ Make Tree

			The test checks that makeSubTree function works.

			So the following tree:

				[1] -> [2] -> [3] -> [7] -> [8] -> [9] -> [10] -> [11] -> [12]
			                   |
							  {4} -> [5] -> [6]

			can be turned into:

				[1] -> [2] -> [3]
				               |
							  {4} -> [5] -> [6]
							   |
							  {7} -> [8] -> [9]
	 						                 |
							                {10}-> [11] -> [12]

			by calling sub-tree on (3), (9) in that order.

			Then add a new subTree:

				[1] -> [2] -> [3]
				               |
							  {4} -> [5] -> [6]
							   |
							  {7} -> [8] -> [9]
	 						   |             |
							   |            {10}-> [11] -> [12]
                               |
		                      {13} -> [14] -> [15]

			By adding a subTree to (3), this will prove it works. Also doing a
			next walk on (3).
		"""
        graph = NestedTree()

        # create the nodes
        nodes = []

        for i in range(16):
            nodes.append(NestedTreeNode(i))

        graph.addChildNode(nodes[1])
        graph.addChildNode(nodes[2])
        graph.addChildNode(nodes[3])
        graph.addChildNode(nodes[7])
        graph.addChildNode(nodes[8])
        graph.addChildNode(nodes[9])
        graph.addChildNode(nodes[10])
        graph.addChildNode(nodes[11])
        graph.addChildNode(nodes[12])

        nodes[3].addChildNode(nodes[4])
        nodes[4].addNodeAfter(nodes[5])
        nodes[5].addNodeAfter(nodes[6])
        self.assertEqual(graph.walkTree(self.collect_function),
                         list(range(1, 13)))
        self.assertEqual(graph.walkTree(self.plain_levels_function),
                         (2, [(1, 1), (1, 2), (1, 3), (2, 4), (2, 5), (2, 6),
                              (1, 7), (1, 8), (1, 9), (1, 10), (1, 11),
                              (1, 12)]))

        # Subtrees don't make sense unless the whole tree are subtrees.

        # ok, let's let makeSubTree do it's thing.
        #		self.assertTrue(graph.makeSubTree(nodes[3]))
        #		self.assertTrue(graph.makeSubTree(nodes[9]))
        #		self.assertEqual(graph.walkTree(self.collect_function), range(1, 13))
        #		self.assertEqual(graph.walkTree(self.plain_levels_function), (5, [(1, 1), (1, 2), (1, 3), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (5, 10), (5, 11), (5, 12)]))

        # ok, add the new sub-tree
        nodes[12].addSubTreeNode(nodes[13])
        nodes[13].addNodeAfter(nodes[14])
        nodes[14].addNodeAfter(nodes[15])

        # walk the tree
        value = graph.walkTree(self.collect_function)

        # now check the ordering is correct
        self.assertEqual(value, list(range(1, 16)))

        # check the shape of the tree
        #self.assertFalse(nodes[3].hasSibling())
        self.assertFalse(nodes[6].hasSibling())
        self.assertFalse(nodes[12].hasSibling())

        self.assertTrue(nodes[3].hasChild())
        self.assertTrue(nodes[12].hasChild())
예제 #17
0
class ProjectPlan:

	# file states
	OPEN_READING_STATE		= 1
	LOAD_PROJECT_STATE		= 2
	LOAD_TASK_STATE			= 3

	""" Project Plan Class

		This class controls the project plan files.
	"""
	def __init__(self):
		self.name				= 'Project'
		self.filename			= None
		self.start_time			= int((time.mktime(time.gmtime()) / (60 * 60 * 24))) * (60 * 60 * 24)	# now
		self.days_per_week 		= 5									# 5 days
		self.minutes_per_day	= 450								# 7.5 hours
		self.first_day_of_week	= 0									# Monday
		self.last_task_id		= 0									# task_id's start at 1
		self.tasks				= {}								# dictionary of tasks

		self.plan_tree			= NestedTree()						# Create the node tree

		self.calcuateTheWeek()

		self.initialised		= False								# project plan state

	def calcuateTheWeek(self):
		""" Calculate the Week.

			This function adjusts the week arrays that are used to help with correcting the time.
		"""
		# create the week structures
		self.day_of_week		= [0,0,0,0,0,0,0]
		self.days_to_week		= [0,0,0,0,0,0,0]
		self.weekend			= [0,0,0,0,0,0,0]

		for index in range(7):
			self.day_of_week[index] = ((index + 7) - self.first_day_of_week) % 7

			if self.day_of_week[index] >= self.days_per_week:
				self.day_of_week[index] = 0
				self.days_to_week[index] = (7 - index + self.first_day_of_week) % 7
				self.weekend[index] = 1

	def calculate_dates_function(self,last_visted_node,node,value,levels,direction,parameter):
		""" This is a function that is used to calculate the start and end times of the
			items in the tree.
		"""
		if direction == NestedTree.DIRECTION_DOWN and not node.is_sub_node:
			prev_payload = node.getPrevPayload()

			if prev_payload is None:
				node.payload.start = self.calculateStartTime(self.start_time)
				node.payload.end   = self.calculateEndTimes(node.payload.start,node.payload.duration)
			else:
				node.payload.start = self.calculateStartTime(prev_payload.start)
				node.payload.end   = self.calculateEndTimes(node.payload.start,node.payload.duration)

		elif direction == NestedTree.DIRECTION_NEXT:
			prev_payload = node.getPrevPayload()
			node.payload.start = self.calculateStartTime(prev_payload.end)
			node.payload.end   = self.calculateEndTimes(node.payload.start,node.payload.duration)

		elif direction == NestedTree.DIRECTION_UP:
			prev_payload = node.getPrevPayload()

			# set the previous end
			if prev_payload.end < last_visted_node.payload.end:
				prev_payload.end = self.calculateStartTime(last_visted_node.payload.end)

			if not node.is_sub_node:
				# now set the current nodes start and end (and the previous end)
				# have stepped up a level
				node.payload.start = self.calculateStartTime(last_visted_node.payload.end)
				node.payload.end   = self.calculateEndTimes(node.payload.start,node.payload.duration)

		return (node,1,False)

	def createProject(self,project_name,project_file):
		""" Create Project File.

			This function will create new project file. It will write the default
			settings to the file.
		"""
		if self.initialised:
			result = False

		elif project_name == None or project_name == '':
			result = False

		elif project_file == None or project_file == '':
			result = False
		else:
			self.name     = project_name
			self.filename = project_file

			result = self.saveProject()

		self.initialised = result

		return result

	def reDateTree(self):
		""" Re-Calculate The Task Dates

			This function will re-calculate the dates for the items in the tree.
			This function should be called after any task (or group of tasks) have
			the duration amended, or a task has been added or removed.
		"""
		# set the start and endtimes of the tasks
		value = self.plan_tree.walkTree(self.calculate_dates_function)

	def loadProject(self,project_name,project_file):
		""" Load the Project Plan

			loadProject(<project_name>,<filename>) -> Boolean

			This function will load the project plan into the class. If the file
			does not exist then it will create an empty project plan.

			This function can only called once and any subsequent calls will fail.
		"""
		if self.initialised:
			result = False

		elif project_name == None or project_name == '':
			result = False

		elif project_file == None or project_file == '':
			result = False
		else:
			self.name     = project_name
			self.filename = project_file

			try:
				# now open the project file
				proj_file = open(self.filename,'r')

				state = ProjectPlan.OPEN_READING_STATE
				result = True

				for line in proj_file:
					if line[0:1] == '[':
						# It's a section header, is it correct
						if line[1:-2] == "project":
							if state != ProjectPlan.OPEN_READING_STATE:
								self.error_string = "bad file format - [project] found in wrong place"
								result = False
							else:
								state = ProjectPlan.LOAD_PROJECT_STATE

						elif line[1:-2] == "tasks":
							if state != ProjectPlan.LOAD_PROJECT_STATE:
								self.error_string = "bad file format - [tasks] found in wrong place"
								result = False
							else:
								state = ProjectPlan.LOAD_TASK_STATE

						else:
							self.error_string = "bad file format - unknown [%s] found in project file" % (line[1:-2])
							result = False

					else:
						if state == ProjectPlan.LOAD_PROJECT_STATE:
							parts = line.partition(" = ")

							if parts[0] == 'name':
								self.name = parts[2]

							elif parts[0] == 'starttime':
								self.start_time = int(parts[2])

							elif parts[0] == 'daysperweek':
								self.days_per_week = int(parts[2])

							elif parts[0] == 'minutesperday':
								self.minutes_per_day = int(parts[2])

							elif parts[0] == 'firstdayofweek':
								self.first_day_of_week = int(parts[2])

						elif state == ProjectPlan.LOAD_TASK_STATE:
							parts = line.partition(" = ")
							t_bits = parts[2].rstrip('\n').split(',')

							if len(t_bits) == 6:
								result = self.AddTask(int(parts[0][4:]),t_bits[0],t_bits[1],t_bits[2],t_bits[3],t_bits[4],int(t_bits[5]))
							else:
								result = False
								break

				# now update the week values
				self.calcuateTheWeek()

				# now calculate the start/end times
				self.reDateTree()

			except IOError:
				result = False

			self.initialised = result
			return result


	def AddTask(self,task_id,task_type,duration,status,name,description,follows_task):
		""" Add Task

			This function will add a task to the project plan.
			If the job number is None, then the function will create a new job and add it into the part of the
			tree specified by the parameters.
		"""
		result = False

		# Use the given Id or add a new one.
		if task_id is None:
			self.last_task_id = self.last_task_id + 1
			task_id = self.last_task_id
		else:
			task_id = task_id

			if task_id > self.last_task_id:
				self.last_task_id = task_id

		if task_id not in self.tasks:
			self.tasks[task_id] = ProjectTask(task_id,task_type,duration,status,name,description,follows_task)

			if follows_task == 0 or follows_task is None:
				self.plan_tree.addChildNode(self.tasks[task_id].node)

			elif task_type == 'task':
				self.tasks[follows_task].node.addNodeAfter(self.tasks[task_id].node)

			elif task_type == 'sub_task':
				self.tasks[follows_task].node.addSubTreeNode(self.tasks[task_id].node)

			result = True

		return result

	def calculateEndTimes(self,start_time,duration):
		""" Calculate End Time.

			This function takes a task and calculates it's endtime from the duration. It will
			take into account the weekend and day lengths of the project to calculate this
			value.
		"""
		# how many weeks does the task take.
		weeks = (duration / self.minutes_per_day) / self.days_per_week
		remain_days = (duration / self.minutes_per_day) - (weeks * self.days_per_week)
		remains = duration - (((weeks * self.days_per_week) + remain_days) * self.minutes_per_day)

		# calculate end time
		end_time  = start_time + (((((weeks * 7) + remain_days) * (60 * 24)) + remains) * 60)

		return end_time

	def calculateStartTime(self,start_time):
		""" Calculate Start Time.

			This function will take in a start time and adjust it to fit the working week. If
			the start time falls outside of the working day, or falls onto the weekend then the
			date will be moved onto the next working day.
		"""
		remains_of_the_day = start_time % (60 * 60 * 24)
		days = remains_of_the_day / (self.minutes_per_day * 60)

		# did the day rollover?
		start_time = start_time + (days * 60 * 60 * 24)  - (days * self.minutes_per_day * 60)

		# in the weekend?
		weekend_adjustment = self.days_to_week[time.gmtime(start_time).tm_wday] * (60 * 60 * 24)
		start_time = start_time + weekend_adjustment

		return start_time

	def saveProject(self):
		""" This function saves the current project.

			This function saves the project header, then dumps all the tasks in the
			list and there connections.
		"""
		try:
			proj_file = open(self.filename,'w')

			# write the header
			header = []
			header.append('[project]\n')

			ini_format = "%s = %s\n"

			header.append(ini_format % ('name',self.name))
			header.append(ini_format % ('starttime',self.start_time))
			header.append(ini_format % ('daysperweek',self.days_per_week))
			header.append(ini_format % ('minutesperday',self.minutes_per_day))
			header.append(ini_format % ('firstdayofweek',self.first_day_of_week))
			header.append('[tasks]\n')

			# write the header
			proj_file.writelines(header)

			for task in self.tasks:
				proj_file.write(self.tasks[task].toFileString())

			# write the footer and close the file
			proj_file.close()
			result = True

		except IOError:
			result = False

		return result

	def getProjectList(self,node):
		""" This function will generate a list of the project tasks.

			If the project tasks has sub-tasks then these will be listed as sub-lists.
		"""

		listing = []

		for item in node.getChildren():
			if item.hasChild():
				children = item.getChildren()
				item_list = []

				for c_list in children:
					sub_list = []

					if type(c_list) == list:
						for child in c_list:
							l_list = child.getChildren()
							sub_list.append((child,0,l_list))
					else:
						sub_list.append((c_list,0,c_list.getChildren()))

					item_list.append(sub_list)

				listing.append((item,0,item_list))

			else:
				listing.append((item,0,[]))

		return listing