[Checkins] SVN: zc.preview/trunk/src/zc/preview/ Initial import. File previews based on mimetype. Currently somewhat minimal.

Gary Poster gary at zope.com
Tue Aug 15 17:14:00 EDT 2006


Log message for revision 69542:
  Initial import.  File previews based on mimetype.  Currently somewhat minimal.
  

Changed:
  A   zc.preview/trunk/src/zc/preview/README.txt
  A   zc.preview/trunk/src/zc/preview/__init__.py
  A   zc.preview/trunk/src/zc/preview/configure.zcml
  A   zc.preview/trunk/src/zc/preview/default.pt
  A   zc.preview/trunk/src/zc/preview/default.py
  A   zc.preview/trunk/src/zc/preview/default.zcml
  A   zc.preview/trunk/src/zc/preview/i18n.py
  A   zc.preview/trunk/src/zc/preview/iframe.pt
  A   zc.preview/trunk/src/zc/preview/iframe.py
  A   zc.preview/trunk/src/zc/preview/iframe.txt
  A   zc.preview/trunk/src/zc/preview/iframe.zcml
  A   zc.preview/trunk/src/zc/preview/image.pt
  A   zc.preview/trunk/src/zc/preview/image.py
  A   zc.preview/trunk/src/zc/preview/image.txt
  A   zc.preview/trunk/src/zc/preview/image.zcml
  A   zc.preview/trunk/src/zc/preview/ntests.py
  A   zc.preview/trunk/src/zc/preview/test.zcml
  A   zc.preview/trunk/src/zc/preview/text.py
  A   zc.preview/trunk/src/zc/preview/text.txt
  A   zc.preview/trunk/src/zc/preview/text.zcml

-=-
Added: zc.preview/trunk/src/zc/preview/README.txt
===================================================================
--- zc.preview/trunk/src/zc/preview/README.txt	2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/README.txt	2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,8 @@
+=========================
+Uploaded content previews
+=========================
+
+This package contains a variety of preview views that are otherwise
+isolated.  These may be split up in the future should we decide that
+this combination package doesn't work.
+


Property changes on: zc.preview/trunk/src/zc/preview/README.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: zc.preview/trunk/src/zc/preview/__init__.py
===================================================================
--- zc.preview/trunk/src/zc/preview/__init__.py	2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/__init__.py	2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1 @@
+# This directory is a Python package.

Added: zc.preview/trunk/src/zc/preview/configure.zcml
===================================================================
--- zc.preview/trunk/src/zc/preview/configure.zcml	2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/configure.zcml	2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,10 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    >
+
+  <include file="text.zcml"/>
+  <include file="iframe.zcml"/>
+  <include file="image.zcml"/>
+  <include file="default.zcml"/>
+
+</configure>

Added: zc.preview/trunk/src/zc/preview/default.pt
===================================================================
--- zc.preview/trunk/src/zc/preview/default.pt	2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/default.pt	2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,11 @@
+<html metal:use-macro="context/@@standard_macros/view" 
+      i18n:domain="zc.preview">
+<head>
+</head>
+<body>
+<metal:block metal:fill-slot="body">
+  <p i18n:translate="">The system does not support previewing this file type.
+  </p>
+</metal:block>
+</body>
+</html>

Added: zc.preview/trunk/src/zc/preview/default.py
===================================================================
--- zc.preview/trunk/src/zc/preview/default.py	2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/default.py	2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,21 @@
+"""A preview that declares something is not previewable.
+"""
+
+from zope import component, interface
+from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
+from zope.formlib import namedtemplate
+import zope.publisher.browser
+from zope.publisher.interfaces.browser import IBrowserRequest
+
+class Preview(zope.publisher.browser.BrowserPage):
+    interface.implements(interface.Interface)
+    
+    template = namedtemplate.NamedTemplate('default')
+
+    def __call__(self):
+        return self.template()
+
+default_template = namedtemplate.NamedTemplateImplementation(
+    ViewPageTemplateFile('default.pt'),
+    Preview
+    )

Added: zc.preview/trunk/src/zc/preview/default.zcml
===================================================================
--- zc.preview/trunk/src/zc/preview/default.zcml	2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/default.zcml	2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,16 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    i18n_domain='zc.preview'>
+
+  <adapter factory=".default.default_template" name="default" />
+
+  <browser:view
+      class=".default.Preview"
+      for="zope.file.interfaces.IFile"
+      name="display.html"
+      menu="zmi_views" title="Display"
+      permission="zope.View"
+      />
+
+</configure>

