diff --git a/browser/concept.py b/browser/concept.py index 01084b0..c4bf3e6 100644 --- a/browser/concept.py +++ b/browser/concept.py @@ -276,7 +276,8 @@ class ConceptView(BaseView): if r.order != pos: r.order = pos - def getChildren(self, topLevelOnly=True, sort=True, noDuplicates=True): + def getChildren(self, topLevelOnly=True, sort=True, noDuplicates=True, + useFilter=True): form = self.request.form #if form.get('loops.viewName') == 'index.html' and self.editable: if self.editable: @@ -311,11 +312,13 @@ class ConceptView(BaseView): break if skip: continue - options = IOptions(adapted(r.predicate), None) - if options is not None and options('hide_children'): - continue - if fv.check(r.context): - yield r + if useFilter: + options = IOptions(adapted(r.predicate), None) + if options is not None and options('hide_children'): + continue + if not fv.check(r.context): + continue + yield r def checkCriteria(self, relation, criteria): result = True @@ -347,9 +350,10 @@ class ConceptView(BaseView): return result def isHidden(self, pr): - if (getName(pr.second.conceptType) in - IOptions(adapted(pr.predicate))('hide_parents_for', [])): - #IOptions(pr.predicate)('hide_parents_for', [])): + predOptions = IOptions(adapted(pr.predicate)) + if predOptions('hide_parents'): + return True + if (getName(pr.second.conceptType) in predOptions('hide_parents_for', [])): return True hideRoles = None options = component.queryAdapter(adapted(pr.first), IOptions) diff --git a/browser/concept_related.pt b/browser/concept_related.pt index 1348617..0b680d0 100644 --- a/browser/concept_related.pt +++ b/browser/concept_related.pt @@ -23,7 +23,8 @@
-
>> from loops.expert.browser.base import BaseQueryView +Reports +======= + + >>> from loops.expert.report import IReport, Report + >>> component.provideAdapter(Report, provides=IReport) + + >>> report = Report(None) + + >>> from loops.expert.report import IReportInstance, DefaultConceptReportInstance + >>> component.provideAdapter(DefaultConceptReportInstance, + ... provides=IReportInstance, + ... name='default_concept_report') + + >>> from loops.expert.report import ReportTypeSourceList + >>> source = ReportTypeSourceList(report) + >>> list(source) + [(u'default_concept_report', u'Default Concept Report')] + + Fin de partie ============= diff --git a/expert/browser/configure.zcml b/expert/browser/configure.zcml index 4d71dfa..2014a46 100644 --- a/expert/browser/configure.zcml +++ b/expert/browser/configure.zcml @@ -54,4 +54,25 @@ factory="loops.expert.browser.search.ActionExecutor" permission="zope.ManageContent" /> + + + + + + + + diff --git a/expert/browser/report.pt b/expert/browser/report.pt new file mode 100644 index 0000000..e1237dd --- /dev/null +++ b/expert/browser/report.pt @@ -0,0 +1,22 @@ + + + +
+
+ +
+ + +
+ +
+
+
+
+ + + diff --git a/expert/browser/report.py b/expert/browser/report.py new file mode 100644 index 0000000..b8f5f9b --- /dev/null +++ b/expert/browser/report.py @@ -0,0 +1,107 @@ +# +# Copyright (c) 2011 Helmut Merz helmutm@cy55.de +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +""" +View classes for reporting. +""" + +from urllib import urlencode +from zope import interface, component +from zope.app.pagetemplate import ViewPageTemplateFile +from zope.cachedescriptors.property import Lazy +from zope.traversing.api import getName, getParent + +from cybertools.browser.form import FormController +from loops.browser.concept import ConceptView +from loops.browser.node import NodeView +from loops.common import adapted, AdapterBase +from loops.expert.report import IReportInstance +from loops.organize.personal.browser.filter import FilterView +from loops.security.common import canWriteObject, checkPermission +from loops import util +from loops.util import _ + + +report_template = ViewPageTemplateFile('report.pt') +results_template = ViewPageTemplateFile('results.pt') + + +class ReportView(ConceptView): + + @Lazy + def report_macros(self): + return self.controller.getTemplateMacros('report', report_template) + + @Lazy + def macro(self): + return self.report_macros['main'] + + @Lazy + def dynamicParams(self): + return self.request.form + + +class ResultsView(NodeView): + + @Lazy + def result_macros(self): + return self.controller.getTemplateMacros('results', results_template) + + @Lazy + def macro(self): + return self.result_macros['main'] + + @Lazy + def item(self): + return self + + @Lazy + def params(self): + params = dict(self.request.form) + if 'report_execute' in params: + del params['report_execute'] + return params + + @Lazy + def report(self): + return adapted(self.virtualTargetObject) + + @Lazy + def reportInstance(self): + instance = component.getAdapter(self.report, IReportInstance, + name=self.report.reportType) + instance.request = self.request + return instance + + #@Lazy + def results(self): + return self.reportInstance.getResults(self.params) + + @Lazy + def resultsRenderer(self): + return self.reportInstance.getResultsRenderer('results', self.result_macros) + + @Lazy + def reportUrl(self): + url = self.virtualTargetUrl + return '?'.join((url, urlencode(self.params))) + + @Lazy + def displayedColumns(self): + return self.reportInstance.getActiveOutputFields() + diff --git a/expert/browser/results.pt b/expert/browser/results.pt new file mode 100644 index 0000000..9c892ad --- /dev/null +++ b/expert/browser/results.pt @@ -0,0 +1,22 @@ + + + +
+
+ +
+ +
+
+ + +
+ Default Results Listing +
+ + + diff --git a/expert/configure.zcml b/expert/configure.zcml index 3eff3c3..03543ad 100644 --- a/expert/configure.zcml +++ b/expert/configure.zcml @@ -16,6 +16,35 @@ + + + + + + + + + + + + + + + + + + diff --git a/expert/report.py b/expert/report.py new file mode 100644 index 0000000..fdcef10 --- /dev/null +++ b/expert/report.py @@ -0,0 +1,143 @@ +# +# Copyright (c) 2011 Helmut Merz helmutm@cy55.de +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +""" +Report type, report concept adapter, and other reporting stuff. +""" + +from zope import schema, component +from zope.component import adapts +from zope.interface import Interface, Attribute, implements +from zope.cachedescriptors.property import Lazy +from zope.security.proxy import removeSecurityProxy + +from cybertools.composer.report.base import Report as BaseReport +from cybertools.composer.report.base import LeafQueryCriteria, CompoundQueryCriteria +from cybertools.composer.report.interfaces import IReport as IBaseReport +from cybertools.composer.report.result import ResultSet, Row +from cybertools.util.jeep import Jeep +from loops.common import AdapterBase +from loops.interfaces import ILoopsAdapter +from loops.type import TypeInterfaceSourceList +from loops import util +from loops.util import _ + + +# interfaces + +class IReport(ILoopsAdapter): + """ The report adapter for the persistent object (concept) that stores + the report in the concept map. + """ + + reportType = schema.Choice( + title=_(u'Report Type'), + description=_(u'The type of the report.'), + default=None, + source='loops.expert.reportTypeSource', + required=True) + + +class IReportSchema(IBaseReport, IReport): + """ All report attributes - use for security declarations. + """ + + +class IReportInstance(Interface): + """ The report-type-specific object (an adapter on the report) that + does the real report execution stuff. + """ + + label = Attribute('The user-friendly label of the report type specified ' + 'by this instance class.') + + +# report concept adapter and instances + +class Report(AdapterBase): + + implements(IReport) + + _contextAttributes = list(IReport) + +TypeInterfaceSourceList.typeInterfaces += (IReport,) + + +class ReportInstance(BaseReport): + + implements(IReportInstance) + adapts(IReport) + + rowFactory = Row + + def __init__(self, context): + self.context = context + + def getResultsRenderer(self, name, macros): + return macros[name] + + def getResults(self, dynaParams=None): + crit = self.queryCriteria + if crit is None: + return [] + for k, v in dynaParams.items(): + if k in crit.parts.keys(): + crit.parts[k].value = v + parts = Jeep(crit.parts) + result = list(self.selectObjects(parts)) # may modify parts + qc = CompoundQueryCriteria(parts) + return ResultSet(self, result, rowFactory=self.rowFactory, + sortCriteria=self.getSortCriteria(), queryCriteria=qc) + + def selectObjects(self, parts): + return [] + + +class ReportTypeSourceList(object): + + implements(schema.interfaces.IIterableSource) + + def __init__(self, context): + self.context = context + + def __iter__(self): + return iter(self.reportTypes) + + def __contains__(self, value): + return value in [item[0] for item in self] + + @Lazy + def reportTypes(self): + result = [] + for item in component.getAdapters([self.context], IReportInstance): + name, adapter = item + adapter = removeSecurityProxy(adapter) + label = getattr(adapter, 'label', name) + result.append((name, label,)) + return result + + def __len__(self): + return len(self.reportTypes) + + +# default concept report + +class DefaultConceptReportInstance(ReportInstance): + + label = u'Default Concept Report' + diff --git a/organize/work/README.txt b/organize/work/README.txt index 85d6bc0..2946e1e 100644 --- a/organize/work/README.txt +++ b/organize/work/README.txt @@ -180,6 +180,16 @@ So we use the PersonWorkItems view, assigning john to the query. 'creator': '33'}>] +Work Reports +============ + + >>> from loops.organize.work.report import WorkReportInstance + >>> from loops.expert.report import IReportInstance + >>> component.provideAdapter(WorkReportInstance, + ... provides=IReportInstance, + ... name='work_report') + + Fin de partie ============= diff --git a/organize/work/configure.zcml b/organize/work/configure.zcml index b48b04c..ccd434f 100644 --- a/organize/work/configure.zcml +++ b/organize/work/configure.zcml @@ -73,6 +73,19 @@ class="loops.organize.work.browser.WorkItemInfo" permission="zope.View" /> + + + + + + + + + + +
+

Work Items

+ + + + + + + + +
+
+
+ + +
+ Work Items Listing + + + + + + + + + + + + + + + + + + + +
Task
2009-01
2007-03-3017:3020:002:30 + Task + JohnTitle
+
+ + +