more on the organize sub-package; set up query machinery for dynamically providing views
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1216 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
		
							parent
							
								
									8edec76c1d
								
							
						
					
					
						commit
						4041b91fca
					
				
					 11 changed files with 194 additions and 35 deletions
				
			
		|  | @ -96,6 +96,10 @@ class BaseView(object): | |||
|     def url(self): | ||||
|         return zapi.absoluteURL(self.context, self.request) | ||||
| 
 | ||||
|     @Lazy | ||||
|     def view(self): | ||||
|         return self | ||||
| 
 | ||||
|     @Lazy | ||||
|     def token(self): | ||||
|         return self.loopsRoot.getLoopsUri(self.context) | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ Definition of the Task view class. | |||
| $Id$ | ||||
| """ | ||||
| 
 | ||||
| from zope import interface, component, schema | ||||
| from zope.app import zapi | ||||
| from zope.app.catalog.interfaces import ICatalog | ||||
| from zope.app.event.objectevent import ObjectCreatedEvent, ObjectModifiedEvent | ||||
|  | @ -35,7 +36,6 @@ from zope.formlib.form import EditForm, FormFields | |||
| from zope.interface import implements | ||||
| from zope.publisher.interfaces import BadRequest | ||||
| from zope.publisher.interfaces.browser import IBrowserRequest | ||||
| from zope import schema | ||||
| from zope.schema.interfaces import IIterableSource | ||||
| from zope.security.proxy import removeSecurityProxy | ||||
| 
 | ||||
|  | @ -78,6 +78,25 @@ class ConceptView(BaseView): | |||
|         for r in self.context.getResourceRelations(): | ||||
|             yield ConceptRelationView(r, self.request, contextIsSecond=True) | ||||
| 
 | ||||
|     @Lazy | ||||
|     def view(self): | ||||
|         ti = IType(self.context).typeInterface | ||||
|         # TODO: check the interface (maybe for a base interface IViewProvider) | ||||
|         #       instead of the viewName attribute: | ||||
|         if ti and 'viewName' in ti: | ||||
|             typeAdapter = ti(self.context) | ||||
|             viewName = typeAdapter.viewName | ||||
|             # ??? Would it make sense to use a somehow restricted interface | ||||
|             #     that should be provided by the view like IQuery? | ||||
|             #viewInterface = getattr(typeAdapter, 'viewInterface', None) or IQuery | ||||
|             if viewName: | ||||
|                 adapter = component.queryMultiAdapter((self.context, self.request), | ||||
|                                          interface.Interface, name=viewName) | ||||
|                 if adapter is not None: | ||||
|                     return adapter | ||||
|         #elif type provides view: use this | ||||
|         return self | ||||
| 
 | ||||
| 
 | ||||
| class ConceptConfigureView(ConceptView): | ||||
| 
 | ||||
|  |  | |||
|  | @ -105,7 +105,9 @@ class NodeView(BaseView): | |||
|     def target(self): | ||||
|         obj = self.targetObject | ||||
|         if obj is not None: | ||||
|             return zapi.getMultiAdapter((obj, self.request)) | ||||
|             basicView = zapi.getMultiAdapter((obj, self.request)) | ||||
|             return basicView.view | ||||
|             #return zapi.getMultiAdapter((obj, self.request)) | ||||
| 
 | ||||
|     def renderTarget(self): | ||||
|         target = self.target | ||||
|  | @ -117,6 +119,7 @@ class NodeView(BaseView): | |||
| 
 | ||||
|     @Lazy | ||||
|     def bodyMacro(self): | ||||
|         # ?TODO: replace by: return self.target.macroName | ||||
|         target = self.targetObject | ||||
|         if target is None or IDocument.providedBy(target): | ||||
|             return 'textbody' | ||||
|  |  | |||
|  | @ -39,8 +39,10 @@ | |||
|                          ondblclick python: item.openEditWindow('configure.html')"> | ||||
|       <span tal:content="structure body">Node Body</span> | ||||
|     </div> | ||||
|     <tal:concepts define="item item/target"> | ||||
|       <div metal:use-macro="views/concept_macros/conceptlisting2" /> | ||||
|     <tal:concepts define="item item/target; | ||||
|                           macro item/macro"> | ||||
|       <div metal:use-macro="macro" /> | ||||
|       <!--<div metal:use-macro="views/concept_macros/conceptlisting2" />--> | ||||
|     </tal:concepts> | ||||
|   </tal:body> | ||||
| </metal:body> | ||||
|  |  | |||
|  | @ -279,6 +279,7 @@ | |||
|   <adapter factory="loops.type.LoopsTypeManager" /> | ||||
|    | ||||
|   <adapter factory="loops.type.TypeConcept" /> | ||||
|   <adapter factory="loops.query.QueryConcept" /> | ||||
|    | ||||
|   <adapter factory="loops.external.NodesLoader" /> | ||||
|   <adapter factory="loops.external.NodesExporter" /> | ||||
|  |  | |||
							
								
								
									
										54
									
								
								helpers.txt
									
										
									
									
									
								
							
							
						
						
									
										54
									
								
								helpers.txt
									
										
									
									
									
								
							|  | @ -215,7 +215,6 @@ Type-based interfaces and adapters | |||
| A type has an optional typeInterface attribute that objects of this type | ||||
| will be adaptable to. The default for this is None: | ||||
| 
 | ||||
|   >>> cc1_type.typeInterface | ||||
|   >>> cc1_type.typeInterface is None | ||||
|   True | ||||
| 
 | ||||
|  | @ -235,7 +234,7 @@ i.e. the 'topic' concept, via an adapter: | |||
|   >>> class Topic(object): | ||||
|   ...     implements(ITopic) | ||||
|   ...     def __init__(self, context): pass | ||||
|   >>> ztapi.provideAdapter(IConcept, ITopic, Topic) | ||||
|   >>> component.provideAdapter(Topic, (IConcept,), ITopic) | ||||
|    | ||||
|   >>> ITypeConcept(topic).typeInterface = ITopic | ||||
|   >>> cc1.conceptType = topic | ||||
|  | @ -246,6 +245,57 @@ i.e. the 'topic' concept, via an adapter: | |||
|   True | ||||
| 
 | ||||
| 
 | ||||
| Concepts as queries | ||||
| ------------------- | ||||
| 
 | ||||
| We first have to set up the query type, i.e. a type concept associated | ||||
| with the IQueryConcept interface: | ||||
| 
 | ||||
|   >>> from loops.query import IQueryConcept, QueryConcept | ||||
|   >>> component.provideAdapter(QueryConcept, (IConcept,), IQueryConcept) | ||||
| 
 | ||||
|   >>> query = concepts['query'] = Concept(u'Query') | ||||
|   >>> query.conceptType = typeObject | ||||
|   >>> ITypeConcept(query).typeInterface = IQueryConcept | ||||
| 
 | ||||
| Next we need a concept of this type: | ||||
| 
 | ||||
|   >>> simpleQuery = concepts['simpleQuery'] = Concept(u'Simple query') | ||||
|   >>> simpleQuery.conceptType = query | ||||
|   >>> sq_type = IType(simpleQuery) | ||||
|   >>> sq_adapter = sq_type.typeInterface(simpleQuery) | ||||
|   >>> sq_adapter.viewName = 'simpleview.html' | ||||
|   >>> simpleQuery._viewName | ||||
|   'simpleview.html' | ||||
| 
 | ||||
| This viewName attribute of the query will be automatically used by | ||||
| a concept view when asked for the view that should be used for rendering | ||||
| the concept... | ||||
| 
 | ||||
|   >>> from loops.browser.concept import ConceptView | ||||
|   >>> from zope.publisher.browser import TestRequest | ||||
|   >>> sq_baseView = ConceptView(simpleQuery, TestRequest()) | ||||
|   >>> sq_view = sq_baseView.view | ||||
| 
 | ||||
| ...but only when the view exists, i.e. there is a class registered as a | ||||
| view/multi-adapter with this name: | ||||
|    | ||||
|   >>> sq_view is sq_baseView | ||||
|   True | ||||
| 
 | ||||
|   >>> class SimpleView(object): | ||||
|   ...     def __init__(self, context, request): pass | ||||
|   >>> from zope.publisher.interfaces.browser import IBrowserRequest | ||||
|   >>> component.provideAdapter(SimpleView, (IConcept, IBrowserRequest), Interface, | ||||
|   ...                          name='simpleview.html') | ||||
|   >>> sq_baseView = ConceptView(simpleQuery, TestRequest()) | ||||
|   >>> sq_view = sq_baseView.view | ||||
|   >>> sq_view is sq_baseView | ||||
|   False | ||||
|   >>> sq_view.__class__ | ||||
|   <class 'SimpleView'> | ||||
| 
 | ||||
| 
 | ||||
| Controlling presentation using view properties | ||||
| ---------------------------------------------- | ||||
| 
 | ||||
|  |  | |||
|  | @ -22,8 +22,7 @@ ZCML setup): | |||
|   >>> from loops.concept import ConceptManager, Concept | ||||
|   >>> from loops.interfaces import IConcept, ITypeConcept | ||||
| 
 | ||||
|   >>> site['loops'] = Loops() | ||||
|   >>> loopsRoot = site['loops'] | ||||
|   >>> loopsRoot = site['loops'] = Loops() | ||||
| 
 | ||||
|   >>> from cybertools.relation.interfaces import IRelationRegistry | ||||
|   >>> from cybertools.relation.registry import DummyRelationRegistry | ||||
|  |  | |||
|  | @ -54,13 +54,14 @@ class UserId(schema.TextLine): | |||
|         try: | ||||
|             principal = auth.getPrincipal(userId) | ||||
|         except PrincipalLookupError: | ||||
|             raiseValidationError(u'User %s does not exist' % userId) | ||||
|             raiseValidationError(_(u'User $userId does not exist', | ||||
|                                    mapping={'userId': userId})) | ||||
|         pa = annotations(principal) | ||||
|         person = pa.get(ANNOTATION_KEY, None) | ||||
|         if person is not None and person != self.context: | ||||
|             raiseValidationError( | ||||
|                 u'There is alread a person (%s) assigned to user %s.' | ||||
|                 % (zapi.getName(person), userId)) | ||||
|                 _(u'There is alread a person ($person) assigned to user $userId.', | ||||
|                  mapping={'person': zapi.getName(person), 'userId': userId})) | ||||
| 
 | ||||
| 
 | ||||
| class IPerson(IBasePerson): | ||||
|  |  | |||
|  | @ -37,7 +37,7 @@ from cybertools.organize.party import Person as BasePerson | |||
| from cybertools.typology.interfaces import IType | ||||
| from loops.interfaces import IConcept | ||||
| from loops.organize.interfaces import IPerson, ANNOTATION_KEY | ||||
| from loops.type import TypeInterfaceSourceList | ||||
| from loops.type import TypeInterfaceSourceList, AdapterBase | ||||
| 
 | ||||
| 
 | ||||
| # register IPerson as a type interface - (TODO: use a function for this) | ||||
|  | @ -45,34 +45,14 @@ from loops.type import TypeInterfaceSourceList | |||
| TypeInterfaceSourceList.typeInterfaces += (IPerson,) | ||||
| 
 | ||||
| 
 | ||||
| class Person(BasePerson): | ||||
| class Person(AdapterBase, BasePerson): | ||||
|     """ typeInterface adapter for concepts of type 'person'. | ||||
|     """ | ||||
| 
 | ||||
|     implements(IPerson) | ||||
|     adapts(IConcept) | ||||
| 
 | ||||
|     __attributes = ('context', '__parent__', 'userId',) | ||||
|     __schemas = list(IPerson) + list(IConcept) | ||||
| 
 | ||||
|     def __init__(self, context): | ||||
|         self.context = context # to get the permission stuff right | ||||
|         self.__parent__ = context | ||||
| 
 | ||||
|     def __getattr__(self, attr): | ||||
|         self.checkAttr(attr) | ||||
|         return getattr(self.context, '_' + attr, None) | ||||
| 
 | ||||
|     def __setattr__(self, attr, value): | ||||
|         if attr in self.__attributes: | ||||
|             object.__setattr__(self, attr, value) | ||||
|         else: | ||||
|             self.checkAttr(attr) | ||||
|             setattr(self.context, '_' + attr, value) | ||||
| 
 | ||||
|     def checkAttr(self, attr): | ||||
|         if attr not in self.__schemas: | ||||
|             raise AttributeError(attr) | ||||
|     _attributes = ('context', '__parent__', 'userId',) | ||||
|     _schemas = list(IPerson) + list(IConcept) | ||||
| 
 | ||||
|     def getUserId(self): | ||||
|         return getattr(self.context, '_userId', None) | ||||
|  |  | |||
							
								
								
									
										70
									
								
								query.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								query.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,70 @@ | |||
| # | ||||
| #  Copyright (c) 2006 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 | ||||
| # | ||||
| 
 | ||||
| """ | ||||
| Query management stuff. | ||||
| 
 | ||||