Added: zc.preview/trunk/src/zc/preview/i18n.py
===================================================================
--- zc.preview/trunk/src/zc/preview/i18n.py	2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/i18n.py	2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,8 @@
+"""Internationalization for zc.preview.
+
+"""
+__docformat__ = "reStructuredText"
+
+from zope.i18nmessageid import MessageFactory
+
+_ = MessageFactory('zc.preview')

Added: zc.preview/trunk/src/zc/preview/iframe.pt
===================================================================
--- zc.preview/trunk/src/zc/preview/iframe.pt	2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/iframe.pt	2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,14 @@
+<html metal:use-macro="context/@@standard_macros/view" 
+      i18n:domain="zc.preview">
+<head>
+</head>
+<body>
+<metal:block metal:fill-slot="body">
+  <iframe width="100%" height="300" i18n:translate="iframe-not-supported"
+          tal:attributes="src string:${context/@@traversedURL}/@@inline">
+      The inline preview is not possible because your browser
+      does not support inline frames.
+  </iframe>
+</metal:block>
+</body>
+</html>

Added: zc.preview/trunk/src/zc/preview/iframe.py
===================================================================
--- zc.preview/trunk/src/zc/preview/iframe.py	2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/iframe.py	2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,23 @@
+"""Very simple preview-view. It displays content in an iframe with its
+source link pointing to the 'inline' view on the content.
+"""
+
+from zope import component, interface
+from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
+from zope.formlib import namedtemplate
+import zope.publisher.browser
+from zope.publisher.interfaces.browser import IBrowserRequest
+from zope.mimetype.types import IContentTypeMicrosoftWord
+
+class Preview(zope.publisher.browser.BrowserPage):
+    interface.implements(interface.Interface)
+    
+    template = namedtemplate.NamedTemplate('iframe')
+
+    def __call__(self):
+        return self.template()
+
+default_template = namedtemplate.NamedTemplateImplementation(
+    ViewPageTemplateFile('iframe.pt'),
+    Preview
+    )

Added: zc.preview/trunk/src/zc/preview/iframe.txt
===================================================================
--- zc.preview/trunk/src/zc/preview/iframe.txt	2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/iframe.txt	2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,117 @@
+===============
+iframe previews
+===============
+
+The iframe view is used for any content type that the browser knows
+how to display in an iframe.
+
+Create the browser object we'll be using.
+
+    >>> from zope.testbrowser.testing import Browser
+    >>> browser = Browser()
+    >>> browser.addHeader('Accept-Language', 'test')
+
+For each content type we will test that the view is registered and
+working, by creating a simple content content object and clicking the
+link to see the resulting view.
+
+Microsoft Word
+--------------
+
+To see how the view works, we'll create an instance of a simple content
+object:
+
+    >>> browser.open('http://localhost/@@contents.html')
+    >>> browser.getLink('[[zope][[top]]]').click()
+    >>> browser.getLink('[[zc.preview][DemoContentMicrosoftWord]]').click()
+    >>> browser.getControl(name='new_value').value = 'test.doc'
+    >>> browser.getControl('[[zope][container-apply-button (Apply)]]').click()
+
+Now click on the link to our object to see if we are getting the expected view.
+
+    >>> browser.getLink('test.doc').click()
+    >>> print browser.contents
+    <...
+       <iframe width="100%" height="300"
+               src="http://localhost/test.doc/@@inline">[[zc.preview][iframe-not-supported (
+           The inline preview is not possible because your browser
+           does not support inline frames.
+       )]]</iframe>
+    ...>
+
+
+Microsoft Excel
+---------------
+
+To see how the view works, we'll create an instance of a simple content
+object:
+
+    >>> browser.open('http://localhost/@@contents.html')
+    >>> browser.getLink('[[zope][[top]]]').click()
+    >>> browser.getLink('[[zc.preview][DemoContentMicrosoftExcel]]').click()
+    >>> browser.getControl(name='new_value').value = 'test.xls'
+    >>> browser.getControl('[[zope][container-apply-button (Apply)]]').click()
+
+Now click on the link to our object to see if we are getting the expected view.
+
+    >>> browser.getLink('test.xls').click()
+    >>> print browser.contents
+    <...
+       <iframe width="100%" height="300"
+               src="http://localhost/test.xls/@@inline">[[zc.preview][iframe-not-supported (
+           The inline preview is not possible because your browser
+           does not support inline frames.
+       )]]</iframe>
+    ...>
+
+
+Microsoft Powerpoint
+--------------------
+
+To see how the view works, we'll create an instance of a simple content
+object:
+
+    >>> browser.open('http://localhost/@@contents.html')
+    >>> browser.getLink('[[zope][[top]]]').click()
+    >>> browser.getLink('[[zc.preview][DemoContentMicrosoftPowerPoint]]').click()
+    >>> browser.getControl(name='new_value').value = 'test.ppt'
+    >>> browser.getControl('[[zope][container-apply-button (Apply)]]').click()
+
+Now click on the link to our object to see if we are getting the expected view.
+
+    >>> browser.getLink('test.ppt').click()
+    >>> print browser.contents
+    <...
+       <iframe width="100%" height="300"
+               src="http://localhost/test.ppt/@@inline">[[zc.preview][iframe-not-supported (
+           The inline preview is not possible because your browser
+           does not support inline frames.
+       )]]</iframe>
+    ...>
+
+
+Adobe Pdf
+---------
+
+To see how the view works, we'll create an instance of a simple content
+object:
+
+    >>> browser.open('http://localhost/@@contents.html')
+    >>> browser.getLink('[[zope][[top]]]').click()
+    >>> browser.getLink('[[zc.preview][DemoContentPdf]]').click()
+    >>> browser.getControl(name='new_value').value = 'test.pdf'
+    >>> browser.getControl('[[zope][container-apply-button (Apply)]]').click()
+
+Now click on the link to our object to see if we are getting the expected view.
+
+    >>> browser.getLink('test.pdf').click()
+    >>> print browser.contents
+    <...
+       <iframe width="100%" height="300"
+               src="http://localhost/test.pdf/@@inline">[[zc.preview][iframe-not-supported (
+           The inline preview is not possible because your browser
+           does not support inline frames.
+       )]]</iframe>
+    ...>
+
+


