[Zope3-checkins] CVS: zopeproducts/photoslide/browser - __init__.py:1.1 add.pt:1.1 configure.zcml:1.1 editPhotos.pt:1.1 photoslide.py:1.1 viewPhoto.pt:1.1 viewThumbnails.pt:1.1

Bjorn Tillenius bjorn at codeworks.lt
Fri Aug 15 09:15:26 EDT 2003


Update of /cvs-repository/zopeproducts/photoslide/browser
In directory cvs.zope.org:/tmp/cvs-serv26803/browser

Added Files:
	__init__.py add.pt configure.zcml editPhotos.pt photoslide.py 
	viewPhoto.pt viewThumbnails.pt 
Log Message:
First checkin of the photoslide product.

This product produces a slide show of photos. It works, although the
views aren't that nice yet. 


=== Added File zopeproducts/photoslide/browser/__init__.py ===


=== Added File zopeproducts/photoslide/browser/add.pt ===
<html metal:use-macro="views/standard_macros/dialog" i18n:domain="zope">
<body>

<div metal:fill-slot="body">
<form action="action.html" method="post">
<table class="TypeListing" cellpadding="3">

  <caption i18n:translate="">Add Content</caption>

  <tbody tal:define="infos view/addingInfo">

    <tr tal:repeat="info infos">

      <td class="Selector">
        <input type="radio" name="type_name"
               tal:attributes="value   info/action;
                               id      info/action;
                               checked python:len(infos)==1" />
      </td>

      <td class="TypeName">
        <label style="font-weight: bold;"
               tal:attributes="for info/action">
          <span tal:replace="info/title" >Folder</span>
        </label>
        <div class="TypeDescription" tal:content="info/description">
          Folders are generic containers for content, including other
          folders.
        </div>
      </td>
    </tr>

  <tr>
    <td><br /></td>
    <td>
        <input type="text" name="id"
               tal:condition="view/namesAccepted"
               tal:attributes="value request/id | nothing"
        />
        <input type="submit" value=" Add " i18n:attributes="value" />
    </td>
  </tr>

  </tbody>

</table>
</form>
</div>
</body>
</html>


=== Added File zopeproducts/photoslide/browser/configure.zcml ===
<configure
    xmlns="http://namespaces.zope.org/zope"
    xmlns:browser="http://namespaces.zope.org/browser"
    >

<!-- PhotoSlide -->

<browser:addform
    label="Add Photo Slide"
    name="AddPhotoSlide"
    content_factory="zopeproducts.photoslide.PhotoSlide"
    schema="zopeproducts.photoslide.interfaces.IPhotoSlide"
    permission="zope.ManageContent"
    menu="add_content"
    title="Photo Slide"
    class="zopeproducts.photo.browser.photo.CurrentDisplayIdFix"
    />

<browser:editform
    label="Edit Photo Slide"
    name="edit.html"
    schema="zopeproducts.photoslide.interfaces.IPhotoSlide"
    permission="zope.ManageContent"
    menu="zmi_views"
    title="Edit"
    class="zopeproducts.photo.browser.photo.CurrentDisplayIdFix"
    />

<browser:menu
    id="add_photoslide"
    title="Menu of objects to be added to the Photo Slide"
    />

<browser:menuItem
    menu="add_photoslide"
    for="zope.app.interfaces.container.IAdding"
    action="AddPhoto"
    title="Photo"
    />

<browser:menuItem
    menu="zmi_views"
    for="zopeproducts.photoslide.interfaces.IPhotoSlide"
    action="@@viewThumbnails.html"
    title="View Slide Show"
    />

<browser:view
    name="+"
    for="zopeproducts.photoslide.interfaces.IPhotoSlide"
    class=".photoslide.PhotoSlideAdding"
    permission="zope.ManageContent"
    allowed_attributes="addingInfo"
    menu="zmi_actions"
    title="Add"
    >
      <browser:page name="index.html"  template="add.pt" />
      <browser:page name="action.html" attribute="action" />
</browser:view>

