changeset 12:2ccae1e872e9

Initial checkin for project trees. !!!Work in progress!!!
author Sascha L. Teichmann <teichmann@intevation.de>
date Mon, 11 Aug 2008 01:12:47 +0200
parents feb6bb4427fe
children e347f0de5e22
files ChangeLog getan
diffstat 2 files changed, 119 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Aug 04 12:32:46 2008 +0200
+++ b/ChangeLog	Mon Aug 11 01:12:47 2008 +0200
@@ -1,3 +1,24 @@
+2008-08-11	Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+	* getan: !!! Work in progress !!! Project Trees
+	  The classic worklog only has one key to address a project.
+	  This is major short comming. The getan database allows 
+	  to store projects keys with more than one character.
+	  This feature will be exploited to build trees of projects.
+	  
+	  Lets say you have two main tasks foo and bar with two sub 
+	  tasks each you can name them f1, f2 and b1, b2. getan
+	  stores these four tasks in a tree with top level f and b
+	  and tow second level branches 1 and 2. To choose a task you 
+	  have to press f or b followed by 1 or 2.
+
+	  At the moment only selection works.
+
+	  TODO and next steps: 
+	  - Remove all old linear data structures.
+	  - adjust rendering to only show active branches.
+	  - sort anonymous task after naming into project tree.
+
 2008-08-04	Sascha L. Teichmann <sascha.teichmann@intevation.de>
 
 	* contrib/zeiterfassung: Applied a variation of Stephan Holl's
--- a/getan	Mon Aug 04 12:32:46 2008 +0200
+++ b/getan	Mon Aug 11 01:12:47 2008 +0200
@@ -277,15 +277,69 @@
         })
         cur.connection.commit()
         self.total += seconds
-        
+
+def build_tree(project, depth):
+    if len(project.key) == depth+1:
+        return ProjectNode(project, project.key[depth])
+    node = ProjectNode(None, project.key[depth])
+    node.children.append(build_tree(project, depth+1))
+    return node
+
+class ProjectNode:
+
+    def __init__(self, project = None, key = None):
+        self.children = []
+        self.project  = project
+        self.key      = key
+
+    def insertProject(self, project, depth = 0):
+
+        if not project.key: # anonym -> end
+            node = ProjectNode(project)
+            self.children.append(node)
+            return
+
+        for i, child in enumerate(self.children):
+            if not child.key: # before anonym projects
+                self.children.insert(i, build_tree(project, depth))
+                return
+            if child.key == project.key[depth]:
+                child.insertProject(project, depth+1)
+                return
+        self.children.append(build_tree(project, depth))
+
+    def isLeaf(self):
+        return not self.project is None
+
+    def findProject(self, key):
+        l, lower = key.lower(), None
+        for child in self.children:
+            if child.key == key:
+                return child
+            if child.key and child.key.lower() == l:
+                lower = child
+        return lower
+
+    def dump(self, depth = 0):
+        out = []
+        indent = "  " * depth
+        out.append("%skey: %s" % (indent, self.key))
+        if self.project:
+            out.append("%sdescription: %s" % (indent, self.project.desc))
+        for child in self.children:
+            out.append(child.dump(depth+1))
+        return "\n".join(out)
 
 class Worklog:
 
     def __init__(self, database):
         self.initDB(database)
+        self.projects        = []
+        self.tree            = ProjectNode()
+        self.state           = PAUSED
+        self.current_project = None
+        self.selection       = self.tree
         self.loadProjects()
-        self.state = PAUSED
-        self.current_project = None
 
     def initDB(self, database):
         self.con = db.connect(database)
@@ -295,7 +349,12 @@
         try:
             cur = self.con.cursor()
             cur.execute(LOAD_ACTIVE_PROJECTS)
-            self.projects = [Project(*row) for row in cur.fetchall()]
+            while True:
+                row = cur.fetchone()
+                if not row: break
+                project = Project(*row)
+                self.projects.append(project)
+                self.tree.insertProject(project)
         finally:
             tolerantClose(cur)
 
@@ -460,6 +519,7 @@
 
         elif curses.ascii.isascii(c):
             if c == ord('-'):
+                self.selection = self.tree
                 stdscr.erase()
                 ofs = self.render()
                 old_cur = cursor_visible(1)
@@ -485,6 +545,7 @@
                 stdscr.refresh()
 
             elif c == ord('+'):
+                self.selection = self.tree
                 stdscr.erase()
                 ofs = self.render()
                 old_cur = cursor_visible(1)
@@ -512,16 +573,23 @@
                 stdscr.refresh()
 
             else:
-                nproject = self.findProject(chr(c))
-                if nproject is None: return
-                self.current_project = nproject
-                nproject.start_time = datetime.now()
-                stdscr.erase()
-                ofs = self.render()
-                stdscr.refresh()
-                self.state = RUNNING
-                signal.signal(signal.SIGALRM, alarm_handler)
-                signal.alarm(1)
+                node = self.selection.findProject(chr(c))
+                if not node:
+                    self.selection = self.tree
+                    return
+                if node.isLeaf():
+                    self.selection = self.tree
+                    nproject = node.project
+                    self.current_project = nproject
+                    nproject.start_time = datetime.now()
+                    stdscr.erase()
+                    ofs = self.render()
+                    stdscr.refresh()
+                    self.state = RUNNING
+                    signal.signal(signal.SIGALRM, alarm_handler)
+                    signal.alarm(1)
+                else:
+                    self.selection = node
 
     def runningState(self, c):
         global stdscr
@@ -551,14 +619,23 @@
             stdscr.refresh()
             
         elif curses.ascii.isascii(c):
-            nproject = self.findProject(chr(c))
-            if nproject is None or nproject == self.current_project:
+            project_node = self.selection.findProject(chr(c))
+            if project_node is None:
+                self.selection = self.tree
                 return
-            nproject.start_time = self.writeLog()
-            self.current_project = nproject
-            stdscr.erase()
-            ofs = self.render()
-            stdscr.refresh()
+
+            if project_node.isLeaf():
+                self.selection = self.tree
+                nproject = project_node.project
+                if nproject == self.current_project:
+                    return
+                nproject.start_time = self.writeLog()
+                self.current_project = nproject
+                stdscr.erase()
+                ofs = self.render()
+                stdscr.refresh()
+            else:
+                self.selection = project_node
 
     def pausedEscapeState(self, c):
         global stdscr
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)