Property changes on: zc.preview/trunk/src/zc/preview/iframe.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: zc.preview/trunk/src/zc/preview/iframe.zcml
===================================================================
--- zc.preview/trunk/src/zc/preview/iframe.zcml	2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/iframe.zcml	2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,64 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    i18n_domain="zc.preview">
+
+  <adapter factory=".iframe.default_template" name="iframe" />
+
+  <browser:view
+      class=".iframe.Preview"
+      for="zope.mimetype.types.IContentTypeMicrosoftWord"
+      name="display.html"
+      menu="zmi_views" title="Display"
+      permission="zope.View"
+      />
+
+  <browser:view
+      class=".iframe.Preview"
+      for="zope.mimetype.types.IContentTypeMicrosoftExcel"
+      name="display.html"
+      menu="zmi_views" title="Display"
+      permission="zope.View"
+      />
+
+  <browser:view
+      class=".iframe.Preview"
+      for="zope.mimetype.types.IContentTypeMicrosoftPowerPoint"
+      name="display.html"
+      menu="zmi_views" title="Display"
+      permission="zope.View"
+      />
+
+  <browser:view
+      class=".iframe.Preview"
+      for="zope.mimetype.types.IContentTypePdf"
+      name="display.html"
+      menu="zmi_views" title="Display"
+      permission="zope.View"
+      />
+
+  <browser:view
+      class=".iframe.Preview"
+      for="zope.mimetype.types.IContentTypeTextHtml"
+      name="display.html"
+      menu="zmi_views" title="Display"
+      permission="zope.View"
+      />
+
+  <browser:view
+      class=".iframe.Preview"
+      for="zope.mimetype.types.IContentTypeHtmlApplication"
+      name="display.html"
+      menu="zmi_views" title="Display"
+      permission="zope.View"
+      />
+
+  <browser:view
+      class=".iframe.Preview"
+      for="zope.mimetype.types.IContentTypeXhtml"
+      name="display.html"
+      menu="zmi_views" title="Display"
+      permission="zope.View"
+      />
+
+</configure>

