Mercurial > hg > MPIWGWeb
changeset 27:9a75eb1b31b3
more work on projects.
author | casties |
---|---|
date | Mon, 22 Apr 2013 21:01:00 +0200 |
parents | 8a99ad8713d6 |
children | dd765003647b |
files | HashTree.py MPIWGDepartment.py MPIWGProjects.py MPIWGRoot.py __init__.py css/mpiwg.css zpt/project/manage_add_MPIWGProjectFolder.zpt |
diffstat | 7 files changed, 315 insertions(+), 19 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HashTree.py Mon Apr 22 21:01:00 2013 +0200 @@ -0,0 +1,147 @@ +import logging + +class HashTreeNode: + """Node of a HashTree. + Has a value and keeps children in a dict indexed by key.""" + key = None + value = None + children = None + + def __init__(self, key=None, value=None, children=None): + """create node""" + self.key = key + self.value = value + self.children = children + + + def getNode(self, key): + """return node under key""" + if self.children is None: + return None + else: + return self.children.get(key, None) + + + def addNode(self, node): + """add child node using key from node""" + if self.children is None: + self.children = {node.key : node} + else: + self.children[node.key] = node + + + def getSubtreeList(self): + """returns the subtree as list sorted by key (depth first)""" + if self.children is None: + if self.value is None: + return [] + else: + return [self.value] + + else: + if self.value is None: + sub = [] + else: + sub = [self.value] + + keys = self.children.keys() + keys.sort() + for k in keys: + #logging.debug("getSubtreeList: k=%s sub=%s"%(k,sub)) + sub.extend(self.children.get(k).getSubtreeList()) + + return sub + + + def getSubtreeAsText(self): + """prints whole tree as text""" + if self.children is None: + return "(%s:%s)"%(self.key, self.value) + else: + sub = "(%s:%s):["%(self.key, self.value) + keys = self.children.keys() + keys.sort() + for k in keys: + sub += self.children.get(k).getSubtreeAsText() + sub += ", " + + return sub + "] " + + +class HashTree: + """Tree using dictionaries""" + + root = None + keySeparator = '.' + keyFn = None + + def __init__(self, keySeparator='.', keyFn=None): + """creates a HashTree""" + self.root = HashTreeNode() + self.keySeparator = keySeparator + self.keyFn = keyFn + + + def getNode(self, key): + """gets node under key from the tree. + key can be sequence of key string or a single string using keySeparator. + """ + #logging.debug("getNode(key=%s)"%(key)) + if isinstance(key, basestring): + keys = key.split(self.keySeparator) + if self.keyFn is not None: + keys = [self.keyFn(k) for k in keys] + elif isinstance(key, list): + keys = key + else: + keys = [key] + + node = self.root + for k in keys: + #logging.debug("getNode node=%s k=%s"%(node, repr(k))) + node = node.getNode(k) + #logging.debug("getNode got:%s"%(node)) + if node is None: + return None + + return node + + + def get(self, key): + """gets value under key from the tree. + key can be sequence of key string or a single string using keySeparator. + """ + node = self.getNode(key) + if node is None: + return None + + return node.value + + + def add(self, key, value): + """adds value under key to the tree. + key can be sequence of key string or a single string using keySeparator. + """ + #logging.debug("add(key=%s, value=%s)"%(repr(key), value)) + if isinstance(key, basestring): + keys = key.split(self.keySeparator) + if self.keyFn is not None: + keys = [self.keyFn(k) for k in keys] + elif isinstance(key, list): + keys = key + else: + keys = [key] + + node = self.root + for k in keys: + nextnode = node.getNode(k) + if nextnode is None: + nextnode = HashTreeNode(key=k) + node.addNode(nextnode) + + node = nextnode + + node.value = value + + +
--- a/MPIWGDepartment.py Thu Apr 18 20:39:01 2013 +0200 +++ b/MPIWGDepartment.py Mon Apr 22 21:01:00 2013 +0200 @@ -7,6 +7,9 @@ import logging from OFS.Folder import Folder from AccessControl import ClassSecurityInfo + +from SrvTxtUtils import getAt + import MPIWGHelper class MPIWGDepartment(Folder): @@ -136,7 +139,12 @@ img = getattr(self, 'img-thumb.jpg') return img.absolute_url() - def getProjects(self, onlyActive=0, onlyArchived=0): + def getProject(self): + """returns the default project""" + proj = self.getProjects(count=1, onlyActive=1, onlyArchived=1) + return getAt(proj, 0, None) + + def getProjects(self, count=0, onlyActive=0, onlyArchived=0): """returns a list of projects of this department. onlyActive = 0 : all projects @@ -147,12 +155,11 @@ onlyArchived = 1 : current projects onlyArchived = 2 : archived projects """ - # getTree: jeder Eintrag ist ein Tupel (Tiefe, ProjektNummer,Titel,ProjektObject) - tree = self.getTree(dep=self.getProjectId(), date=None, onlyActive=onlyActive, onlyArchived=onlyArchived) - # re-pack into simple list - projects = [] - for item in tree: - projects.append(item[3]) + pf = self.en.getProjectsFolder() + projects = pf.getProjectList(self.getProjectId(), active=onlyActive, archived=onlyArchived) + #logging.debug("getProjects projects=%s"%repr(projects)) + if count > 0: + return projects[:count] return projects
--- a/MPIWGProjects.py Thu Apr 18 20:39:01 2013 +0200 +++ b/MPIWGProjects.py Mon Apr 22 21:01:00 2013 +0200 @@ -40,6 +40,7 @@ #import MPIWGStaff +from HashTree import HashTree from MPIWGHelper import * import MPIWGRoot @@ -712,12 +713,26 @@ if RESPONSE: self.redirect(RESPONSE,'manageRelatedProjects') + + + def getNumber(self): + """returns sorting number""" + return getattr(self, 'xdata_05', None) + - def getThumbUrl(self): + def getUrl(self, baseUrl=None): + """returns URL to this Project""" + if baseUrl is None: + return self.absolute_url() + + return '%s/%s'%(baseUrl, self.getId()) + + + def getThumbUrl(self, default='http://defaultthumb.jpg'): """returns the URL of the project thumbnail image""" # TODO: improve this imgs = self.getImageList() - url = 'http://defaultthumb.jpg' + url = default if len(imgs) > 0: img = imgs[0] url = img.absolute_url() @@ -963,20 +978,34 @@ """check if the project is still active, default is true, set to false is the project is accomplished""" return getattr(self,'isActiveFlag',True) + def checkActive(self, active): + """returns if the project state matches the active state. + active = 0 : all projects + active = 1 : active projects + active = 2 : inactive projects + """ + act = getattr(self,'isActiveFlag',True) + return (active == 1 and act) or (active == 0) or (active == 2 and not act) + def isArchivedProject(self): """check if the project is archived""" - completed=self.getCompletedAt() - - #completed leer + #completed leer if completed=="" : return False; if completed == 0: return False; - return True + def checkArchived(self, archived): + """returns if the project state matches the archived state. + archived = 0 : all projects + archived = 1 : current projects + archived = 2 : archived projects + """ + arch = self.isArchivedProject() + return (archived == 1 and not arch) or (archived == 0) or (archived == 2 and arch) def setActiveFlag(self,status=True): """set the active flag""" @@ -1808,3 +1837,75 @@ if RESPONSE is not None: RESPONSE.redirect('manage_main') + + +class MPIWGProjectFolder(Folder): + """Folder of project objects""" + + meta_type="MPIWGProjectFolder" + security=ClassSecurityInfo() + + # cached HashTree with project hierarchy + _v_projectTree = None + + + def __init__(self, id, title=None): + self.id = id + if title is None: + self.title = id + else: + self.title = title + + + def getTree(self): + """returns the hierarchy tree (and caches it)""" + tree = self._v_projectTree + if tree is None: + tree = HashTree(keySeparator='.', keyFn=lambda x:getInt(x)) + for p in self.objectValues(spec='MPIWGProject'): + tree.add(p.getNumber(), p) + + self._v_projectTree = tree + #logging.debug("getTree: tree=%s"%(tree.root.getSubtreeAsText())) + + return tree + + + def getProjectList(self, start, active=1, archived=1): + """returns list of projects starting at start. + active = 0 : all projects + active = 1 : active projects + active = 2 : inactive projects + archived = 0 : all projects + archived = 1 : current projects + archived = 2 : archived projects + """ + #logging.debug("getProjectList(start=%s,active=%s,archived=%s)"%(repr(start),active,archived)) + tree = self.getTree() + node = tree.getNode(start) + if node is None: + return [] + + pl = node.getSubtreeList() + #logging.debug("getProjectList: node=(%s,%s) pl=%s"%(node.key,node.value,pl)) + # return filtered list + return [p for p in pl if (p.checkActive(active) and p.checkArchived(archived))] + + +def manage_addMPIWGProjectFolderForm(self): + """form for adding the project""" + pt = PageTemplateFile('zpt/project/manage_add_MPIWGProjectFolder', globals()).__of__(self) + return pt() + +def manage_addMPIWGProjectFolder(self,id,title,RESPONSE=None): + """add it""" + newObj=MPIWGProjectFolder(id,title) + + self._setObject(id,newObj) + + if RESPONSE is not None: + RESPONSE.redirect('manage_main') + + + + \ No newline at end of file
--- a/MPIWGRoot.py Thu Apr 18 20:39:01 2013 +0200 +++ b/MPIWGRoot.py Mon Apr 22 21:01:00 2013 +0200 @@ -273,6 +273,11 @@ items.sort(key=lambda x:int(x.weight)) return items + def getProjectsFolder(self): + """returns the MPIWGProjectFolder""" + dir = getattr(self, 'projects', None) + return dir + def getMPIWGRoot(self): """returns the MPIWG root""" return self @@ -923,6 +928,7 @@ department fuer das Tree geholt werden soll """ + logging.debug("MPIWGRoot.getTree()") returnListTmp=[] returnList=[]
--- a/__init__.py Thu Apr 18 20:39:01 2013 +0200 +++ b/__init__.py Mon Apr 22 21:01:00 2013 +0200 @@ -20,6 +20,14 @@ ) context.registerClass( + MPIWGProjects.MPIWGProjectFolder, + constructors = ( + MPIWGProjects.manage_addMPIWGProjectFolderForm, + MPIWGProjects.manage_addMPIWGProjectFolder + ) + ) + + context.registerClass( MPIWGLink.MPIWGLink, constructors = ( MPIWGLink.manage_addMPIWGLinkForm,
--- a/css/mpiwg.css Thu Apr 18 20:39:01 2013 +0200 +++ b/css/mpiwg.css Mon Apr 22 21:01:00 2013 +0200 @@ -366,12 +366,12 @@ padding-left: 21px; } -div.main.home div.box h2 { +div.box h2 { /* more-links in title are right */ position: relative; } -div.main.home div.box h2 a:link { +div.box h2 a:link { /* more-links in title are right */ position: absolute; right: 0; @@ -620,8 +620,9 @@ margin-bottom: 5px; border: 0; } + /* - * sonstige boxen + * other boxes */ div.box { margin: 20px 0; @@ -645,13 +646,21 @@ color: #6a4d3c; } -div.box h3+h2 { +div.box h3 + h2 { /* directly over h2 */ margin-top: 0; } +/* + * small boxes with thumbnail + */ div.mini { padding: 10px 0; + /* line-height: 1; */ +} + +div.row.quintuple div.mini { + font-size: 11px; } div.mini div.thumb { @@ -659,13 +668,22 @@ text-align: center; } +div.row.quintuple div.mini div.thumb img { + width: 120px; + height: 75px; +} + div.mini div.type { - font-size: 11px; color: #9f917a; } -div.box div.source div.author,div.box div.website div.title { +div.mini div.title { + margin-top: 0.5em; +} + +div.mini div.author { color: #3b4186; + margin-top: 0.5em; } div.box div.website div.description {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/zpt/project/manage_add_MPIWGProjectFolder.zpt Mon Apr 22 21:01:00 2013 +0200 @@ -0,0 +1,9 @@ + <div tal:replace="structure here/manage_page_header">Header</div> + <h2>Add a MPIWGProjectFolder</h2> + <form method="post" action="manage_addMPIWGProjectFolder"> + <p class="form-label">ID</p> + <p class="form-element"><input size="80" name="id"/></p> + <p class="form-label">Title</p> + <p class="form-element"><input size="80" name="title"/></p> + <p><input type="submit" value="Add" /></p> + </form>