From b1cb9456fa4f0127983a02c049d39d24482f5511 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Thu, 8 Mar 2012 16:55:52 +0100 Subject: [PATCH 01/11] improve decimal field: use pattern, show right-aligned --- expert/field.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/expert/field.py b/expert/field.py index 5664c54..7c500bd 100644 --- a/expert/field.py +++ b/expert/field.py @@ -41,7 +41,9 @@ class TextField(Field): class DecimalField(Field): - format = '###,###,##0.##' + format = 'decimal' + pattern = u'#,##0.00;-#,##0.00' + renderer = 'right' def getDisplayValue(self, row): value = self.getRawValue(row) @@ -53,8 +55,8 @@ class DecimalField(Field): langInfo = nv and getattr(nv, 'languageInfo', None) or None if langInfo: locale = locales.getLocale(langInfo.language) - fmt = locale.numbers.getFormatter('decimal') - return fmt.format(value) + fmt = locale.numbers.getFormatter(self.format) + return fmt.format(value, pattern=self.pattern) return '%.2f' % value From fccc9a7f50b8552ecf72a3a468db3be1ff177c38 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Fri, 9 Mar 2012 14:06:08 +0100 Subject: [PATCH 02/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 03/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 04/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 05/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 06/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 07/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 08/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 09/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 10/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

Date: Mon, 12 Mar 2012 08:14:44 +0100 Subject: [PATCH 11/11] check for principal is None - may happen when zope.authentication is patched --- browser/common.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/browser/common.py b/browser/common.py index 1e400cb..ef4ef49 100644 --- a/browser/common.py +++ b/browser/common.py @@ -269,7 +269,10 @@ class BaseView(GenericView, I18NView): for c in cr: try: principal = pau.getPrincipal(c) - creators.append(principal.title) + if principal is None: + creators.append(c) + else: + creators.append(principal.title) except PrincipalLookupError: creators.append(c) return creators