Added: zc.preview/trunk/src/zc/preview/image.pt
===================================================================
--- zc.preview/trunk/src/zc/preview/image.pt	2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/image.pt	2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,11 @@
+<html metal:use-macro="context/@@standard_macros/view" 
+      i18n:domain="zc.preview">
+<head>
+</head>
+<body>
+<metal:block metal:fill-slot="body">
+<img tal:attributes="src string:${context/@@traversedURL}/@@inline;
+                     alt context/zope:name" />
+</metal:block>
+</body>
+</html>

Added: zc.preview/trunk/src/zc/preview/image.py
===================================================================
--- zc.preview/trunk/src/zc/preview/image.py	2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/image.py	2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,20 @@
+"""Very simple preview-view for images.
+"""
+
+from zope import interface
+from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
+from zope.formlib import namedtemplate
+import zope.publisher.browser
+
+class Preview(zope.publisher.browser.BrowserPage):
+    interface.implements(interface.Interface)
+
+    template = namedtemplate.NamedTemplate('image')
+
+    def __call__(self):
+        return self.template()
+
+default_template = namedtemplate.NamedTemplateImplementation(
+    ViewPageTemplateFile('image.pt'),
+    Preview
+    )

Added: zc.preview/trunk/src/zc/preview/image.txt
===================================================================
--- zc.preview/trunk/src/zc/preview/image.txt	2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/image.txt	2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,34 @@
+==============
+Image previews
+==============
+
+Simple preview of images.
+
+Create the browser object we'll be using.
+
+    >>> from zope.testbrowser.testing import Browser
+    >>> browser = Browser()
+    >>> browser.addHeader("Authorization", "Basic user:userpw")
+    >>> browser.addHeader("Accept-Language", "en-US")
+
+Let's start by creating a small "image"::
+
+    >>> import StringIO
+    >>> def createFile(data, name, contentType):
+    ...     sio = StringIO.StringIO(data)
+    ...     browser.open("http://localhost/@@+/zope.file.File")
+    ...     ctrl = browser.getControl(name="form.data")
+    ...     ctrl.add_file(sio, contentType, name)
+    ...     browser.getControl("Add").click()
+
+    >>> createFile("(pretend this is png data)", "sample-1.png", "image/png")
+
+The preview view shows a simple <img> tag.
+
+    >>> browser.getLink("sample-1.png").click()
+    >>> browser.getLink("Display").click()
+    >>> print browser.contents
+    <...
+       <img src="http://localhost/sample-1.png/@@inline" alt="sample-1.png" />
+    ...
+


Property changes on: zc.preview/trunk/src/zc/preview/image.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: zc.preview/trunk/src/zc/preview/image.zcml
===================================================================
--- zc.preview/trunk/src/zc/preview/image.zcml	2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/image.zcml	2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,31 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    i18n_domain="zc.preview">
+
+  <adapter factory=".image.default_template" name="image" />
+
+  <browser:view
+      class=".image.Preview"
+      for="zope.mimetype.types.IContentTypeImageGif"
+      name="display.html"
+      menu="zmi_views" title="Display"
+      permission="zope.View"
+      />
+
+  <browser:view
+      class=".image.Preview"
+      for="zope.mimetype.types.IContentTypeImageJpeg"
+      name="display.html"
+      menu="zmi_views" title="Display"
+      permission="zope.View"
+      />
+  <browser:view
+      class=".image.Preview"
+      for="zope.mimetype.types.IContentTypeImagePng"
+      name="display.html"
+      menu="zmi_views" title="Display"
+      permission="zope.View"
+      />
+
+</configure>

