open up media asset type for all kinds of external files

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@3205 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2009-02-05 10:29:01 +00:00
parent b3962aba0e
commit 1c1147cda9
13 changed files with 332 additions and 16 deletions

View file

@ -403,6 +403,10 @@ class BaseView(GenericView, I18NView):
def globalOptions(self):
return IOptions(self.loopsRoot)
@Lazy
def typeOptions(self):
return IOptions(adapted(self.typeProvider))
# versioning
@Lazy

View file

@ -140,9 +140,16 @@
<containerViews
for="loops.interfaces.IConceptManager"
index="loops.ManageSite"
contents="loops.ManageSite"
add="loops.ManageSite" />
<page
for="loops.interfaces.IConceptManager"
name="contents.html"
template="contents.pt"
class="cybertools.container.ordered.ContainerView"
permission="loops.ManageSite"
menu="zmi_views" title="Contents" />
<!-- concept -->
<addform
@ -237,15 +244,21 @@
schema="loops.interfaces.IResourceManager"
content_factory="loops.resource.ResourceManager"
template="add.pt"
permission="zope.ManageContent"
/>
permission="zope.ManageContent" />
<containerViews
for="loops.interfaces.IResourceManager"
index="loops.ManageSite"
contents="loops.ManageSite"
add="loops.ManageSite" />
<page
for="loops.interfaces.IResourceManager"
name="contents.html"
template="contents.pt"
class="cybertools.container.ordered.ContainerView"
permission="loops.ManageSite"
menu="zmi_views" title="Contents" />
<!-- resource in general -->
<page

234
browser/contents.pt Normal file
View file