<browser:page
    for="zopeproducts.photoslide.interfaces.IPhotoSlide"
    name="contents.html"
    permission="zope.ManageContent"
    class="zope.app.browser.container.contents.Contents"
    attribute="contents"
    menu="zmi_views"
    title="Contents"
    />

<browser:page
    for="zopeproducts.photoslide.interfaces.IPhotoSlide"
    name="viewThumbnails.html"
    permission="zope.Public"
    class=".photoslide.PhotoSlideViewThumbnails"
    template="viewThumbnails.pt"
    menu="zmi_views"
    title="View"
    />

<browser:page
    for="zopeproducts.photoslide.interfaces.IPhotoSlide"
    name="viewPhoto.html"
    permission="zope.Public"
    class=".photoslide.PhotoSlideViewPhoto"
    template="viewPhoto.pt"
    />

<browser:page
    for="zopeproducts.photoslide.interfaces.IPhotoSlide"
    name="editPhotos.html"
    permission="zope.ManageContent"
    class=".photoslide.PhotoSlideViewEditPhotos"
    template="editPhotos.pt"
    menu="zmi_views"
    title="Edit Photos"
    />

<browser:defaultView
    for="zopeproducts.photoslide.interfaces.IPhotoSlide"
    name="viewThumbnails.html"
    />

<!-- PhotoSlideFolder -->

<browser:page
    for="zopeproducts.photoslide.interfaces.IPhotoSlideFolder"
    name="contents.html"
    permission="zope.ManageContent"
    class="zope.app.browser.container.contents.Contents"
    attribute="contents"
    menu="zmi_views"
    title="Contents"
    />

<browser:view
    name="+"
    for="zopeproducts.photoslide.interfaces.IPhotoSlideFolder"
    class=".photoslide.PhotoSlideFolderAdding"
    permission="zope.ManageContent"
    allowed_attributes="addingInfo"
    menu="zmi_actions"
    title="Add"
    >
      <browser:page name="index.html"  template="add.pt" />
      <browser:page name="action.html" attribute="action" />
</browser:view>

<browser:menu
    id="add_photoslidefolder"
    title="Menu of objects to be added to the Photo Slide Collection"
    />

<browser:menuItem
    menu="add_photoslidefolder"
    for="zope.app.interfaces.container.IAdding"
    action="AddPhoto"
    title="Photo"
    />

<browser:menuItem
    menu="add_photoslidefolder"
    for="zope.app.interfaces.container.IAdding"
    action="AddPhotoSlide"
    title="Photo Slide"
    />

<browser:menuItem
    menu="add_content"
    for="zope.app.interfaces.container.IAdding"
    title="Photo Slide Folder"
    action="PhotoSlideFolder"
    description="Photo Slide Collection"
    />

<browser:defaultView
    for="zopeproducts.photoslide.interfaces.IPhotoSlideFolder"
    name="contents.html"
    />

</configure>


=== Added File zopeproducts/photoslide/browser/editPhotos.pt ===
<html metal:use-macro="views/standard_macros/page">
  <body>
    <div metal:fill-slot="body" i18n:domain="photo">
      <h3 i18n:translate="">Edit Photos</h3>

      <p tal:define="status view/update"
         tal:condition="status"
         tal:content="status" />

<br>
      <form method="POST" tal:attributes="action request/URL">
      <center>
        <table width="90%" align="center">
          <tr tal:repeat="photo context/getPhotos" >
	    <tal:block
	        tal:define="photoView python: view.getPhotoView(photo)"
		>
	      <td width="30%" valign="top" align="left">
	        <span tal:replace="structure photoView/title_widget/row" />
	        <img src=""
	     tal:attributes="src python:view.getPhotoURL(photo,'thumbnail')"/>
	        <span tal:replace="structure photoView/position_widget/row" />
              </td>
	      <td width="70%">
	        <span
		    tal:replace="structure photoView/description_widget/row"/>
              </td>
	    </tal:block>
	  </tr>
	</table>
      </center>
        <div class="controls">
          <input type="submit" name="UPDATE_EDIT_PHOTOS"
                 value="Submit" i18n:attributes="value submit-button" />
        </div>	
      </form>
    </div>
  </body>