Added: zc.preview/trunk/src/zc/preview/ntests.py
===================================================================
--- zc.preview/trunk/src/zc/preview/ntests.py	2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/ntests.py	2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,63 @@
+"""Test harness for zc.preview functional tests.
+
+"""
+import os
+import unittest
+
+import pytz
+
+import persistent
+from zope import component, interface
+
+import zope.interface.common.idatetime
+import zope.publisher.interfaces
+
+import zope.testing.module
+from zope.app.testing import functional
+
+#### testing framework ####
+
+ at component.adapter(zope.publisher.interfaces.IRequest)
+ at interface.implementer(zope.interface.common.idatetime.ITZInfo)
+def requestToTZInfo(request):
+    return pytz.timezone('US/Eastern')
+
+#### test setup ####
+
+zope.app.testing.functional.defineLayer('PreviewLayer')
+
+class DemoContentMicrosoftWord(persistent.Persistent):
+    """A content type that claims to be application/vnd.ms-word."""
+
+class DemoContentMicrosoftExcel(persistent.Persistent):
+    """A content type that claims to be application/vnd.ms-excel."""
+
+class DemoContentMicrosoftPowerPoint(persistent.Persistent):
+    """A content type that claims to be application/vnd.ms-powerpoint."""
+
+class DemoContentPdf(persistent.Persistent):
+    """A content type that claims to be appliction/pdf."""
+
+
+def test_text():
+    suite = functional.FunctionalDocFileSuite("text.txt")
+    suite.layer = PreviewLayer
+    return suite
+
+def test_iframe():
+    suite = functional.FunctionalDocFileSuite("iframe.txt")
+    suite.layer = PreviewLayer
+    return suite
+
+def test_image():
+    suite = functional.FunctionalDocFileSuite("image.txt")
+    suite.layer = PreviewLayer
+    return suite
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(test_text())
+    suite.addTest(test_iframe())
+    suite.addTest(test_image())
+    return suite

Added: zc.preview/trunk/src/zc/preview/test.zcml
===================================================================
--- zc.preview/trunk/src/zc/preview/test.zcml	2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/test.zcml	2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,90 @@
+<configure 
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    i18n_domain="zc.preview"
+    package="zc.preview"
+    >
+
+  <!-- This file is the equivalent of site.zcml and it is -->
+  <!-- used for functional testing setup -->
+
+  <include package="zope.app" />
+  <include package="zope.app.debugskin" />
+  <include package="zope.app.server" />
+  <include package="zope.app.authentication" />
+
+  <authenticatedGroup
+    id="zope.Authenticated"
+    title="Everybody" 
+    />
+
+  <unauthenticatedPrincipal
+      id="zope.anybody"
+      title="Unauthenticated User" />
+
+  <!-- Principal that tests generally run as -->
+  <principal
+      id="zope.user"
+      title="User"
+      login="user"
+      password="userpw" />
+
+  <include package="zope.formlib"/>
+  <include package="zope.mimetype" file="meta.zcml"/>
+  <include package="zope.mimetype"/>
+  <include package="zope.file"/>
+  <include package="zc.shortcut"/>
+  <include package="zc.preview"/>
+
+  <securityPolicy
+      component="zope.security.simplepolicies.PermissiveSecurityPolicy"
+      />
+
+  <adapter factory=".ntests.requestToTZInfo"/>
+
+  <!-- Load a "default" i18n domain for debugging purposes
+     production sites shouldn't do this -->
+  <include package="zope.app.i18n.tests" />
+
+  <class class=".ntests.DemoContentMicrosoftWord">
+    <implements interface="zope.mimetype.types.IContentTypeMicrosoftWord" />
+  </class>
+
+  <browser:addMenuItem
+    class=".ntests.DemoContentMicrosoftWord"
+    title="DemoContentMicrosoftWord"
+    permission="zope.ManageContent"
+    />
+
+  <class class=".ntests.DemoContentMicrosoftExcel">
+    <implements interface="zope.mimetype.types.IContentTypeMicrosoftExcel" />
+  </class>
+
+  <browser:addMenuItem
+    class=".ntests.DemoContentMicrosoftExcel"
+    title="DemoContentMicrosoftExcel"
+    permission="zope.ManageContent"
+    />
+
+  <class class=".ntests.DemoContentMicrosoftPowerPoint">
+    <implements interface="zope.mimetype.types.IContentTypeMicrosoftPowerPoint" />
+  </class>
+
+  <browser:addMenuItem
+    class=".ntests.DemoContentMicrosoftPowerPoint"
+    title="DemoContentMicrosoftPowerPoint"
+    permission="zope.ManageContent"
+    />
+
+  <class class=".ntests.DemoContentPdf">
+    <implements interface="zope.mimetype.types.IContentTypePdf" />
+  </class>
+
+  <browser:addMenuItem
+    class=".ntests.DemoContentPdf"
+    title="DemoContentPdf"
+    permission="zope.ManageContent"
+    />
+
+
+</configure>