@ -0,0 +1,234 @@
<html metal:use-macro="context/@@standard_macros/view"
i18n:domain="zope">
<body>
<metal:ecmascript fill-slot="ecmascript_slot">
<metal:use use-macro="views/ajax.dojo/main" />
</metal:ecmascript>
<div metal:fill-slot="body">
<div metal:define-macro="contents"
id="body.contents">
<tal:checkmove define="dummy view/checkMoveAction">
<form name="contents" method="post" action="."
tal:attributes="action request/URL"
tal:define="container_contents view/listContentInfo">
<metal:keep-batch define-macro="keep_batch_params">
<tal:param repeat="param python:('b_page', 'b_size', 'b_overlap', 'b_orphan')">
<input type="hidden"
tal:define="value request/?param|nothing"
tal:condition="value"
tal:attributes="name param;
value value" />
</tal:param>
</metal:keep-batch>
<input type="hidden" name="type_name" value=""
tal:attributes="value request/type_name"
tal:condition="request/type_name|nothing" />
<input type="hidden" name="retitle_id" value=""
tal:attributes="value request/retitle_id"
tal:condition="request/retitle_id|nothing" />
<div class="page_error"
tal:condition="view/error"
tal:content="view/error"
i18n:translate="">
Error message
</div>
<table id="sortable" class="listing" summary="Content listing"
i18n:attributes="summary">
<thead>
<tr>
<th style="margin:0; padding:0">
<input type="checkbox" class="noborder" title="Select all items"
i18n:attributes="title"
onclick="f = document.forms.contents['ids:list'];
for (i in f) f[i].checked=this.checked;" /></th>
<th i18n:translate="">Name</th>
<th i18n:translate="">Title</th>
<th i18n:translate="">Size</th>
<th i18n:translate="">Created</th>
<th i18n:translate="">Modified</th>
</tr>
</thead>
<tbody>
<metal:block tal:condition="view/hasAdding">
<tr tal:define="names_required context/@@+/nameAllowed"
tal:condition="python:names_required and request.has_key('type_name')">
<td></td>
<td><input name="new_value" id="focusid" value="" /></td>
<td></td><td></td><td></td>
</tr>
</metal:block>
<metal:block tal:define="supportsRename view/supportsRename;
batch nocall:context/@@cybertools.reporter.batch;
batch python:batch.setup(container_contents)">
<tal:list repeat="item batch/items">
<tr tal:define="oddrow repeat/item/odd;
url item/url;
id_quoted item/id/url:quote"
tal:attributes="class python:oddrow and 'even' or 'odd'" >
<td>
<input type="checkbox" class="noborder" name="ids:list"
tal:attributes="value item/id;
id item/cb_id;
checked request/ids_checked|nothing;"/>
</td>
<td>
<a href="#"
tal:attributes="href string:${url}/@@SelectedManagementView.html"
tal:content="structure item/icon|default"></a>
<span tal:condition="item/rename">
<input name="new_value:list"
tal:attributes="value item/id"/>
<input type="hidden" name="rename_ids:list" value=""
tal:attributes="value item/rename" />
</span>
<span tal:condition="not:item/rename">
<a href="#"
tal:attributes="href
string:${url}/@@SelectedManagementView.html"
tal:content="item/id">foo</a>
</span>
</td>
<td>
<a href="#"
tal:attributes="href string:${url}/@@SelectedManagementView.html"
tal:content="item/title|default">Title</a>
</td>
<td><span tal:content="item/size/sizeForDisplay|nothing"
i18n:translate="">
&nbsp;</span></td>
<td><span tal:define="created item/created|default"
tal:content="created"
i18n:translate="">&nbsp;</span></td>
<td><span tal:define="modified item/modified|default"
tal:content="modified"
i18n:translate="">&nbsp;</span></td>
</tr>
</tal:list>
<metal:nav define-macro="batch_navigation_tr">
<tr class="batch_navigation"
style="border-top: 1px solid #ccc"
tal:condition="batch/showNavigation">
<td colspan="6"
style="text-align: center">
Pages:
<metal:nav define-macro="batch_navigation"
tal:define="first batch/first/title;
previous batch/previous/title;
current batch/current/title;
next batch/next/title;
last batch/last/title;">
<a href="#"
tal:attributes="href batch/first/url;"
tal:content="first"
tal:condition="python: first != current">1</a>
<span tal:condition="python: first &lt; previous-1">...</span>
<a href="#"
tal:attributes="href batch/previous/url;"
tal:content="batch/previous/title"
tal:condition="python: first != previous and previous != current">2</a>
<b tal:content="batch/current/title">3</b>
<a href="#"
tal:attributes="href batch/next/url;"
tal:content="batch/next/title"
tal:condition="python: last != next and next != current">3</a>
<span tal:condition="python: last > next+1">...</span>
<a href="#"
tal:attributes="href batch/last/url;"
tal:content="batch/last/title"
tal:condition="python: last != current">5</a>
</metal:nav>
</td>
</tr>
</metal:nav>
</metal:block>
</tbody>
</table>
<div tal:condition="view/normalButtons">
<input type="submit" name="container_rename_button" value="Rename"
i18n:attributes="value container-rename-button"
tal:condition="view/supportsRename" />
<input type="submit" name="container_cut_button" value="Cut"
i18n:attributes="value container-cut-button"
tal:condition="view/supportsCut" />
<input type="submit" name="container_copy_button" value="Copy"
i18n:attributes="value container-copy-button"
tal:condition="view/supportsCopy" />
<input type="submit" name="container_paste_button" value="Paste"
tal:condition="view/hasClipboardContents"
i18n:attributes="value container-paste-button" />
<input type="submit" name="container_delete_button" value="Delete"
i18n:attributes="value container-delete-button"
tal:condition="view/supportsDelete"
i18n:domain="zope" />
<div tal:condition="view/hasAdding" tal:omit-tag="">
<div tal:omit-tag=""
tal:define="adding nocall:context/@@+;
addingInfo adding/addingInfo;
has_custom_add_view adding/hasCustomAddView;
names_required adding/nameAllowed"
tal:condition="adding/isSingleMenuItem">
<input type="submit" name="container_add_button" value="Add"
i18n:attributes="value add-button"
i18n:domain="zope" />
<input type="text" name="single_new_value" id="focusid"
tal:condition="python:names_required and not has_custom_add_view"
i18n:domain="zope" />
<input type="hidden" name="single_type_name"
tal:attributes="value python:addingInfo[0]['action']" />
</div>
</div>
<div tal:condition="view/orderable">
<input type="submit" name="move_top" value="Top"
i18n:attributes="value container-movetop-button"
i18n:domain="zope" />
<input type="submit" name="move_up" value="Up"
i18n:attributes="value container-moveup-button"
i18n:domain="zope" />
<input type="text" size="2" name="delta" value="1" />
<input type="submit" name="move_down" value="Down"
i18n:attributes="value container-moveup-button"
i18n:domain="zope" />
<input type="submit" name="move_bottom" value="Bottom"
i18n:attributes="value container-movebottom-button"
i18n:domain="zope" />
</div>
</div>
<div tal:condition="view/specialButtons">
<input type="submit" value="Apply"
i18n:attributes="value container-apply-button" />
<input type="submit" name="container_cancel_button" value="Cancel"
i18n:attributes="value container-cancel-button" />
</div>
</form>
</tal:checkmove>
<script type="text/javascript"><!--
if (document.forms.contents.new_value)
document.forms.contents.new_value.focus();
//-->
</script>
</div>
</div>
</body>
</html>