</html>


=== Added File zopeproducts/photoslide/browser/photoslide.py ===
##############################################################################
#
# Copyright (c) 2003 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.
#
##############################################################################
"""View classes for PhotoSlide

$Id: photoslide.py,v 1.1 2003/08/15 12:15:17 BjornT Exp $
"""
from datetime import datetime

from zope.app.browser.container.adding import Adding
from zope.app.browser.form.widget import ListWidget
from zope.app import zapi
from zope.publisher.browser import BrowserView
from zope.schema import EnumeratedInt
from zope.i18n import MessageIDFactory

_ = MessageIDFactory("photo")


class PhotoSlideAdding(Adding):
    """Custom adding view for PhotoSlide objects."""
    menu_id = "add_photoslide"

class PhotoSlideFolderAdding(Adding):
    """Custom adding view for PhotoSlideFolder objects."""
    menu_id = "add_photoslides"


class PhotoSlideViewBase(BrowserView):
    """Photo Slide View base class.

    Defines some helper functions for all sub-classes.
    """
    def __init__(self, context, request):
        self.context = context
        self.request = request
        self._setAttributes(request)

    def getPhotoURL(self, photo, display=None):
        """Returns the relative URL of the current photo"""
        photo_name = self._getPhotoName(photo)
        
        if hasattr(self, 'rq_display') and self.rq_display and not display:
            display = self.rq_display
        if display:    
            return "%s?display=%s" % (photo_name, display)
        else:
            return photo_name 

    def _setAttributes(self, request):
        """Sets all attributes in request to local attributes."""
        for attr in ('page', 'display'):
            if attr in request:
                setattr(self, 'rq_' + attr, request[attr])

    def _getPhotoName(self, photo):
        return self.context.keys()[self.context.values().index(photo)]

    def _createUrl(self, pageName, **kw):
        """Returns the page name concatenated with it's needed parameters.
        The value of each parameter is fetch from self, though it can
        be overidden by passing it along as a keyword argument.
        """
        paramDict = kw
        # put all parameters in paramDict
        for param in ('page', 'display'):
            if param not in paramDict and getattr(self, 'rq_'+param):
                paramDict[param] = getattr(self, 'rq_'+param)
        # build the url
        url = pageName + '?'
        for name, value in paramDict.items():
            if url[len(url)-1] != '?':
                url += '&'
            url += name + '=' + str(value)
        return url
    

class PhotoSlideViewThumbnails(PhotoSlideViewBase):
    """View class for viewThumbnails.html"""

    def getPhotosPage(self):
        """Returns a list of lists of tuples containing the relative
        thumbnail URL and the relative URL the the view page of the
        photo
        """ 
        result = []
        max_col = 3
        row_count = 0
        col_count = 0
        index = 0
        photos = self.context.getPhotos()
        # XXX should be possible to get several pages
        for photo in photos:
            index += 1
            if col_count >= max_col:
                col_count = 0
                row_count += 1
            if col_count == 0:
                result.append([])
            result[row_count].append(('viewPhoto.html?page=%i' % index,
                                      self.getPhotoURL(photo,
                                                       'thumbnail')))
            col_count += 1

        return result