Added: zc.preview/trunk/src/zc/preview/text.py
===================================================================
--- zc.preview/trunk/src/zc/preview/text.py	2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/text.py	2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,126 @@
+"""Very simple preview-view for text/plain content.
+
+A more elaborate approach is needed if we care about supporting
+specific structured flavors used among programmers, but this is
+sufficient for the most basic use.
+
+"""
+__docformat__ = "reStructuredText"
+
+import codecs
+
+import zope.formlib.form
+import zope.mimetype.interfaces
+import zope.mimetype.source
+import zope.schema
+
+from i18n import _
+
+
+class TextPreview(zope.formlib.form.Form):
+
+    actions = ()
+
+    def get_rendered_encoding(self):
+        return self.codec
+
+    def get_rendered_text(self):
+        return self.text
+
+    encoding_field = zope.formlib.form.Field(
+        zope.schema.Choice(
+            __name__=_("encoding"),
+            title=_("Encoding"),
+            description=_("Character data encoding"),
+            source=zope.mimetype.source.codecSource,
+            required=False,
+            ),
+        for_display=True,
+        get_rendered=get_rendered_encoding,
+        )
+
+    text_field = zope.formlib.form.Field(
+        zope.schema.Text(
+            __name__="text",
+            title=_("Text"),
+            description=_("The text of the document."),
+            required=False,
+            ),
+        get_rendered=get_rendered_text,
+        )
+
+    msgTextEncodingNotSpecified = _(
+        "Text encoding not specified and could not be determined.")
+
+    msgErrorDecodingText = _(
+        "Specified text encoding does not match data.")
+
+    def __init__(self, context, request):
+        # set up fields
+        fields = []
+
+        f = context.open("rb")
+        data = f.read()
+        f.close()
+
+        # determine if the text is decodable, or unmarked ASCII
+        ci = zope.mimetype.interfaces.IContentInfo(context)
+        charset = ci.effectiveParameters.get("charset")
+        if not charset:
+            # The `IContentInfo` adapter should have gotten this, but
+            # if not, we fall back to a simple encoding sniff that
+            # only supports a few sure-bet values.  This lets us work
+            # with the most common encodings regardless of the
+            # software configuration.
+            #
+            charset = sniffEncoding(data)
+            try:
+                self.text = unicode(data, charset)
+            except UnicodeError:
+                self.status = self.msgTextEncodingNotSpecified
+                self.have_text = False
+            else:
+                self.have_text = True
+        else:
+            try:
+                self.text = ci.decode(data)
+            except UnicodeError:
+                self.status = self.msgErrorDecodingText
+                self.have_text = False
+            else:
+                self.codec = ci.getCodec()
+                fields.append(self.encoding_field)
+                self.have_text = True
+
+        if self.have_text:
+            fields.append(self.text_field)
+
+        self.form_fields = zope.formlib.form.Fields(*fields)
+        super(TextPreview, self).__init__(context, request)
+
+    def setUpWidgets(self, ignore_request=False):
+        super(TextPreview, self).setUpWidgets(ignore_request=ignore_request)
+        if self.have_text:
+            w = self.widgets["text"]
+            w.extra = 'disabled="disabled"'
+            w.cssClass = "display-only"
+            w.width = 80
+
+
+def sniffEncoding(data):
+    """Guess what encoding might work to decode `data`.
+
+    The result is considered the 'most likely' candidate, but decoding
+    might fail.
+
+    """
+    for prefix, charset in _bom_prefix:
+        if data.startswith(prefix):
+            return charset
+    return "ascii"
+
+_bom_prefix = (
+    (codecs.BOM_UTF8, "utf-8"),
+    (codecs.BOM_UTF16_BE, "utf-16be"),
+    (codecs.BOM_UTF16_LE, "utf-16le"),
+    )

