Back to index

plone3  3.1.7
document.py
Go to the documentation of this file.
00001 #  ATContentTypes http://plone.org/products/atcontenttypes/
00002 #  Archetypes reimplementation of the CMF core types
00003 #  Copyright (c) 2003-2006 AT Content Types development team
00004 #
00005 #  This program is free software; you can redistribute it and/or modify
00006 #  it under the terms of the GNU General Public License as published by
00007 #  the Free Software Foundation; either version 2 of the License, or
00008 #  (at your option) any later version.
00009 #
00010 #  This program is distributed in the hope that it will be useful,
00011 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 #  GNU General Public License for more details.
00014 #
00015 #  You should have received a copy of the GNU General Public License
00016 #  along with this program; if not, write to the Free Software
00017 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 #
00019 """
00020 
00021 """
00022 __author__  = 'Christian Heimes <tiran@cheimes.de>'
00023 __docformat__ = 'restructuredtext'
00024 __old_name__ = 'Products.ATContentTypes.types.ATDocument'
00025 
00026 from types import TupleType
00027 
00028 import time
00029 
00030 from ZPublisher.HTTPRequest import HTTPRequest
00031 from Products.CMFCore.permissions import View
00032 from Products.CMFCore.permissions import ModifyPortalContent
00033 from Products.CMFCore.utils import getToolByName
00034 from AccessControl import ClassSecurityInfo
00035 from ComputedAttribute import ComputedAttribute
00036 
00037 from Products.CMFDefault.utils import SimpleHTMLParser
00038 
00039 from Products.Archetypes.atapi import Schema
00040 from Products.Archetypes.atapi import TextField
00041 from Products.Archetypes.atapi import BooleanField
00042 from Products.Archetypes.atapi import RichWidget
00043 from Products.Archetypes.atapi import BooleanWidget
00044 from Products.Archetypes.atapi import RFC822Marshaller
00045 from Products.Archetypes.atapi import AnnotationStorage
00046 
00047 from Products.ATContentTypes.configuration import zconf
00048 from Products.ATContentTypes.config import PROJECTNAME
00049 from Products.ATContentTypes.content.base import registerATCT
00050 from Products.ATContentTypes.content.base import ATCTContent
00051 from Products.ATContentTypes.content.base import translateMimetypeAlias
00052 from Products.ATContentTypes.content.schemata import ATContentTypeSchema
00053 from Products.ATContentTypes.content.schemata import finalizeATCTSchema
00054 from Products.ATContentTypes.lib.historyaware import HistoryAwareMixin
00055 from Products.ATContentTypes.interfaces import IATDocument
00056 
00057 from Products.ATContentTypes import ATCTMessageFactory as _
00058 
00059 ATDocumentSchema = ATContentTypeSchema.copy() + Schema((
00060     TextField('text',
00061               required=False,
00062               searchable=True,
00063               primary=True,
00064               storage = AnnotationStorage(migrate=True),
00065               validators = ('isTidyHtmlWithCleanup',),
00066               #validators = ('isTidyHtml',),
00067               default_output_type = 'text/x-html-safe',
00068               widget = RichWidget(
00069                         description = '',
00070                         label = _(u'label_body_text', default=u'Body Text'),
00071                         rows = 25,
00072                         allow_file_upload = zconf.ATDocument.allow_document_upload),
00073     ),
00074     BooleanField('presentation',
00075         required = False,
00076         languageIndependent = True,
00077         widget = BooleanWidget(
00078             label= _(
00079                 u'help_enable_presentation', 
00080                 default=u'Presentation mode'),
00081             description = _(
00082                 u'help_enable_presentation_description', 
00083                 default=u'If selected, this will give users the ability to view the contents as presentation slides.')
00084             ),
00085     ),
00086     BooleanField('tableContents',
00087         required = False,
00088         languageIndependent = True,
00089         widget = BooleanWidget(
00090             label= _(
00091                 u'help_enable_table_of_contents', 
00092                 default=u'Table of contents'),
00093             description = _(
00094                 u'help_enable_table_of_contents_description', 
00095                 default=u'If selected, this will show a table of contents at the top of the page.')
00096             ),
00097     )),
00098     marshall=RFC822Marshaller()
00099     )
00100 
00101 finalizeATCTSchema(ATDocumentSchema)
00102 # moved schema setting after finalizeATCTSchema, so the order of the fieldsets
00103 # is preserved
00104 ATDocumentSchema.changeSchemataForField('presentation', 'settings')
00105 ATDocumentSchema.changeSchemataForField('tableContents', 'settings')
00106 
00107 class ATDocumentBase(ATCTContent, HistoryAwareMixin):
00108     """A page in the site. Can contain rich text."""
00109 
00110     __implements__ = (ATCTContent.__implements__,
00111                       HistoryAwareMixin.__implements__,
00112                      )
00113 
00114     security       = ClassSecurityInfo()
00115     cmf_edit_kws   = ('text_format',)
00116 
00117     security.declareProtected(View, 'CookedBody')
00118     def CookedBody(self, stx_level='ignored'):
00119         """CMF compatibility method
00120         """
00121         return self.getText()
00122 
00123 
00124     security.declareProtected(ModifyPortalContent, 'EditableBody')
00125     def EditableBody(self):
00126         """CMF compatibility method
00127         """
00128         return self.getRawText()
00129 
00130     security.declareProtected(ModifyPortalContent,
00131                               'setFormat')
00132     def setFormat(self, value):
00133         """CMF compatibility method
00134         
00135         The default mutator is overwritten to:
00136         
00137           o add a conversion from stupid CMF content type (e.g. structured-text)
00138             to real mime types used by MTR.
00139         
00140           o Set format to default format if value is empty
00141 
00142         """
00143         if not value:
00144             value = zconf.ATDocument.default_content_type
00145         else:
00146             value = translateMimetypeAlias(value)
00147         ATCTContent.setFormat(self, value)
00148 
00149     security.declareProtected(ModifyPortalContent, 'setText')
00150     def setText(self, value, **kwargs):
00151         """Body text mutator
00152         
00153         * hook into mxTidy an replace the value with the tidied value
00154         """
00155         field = self.getField('text')
00156         # XXX this is ugly
00157         # When an object is initialized the first time we have to 
00158         # set the filename and mimetype.
00159         # In the case the value is empty/None we must not set the value because
00160         # it will overwrite uploaded data like a pdf file.
00161         if (value is None or value == ""):
00162             if not field.getRaw(self):
00163                 # set mimetype and file name although the fi
00164                 if 'mimetype' in kwargs and kwargs['mimetype']:
00165                     field.setContentType(self, kwargs['mimetype'])
00166                 if 'filename' in kwargs and kwargs['filename']:
00167                     field.setFilename(self, kwargs['filename'])
00168             else:
00169                 return
00170 
00171         # hook for mxTidy / isTidyHtmlWithCleanup validator
00172         tidyOutput = self.getTidyOutput(field)
00173         if tidyOutput:
00174             value = tidyOutput
00175 
00176         field.set(self, value, **kwargs) # set is ok
00177 
00178     text_format = ComputedAttribute(ATCTContent.getContentType, 1)
00179 
00180     security.declarePrivate('guessMimetypeOfText')
00181     def guessMimetypeOfText(self):
00182         """For ftp/webdav upload: get the mimetype from the id and data
00183         """
00184         mtr  = getToolByName(self, 'mimetypes_registry')
00185         id   = self.getId()
00186         data = self.getRawText()
00187         ext  = id.split('.')[-1]
00188 
00189         if ext != id:
00190             mimetype = mtr.classify(data, filename=ext)
00191         else:
00192             # no extension
00193             mimetype = mtr.classify(data)
00194 
00195         if not mimetype or (type(mimetype) is TupleType and not len(mimetype)):
00196             # nothing found
00197             return None
00198 
00199         if type(mimetype) is TupleType and len(mimetype):
00200             mimetype = mimetype[0]
00201         return mimetype.normalized()
00202 
00203     security.declarePrivate('getTidyOutput')
00204     def getTidyOutput(self, field):
00205         """Get the tidied output for a specific field from the request
00206         if available
00207         """
00208         request = getattr(self, 'REQUEST', None)
00209         if request is not None and isinstance(request, HTTPRequest):
00210             tidyAttribute = '%s_tidier_data' % field.getName()
00211             return request.get(tidyAttribute, None)
00212 
00213     def _notifyOfCopyTo(self, container, op=0):
00214         """Override this to store a flag when we are copied, to be able
00215         to discriminate the right thing to do in manage_afterAdd here
00216         below.
00217         """
00218         self._v_renamed = 1
00219         return ATCTContent._notifyOfCopyTo(self, container, op=op)
00220 
00221     security.declarePrivate('manage_afterAdd')
00222     def manage_afterAdd(self, item, container):
00223         """Fix text when created througt webdav
00224         Guess the right mimetype from the id/data
00225         """
00226         ATCTContent.manage_afterAdd(self, item, container)
00227         field = self.getField('text')
00228 
00229         # hook for mxTidy / isTidyHtmlWithCleanup validator
00230         tidyOutput = self.getTidyOutput(field)
00231         if tidyOutput:
00232             if hasattr(self, '_v_renamed'):
00233                 mimetype = field.getContentType(self)
00234                 del self._v_renamed
00235             else:
00236                 mimetype = self.guessMimetypeOfText()
00237             if mimetype:
00238                 field.set(self, tidyOutput, mimetype=mimetype) # set is ok
00239             elif tidyOutput:
00240                 field.set(self, tidyOutput) # set is ok
00241 
00242     security.declarePrivate('cmf_edit')
00243     def cmf_edit(self, text_format, text, file='', safety_belt='', **kwargs):
00244         assert file == '', 'file currently not supported' # XXX
00245         self.setText(text, mimetype=translateMimetypeAlias(text_format))
00246         self.update(**kwargs)
00247 
00248     security.declarePrivate('manage_afterPUT')
00249     def manage_afterPUT(self, data, marshall_data, file, context, mimetype,
00250                         filename, REQUEST, RESPONSE):
00251         """After webdav/ftp PUT method
00252 
00253         Set title according to the id on webdav/ftp PUTs.
00254         """
00255 
00256         if '' == data:
00257             file.seek(0)
00258             content = file.read(65536)
00259         else:
00260             content = data
00261 
00262         if -1 != content.lower().find("<html"):
00263             parser = SimpleHTMLParser()
00264             parser.feed(content)
00265             if parser.title:
00266                 self.setTitle(parser.title)
00267             return
00268 
00269         ATCTContent.manage_afterPUT(self, data, marshall_data, file,
00270                                     context, mimetype, filename, REQUEST,
00271                                     RESPONSE)
00272 
00273 class ATDocument(ATDocumentBase):
00274     """A page in the site. Can contain rich text."""
00275 
00276     schema         =  ATDocumentSchema
00277 
00278     portal_type    = 'Document'
00279     archetype_name = 'Page'
00280     _atct_newTypeFor = {'portal_type' : 'CMF Document', 'meta_type' : 'Document'}
00281     assocMimetypes = ('application/xhtml+xml', 'message/rfc822', 'text/*',)
00282     assocFileExt   = ('txt', 'stx', 'rst', 'rest', 'py',)
00283 
00284     __implements__ = ATDocumentBase.__implements__, IATDocument
00285 
00286 registerATCT(ATDocument, PROJECTNAME)