class PhotoSlideViewEditPhotos(PhotoSlideViewBase):
    """View class for editPhotos.html"""

    def __init__(self, context, request):
        self.context = context
        self.request = request

    def update(self):
        if self.request.get('UPDATE_EDIT_PHOTOS', None):
            changed = False
            orgPositions = self.context.getPhotoNames()
            changedPositions = []
            for name in orgPositions:
                photo = zapi.traverseName(self.context, name,
                                          request=self.request)
                changed = changed or \
                          self._setPhotoAttribute(photo, name, 'title',
                                                  self.request)
                changed = changed or \
                          self._setPhotoAttribute(photo, name, 'description',
                                                  self.request)
                if self._isPositionChanged(name, orgPositions, self.request):
                    changed = True
                    changedPositions.append(name)
            self._setPhotoPositions(changedPositions, self.request)
            if changed:
                formatter = self.request.locale.getDateTimeFormatter('medium')
                result = _("Values updated on ${date_time}")
                # XXX Should probably not use UTC all the time
                result.mapping = {'date_time':
                                  formatter.format(datetime.utcnow())}
            else:
                result = _("Nothing was changed")
            return result

    def _setPhotoAttribute(self, photo, photoName, photoAttr, dict):
        """Sets the photo attribute in case it has changed and is in dict"""
        widgetName = 'photo_%s_%s' % (photoName, photoAttr)
        changed = False
        if widgetName in dict: 
            if getattr(photo, photoAttr) <> dict[widgetName]:
                changed = True
                setattr(photo, photoAttr, dict[widgetName])
        return changed
              
    def _isPositionChanged(self, photoName, orgPositions, dict):
        widgetName = 'photo_%s_position' % photoName
        return orgPositions.index(photoName)+1 != int(dict[widgetName])

    def _setPhotoPositions(self, photoNames, dict):
        """Sets the photo's position in case it has been changed."""
        for name in photoNames:
            widgetName = 'photo_%s_position' % name
            self.context.setPosition(name, dict[widgetName])

    def getPhotoView(self, photo):
        """Returns a view for the photo.

        This way we can re-use the widget's the photo has.
        """
        view = zapi.getView(photo, 'edit.html', self.request)
        photoName = self._getPhotoName(photo)

        # Add a positions widget
        field = EnumeratedInt(
            __name__='position',
            title=u'Pos',
            description=u'The position of the photo.',
            allowed_values=range(1, len(self.context)+1),
            default=self.context.getPosition(photoName)
            )
        view.position_widget = ListWidget( field, self.request)
        pos = self.context.getPosition(photoName)
        view.position_widget.setData(pos)
        # Make the widget's names unique
        view.title_widget.name = 'photo_%s_title' % photoName
        view.position_widget.name = 'photo_%s_position' % photoName
        view.position_widget.size = 1
        view.description_widget.name = 'photo_%s_description' % photoName
        view.description_widget.height = 5
        
        return view



class PhotoSlideViewPhoto(PhotoSlideViewBase):
    """View class for viewPhoto.html"""
    rq_page = 1
    rq_display = None

    def __init__(self, context, request):
        super(PhotoSlideViewPhoto, self).__init__(context, request)
        self.rq_page = int(self.rq_page)

    def getNumberOfPhotos(self):
        """Returns the number of photos in the photo slide."""
        return self.context.__len__()

    def getCurrentDisplayId(self):
        """Returns the display id that's being used."""
        if self.rq_display:
            return self.rq_display
        else:
            photo = self.getCurrentPhoto()
            return photo.currentDisplayId

    def getDisplayIds(self):
        """Returns a list of tuples consisting of the display id and
        the relative URL to it's view page.
        It returns all display ids found in the current photo, except
        the thumbnail.
        It sorts them by their size, smallest first.
        """
        photo = self.getCurrentPhoto()
        dispIds = list(photo.getDisplayIds())
        dispIds.remove('thumbnail')
        # XXX should consider the size with regards to aspect ratio
        dispIds.sort(
            lambda x,y:
            photo.getDisplaySize(x)[0].__cmp__(photo.getDisplaySize(y)[0]))
        result = map(lambda dispId: (dispId, self._createUrl('viewPhoto.html',
                                                    display=dispId)),
                     dispIds)
        return result

    def getPageURLs(self):
        """Returns a list of tuples consisting of the position of the
        page and the URL to it
        """
        startPage = self.rq_page-4
        endPage = self.rq_page+4
        if startPage < 1:
            endPage += 1 - startPage
            startPage = 1
        if endPage > self.getNumberOfPhotos():
            startPage -= (endPage - self.getNumberOfPhotos())
            endPage = self.getNumberOfPhotos()
        # Last check
        if startPage < 1:
            startPage = 1

        names = self.context.getPhotoNames()
        names = names[startPage-1:endPage-1]
        positions = range(startPage, endPage+1)
        urls = map(lambda pos: self._createUrl('viewPhoto.html', page=pos),
                   positions)

        return zip(positions, urls)

    def getNextURL(self):
        """Returns the URL to the next page"""
        url = self._createUrl('viewPhoto.html', page=self.rq_page+1)
        return url

    def getPreviousURL(self):
        """Returns the URL to the previous page"""
        url = self._createUrl('viewPhoto.html', page=self.rq_page-1)
        return url


    def isFirstPhoto(self):
        """Returns true iff the current photo is the first one"""
        return self.rq_page == 1

    def isLastPhoto(self):
        """Returns true iff the current photo is the last one"""
        return self.rq_page == self.getNumberOfPhotos()

    def getCurrentPhoto(self):
        """Returns the photo with position self.rq_page"""
        photos = self.context.getPhotoNames()
        return  zapi.traverseName(self.context,
                                  photos[self.rq_page-1],
                                  request=self.request)