| $Id$ | ||||
| """ | ||||
| 
 | ||||
| from zope.app import zapi | ||||
| from zope.component import adapts | ||||
| from zope.interface import Interface, Attribute, implements | ||||
| from zope.i18nmessageid import MessageFactory | ||||
| from zope.cachedescriptors.property import Lazy | ||||
| from zope import schema | ||||
| from zope.security.proxy import removeSecurityProxy | ||||
| 
 | ||||
| from cybertools.typology.type import BaseType, TypeManager | ||||
| from loops.interfaces import IConcept | ||||
| from loops.type import AdapterBase, TypeInterfaceSourceList | ||||
| 
 | ||||
| _ = MessageFactory('loops') | ||||
| 
 | ||||
| 
 | ||||
| class IQuery(Interface): | ||||
|     """ The basic query interface. | ||||
|     """ | ||||
| 
 | ||||
|     def query(self, **kw): | ||||
|         """ Execute the query and return a sequence of objects. | ||||
|         """ | ||||
| 
 | ||||
| 
 | ||||
| class IQueryConcept(Interface): | ||||
|     """ The schema for the query type. | ||||
|     """ | ||||
| 
 | ||||
|     viewName = schema.TextLine( | ||||
|         title=_(u'Adapter/View name'), | ||||
|         description=_(u'The name of the (mulit-) adapter (typically a view) ' | ||||
|                        'to be used for the query and for presenting ' | ||||
|                        'the results'), | ||||
|         default=u'', | ||||
|         required=True) | ||||
| 
 | ||||
| 
 | ||||
| class QueryConcept(AdapterBase): | ||||
| 
 | ||||
|     implements(IQueryConcept) | ||||
| 
 | ||||
|     _schemas = list(IQueryConcept) + list(IConcept) | ||||
| 
 | ||||
| 
 | ||||
| TypeInterfaceSourceList.typeInterfaces += (IQueryConcept,) | ||||
| 
 | ||||
							
								
								
									
										30
									
								
								type.py
									
										
									
									
									
								
							
							
						
						
									
										30
									
								
								type.py
									
										
									
									
									
								
							|  | @ -215,3 +215,33 @@ class TypeInterfaceSourceList(object): | |||
|     def __len__(self): | ||||
|         return len(self.typeInterfaces) | ||||
| 
 | ||||
| 
 | ||||
| class AdapterBase(object): | ||||
|     """ (Mix-in) Class for concept adapters that provide editing of fields | ||||
|         defined by the type interface. | ||||
|     """ | ||||
| 
 | ||||
|     adapts(IConcept) | ||||
|      | ||||
|     _attributes = ('context', '__parent__', ) | ||||
|     _schemas = (IConcept,) | ||||
|      | ||||
|     def __init__(self, context): | ||||
|         self.context = context # to get the permission stuff right | ||||
|         self.__parent__ = context | ||||
| 
 | ||||
|     def __getattr__(self, attr): | ||||
|         self.checkAttr(attr) | ||||
|         return getattr(self.context, '_' + attr, None) | ||||
| 
 | ||||
|     def __setattr__(self, attr, value): | ||||
|         if attr in self._attributes: | ||||
|             object.__setattr__(self, attr, value) | ||||
|         else: | ||||
|             self.checkAttr(attr) | ||||
|             setattr(self.context, '_' + attr, value) | ||||
| 
 | ||||
|     def checkAttr(self, attr): | ||||
|         if attr not in self._schemas: | ||||
|             raise AttributeError(attr) | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 helmutm
						helmutm