Permalink
Browse files

First working version

  • Loading branch information...
0 parents commit 36a408470f0f1e3c6009927611032a491fdf1271 @dnet committed Mar 12, 2011
Showing with 377 additions and 0 deletions.
  1. +1 −0 .gitignore
  2. +333 −0 Orgnode.py
  3. +5 −0 config.py
  4. +8 −0 dashboard.py
  5. +20 −0 orgmode.py
  6. +10 −0 redmine.py
@@ -0,0 +1 @@
+*.pyc
@@ -0,0 +1,333 @@
+# Copyright (c) 2010 Charles Cave
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use, copy,
+# modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+# Program written by Charles Cave (charlesweb@optusnet.com.au)
+# February - March 2009
+# Version 2 - June 2009
+# Added support for all tags, TODO priority and checking existence of a tag
+# More information at
+# http://members.optusnet.com.au/~charles57/GTD
+
+"""
+The Orgnode module consists of the Orgnode class for representing a
+headline and associated text from an org-mode file, and routines for
+constructing data structures of these classes.
+"""
+
+import re, sys
+import datetime
+import codecs
+
+def makelist(filename):
+ """
+ Read an org-mode file and return a list of Orgnode objects
+ created from this file.
+ """
+ ctr = 0
+
+ try:
+ f = codecs.open(filename, 'r', 'utf-8')
+ except IOError:
+ print "Unable to open file [%s] " % filename
+ print "Program terminating."
+ sys.exit(1)
+
+ todos = dict() # populated from #+SEQ_TODO line
+ todos['TODO'] = '' # default values
+ todos['DONE'] = '' # default values
+ level = 0
+ heading = ""
+ bodytext = ""
+ tag1 = "" # The first tag enclosed in ::
+ alltags = [] # list of all tags in headline
+ sched_date = ''
+ deadline_date = ''
+ nodelist = []
+ propdict = dict()
+
+ for line in f:
+ ctr += 1
+ hdng = re.search('^(\*+)\s(.*?)\s*$', line)
+ if hdng:
+ if heading: # we are processing a heading line
+ thisNode = Orgnode(level, heading, bodytext, tag1, alltags)
+ if sched_date:
+ thisNode.setScheduled(sched_date)
+ sched_date = ""
+ if deadline_date:
+ thisNode.setDeadline(deadline_date)
+ deadline_date = ''
+ thisNode.setProperties(propdict)
+ nodelist.append( thisNode )
+ propdict = dict()
+ level = hdng.group(1)
+ heading = hdng.group(2)
+ bodytext = ""
+ tag1 = ""
+ alltags = [] # list of all tags in headline
+ tagsrch = re.search('(.*?)\s*:(.*?):(.*?)$',heading)
+ if tagsrch:
+ heading = tagsrch.group(1)
+ tag1 = tagsrch.group(2)
+ alltags.append(tag1)
+ tag2 = tagsrch.group(3)
+ if tag2:
+ for t in tag2.split(':'):
+ if t != '': alltags.append(t)
+ else: # we are processing a non-heading line
+ if line[:10] == '#+SEQ_TODO':
+ kwlist = re.findall('([A-Z]+)\(', line)
+ for kw in kwlist: todos[kw] = ""
+
+ if line[:1] != '#':
+ bodytext = bodytext + line
+
+ if re.search(':PROPERTIES:', line): continue
+ if re.search(':END:', line): continue
+ prop_srch = re.search('^\s*:(.*?):\s*(.*?)\s*$', line)
+ if prop_srch:
+ propdict[prop_srch.group(1)] = prop_srch.group(2)
+ continue
+ sd_re = re.search('SCHEDULED:\s+<([0-9]+)\-([0-9]+)\-([0-9]+)', line)
+ if sd_re:
+ sched_date = datetime.date(int(sd_re.group(1)),
+ int(sd_re.group(2)),
+ int(sd_re.group(3)) )
+ dd_re = re.search('DEADLINE:\s*<(\d+)\-(\d+)\-(\d+)([\ a-zA-Z]+(\d+):(\d+))?', line)
+ if dd_re:
+ if dd_re.group(5) is None:
+ deadline_date = datetime.date(int(dd_re.group(1)),
+ int(dd_re.group(2)),
+ int(dd_re.group(3)) )
+ else:
+ deadline_date = datetime.datetime(int(dd_re.group(1)),
+ int(dd_re.group(2)),
+ int(dd_re.group(3)),
+ int(dd_re.group(5)),
+ int(dd_re.group(6)) )
+
+ # write out last node
+ thisNode = Orgnode(level, heading, bodytext, tag1, alltags)
+ thisNode.setProperties(propdict)
+ if sched_date:
+ thisNode.setScheduled(sched_date)
+ if deadline_date:
+ thisNode.setDeadline(deadline_date)
+ nodelist.append( thisNode )
+
+ # using the list of TODO keywords found in the file
+ # process the headings searching for TODO keywords
+ for n in nodelist:
+ h = n.Heading()
+ todoSrch = re.search('([A-Z]+)\s(.*?)$', h)
+ if todoSrch:
+ if todos.has_key( todoSrch.group(1) ):
+ n.setHeading( todoSrch.group(2) )
+ n.setTodo ( todoSrch.group(1) )
+ prtysrch = re.search('^\[\#(A|B|C)\] (.*?)$', n.Heading())
+ if prtysrch:
+ n.setPriority(prtysrch.group(1))
+ n.setHeading(prtysrch.group(2))
+
+ return nodelist
+
+######################
+class Orgnode(object):
+ """
+ Orgnode class represents a headline, tags and text associated
+ with the headline.
+ """
+ def __init__(self, level, headline, body, tag, alltags):
+ """
+ Create an Orgnode object given the parameters of level (as the
+ raw asterisks), headline text (including the TODO tag), and
+ first tag. The makelist routine postprocesses the list to
+ identify TODO tags and updates headline and todo fields.
+ """
+ self.level = len(level)
+ self.headline = headline
+ self.body = body
+ self.tag = tag # The first tag in the list
+ self.tags = dict() # All tags in the headline
+ self.todo = ""
+ self.prty = "" # empty of A, B or C
+ self.scheduled = "" # Scheduled date
+ self.deadline = "" # Deadline date
+ self.properties = dict()
+ for t in alltags:
+ self.tags[t] = ''
+
+ # Look for priority in headline and transfer to prty field
+
+ def Heading(self):
+ """
+ Return the Heading text of the node without the TODO tag
+ """
+ return self.headline
+
+ def setHeading(self, newhdng):
+ """
+ Change the heading to the supplied string
+ """
+ self.headline = newhdng
+
+ def Body(self):
+ """
+ Returns all lines of text of the body of this node except the
+ Property Drawer
+ """
+ return self.body
+
+ def Level(self):
+ """
+ Returns an integer corresponding to the level of the node.
+ Top level (one asterisk) has a level of 1.
+ """
+ return self.level
+
+ def Priority(self):
+ """
+ Returns the priority of this headline: 'A', 'B', 'C' or empty
+ string if priority has not been set.
+ """
+ return self.prty
+
+ def setPriority(self, newprty):
+ """
+ Change the value of the priority of this headline.
+ Values values are '', 'A', 'B', 'C'
+ """
+ self.prty = newprty
+
+ def Tag(self):
+ """
+ Returns the value of the first tag.
+ For example, :HOME:COMPUTER: would return HOME
+ """
+ return self.tag
+
+ def Tags(self):
+ """
+ Returns a list of all tags
+ For example, :HOME:COMPUTER: would return ['HOME', 'COMPUTER']
+ """
+ return self.tags.keys()
+
+ def hasTag(self, srch):
+ """
+ Returns True if the supplied tag is present in this headline
+ For example, hasTag('COMPUTER') on headling containing
+ :HOME:COMPUTER: would return True.
+ """
+ return self.tags.has_key(srch)
+
+ def setTag(self, newtag):
+ """
+ Change the value of the first tag to the supplied string
+ """
+ self.tag = newtag
+
+ def setTags(self, taglist):
+ """
+ Store all the tags found in the headline. The first tag will
+ also be stored as if the setTag method was called.
+ """
+ for t in taglist:
+ self.tags[t] = ''
+
+ def Todo(self):
+ """
+ Return the value of the TODO tag
+ """
+ return self.todo
+
+ def setTodo(self, value):
+ """
+ Set the value of the TODO tag to the supplied string
+ """
+ self.todo = value
+
+ def setProperties(self, dictval):
+ """
+ Sets all properties using the supplied dictionary of
+ name/value pairs
+ """
+ self.properties = dictval
+
+ def Property(self, keyval):
+ """
+ Returns the value of the requested property or null if the
+ property does not exist.
+ """
+ return self.properties.get(keyval, "")
+
+ def setScheduled(self, dateval):
+ """
+ Set the scheduled date using the supplied date object
+ """
+ self.scheduled = dateval
+
+ def Scheduled(self):
+ """
+ Return the scheduled date object or null if nonexistent
+ """
+ return self.scheduled
+
+ def setDeadline(self, dateval):
+ """
+ Set the deadline (due) date using the supplied date object
+ """
+ self.deadline = dateval
+
+ def Deadline(self):
+ """
+ Return the deadline date object or null if nonexistent
+ """
+ return self.deadline
+
+ def __repr__(self):
+ """
+ Print the level, heading text and tag of a node and the body
+ text as used to construct the node.
+ """
+ # This method is not completed yet.
+ n = ''
+ for i in range(0, self.level):
+ n = n + '*'
+ n = n + ' ' + self.todo + ' '
+ if self.prty:
+ n = n + '[#' + self.prty + '] '
+ n = n + self.headline
+ n = "%-60s " % n # hack - tags will start in column 62
+ closecolon = ''
+ for t in self.tags.keys():
+ n = n + ':' + t
+ closecolon = ':'
+ n = n + closecolon
+# Need to output Scheduled Date, Deadline Date, property tags The
+# following will output the text used to construct the object
+ n = n + "\n" + self.body
+
+ return n
+
+
+
@@ -0,0 +1,5 @@
+from PyQt4 import QtCore
+
+class Config(QtCore.QSettings):
+ def __init__(self):
+ QtCore.QSettings.__init__(self, 'dnet', 'dashboard')
@@ -0,0 +1,8 @@
+from config import Config
+
+modnames = str(Config().value('core/modules').toString())
+mods = [getattr(__import__(m), m.capitalize())() for m in modnames.split(',')]
+todos = reduce(lambda a, e: a + e.getTodos(), mods, [])
+
+for todo in todos:
+ print todo['title']
@@ -0,0 +1,20 @@
+import Orgnode
+import os
+from config import Config
+
+class Orgmode:
+ def __init__(self):
+ self.dir = unicode(Config().value('orgmode/dir').toString())
+
+ def getTodos(self):
+ ls = filter(lambda x: x.endswith('.org'), os.listdir(self.dir))
+ result = list()
+ for f in ls:
+ fn = os.path.join(self.dir, f)
+ nodes = Orgnode.makelist(fn)
+ for node in nodes:
+ if node.Todo() != 'TODO':
+ continue
+ result.append({'title': node.Heading(), 'deadline': node.Deadline(),
+ 'link': 'file://' + fn})
+ return result
@@ -0,0 +1,10 @@
+from config import Config
+import feedparser
+
+class Redmine:
+ def __init__(self):
+ self.url = unicode(Config().value('redmine/url').toString())
+
+ def getTodos(self):
+ d = feedparser.parse(self.url)
+ return d.entries

0 comments on commit 36a4084

Please sign in to comment.