Added: zc.preview/trunk/src/zc/preview/text.txt
===================================================================
--- zc.preview/trunk/src/zc/preview/text.txt	2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/text.txt	2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,107 @@
+=======================
+Plain text display view
+=======================
+
+The "preview" for plain text is simple.  It deals with documents for
+which the encoding is known, including the case of the "known"
+encoding not working with the actual data, and the case where the
+encoding is not known at all.  For the later, some attempts to guess
+common text encodings is attempted.
+
+  >>> import StringIO
+  >>> from zope.testbrowser.testing import Browser
+
+We'll be creating many example file objects, so let's create a
+convenience function to make one for us::
+
+  >>> browser = Browser()
+  >>> browser.addHeader("Authorization", "Basic user:userpw")
+  >>> browser.addHeader("Accept-Language", "en-US")
+
+  >>> def createFile(data, name, contentType="text/plain"):
+  ...     sio = StringIO.StringIO(data)
+  ...     browser.open("http://localhost/@@+/zope.file.File")
+  ...     ctrl = browser.getControl(name="form.data")
+  ...     ctrl.add_file(sio, contentType, name)
+  ...     browser.getControl("Add").click()
+
+Let's start by creating a plain text file in a simple, known
+encoding::
+
+  >>> createFile("Plain text in Latin-1: \xd8.",
+  ...            "sample-1.txt", "text/plain; charset=iso-8859-1")
+
+Using the display view, we can see the document plainly, as well as a
+note about the current encoding (since it is known)::
+
+  >>> browser.getLink("sample-1.txt").click()
+  >>> print browser.contents
+  <...utf-8...
+  ...Plain text in Latin-1: ...
+
+If we don't provide encoding information when we create the document,
+but use an encoding that's easily recognizable, we'll still be able to
+see the document text, but won't get the annotation about the encoding
+that's been used, since some guesswork was involved::
+
+  >>> createFile("Plain text in US-ASCII.", "sample-2.txt")
+
+  >>> browser.getLink("sample-2.txt").click()
+  >>> print browser.contents
+  <...Plain text in US-ASCII...
+
+A number of UTF encodings are recognized if they include a byte-order
+mark.  We'll use some Japanese example text (maybe; text is from a spam
+email) for subsequent tests::
+
+  >>> text = u"\u4f1a\u91d1\u30fb\u4f1a\u8cbb\u3092\u6255\u3063\u3066"
+  >>> utf8 = text.encode("utf-8")
+
+UTF-8 with the byte-order mark::
+
+  >>> import codecs
+
+  >>> createFile(codecs.BOM_UTF8 + text.encode("utf-8"), "sample-3.txt")
+
+  >>> browser.getLink("sample-3.txt").click()
+  >>> utf8 in browser.contents
+  True
+
+UTF-16 big-endian with the byte-order mark::
+
+  >>> createFile(codecs.BOM_UTF16_BE + text.encode("utf-16be"), "sample-4.txt")
+
+  >>> browser.getLink("sample-4.txt").click()
+  >>> utf8 in browser.contents
+  True
+
+UTF-16 little-endian with the byte-order mark::
+
+  >>> createFile(codecs.BOM_UTF16_LE + text.encode("utf-16le"), "sample-5.txt")
+
+  >>> browser.getLink("sample-5.txt").click()
+  >>> utf8 in browser.contents
+  True
+
+Handling un-decodable text
+--------------------------
+
+On the other hand, if we upload a file for which the encoding is not
+recognized automatically and don't provide encoding information, we
+get a message that the encoding is not known::
+
+  >>> createFile(text.encode("utf-8"), "bad-1.txt")
+
+  >>> browser.getLink("bad-1.txt").click()
+  >>> print browser.contents
+  <...Text encoding not specified and could not be determined...
+
+For an encoding that's specified in the initial upload of the file,
+but which is incorrect, a different error message is provided::
+
+  >>> createFile(text.encode("utf-8"),
+  ...            "bad-2.txt", "text/plain; charset=utf-16le")
+
+  >>> browser.getLink("bad-2.txt").click()
+  >>> print browser.contents
+  <...Specified text encoding does not match data...


Property changes on: zc.preview/trunk/src/zc/preview/text.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: zc.preview/trunk/src/zc/preview/text.zcml
===================================================================
--- zc.preview/trunk/src/zc/preview/text.zcml	2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/text.zcml	2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,31 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    i18n_domain="zc.preview"
+    >
+
+  <browser:view
+      class=".text.TextPreview"
+      for="zope.mimetype.types.IContentTypeTextPlain"
+      name="display.html"
+      menu="zmi_views" title="Display"
+      permission="zope.View"
+      />
+
+  <browser:view
+      class=".text.TextPreview"
+      for="zope.mimetype.types.IContentTypeJavaScript"
+      name="display.html"
+      menu="zmi_views" title="Display"
+      permission="zope.View"
+      />
+
+  <browser:view
+      class=".text.TextPreview"
+      for="zope.mimetype.types.IContentTypeCss"
+      name="display.html"
+      menu="zmi_views" title="Display"
+      permission="zope.View"
+      />
+
+</configure>



More information about the Checkins mailing list