[Zope3-checkins] CVS: Zope3/src/zope/products/content -
__init__.py:1.1.2.1 configure.zcml:1.1.2.1 file.py:1.1.2.1
fssync.py:1.1.2.1 i18nfile.py:1.1.2.1 i18nimage.py:1.1.2.1
image.py:1.1.2.1
Philipp von Weitershausen
philikon at philikon.de
Sun Feb 8 09:03:45 EST 2004
Update of /cvs-repository/Zope3/src/zope/products/content
In directory cvs.zope.org:/tmp/cvs-serv10229/products/content
Added Files:
Tag: philikon-movecontent-branch
__init__.py configure.zcml file.py fssync.py i18nfile.py
i18nimage.py image.py
Log Message:
Move zope.app.content,
zope.app.interfaces.content,
and zope.app.browser.content
to zope.products.content and zope.products.codecontent, respectively.
=== Added File Zope3/src/zope/products/content/__init__.py ===
#
# This file is necessary to make this directory a package.
=== Added File Zope3/src/zope/products/content/configure.zcml ===
<configure
xmlns='http://namespaces.zope.org/zope'
xmlns:browser='http://namespaces.zope.org/browser'
xmlns:fssync='http://namespaces.zope.org/fssync'
i18n_domain='zope'
>
<!-- Module aliases for backward compat -->
<modulealias
module="zope.app.folder"
alias="zope.app.content.folder"
/>
<modulealias
module=".file"
alias="zope.app.content.file"
/>
<!-- Simple Folder Directives -->
<interface
interface="zope.app.interfaces.folder.IFolder"
type="zope.app.interfaces.content.IContentType"
/>
<content class="zope.app.folder.Folder">
<implements interface="zope.app.interfaces.container.IContentContainer" />
<implements
interface="zope.app.interfaces.annotation.IAttributeAnnotatable"
/>
<factory
id="Folder"
permission="zope.ManageContent"
title="Folder"
description="Minimal folder" />
<allow
attributes="getSiteManager"
/>
<require
permission="zope.ManageServices"
attributes="setSiteManager"
/>
<require
permission="zope.View"
interface="zope.app.interfaces.container.IReadContainer"
/>
<require
permission="zope.ManageContent"
interface="zope.app.interfaces.container.IWriteContainer"
/>
</content>
<adapter
for="zope.app.interfaces.folder.IFolder"
provides="zope.app.interfaces.file.IDirectoryFactory"
factory="zope.app.container.directory.Cloner"
permission="zope.ManageContent"
/>
<adapter
for="zope.app.interfaces.folder.IFolder"
provides="zope.app.interfaces.file.IFileFactory"
factory=".image.FileFactory"
permission="zope.ManageContent"
/>
<adapter
for="zope.app.interfaces.folder.IFolder"
provides="zope.app.interfaces.file.IReadDirectory"
factory=".fssync.ReadDirectory"
permission="zope.View"
/>
<!-- Image -->
<permission
id="zope.AddImages"
title="[add-images-permission] Add Images"
/>
<interface
interface=".interfaces.image.IImage"
type="zope.app.interfaces.content.IContentType"
/>
<content class=".image.Image">
<factory
id="Image"
permission="zope.ManageContent"
title="Image"
description="An Image" />
<require
permission="zope.View"
interface=".interfaces.file.IReadFile"
attributes="getImageSize"
/>
<require
permission="zope.ManageContent"
interface=".interfaces.file.IWriteFile"
set_schema=".interfaces.file.IReadFile"
/>
<implements
interface="zope.app.interfaces.annotation.IAttributeAnnotatable"
/>
</content>
<adapter
factory=".image.ImageSized"
provides="zope.app.interfaces.size.ISized"
for=".interfaces.image.IImage"
/>
<!-- I18n Image -->
<interface
interface=".interfaces.i18nimage.II18nImage"
type="zope.app.interfaces.content.IContentType"
/>
<content class=".i18nimage.I18nImage">
<factory
id="I18nImage"
permission="zope.ManageContent"
title="I18n Image"
description="An Internationalized Image" />
<require
permission="zope.View"
interface=".interfaces.file.IReadFile"
attributes="getImageSize"
/>
<require
permission="zope.ManageContent"
interface=".interfaces.file.IWriteFile" />
<require
permission="zope.View"
attributes="getDefaultLanguage getAvailableLanguages" />
<require
permission="zope.ManageContent"
attributes="setDefaultLanguage removeLanguage" />
<implements
interface="zope.app.interfaces.annotation.IAttributeAnnotatable"
/>
</content>
<!-- File -->
<interface
interface=".interfaces.file.IFile"
type="zope.app.interfaces.content.IContentType"
/>
<content class=".file.File">
<factory
id="File"
permission="zope.ManageContent"
title="File"
description="A File" />
<require
permission="zope.View"
interface=".interfaces.file.IReadFile" />
<require
permission="zope.ManageContent"
interface=".interfaces.file.IWriteFile"
set_schema=".interfaces.file.IReadFile"
/>
<implements
interface="zope.app.interfaces.annotation.IAttributeAnnotatable"
/>
</content>
<adapter
for=".interfaces.file.IFile"
provides="zope.app.interfaces.file.IReadFile"
factory=".file.FileReadFile"
permission="zope.View"
/>
<adapter
for=".interfaces.file.IFile"
provides="zope.app.interfaces.file.IWriteFile"
factory=".file.FileWriteFile"
permission="zope.ManageContent"
/>
<!-- I18n File -->
<interface
interface=".i18nfile.II18nFile"
type="zope.app.interfaces.content.IContentType"
/>
<content class=".i18nfile.I18nFile">
<factory
id=".I18nFile"
permission="zope.ManageContent"
title="I18n File"
description="An Internationalized File" />
<require
permission="zope.View"
interface=".interfaces.file.IReadFile" />
<require
permission="zope.ManageContent"
interface=".interfaces.file.IWriteFile" />
<require
permission="zope.View"
attributes="getDefaultLanguage getAvailableLanguages" />
<require
permission="zope.ManageContent"
attributes="setDefaultLanguage removeLanguage" />
<implements
interface="zope.app.interfaces.annotation.IAttributeAnnotatable"
/>
</content>
<adapter
factory=".file.SearchableText"
provides="zope.app.interfaces.index.text.ISearchableText"
for=".interfaces.file.IReadFile"
/>
<!-- fssync:adapter directives -->
<fssync:adapter
factory="zope.fssync.server.entryadapter.DefaultFileAdpater"
/>
<fssync:adapter
class=".file.File"
factory=".fssync.FileAdapter"
/>
<fssync:adapter
class=".image.Image"
factory=".fssync.FileAdapter"
/>
<fssync:adapter
class="zope.app.folder.Folder"
factory=".fssync.FolderAdapter"
/>
<!-- include the browser package -->
<include package=".browser" />
</configure>
=== Added File Zope3/src/zope/products/content/file.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id: file.py,v 1.1.2.1 2004/02/08 14:03:44 philikon Exp $
"""
from persistence import Persistent
from transaction import get_transaction
from zope.interface import implements
from zope.publisher.browser import FileUpload
from interfaces.file import IFile, IReadFile, IFileContent
# set the size of the chunks
MAXCHUNKSIZE = 1 << 16
class File(Persistent):
implements(IFileContent, IFile)
def __init__(self, data='', contentType=''):
self.data = data
self.contentType = contentType
def __len__(self):
return self.size
def setContentType(self, contentType):
'''See interface IFile'''
self._contentType = contentType
def getContentType(self):
'''See interface IFile'''
return self._contentType
def edit(self, data, contentType=None):
'''See interface IFile'''
# XXX This seems broken to me, as setData can override the
# content type explicitly passed in.
if contentType is not None:
self._contentType = contentType
if isinstance(data, FileUpload) and not data.filename:
data = None # Ignore empty files
if data is not None:
self.data = data
def getData(self):
'''See interface IFile'''
if isinstance(self._data, FileChunk):
return str(self._data)
else:
return self._data
def setData(self, data):
'''See interface IFile'''
# Handle case when data is a string
if isinstance(data, unicode):
data = data.encode('UTF-8')
if isinstance(data, str):
self._data, self._size = FileChunk(data), len(data)
return
# Handle case when data is None
if data is None:
raise TypeError('Cannot set None data on a file.')
# Handle case when data is already a FileChunk
if isinstance(data, FileChunk):
size = len(data)
self._data, self._size = data, size
return
# Handle case when data is a file object
seek = data.seek
read = data.read
seek(0, 2)
size = end = data.tell()
if size <= 2*MAXCHUNKSIZE:
seek(0)
if size < MAXCHUNKSIZE:
self._data, self._size = read(size), size
return
self._data, self._size = FileChunk(read(size)), size
return
# Make sure we have an _p_jar, even if we are a new object, by
# doing a sub-transaction commit.
get_transaction().savepoint()
jar = self._p_jar
if jar is None:
# Ugh
seek(0)
self._data, self._size = FileChunk(read(size)), size
return
# Now we're going to build a linked list from back
# to front to minimize the number of database updates
# and to allow us to get things out of memory as soon as
# possible.
next = None
while end > 0:
pos = end - MAXCHUNKSIZE
if pos < MAXCHUNKSIZE:
pos = 0 # we always want at least MAXCHUNKSIZE bytes
seek(pos)
data = FileChunk(read(end - pos))
# Woooop Woooop Woooop! This is a trick.
# We stuff the data directly into our jar to reduce the
# number of updates necessary.
data._p_jar = jar
# This is needed and has side benefit of getting
# the thing registered:
data.next = next
# Now make it get saved in a sub-transaction!
get_transaction().savepoint()
# Now make it a ghost to free the memory. We
# don't need it anymore!
data._p_changed = None
next = data
end = pos
self._data, self._size = next, size
return
def getSize(self):
'''See interface IFile'''
return self._size
data = property(getData, setData, None,
"""Contains the data of the file.""")
contentType = property(getContentType, setContentType, None,
"""Specifies the content type of the data.""")
size = property(getSize, None, None,
"""Specifies the size of the file in bytes. Read only.""")
# Adapter for ISearchableText
from zope.app.interfaces.index.text import ISearchableText
class SearchableText:
implements(ISearchableText)
__used_for__ = IReadFile
def __init__(self, file):
self.file = file
def getSearchableText(self):
if self.file.contentType == "text/plain":
return [unicode(self.file.data)]
else:
return None
class FileChunk(Persistent):
# Wrapper for possibly large data
next = None
def __init__(self, data):
self._data = data
def __getslice__(self, i, j):
return self._data[i:j]
def __len__(self):
data = str(self)
return len(data)
def __str__(self):
next = self.next
if next is None:
return self._data
result = [self._data]
while next is not None:
self = next
result.append(self._data)
next = self.next
return ''.join(result)
# Adapters for file-system style access
class FileReadFile:
def __init__(self, context):
self.context = context
def read(self):
return self.context.getData()
def size(self):
return len(self.context.getData())
class FileWriteFile:
def __init__(self, context):
self.context = context
def write(self, data):
self.context.setData(data)
=== Added File Zope3/src/zope/products/content/fssync.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Filesystem synchronization support.
$Id: fssync.py,v 1.1.2.1 2004/02/08 14:03:44 philikon Exp $
"""
from zope.interface import implements
from zope.fssync.server.entryadapter import ObjectEntryAdapter, \
DirectoryAdapter, AttrMapping
from zope.fssync.server.interfaces import IObjectFile, IContentDirectory
__metaclass__ = type
class RootDirectoryFactory:
def __init__(self, context):
pass
def __call__(self, name):
return Folder()
class ReadDirectory:
"""Adapter to provide a file-system rendition of folders
"""
def __init__(self, context):
self.context = context
def keys(self):
keys = self.context.keys()
if ISite.isImplementedBy(self.context):
return list(keys) + ['++etc++site']
return keys
def get(self, key, default=None):
if key == '++etc++site' and ISite.isImplementedBy(self.context):
return self.context.getSiteManager()
return self.context.get(key, default)
def __iter__(self):
return iter(self.keys())
def __getitem__(self, key):
v = self.get(key, self)
if v is self:
raise KeyError, key
return v
def values(self):
return map(self.get, self.keys())
def __len__(self):
l = len(self.context)
if ISite.isImplementedBy(self.context):
l += 1
return l
def items(self):
get = self.get
return [(key, get(key)) for key in self.keys()]
def __contains__(self, key):
return self.get(key) is not None
class FolderAdapter(DirectoryAdapter):
"""Adapter to provide an fssync interpretation of folders
"""
def contents(self):
result = super(FolderAdapter, self).contents()
if ISite.isImplementedBy(self.context):
sm = self.context.getSiteManager()
result.append(('++etc++site', sm))
return result
class FileAdapter(ObjectEntryAdapter):
"""ObjectFile adapter for file objects.
"""
implements(IObjectFile)
def getBody(self):
return self.context.getData()
def setBody(self, data):
self.context.setData(data)
def extra(self):
return AttrMapping(self.context, ('contentType',))
=== Added File Zope3/src/zope/products/content/i18nfile.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id: i18nfile.py,v 1.1.2.1 2004/02/08 14:03:44 philikon Exp $
"""
import persistence
from zope.interface import implements
from interfaces.i18nfile import II18nFile
from file import File
# XXX We shouldn't be dependent on Browser here! Aaaargh.
from zope.publisher.browser import FileUpload
class I18nFile(persistence.Persistent):
"""I18n aware file object. It contains a number of File objects --
one for each language.
"""
implements(II18nFile)
def __init__(self, data='', contentType=None, defaultLanguage='en'):
""" """
self._data = {}
self.defaultLanguage = defaultLanguage
self.setData(data, language=defaultLanguage)
if contentType is None:
self.setContentType('')
else:
self.setContentType(contentType)
def __len__(self):
return self.getSize()
def _create(self, data):
"""Create a new subobject of the appropriate type. Should be
overriden in subclasses.
"""
return File(data)
def _get(self, language):
"""Helper function -- return a subobject for a given language,
and if it does not exist, return a subobject for the default
language.
"""
file = self._data.get(language)
if not file:
file = self._data[self.defaultLanguage]
return file
def _get_or_add(self, language, data=''):
"""Helper function -- return a subobject for a given language,
and if it does not exist, create and return a new subobject.
"""
if language is None:
language = self.defaultLanguage
file = self._data.get(language)
if not file:
self._data[language] = file = self._create(data)
self._p_changed = 1
return file
def setContentType(self, contentType):
'''See interface IFile'''
self._contentType = contentType
def getContentType(self):
'''See interface IFile'''
return self._contentType
contentType = property(getContentType, setContentType)
def edit(self, data, contentType=None, language=None):
'''See interface IFile'''
# XXX This seems broken to me, as setData can override the
# content type explicitly passed in.
if contentType is not None:
self.setContentType(contentType)
if isinstance(data, FileUpload) and not data.filename:
data = None # Ignore empty files
if data is not None:
self.setData(data, language)
def getData(self, language=None):
'''See interface IFile'''
return self._get(language).getData()
def setData(self, data, language=None):
'''See interface IFile'''
self._get_or_add(language).setData(data)
data = property(getData, setData)
def getSize(self, language=None):
'''See interface IFile'''
return self._get(language).getSize()
def getDefaultLanguage(self):
'See II18nAware'
return self.defaultLanguage
def setDefaultLanguage(self, language):
'See II18nAware'
if not self._data.has_key(language):
raise ValueError, \
'cannot set nonexistent language (%s) as default' % language
self.defaultLanguage = language
def getAvailableLanguages(self):
'See II18nAware'
return self._data.keys()
def removeLanguage(self, language):
'''See interface II18nFile'''
if language == self.defaultLanguage:
raise ValueError, 'cannot remove default language (%s)' % language
if self._data.has_key(language):
del self._data[language]
self._p_changed = 1
=== Added File Zope3/src/zope/products/content/i18nimage.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
Revision Information:
$Id: i18nimage.py,v 1.1.2.1 2004/02/08 14:03:44 philikon Exp $
"""
from zope.interface import implements
from image import Image, getImageInfo
from i18nfile import I18nFile
from interfaces.i18nimage import II18nImage
class I18nImage(I18nFile):
"""An internationalized Image object. Note that images of all
languages share the same content type.
"""
implements(II18nImage)
def _create(self, data):
return Image(data)
def setData(self, data, language=None):
'''See interface IFile'''
super(I18nImage, self).setData(data, language)
if language is None or language == self.getDefaultLanguage():
# Uploading for the default language only overrides content
# type. Note: do not use the argument data here, it doesn't
# work.
contentType = getImageInfo(self.getData(language))[0]
if contentType:
self.setContentType(contentType)
def getImageSize(self, language=None):
'''See interface IImage'''
return self._get(language).getImageSize()
=== Added File Zope3/src/zope/products/content/image.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id: image.py,v 1.1.2.1 2004/02/08 14:03:44 philikon Exp $
"""
import struct
from cStringIO import StringIO
from zope.interface import implements
from zope.app.interfaces.size import ISized
from zope.app.size import byteDisplay
from zope.app.content_types import guess_content_type
from zope.app.i18n import ZopeMessageIDFactory as _
from interfaces.image import IImage
from file import File
__metaclass__ = type
class Image(File):
implements(IImage)
def __init__(self, data=''):
'''See interface IFile'''
self.contentType, self._width, self._height = getImageInfo(data)
self.data = data
def setData(self, data):
super(Image, self).setData(data)
contentType, self._width, self._height = getImageInfo(self.data)
if contentType:
self.contentType = contentType
def getImageSize(self):
'''See interface IImage'''
return (self._width, self._height)
data = property(File.getData, setData, None,
"""Contains the data of the file.""")
class ImageSized:
implements(ISized)
def __init__(self, image):
self._image = image
def sizeForSorting(self):
'See ISized'
return ('byte', self._image.getSize())
def sizeForDisplay(self):
'See ISized'
w, h = self._image.getImageSize()
if w < 0:
w = '?'
if h < 0:
h = '?'
bytes = self._image.getSize()
byte_size = byteDisplay(bytes)
mapping = byte_size.mapping
size = _(byte_size + ' ${width}x${height}')
mapping.update({'width': str(w), 'height': str(h)})
size.mapping = mapping
return size
def getImageInfo(data):
data = str(data)
size = len(data)
height = -1
width = -1
content_type = ''
# handle GIFs
if (size >= 10) and data[:6] in ('GIF87a', 'GIF89a'):
# Check to see if content_type is correct
content_type = 'image/gif'
w, h = struct.unpack("<HH", data[6:10])
width = int(w)
height = int(h)
# See PNG v1.2 spec (http://www.cdrom.com/pub/png/spec/)
# Bytes 0-7 are below, 4-byte chunk length, then 'IHDR'
# and finally the 4-byte width, height
elif ((size >= 24) and data.startswith('\211PNG\r\n\032\n')
and (data[12:16] == 'IHDR')):
content_type = 'image/png'
w, h = struct.unpack(">LL", data[16:24])
width = int(w)
height = int(h)
# Maybe this is for an older PNG version.
elif (size >= 16) and data.startswith('\211PNG\r\n\032\n'):
# Check to see if we have the right content type
content_type = 'image/png'
w, h = struct.unpack(">LL", data[8:16])
width = int(w)
height = int(h)
# handle JPEGs
elif (size >= 2) and data.startswith('\377\330'):
content_type = 'image/jpeg'
jpeg = StringIO(data)
jpeg.read(2)
b = jpeg.read(1)
try:
while (b and ord(b) != 0xDA):
while (ord(b) != 0xFF): b = jpeg.read(1)
while (ord(b) == 0xFF): b = jpeg.read(1)
if (ord(b) >= 0xC0 and ord(b) <= 0xC3):
jpeg.read(3)
h, w = struct.unpack(">HH", jpeg.read(4))
break
else:
jpeg.read(int(struct.unpack(">H", jpeg.read(2))[0])-2)
b = jpeg.read(1)
width = int(w)
height = int(h)
except struct.error:
pass
except ValueError:
pass
return content_type, width, height
class FileFactory:
def __init__(self, context):
self.context = context
def __call__(self, name, content_type, data):
if not content_type and data:
content_type, width, height = getImageInfo(data)
if not content_type:
content_type, encoding = guess_content_type(name, data, '')
if content_type.startswith('image/'):
return Image(data)
return File(data, content_type)
More information about the Zope3-Checkins
mailing list