View file

@ -283,6 +283,7 @@ class CreateObjectForm(ObjectForm):
def adapted(self):
ad = self.typeInterface(Resource())
ad.storageName = 'unknown' # hack for file objects: don't try to retrieve data
ad.__type__ = adapted(self.typeConcept)
return ad
@Lazy

View file

@ -58,6 +58,9 @@ from loops.versioning.interfaces import IVersionable
from loops.util import _
resource_macros = ViewPageTemplateFile('resource_macros.pt')
class CustomFileWidget(FileWidget):
def hasInput(self):
@ -103,7 +106,8 @@ class MediaAssetEditForm(EditForm):
class ResourceView(BaseView):
template = ViewPageTemplateFile('resource_macros.pt')
#template = ViewPageTemplateFile('resource_macros.pt')
template = resource_macros
@Lazy
def icon(self):

View file

@ -97,6 +97,7 @@ class AdapterBase(object):
_textIndexAttributes = ()
__is_dummy__ = False
__type__ = None
languageInfo = None
@ -138,6 +139,13 @@ class AdapterBase(object):
def name(self):
return getName(self.context)
@Lazy
def type(self):
return self.__type__ or self.getType()
def getType(self):
return adapted(self.context.getType())
@Lazy
def uid(self):
return util.getUidForObject(self.context)

View file

@ -33,7 +33,7 @@ from cybertools.meta.config import GlobalOptions as BaseGlobalOptions
from cybertools.meta.interfaces import IOptions
from cybertools.meta.namespace import Executor, ExecutionError
from cybertools.typology.interfaces import IType
from loops.interfaces import ILoops, ILoopsObject
from loops.interfaces import ILoops, ILoopsObject, ITypeConcept
#from loops.query import IQueryConcept
from loops.expert.concept import IQueryConcept
from loops import util
@ -91,6 +91,11 @@ class LoopsOptions(Options):
raise ExecutionError('\n' + rc)
class TypeOptions(LoopsOptions):
adapts(ITypeConcept)
class QueryOptions(LoopsOptions):
adapts(IQueryConcept)

View file

@ -12,6 +12,11 @@
<allow interface="cybertools.meta.interfaces.IOptions" />
</zope:class>
<zope:adapter factory="loops.config.base.TypeOptions" trusted="True" />
<zope:class class="loops.config.base.TypeOptions">
<allow interface="cybertools.meta.interfaces.IOptions" />
</zope:class>
<zope:adapter factory="loops.config.base.QueryOptions" trusted="True" />
<zope:class class="loops.config.base.QueryOptions">
<allow interface="cybertools.meta.interfaces.IOptions" />

View file

@ -763,8 +763,13 @@ class IExternalFile(IFile):
missing_value='',
required=False)
externalAddress = Attribute('The full address for accessing the object '
'on the external storage, e.g. a filename or path.')
externalAddress = schema.BytesLine(
title=_(u'External Address'),
description=_(u'The full address for accessing the object '
'on the external storage, e.g. a filename or path.'),
default='',
missing_value='',
required=False)
class IAddressableExternalFile(IExternalFile):

View file

@ -28,7 +28,7 @@ from zope.app.pagetemplate import ViewPageTemplateFile
from zope.cachedescriptors.property import Lazy
from loops.browser.node import NodeView
from loops.browser.resource import ResourceView
from loops.browser.resource import ResourceView, resource_macros
from loops.common import adapted
from loops import util
@ -39,7 +39,11 @@ class MediaAssetView(ResourceView):
@Lazy
def macro(self):
return template.macros['asset']
#return template.macros['asset']
if 'image/' in self.context.contentType:
return template.macros['asset']
else:
return resource_macros.macros['download']
def show(self, useAttachment=False):
versionId = self.request.get('v')