=== Added File zopeproducts/photoslide/browser/viewPhoto.pt ===
<html metal:use-macro="views/standard_macros/page">
  <body>
    <div metal:fill-slot="body" tal:define="curPhoto view/getCurrentPhoto" >

      <h1 tal:content="context/title" />
<center>
      <table width="80%" tal:define="n_photos view/getNumberOfPhotos">
        <tr> 
	  <td width="20%" align="left">
	    <a href=""
	       tal:condition="not: view/isFirstPhoto"
	       tal:attributes="href view/getPreviousURL"
               >
	      Previous
	    </a>
	  </td>
	  <td width="60%"
	      align="center"
	      >
	    <tal:block tal:repeat="page_url view/getPageURLs"
	               tal:define="cur_page view/rq_page"
                       >
	      <a href="" 
	         tal:condition="python: cur_page != page_url[0]"
	         tal:content="python: page_url[0]"
	         tal:attributes="href python: page_url[1]"
	         />
	      <tal:block tal:condition="python: cur_page == page_url[0]"
	                 tal:content="python: page_url[0]"
                         />
	    </tal:block>
	    </td>
	  <td width="20%" align="right">
	    <a href=""
	       tal:condition="not: view/isLastPhoto"
	       tal:attributes="href view/getNextURL"
	       >
	      Next
	    </a>
	  </td>
	</tr>
	<tr>
	  <td colspan="3" align="center">
	    <b tal:content="curPhoto/title" />
	  </td>
	</tr>
	</table>
	<table width="80%">	
	<tr>
	  <td colspan="3" align="center">
	    <img src=""
	      tal:attributes="src python: view.getPhotoURL(curPhoto)" />
	  </td>
	</tr>
	<tr>
	  <td colspan="3" align="center">
	    <tal:block tal:repeat="dispId view/getDisplayIds"
	               tal:define="curDispId view/getCurrentDisplayId">
	      <a href="" tal:condition="python: curDispId != dispId[0]"
	         tal:content="python: '[%s] ' % dispId[0]"
	         tal:attributes="href python: dispId[1]"
	         />
	      <span tal:condition="python: curDispId == dispId[0]"
	            tal:replace="python: '%s ' % dispId[0]"
		    />
	    </tal:block>
	  </td>
	</tr>
      </table>
</center>
    </div>
  </body>
</html>


=== Added File zopeproducts/photoslide/browser/viewThumbnails.pt ===
<html metal:use-macro="views/standard_macros/page">
  <body>
    <div metal:fill-slot="body">

      <h1 tal:content="context/title" />

      <table>
        <tr tal:repeat="row view/getPhotosPage">
	  <td tal:repeat="url row">
            <a href="" tal:attributes="href python: url[0]"> 
	      <img src=""
	           tal:attributes="src python: url[1]"/> 
	    </a>
	  </td>
	</tr>
      </table>
    </div>
  </body>
</html>




More information about the Zope3-Checkins mailing list