From 5d3bcf3cfae965ebaaf7f719373dec46285bfe36 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Mon, 5 Mar 2012 18:36:27 +0100 Subject: [PATCH 01/11] provide more control on what is shown in list or grid via new 'represents' predicate for resources --- browser/lobo/standard.pt | 4 ++-- browser/lobo/standard.py | 28 ++++++++++++++++++++++++---- organize/stateful/base.py | 10 +++++++--- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/browser/lobo/standard.pt b/browser/lobo/standard.pt index bb655dc..40a8061 100644 --- a/browser/lobo/standard.pt +++ b/browser/lobo/standard.pt @@ -17,7 +17,7 @@ title cell/description">

- +
@@ -36,7 +36,7 @@
- +
diff --git a/browser/lobo/standard.py b/browser/lobo/standard.py index b70d4eb..5b80e36 100644 --- a/browser/lobo/standard.py +++ b/browser/lobo/standard.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2011 Helmut Merz helmutm@cy55.de +# Copyright (c) 2012 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 @@ -18,8 +18,6 @@ """ View classes for lobo (blueprint-based) layouts. - -$Id$ """ from cgi import parse_qs @@ -66,8 +64,20 @@ class ConceptView(BaseConceptView): @Lazy def resources(self): + return self.getResources() + + @Lazy + def representingResources(self): + pred = self.representationPredicate + if pred is None: + return {} + return self.getResources([pred]) + + def getResources(self, predicates=None): result = dict(texts=[], images=[], files=[]) - for r in self.context.getResources([self.defaultPredicate]): + if predicates is None: + predicates = [self.defaultPredicate] + for r in self.context.getResources(predicates): if r.contentType.startswith('text/'): result['texts'].append(r) if r.contentType.startswith('image/'): @@ -81,6 +91,10 @@ class ConceptView(BaseConceptView): for r in self.resources['images']: yield r + @Lazy + def representationPredicate(self): + return self.conceptManager.get('represents') + # properties from base class: title, description, renderedDescription @Lazy @@ -99,6 +113,12 @@ class ConceptView(BaseConceptView): return u'' return self.renderDescription(self.textDescription) + @Lazy + def textRepresentation(self): + for r in self.representingResources.get('texts', []): + return self.renderText(r.data, r.contentType) + return self.renderedDescription + @Lazy def targetUrl(self): return self.nodeView.getUrlForTarget(self.context) diff --git a/organize/stateful/base.py b/organize/stateful/base.py index f6da53b..fc2d942 100644 --- a/organize/stateful/base.py +++ b/organize/stateful/base.py @@ -67,9 +67,13 @@ class StatefulConceptIndexInfo(IndexInfo): @property def availableStatesDefinitions(self): globalOptions = IOptions(self.context.getLoopsRoot()) - typeOptions = IOptions(adapted(self.context.conceptType)) - return (globalOptions('organize.stateful.concept', []) + - typeOptions('organize.stateful', [])) + type = self.context.conceptType + if type is None: # may happen during object creation + return globalOptions('organize.stateful.concept', []) + else: + typeOptions = IOptions(adapted(type)) + return (globalOptions('organize.stateful.concept', []) + + typeOptions('organize.stateful', [])) class StatefulResourceIndexInfo(IndexInfo): From 66e1a718515c9e4e3d23d72cdfa86918d0be03c0 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Mon, 5 Mar 2012 19:41:54 +0100 Subject: [PATCH 02/11] standard listing: show predicate also for resources --- browser/concept_macros.pt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/browser/concept_macros.pt b/browser/concept_macros.pt index 5123243..8f11c00 100644 --- a/browser/concept_macros.pt +++ b/browser/concept_macros.pt @@ -210,7 +210,10 @@ item.editable and 'dojo.dnd.Source' or ''"> + description related/description; + predicate related/predicateTitle; + info python: ' | '.join( + t for t in (description, predicate) if t)"> + title info">
Resource Title
From fccc9a7f50b8552ecf72a3a468db3be1ff177c38 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Fri, 9 Mar 2012 14:06:08 +0100 Subject: [PATCH 03/11] extend standard import file --- data/loops_std_de.dmp | 52 ++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/data/loops_std_de.dmp b/data/loops_std_de.dmp index a79d673..8b65a11 100644 --- a/data/loops_std_de.dmp +++ b/data/loops_std_de.dmp @@ -1,3 +1,4 @@ +# types type(u'query', u'Abfrage', options=u'', typeInterface='loops.expert.concept.IQueryConcept', viewName=u'') type(u'task', u'Aufgabe', options=u'', @@ -5,55 +6,74 @@ type(u'task', u'Aufgabe', options=u'', type(u'domain', u'Bereich', options=u'', typeInterface=u'', viewName=u'') type(u'classifier', u'Classifier', options=u'', typeInterface='loops.classifier.interfaces.IClassifier', viewName=u'classifier.html') -type(u'documenttype', u'Document Type', options=u'', typeInterface=u'', viewName=u'') +type(u'documenttype', u'Dokumentenart', options=u'', typeInterface=u'', viewName=u'') type(u'extcollection', u'External Collection', options=u'', typeInterface='loops.integrator.interfaces.IExternalCollection', viewName=u'collection.html') +type(u'folder', u'Ordner', options=u'', typeInterface=u'', viewName=u'') type(u'glossaryitem', u'Glossareintrag', options=u'', typeInterface='loops.knowledge.interfaces.ITopic', viewName=u'glossaryitem.html') type(u'media_asset', u'Media Asset', options=u'storage:varsubdir\nstorage_parameters:extfiles/sites_zzz\nasset_transform.minithumb: size(105)\nasset_transform.small: size(230)\nasset_transform.medium: size(480)', typeInterface='loops.media.interfaces.IMediaAsset', viewName=u'image_medium.html') -type(u'note', u'Note', options=u'', typeInterface='loops.interfaces.INote', +type(u'note', u'Notiz', options=u'', typeInterface='loops.interfaces.INote', viewName='note.html') type(u'person', u'Person', options=u'', typeInterface='loops.knowledge.interfaces.IPerson', viewName=u'') -type(u'predicate', u'Predicate', options=u'', +type(u'predicate', u'Prädikat', options=u'', typeInterface=u'loops.interfaces.IPredicate', viewName=u'') type(u'event', u'Termin', options=u'', typeInterface='loops.organize.interfaces.ITask', viewName=u'task.html') type(u'textdocument', u'Text', options=u'', typeInterface='loops.interfaces.ITextDocument', viewName=u'') -type(u'topic', u'Thema', options=u'', typeInterface='loops.knowledge.interfaces.ITopic', - viewName=u'') -type(u'type', u'Type', options=u'', typeInterface='loops.interfaces.ITypeConcept', +type(u'topic', u'Thema', options=u'action.portlet:createTopic,editTopic', + typeInterface='loops.knowledge.interfaces.ITopic', viewName=u'') +type(u'type', u'Typ', options=u'', typeInterface='loops.interfaces.ITypeConcept', viewName=u'') + +# domains +concept(u'general', u'Allgemein', u'domain') +concept(u'system', u'System', u'domain') + +# predicates concept(u'depends', u'depends', u'predicate') concept(u'follows', u'follows', u'predicate') -concept(u'general', u'Allgemein', u'domain') -concept(u'glossary', u'Glossar', u'query', options=u'', viewName=u'glossary.html') concept(u'hasType', u'has Type', u'predicate') concept(u'ispartof', u'is Part of', u'predicate') concept(u'issubtype', u'is Subtype', u'predicate') concept(u'knows', u'knows', u'predicate') concept(u'ownedby', u'owned by', u'predicate') -concept(u'personal_info', u'Pers\xf6nliche Information', u'query', options=u'', - viewName=u'personal_info.html') concept(u'provides', u'provides', u'predicate') concept(u'querytarget', u'is Query Target', u'predicate') concept(u'requires', u'requires', u'predicate') -concept(u'search', u'Suche', u'query', options=u'', viewName=u'search') concept(u'standard', u'subobject', u'predicate') -concept(u'system', u'System', u'domain') + +# queries +concept(u'events', u'Termine', u'query', options=u'delta:2', + viewName=u'list_events.html') +concept(u'glossary', u'Glossar', u'query', options=u'', viewName=u'glossary.html') +concept(u'personal_info', u'Pers\xf6nliche Informationen', u'query', options=u'', + viewName=u'personal_info.html') +concept(u'participants', u'Teilnehmer', u'query', options=u'', + viewName=u'list_children.html') +concept(u'search', u'Suche', u'query', options=u'', viewName=u'search') +concept(u'topics', u'Themen', u'query', options=u'action.portlet:createTopic', + viewName=u'list_children.html') + +# child assignments child(u'general', u'documenttype', u'standard') child(u'general', u'event', u'standard') +child(u'general', u'events', u'standard') +child(u'general', u'participants', u'standard') +child(u'general', u'topics', u'standard') child(u'system', u'classifier', u'standard') child(u'system', u'extcollection', u'standard') child(u'system', u'issubtype', u'standard') child(u'system', u'media_asset', u'standard') child(u'system', u'personal_info', u'standard') + +#nodes node(u'home', u'Startseite', '', 'menu', body=u'Willkommen\n==========') -node(u'participants', u'Teilnehmer', u'home', 'page', body=u'Teilnehmer\n==========', - target=u'concepts/person', viewName=u'listchildren') -node(u'topics', u'Themen', u'home', 'page', body=u'Themen\n======', - target=u'concepts/topic', viewName=u'listchildren') +node(u'participants', u'Teilnehmer', u'home', 'page', + target=u'concepts/participants') +node(u'topics', u'Themen', u'home', 'page', target=u'concepts/topics') node(u'glossary', u'Glossar', u'home', 'page', target=u'concepts/glossary') node(u'search', u'Suche', u'home', 'page', target=u'concepts/search') From 6c16cc9cedbc2a22bb602d3417c7ade9a08fce61 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sat, 10 Mar 2012 09:45:14 +0100 Subject: [PATCH 04/11] fix layout of popup form for Lobo skin --- browser/form.py | 2 +- browser/skin/configure.zcml | 2 ++ browser/skin/lobo/popup.css | 9 +++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 browser/skin/lobo/popup.css diff --git a/browser/form.py b/browser/form.py index 192867e..c6fdd6b 100644 --- a/browser/form.py +++ b/browser/form.py @@ -357,7 +357,7 @@ class CreateObjectPopup(CreateObjectForm): self.registerDojo() cm = self.controller.macros cm.register('css', identifier='popup.css', resourceName='popup.css', - media='all', position=4) + media='all', priority=90) #, position=4) jsCall = ('dojo.require("dojo.parser");' 'dojo.require("dijit.form.FilteringSelect");' 'dojo.require("dojox.data.QueryReadStore");') diff --git a/browser/skin/configure.zcml b/browser/skin/configure.zcml index abb30ca..09ffedb 100644 --- a/browser/skin/configure.zcml +++ b/browser/skin/configure.zcml @@ -55,6 +55,8 @@ layer="loops.browser.skin.Lobo" /> + Date: Sat, 10 Mar 2012 10:46:43 +0100 Subject: [PATCH 05/11] improve standard import file; add new definition file for book structure --- compound/book/loops_book_de.dmp | 16 ++++++++++++++++ data/loops_std_de.dmp | 16 +++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 compound/book/loops_book_de.dmp diff --git a/compound/book/loops_book_de.dmp b/compound/book/loops_book_de.dmp new file mode 100644 index 0000000..db58c68 --- /dev/null +++ b/compound/book/loops_book_de.dmp @@ -0,0 +1,16 @@ +type(u'book', u'Buch', viewName=u'', typeInterface=u'', + options=u'action.portlet:create_subtype,edit_concept') +type(u'page', u'Seite', viewName=u'', typeInterface=u'', + options=u'action.portlet:edit_concept') +type(u'section', u'Kapitel', viewName=u'', typeInterface=u'', + options=u'action.portlet:create_subtype,edit_concept') + +concept(u'ispartof', u'is Part of', u'predicate', options=u'', predicateInterface=u'') +concept(u'issubtype', u'is Subtype', u'predicate', options=u'', predicateInterface=u'') +concept(u'maintext', u'Haupttext', u'documenttype') +concept(u'quote', u'Zitat', u'documenttype') + +child(u'book', u'section', u'issubtype') +child(u'section', u'section', u'issubtype') +child(u'section', u'page', u'issubtype') +child(u'system', u'personal_info', u'standard') diff --git a/data/loops_std_de.dmp b/data/loops_std_de.dmp index 8b65a11..3bb354a 100644 --- a/data/loops_std_de.dmp +++ b/data/loops_std_de.dmp @@ -54,6 +54,9 @@ concept(u'personal_info', u'Pers\xf6nliche Informationen', u'query', options=u'' viewName=u'personal_info.html') concept(u'participants', u'Teilnehmer', u'query', options=u'', viewName=u'list_children.html') +concept(u'recenct_changes', u'Aktuelle \xc4nderungen', u'query', + options=u'types:concept:*,resource:*', + viewName=u'recent_changes.html') concept(u'search', u'Suche', u'query', options=u'', viewName=u'search') concept(u'topics', u'Themen', u'query', options=u'action.portlet:createTopic', viewName=u'list_children.html') @@ -69,11 +72,18 @@ child(u'system', u'extcollection', u'standard') child(u'system', u'issubtype', u'standard') child(u'system', u'media_asset', u'standard') child(u'system', u'personal_info', u'standard') +child(u'topic', u'topic', u'issubtype', 1) + +resource(u'homepage', u'Willkommen', u'textdocument', contentType='text/restructured') +resource(u'impressum', u'Impressum', u'textdocument', contentType='text/restructured') #nodes -node(u'home', u'Startseite', '', 'menu', body=u'Willkommen\n==========') -node(u'participants', u'Teilnehmer', u'home', 'page', - target=u'concepts/participants') +node(u'home', u'Startseite', '', 'menu') +node(u'willkommen', u'Willkommen', u'home', u'text') +node(u'willkommen', u'Willkommen', u'home/willkommen', u'text', + target=u'resources/homepage') +node(u'participants', u'Teilnehmer', u'home', 'page', target=u'concepts/participants') node(u'topics', u'Themen', u'home', 'page', target=u'concepts/topics') node(u'glossary', u'Glossar', u'home', 'page', target=u'concepts/glossary') node(u'search', u'Suche', u'home', 'page', target=u'concepts/search') +node(u'impressum', u'Impressum', u'home', u'info', target=u'resources/impressum') From 47fefc39df1cc7791c707802178e67e391aee989 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sat, 10 Mar 2012 11:43:44 +0100 Subject: [PATCH 06/11] ignore predicate interface on import also when empty string --- external/element.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/element.py b/external/element.py index 5c48146..1490dd2 100644 --- a/external/element.py +++ b/external/element.py @@ -93,7 +93,7 @@ class ConceptElement(Element): formState = self.getInstance().applyTemplate(data=kw, ignoreValidation=True) # simple hack for resolving interface definition: pi = self.get('predicateInterface') - if pi is not None: + if pi: adapted(self.object).predicateInterface = resolve(pi) def getInstance(self, omit=['title']): From d1b8ece123fd122d31fe3e4ccd8044e142205339 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sat, 10 Mar 2012 14:02:30 +0100 Subject: [PATCH 07/11] make sure request data are correctly converted to unicode --- browser/form.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/browser/form.py b/browser/form.py index c6fdd6b..481f30e 100644 --- a/browser/form.py +++ b/browser/form.py @@ -47,6 +47,7 @@ from cybertools.composer.schema.browser.common import schema_macros, schema_edit from cybertools.composer.schema.schema import FormState from cybertools.stateful.interfaces import IStateful from cybertools.typology.interfaces import IType, ITypeManager +from cybertools.util.format import toUnicode from loops.browser.node import NodeView from loops.browser.concept import ConceptRelationView from loops.common import adapted @@ -154,7 +155,7 @@ class ObjectForm(NodeView): for k, v in data.items(): #overwrite data with values from request.form if k in self.request.form: - data[k] = form[k] + data[k] = toUnicode(form[k]) return data @Lazy From cdb3cd13fcfc2072480d11da925c48203f7d5654 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sat, 10 Mar 2012 16:01:41 +0100 Subject: [PATCH 08/11] mark getAction() method on folder as obsolete --- browser/folder.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/browser/folder.py b/browser/folder.py index 8177b85..e3c5025 100755 --- a/browser/folder.py +++ b/browser/folder.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2008 Helmut Merz helmutm@cy55.de +# Copyright (c) 2012 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 @@ -18,8 +18,6 @@ """ Elements for handling and presentation of pseudo folders. - -$Id$ """ @@ -50,6 +48,7 @@ actions.register('editFolder', 'portlet', DialogAction, class FolderView(ConceptView): def getActions(self, category='concept', page=None, target=None): + # obsolete: define actions via type option if category == 'portlet': return actions.get(category, ['createFolder', 'editFolder'], view=self, page=page, target=target) From 46648c92faf01deccb6ef6b8ba2cdad97ff8c355 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sat, 10 Mar 2012 17:59:52 +0100 Subject: [PATCH 09/11] new VocabularyField that decodes a value according to the vocabulary given --- expert/field.py | 70 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/expert/field.py b/expert/field.py index 7c50b60..d87165a 100644 --- a/expert/field.py +++ b/expert/field.py @@ -20,7 +20,10 @@ Field definitions for reports. """ +from zope.app.form.browser.interfaces import ITerms +from zope import component from zope.i18n.locales import locales +from zope.schema.interfaces import IVocabularyFactory, IContextSourceBinder from cybertools.composer.report.field import Field from cybertools.composer.report.result import ResultSet @@ -39,6 +42,27 @@ class TextField(Field): return row.parent.context.view.renderText(value, self.format) +class DecimalField(Field): + + format = 'decimal' + pattern = u'#,##0.00;-#,##0.00' + renderer = 'right' + + def getDisplayValue(self, row): + value = self.getRawValue(row) + if not value: + return u'' + if not isinstance(value, float): + value = float(value) + nv = row.parent.context.view.nodeView + langInfo = nv and getattr(nv, 'languageInfo', None) or None + if langInfo: + locale = locales.getLocale(langInfo.language) + fmt = locale.numbers.getFormatter(self.format) + return fmt.format(value, pattern=self.pattern) + return '%.2f' % value + + class DateField(Field): format = ('date', 'short') @@ -59,6 +83,52 @@ class DateField(Field): return value.isoformat()[:10] +class VocabularyField(Field): + + vocabulary = None + + def getDisplayValue(self, row): + value = self.getRawValue(row) + if self.vocabulary is None: + return value + items = self.getVocabularyItems(row) + for item in items: + if item['token'] == value: + return item['title'] + + def getVocabularyItems(self, row): + context = row.context + request = row.parent.context.view.request + voc = self.vocabulary + if isinstance(voc, basestring): + terms = self.getVocabularyTerms(voc, context, request) + if terms is not None: + return terms + voc = voc.splitlines() + return [dict(token=t, title=t) for t in voc if t.strip()] + elif IContextSourceBinder.providedBy(voc): + source = voc(row.parent.context) + terms = component.queryMultiAdapter((source, request), ITerms) + if terms is not None: + termsList = [terms.getTerm(value) for value in source] + return [dict(token=t.token, title=t.title) for t in termsList] + else: + return [] + return [dict(token=t.token, title=t.title or t.value) for t in voc] + + def getVocabularyTerms(self, name, context, request): + if context is None or request is None: + return None + source = component.queryUtility(IVocabularyFactory, name=name) + if source is not None: + source = source(context) + terms = component.queryMultiAdapter((source, request), ITerms) + if terms is not None: + termsList = [terms.getTerm(value) for value in source] + return [dict(token=t.token, title=t.title) for t in termsList] + return None + + class UrlField(Field): renderer = 'target' From a415e83468cfc93c4963de2ae20097a7bfc7a582 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sun, 11 Mar 2012 12:49:53 +0100 Subject: [PATCH 10/11] add renderer 'center' for centered report columns --- expert/browser/results.pt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/expert/browser/results.pt b/expert/browser/results.pt index 9a1d2db..adb9060 100644 --- a/expert/browser/results.pt +++ b/expert/browser/results.pt @@ -42,6 +42,12 @@ + + + + + From 364a0c8c5887b21f9e97fcff7d78659ddec26b12 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sun, 11 Mar 2012 16:17:45 +0100 Subject: [PATCH 11/11] add some flexibility to resources listing and Lobo Layout --- browser/concept_macros.pt | 2 +- browser/lobo/standard.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/browser/concept_macros.pt b/browser/concept_macros.pt index 8f11c00..f3109df 100644 --- a/browser/concept_macros.pt +++ b/browser/concept_macros.pt @@ -182,7 +182,7 @@

Resources