View file

@ -224,6 +224,11 @@ class Resource(Image, Contained):
def getSize(self):
if self._size:
return self._size
size = getattr(adapted(self), 'size', None)
if size is None:
return len(adapted(self).data)
return size
tp = IType(self, None)
if tp is not None:
ti = tp.typeInterface
@ -357,9 +362,15 @@ class ExternalFileAdapter(FileAdapter):
storageParams = property(getStorageParams, setStorageParams)
def getExternalAddress(self):
return getattr(self.context, '_externalAddress', self.context.__name__)
return getattr(self.context, '_externalAddress', None) or self.context.__name__
def setExternalAddress(self, addr):
self.context._externalAddress = addr
if addr:
data = self.data
self.context._size = len(data)
contentType = guess_content_type(addr, self.data[:100])
if contentType:
self.contentType = contentType[0]
externalAddress = property(getExternalAddress, setExternalAddress)
@property
@ -372,12 +383,14 @@ class ExternalFileAdapter(FileAdapter):
def setData(self, data):
storageParams = self.storageParams
storageName = self.storageName
externalAddress = self.externalAddress
storage = component.getUtility(IExternalStorage, name=storageName)
storage.setData(self.externalAddress, data, params=storageParams)
self.context._size = len(data)
# remember storage settings:
self.storageParams = storageParams
self.storageName = storageName
self.externalAddress = externalAddress
def getData(self):
if self.storageName in ('unknown', None): # object not set up yet
@ -387,6 +400,13 @@ class ExternalFileAdapter(FileAdapter):
data = property(getData, setData)
@property
def size(self):
if self.storageName in ('unknown', None): # object not set up yet
return ''
storage = component.getUtility(IExternalStorage, name=self.storageName)
return storage.getSize(self.externalAddress, params=self.storageParams)
class AddressableExternalFileAdapter(ExternalFileAdapter):

View file

@ -25,7 +25,10 @@ $Id$
from zope.component import adapts
from cybertools.composer.schema.factory import SchemaFactory
from loops.common import adapted
from loops.interfaces import IResourceAdapter, IFile, INote, IAddressableExternalFile
from cybertools.meta.interfaces import IOptions
from cybertools.typology.interfaces import IType
class ResourceSchemaFactory(SchemaFactory):
@ -47,10 +50,19 @@ class FileSchemaFactory(SchemaFactory):
def __call__(self, interface, **kw):
schema = super(FileSchemaFactory, self).__call__(interface, **kw)
if 'request' in kw:
principal = kw['request'].principal
if not principal or principal.id != 'rootadmin':
schema.fields.remove('contentType')
options = IOptions(self.context.type)
hide = options('hide_fields') or []
show = options('show_fields') or []
for f in ('contentType', 'externalAddress',):
if f in schema.fields and f not in show:
schema.fields.remove(f)
for f in hide:
if f in schema.fields:
schema.fields.remove(f)
#if 'request' in kw:
# principal = kw['request'].principal
# if not principal or principal.id != 'rootadmin':
# schema.fields.remove('contentType')
return schema

View file

@ -50,7 +50,7 @@ from loops.browser.node import ViewPropertiesConfigurator
from loops.common import NameChooser
from loops.concept import Concept
from loops.concept import IndexAttributes as ConceptIndexAttributes
from loops.config.base import GlobalOptions, LoopsOptions, QueryOptions
from loops.config.base import GlobalOptions, LoopsOptions, QueryOptions, TypeOptions
from loops.interfaces import ILoopsObject, IIndexAttributes
from loops.interfaces import IDocument, IFile, ITextDocument
from loops.layout.base import LayoutNode
@ -132,6 +132,7 @@ class TestSite(object):
component.provideAdapter(BaseSecuritySetter)
component.provideAdapter(LoopsOptions)
component.provideAdapter(QueryOptions)
component.provideAdapter(TypeOptions)
component.provideUtility(GlobalOptions())
component.provideAdapter(Instance)