File:  [Repository] / zogiLib / zogiLib.py
Revision 1.10: download - view: text, annotated - select for diffs - revision graph
Wed Apr 28 09:03:22 2004 UTC (20 years ago) by casties
Branches: MAIN
CVS tags: HEAD
new and nice version of navigation.js (truely transform-based!)

from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from Products.PageTemplates.PageTemplate import PageTemplate
from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
from OFS.Image import Image
from webdav.common import rfc1123_date

import xml.dom.minidom
from OFS.Folder import Folder
from xml_helpers import getText
import os
import re
import string
import urllib
from Globals import package_home

def getString(self,key,default=''):
    try:
        return self.REQUEST[key]
    except:
        return default

    
class zogiLib_navTemplate(ZopePageTemplate):
    """pageTemplate Objekt"""
    meta_type="zogiLib_navTemplate"

    _default_content_fn = os.path.join(package_home(globals()),
                                       'zpt/zogiLib_NavTemplateDefault.zpt')

    manage_options=ZopePageTemplate.manage_options+(
        {'label':'Copy to Filesystem','action':'copyContent'},
       )

    def getPath(self):
        """get path"""
        return getPath(self,'thumbtemplate.templ')
    

    def copyContent(self):
        """copycontent to path"""

        return "copied to:"+copyContent(self,'thumbtemplate.templ')
        
    
def manage_addZogiLib_NavTemplateForm(self):
    """Form for adding"""
    pt=PageTemplateFile('Products/zogiLib/zpt/AddZogilib_NavTemplate.zpt').__of__(self)
    return pt()




def manage_addZogiLib_NavTemplate(self, id,title=None, text=None,
                           REQUEST=None, submit=None):
    "Add a Page Template with optional file content."

    
    id = str(id)
    if REQUEST is None:
        self._setObject(id, zogilib_NavTemplate(id, text))
        ob = getattr(self, id)
       
        if title:
            ob.pt_setTitle(title)
        return ob
    else:
        file = REQUEST.form.get('file')
        headers = getattr(file, 'headers', None)
        if headers is None or not file.filename:
            zpt = zogilib_NavTemplate(id)
        else:
            zpt = zogilib_NavTemplate(id, file, headers.get('content_type'))

        self._setObject(id, zpt)
        ob = getattr(self, id)


        try:
            u = self.DestinationURL()
        except AttributeError:
            u = REQUEST['URL1']

        if submit == " Add and Edit ":
            u = "%s/%s" % (u, quote(id))
        REQUEST.RESPONSE.redirect(u+'/manage_main')
    return ''


        
def readNavTemp(fileName):
    """navtemp"""
    
    
    if os.path.exists(fileName+"/index.meta"):
        dom=xml.dom.minidom.parse(fileName+"/index.meta")
    else:
        return None
    
    
    try:
        navTag=getText(dom.getElementsByTagName('zogilibtemplate')[0].childNodes)
    except:
        navTag=None
    return navTag

class zogiLib_mainTemplate(ZopePageTemplate):
    """pageTemplate Objekt"""
    meta_type="zogiLib_mainTemplate"

    
    def __init__(self, id, text=None, content_type=None, version="book"):

        default_content_string="zpt/zogiLibMain_%s.zpt"%version
        self._default_content_fn = os.path.join(package_home(globals()),default_content_string)
        self.id = str(id)
        self.ZBindings_edit(self._default_bindings)
        if text is None:
            text = open(self._default_content_fn).read()
        self.pt_edit(text, content_type)

    
def manage_addZogiLibMainTemplateForm(self):
    """Form for adding"""
    pt=PageTemplateFile('Products/ECHO_content/zpt/AddOSAS_thumbTemplate.zpt').__of__(self)
    return pt()




def manage_addZogiLibMainTemplate(self, id,title=None, text=None,
                           REQUEST=None, submit=None):
    "Add a Page Template with optional file content."

    
    id = str(id)
    if REQUEST is None:
        self._setObject(id, zogiLib_mainTemplate(id, text))
        ob = getattr(self, id)
       
        if title:
            ob.pt_setTitle(title)
        return ob
    else:
        file = REQUEST.form.get('file')
        headers = getattr(file, 'headers', None)
        if headers is None or not file.filename:
            zpt = zogiLib_mainTemplate(id)
        else:
            zpt = zogiLib_mainTemplate(id, file, headers.get('content_type'))

        self._setObject(id, zpt)
        ob = getattr(self, id)


        try:
            u = self.DestinationURL()
        except AttributeError:
            u = REQUEST['URL1']

        if submit == " Add and Edit ":
            u = "%s/%s" % (u, quote(id))
        REQUEST.RESPONSE.redirect(u+'/manage_main')
    return ''

    
class zogiImage(Image):
    """einzelnes Image"""
    meta_type="zogiImage"

    
    
    def __init__(self,id,title,baseUrl,queryString,content_type='',precondition=''):
        """init"""
        self.id=id
        self.title=title
        self.baseUrl=baseUrl
        self.queryString=queryString
        self.content_type=content_type
        self.precondition=precondition

    def getData(self):
        """getUrlData"""
        return urllib.urlopen(self.baseUrl+self.queryString)

    def changeZogiImageForm(self):
        """Main configuration"""
        pt=PageTemplateFile('Products/zogiLib/zpt/changeZogiImageForm.zpt').__of__(self)
        return pt()
    
    def changeZogiImage(self,title,baseUrl, queryString,RESPONSE=None):
        """change it"""
        self.title=title
        self.baseUrl=baseUrl
        self.queryString=queryString

        if RESPONSE is not None:
            RESPONSE.redirect('manage_main')


    manage_options=ZopePageTemplate.manage_options+(
        {'label':'Main config','action':'changeZogiImageForm'},
       )

    

        
    def index_html(self, REQUEST, RESPONSE):
        """
        Modified version of OFS/Image.py
        
        The default view of the contents of a File or Image.

        Returns the contents of the file or image.  Also, sets the
        Content-Type HTTP header to the objects content type.
        """

        # HTTP If-Modified-Since header handling.
        header=REQUEST.get_header('If-Modified-Since', None)
        if header is not None:
            header=header.split( ';')[0]
            # Some proxies seem to send invalid date strings for this
            # header. If the date string is not valid, we ignore it
            # rather than raise an error to be generally consistent
            # with common servers such as Apache (which can usually
            # understand the screwy date string as a lucky side effect
            # of the way they parse it).
            # This happens to be what RFC2616 tells us to do in the face of an
            # invalid date.
            try:    mod_since=long(DateTime(header).timeTime())
            except: mod_since=None
            if mod_since is not None:
                if self._p_mtime:
                    last_mod = long(self._p_mtime)
                else:
                    last_mod = long(0)
                if last_mod > 0 and last_mod <= mod_since:
                    # Set header values since apache caching will return Content-Length
                    # of 0 in response if size is not set here
                    RESPONSE.setHeader('Last-Modified', rfc1123_date(self._p_mtime))
                    RESPONSE.setHeader('Content-Type', self.content_type)
                    RESPONSE.setHeader('Content-Length', self.size)
                    RESPONSE.setHeader('Accept-Ranges', 'bytes')
                    self.ZCacheable_set(None)
                    RESPONSE.setStatus(304)
                    return ''

        if self.precondition and hasattr(self,self.precondition):
            # Grab whatever precondition was defined and then
            # execute it.  The precondition will raise an exception
            # if something violates its terms.
            c=getattr(self,self.precondition)
            if hasattr(c,'isDocTemp') and c.isDocTemp:
                c(REQUEST['PARENTS'][1],REQUEST)
            else:
                c()

        # HTTP Range header handling
        range = REQUEST.get_header('Range', None)
        request_range = REQUEST.get_header('Request-Range', None)
        if request_range is not None:
            # Netscape 2 through 4 and MSIE 3 implement a draft version
            # Later on, we need to serve a different mime-type as well.
            range = request_range
        if_range = REQUEST.get_header('If-Range', None)
        if range is not None:
            ranges = HTTPRangeSupport.parseRange(range)

            if if_range is not None:
                # Only send ranges if the data isn't modified, otherwise send
                # the whole object. Support both ETags and Last-Modified dates!
                if len(if_range) > 1 and if_range[:2] == 'ts':
                    # ETag:
                    if if_range != self.http__etag():
                        # Modified, so send a normal response. We delete
                        # the ranges, which causes us to skip to the 200
                        # response.
                        ranges = None
                else:
                    # Date
                    date = if_range.split( ';')[0]
                    try: mod_since=long(DateTime(date).timeTime())
                    except: mod_since=None
                    if mod_since is not None:
                        if self._p_mtime:
                            last_mod = long(self._p_mtime)
                        else:
                            last_mod = long(0)
                        if last_mod > mod_since:
                            # Modified, so send a normal response. We delete
                            # the ranges, which causes us to skip to the 200
                            # response.
                            ranges = None

            if ranges:
                # Search for satisfiable ranges.
                satisfiable = 0
                for start, end in ranges:
                    if start < self.size:
                        satisfiable = 1
                        break

                if not satisfiable:
                    RESPONSE.setHeader('Content-Range',
                        'bytes */%d' % self.size)
                    RESPONSE.setHeader('Accept-Ranges', 'bytes')
                    RESPONSE.setHeader('Last-Modified',
                        rfc1123_date(self._p_mtime))
                    RESPONSE.setHeader('Content-Type', self.content_type)
                    RESPONSE.setHeader('Content-Length', self.size)
                    RESPONSE.setStatus(416)
                    return ''

                ranges = HTTPRangeSupport.expandRanges(ranges, self.size)
                                
                if len(ranges) == 1:
                    # Easy case, set extra header and return partial set.
                    start, end = ranges[0]
                    size = end - start

                    RESPONSE.setHeader('Last-Modified',
                        rfc1123_date(self._p_mtime))
                    RESPONSE.setHeader('Content-Type', self.content_type)
                    RESPONSE.setHeader('Content-Length', size)
                    RESPONSE.setHeader('Accept-Ranges', 'bytes')
                    RESPONSE.setHeader('Content-Range',
                        'bytes %d-%d/%d' % (start, end - 1, self.size))
                    RESPONSE.setStatus(206) # Partial content

                    data = urllib.urlopen(self.baseUrl+self.queryString).read()
                    if type(data) is StringType:
                        return data[start:end]

                    # Linked Pdata objects. Urgh.
                    pos = 0
                    while data is not None:
                        l = len(data.data)
                        pos = pos + l
                        if pos > start:
                            # We are within the range
                            lstart = l - (pos - start)

                            if lstart < 0: lstart = 0

                            # find the endpoint
                            if end <= pos:
                                lend = l - (pos - end)

                                # Send and end transmission
                                RESPONSE.write(data[lstart:lend])
                                break

                            # Not yet at the end, transmit what we have.
                            RESPONSE.write(data[lstart:])

                        data = data.next

                    return ''

                else:
                    boundary = choose_boundary()

                    # Calculate the content length
                    size = (8 + len(boundary) + # End marker length
                        len(ranges) * (         # Constant lenght per set
                            49 + len(boundary) + len(self.content_type) +
                            len('%d' % self.size)))
                    for start, end in ranges:
                        # Variable length per set
                        size = (size + len('%d%d' % (start, end - 1)) +
                            end - start)


                    # Some clients implement an earlier draft of the spec, they
                    # will only accept x-byteranges.
                    draftprefix = (request_range is not None) and 'x-' or ''

                    RESPONSE.setHeader('Content-Length', size)
                    RESPONSE.setHeader('Accept-Ranges', 'bytes')
                    RESPONSE.setHeader('Last-Modified',
                        rfc1123_date(self._p_mtime))
                    RESPONSE.setHeader('Content-Type',
                        'multipart/%sbyteranges; boundary=%s' % (
                            draftprefix, boundary))
                    RESPONSE.setStatus(206) # Partial content

                    data = urllib.urlopen(self.baseUrl+self.queryString).read()
                    # The Pdata map allows us to jump into the Pdata chain
                    # arbitrarily during out-of-order range searching.
                    pdata_map = {}
                    pdata_map[0] = data

                    for start, end in ranges:
                        RESPONSE.write('\r\n--%s\r\n' % boundary)
                        RESPONSE.write('Content-Type: %s\r\n' %
                            self.content_type)
                        RESPONSE.write(
                            'Content-Range: bytes %d-%d/%d\r\n\r\n' % (
                                start, end - 1, self.size))

                        if type(data) is StringType:
                            RESPONSE.write(data[start:end])

                        else:
                            # Yippee. Linked Pdata objects. The following
                            # calculations allow us to fast-forward through the
                            # Pdata chain without a lot of dereferencing if we
                            # did the work already.
                            first_size = len(pdata_map[0].data)
                            if start < first_size:
                                closest_pos = 0
                            else:
                                closest_pos = (
                                    ((start - first_size) >> 16 << 16) +
                                    first_size)
                            pos = min(closest_pos, max(pdata_map.keys()))
                            data = pdata_map[pos]

                            while data is not None:
                                l = len(data.data)
                                pos = pos + l
                                if pos > start:
                                    # We are within the range
                                    lstart = l - (pos - start)

                                    if lstart < 0: lstart = 0

                                    # find the endpoint
                                    if end <= pos:
                                        lend = l - (pos - end)

                                        # Send and loop to next range
                                        RESPONSE.write(data[lstart:lend])
                                        break

                                    # Not yet at the end, transmit what we have.
                                    RESPONSE.write(data[lstart:])

                                data = data.next
                                # Store a reference to a Pdata chain link so we
                                # don't have to deref during this request again.
                                pdata_map[pos] = data

                    # Do not keep the link references around.
                    del pdata_map

                    RESPONSE.write('\r\n--%s--\r\n' % boundary)
                    return ''

        RESPONSE.setHeader('Last-Modified', rfc1123_date(self._p_mtime))
        RESPONSE.setHeader('Content-Type', self.content_type)
        RESPONSE.setHeader('Content-Length', self.size)
        RESPONSE.setHeader('Accept-Ranges', 'bytes')

        # Don't cache the data itself, but provide an opportunity
        # for a cache manager to set response headers.
        self.ZCacheable_set(None)

        data=urllib.urlopen(self.baseUrl+self.queryString).read()
        
        if type(data) is type(''): 
            RESPONSE.setBase(None)
            return data

        while data is not None:
            RESPONSE.write(data.data)
            data=data.next

        return ''


def manage_addZogiImageForm(self):
    """Form for adding"""
    pt=PageTemplateFile('Products/zogiLib/zpt/addZogiImage.zpt').__of__(self)
    return pt()


def manage_addZogiImage(self,id,title,baseUrl, queryString,RESPONSE=None):
    """add dgilib"""
    newObj=zogiImage(id,title,baseUrl, queryString)
    self.Destination()._setObject(id,newObj)
    if RESPONSE is not None:
        RESPONSE.redirect('manage_main')



class zogiLib(Folder):
    """StandardElement"""

    meta_type="zogiLib"

    def getDlInfo(self):
        """DLInfo"""
        paramH={}
        baseUrl=re.sub("servlet/Scaler","dlInfo-xml.jsp",self.digilibBaseUrl)
        
        url=urllib.urlopen(baseUrl+self.REQUEST['QUERY_STRING'])
        dom=xml.dom.minidom.parse(url)
        params=dom.getElementsByTagName('parameter')
        for param in params:
            paramH[param.getAttribute('name')]=param.getAttribute('value')
        return paramH

    def getPageNumTotal(self):
        """pagenums"""
        return self.getDlInfo()['pt'].encode('utf-8')
    
    
    def generateImageFolder(self):
        """images ablegen"""
        self.manage_addFolder('images')
        pathName=os.path.join(package_home(globals()),'images')
        for image in os.listdir(pathName):
            try:
                
                fn=file(os.path.join(pathName,image))
                self.images.manage_addImage(image,fn)
            except:
                print "ZOGILIB not imported:",image
                
            
        

    def __init__(self, id,title,digilibBaseUrl, localFileBase,version="book"):
        """init"""

        self.id=id
        self.title=title
        self.digilibBaseUrl=digilibBaseUrl
        self.localFileBase=localFileBase
        #self._setObject('topTemplate',zogiLib_navTemplate(id='topTemplate'))
        self._setObject('mainTemplate',zogiLib_mainTemplate(id='mainTemplate',version=version))
        self.generateImageFolder()


    manage_options = Folder.manage_options+(
            {'label':'Main Config','action':'changeZogiLibForm'},
            )

    def option_js(self):
        """option_js"""
        ret="""function setDLParam(e) {
          if (document.all) {
            s=e.srcElement;
          } else {
            s=e.target;
          }
          if (window.opener) {
            window.opener.setParameter(s.name, s.value);
            window.opener.display(9);
          } else {
            setParameter(s.name, s.value);
            display(9);
          }
        }"""
        return ret
                        
                        
    def navigation_js(self):
        """Javascript"""
        fileName=os.path.join(package_home(globals()),'js/navigation.js')
        return file(fileName).read()


            
    def generateTopJavaScript(self):
        """generate script"""
        ret="""
        var baseUrl = '%s'; """% self.REQUEST['URL0']
        ret+="""
        newParameter('fn', '', 1);
        newParameter('pn', '1', 1);
        newParameter('ws', '1.0', 1);
        newParameter('mo', '', 1);
        newParameter('mk', '', 3);
        newParameter('wx', '0.0', 2);
        newParameter('wy', '0.0', 2);
        newParameter('ww', '1.0', 2);
        newParameter('wh', '1.0', 2);
        newParameter('pt', '0', 9);
        newParameter('brgt', '0.0', 1);
        newParameter('cont', '0.0', 1);
        newParameter('rot', '0.0', 1);
        newParameter('rgba', '', 1);
        newParameter('rgbm', '', 1);
        newParameter('ddpix', '', 9);
        newParameter('ddpiy', '', 9);
        var picsize = new Size(100, 100);
        document.id='digilib';

        """
        return ret

        
    def generateScalerImg(self,requestString):
        """generate Scaler IMG Tag"""
        retStr=self.digilibBaseUrl+requestString
        jS="""<script type="text/javascript">var ps = bestPicSize('scaler');
        document.write('<img id="pic" src="%s&dw='+ps.width+'&dh='+ps.height+'" />')
        </script>"""%retStr
        return jS

    def changeZogiLibForm(self):
        """Main configuration"""
        pt=PageTemplateFile('Products/zogiLib/zpt/changeZogiLibForm.zpt').__of__(self)
        return pt()
    
    def changeZogiLib(self,title,digilibBaseUrl, localFileBase,RESPONSE=None):
        """change it"""
        self.title=title
        self.digilibBaseUrl=digilibBaseUrl
        self.localFileBase=localFileBase

        if RESPONSE is not None:
            RESPONSE.redirect('manage_main')

            
    def nav_html(self,fileName):
        """navigations frame"""
        ## currently not in use
        # suche nach index.meta mit zogilib thumb info
        
        templ=readNavTemp(self.localFileBase+"/"+fileName)
        if not templ:
            templ=readNavTemp(self.localFileBase+"/"+fileName.split("/")[0])
            if not templ:
                return self.topTemplate.document_src()

        return urllib.urlopen(templ).read()
    
    
    def index_html(self):
        """main action"""


        #pt=PageTemplateFile('Products/zogiLib/zpt/zogiLibMain_image.zpt').__of__(self)
        #return pt()
        return self.mainTemplate()

    def storeQuery(self):
        """storeQuery in session"""
        self.REQUEST.SESSION['query']={}
        for fm in self.REQUEST.form.keys():
            self.REQUEST.SESSION['query'][fm]=self.REQUEST.form[fm]

        self.REQUEST.SESSION['dlInfo']=self.getDlInfo()
        
    def getParam(self,param):
        """Gebe Parameter aus"""
        try:
            return self.REQUEST.SESSION['query'][param]
        except:
            return None

    def getPageNum(self):
        """PAgenum"""
        pn=self.getParam('pn')
        if pn:
            return pn
        else:
            return 1

    def biggerWS(self):
        """ws+1"""
        ws=self.getParam('ws')
        if ws:
            return int(ws)+1
        else:
            return 2

    def options(self):
        """showoptions"""
        pt=PageTemplateFile('Products/zogiLib/zpt/optionwindow.zpt').__of__(self)
        return pt()

        
    def smallerWS(self):
        """ws-11"""
        ws=self.getParam('ws')
        if ws:
            if int(ws)==1:
                return
            else:
                return int(ws)-1
        else:
            return 1
        
        
    def setParam(self,pn=None,ws=None,rot=None,brgt=None,cont=None):
        """setze Parameter"""
        ret=""

        if brgt:
            self.REQUEST.SESSION['query']['brgt']=brgt

        if cont:
            self.REQUEST.SESSION['query']['cont']=cont

        if pn:
            self.REQUEST.SESSION['query']['pn']=pn

        if ws:
            self.REQUEST.SESSION['query']['ws']=ws

        if rot:
            self.REQUEST.SESSION['query']['rot']=rot
            
        for param in self.REQUEST.SESSION['query'].keys():
            
            ret+=param+"="+str(self.REQUEST.SESSION['query'][param])+"&"
        
        self.REQUEST.RESPONSE.redirect(self.REQUEST['URL1']+'?'+ret)

   
    def mirrorPage(self,mi):
        """mirror"""
        ret=""
        try:
            splitted=self.REQUEST.SESSION['query']['mo'].split(',')
        except:
            splitted=[]
        
        if mi=="h":
                    
            if 'hmir' in splitted:
                splitted.remove('hmir')
            else:
                splitted.append('hmir')

        if mi=="v":

            if 'vmir' in splitted:
                splitted.remove('vmir')
            else:
                splitted.append('vmir')


        self.REQUEST.SESSION['query']['mo']=string.join(splitted,",")
        
        
        
        
        for param in self.REQUEST.SESSION['query'].keys():
            
            ret+=param+"="+str(self.REQUEST.SESSION['query'][param])+"&"
        
        self.REQUEST.RESPONSE.redirect(self.REQUEST['URL1']+'?'+ret)
        
    def decode(self,strR):
        """decode &"""
        
        return re.sub('\&amp','\&',strR)
    
    def wholePage(self):
        """zoom out"""
        ret=""
        
        self.REQUEST.SESSION['query']['ww']=1
        self.REQUEST.SESSION['query']['wh']=1
        self.REQUEST.SESSION['query']['wx']=0
        self.REQUEST.SESSION['query']['wy']=0
            
        for param in self.REQUEST.SESSION['query'].keys():
            
            ret+=param+"="+str(self.REQUEST.SESSION['query'][param])+"&"
        
        self.REQUEST.RESPONSE.redirect(self.REQUEST['URL1']+'?'+ret)
        
    def prevPage(self,pn=None):
        """next page"""
        ret=""

        if pn and pn>0:
            pn=str(int(pn)-1)
        

        self.REQUEST.form['pn']=pn
        
        for param in self.REQUEST.form.keys():
            
            ret+=param+"="+str(self.REQUEST.form[param])+"&"
        
        self.REQUEST.RESPONSE.redirect(self.REQUEST['URL1']+'?'+ret)

    def firstPage(self):
        """erste Seite"""
        return self.setParam(pn="1")
    
    def lastPage(self):
        """letzte Seite"""

        
    def nextPage(self,pn=None):
        """next page"""
        ret=""
        
        try:
            pn=str(int(pn)+1)
        except:
            pn=str(2)

        self.REQUEST.form['pn']=pn
        
        for param in self.REQUEST.form.keys():
            ret+=param+"="+str(self.REQUEST.form[param])+"&"
        
        self.REQUEST.RESPONSE.redirect(self.REQUEST['URL1']+'?'+ret)

    def generateDivs(self):
        """generate divs"""
        pt=PageTemplateFile('Products/zogiLib/zpt/zogilib_divs').__of__(self)
        return pt()

        #divFileName=os.path.join(package_home(globals()),'zpt/zogilib_divs.zpt')
        #return open(divFileName).read()
          
def manage_addZogiLibForm(self):
    """interface for adding zogilib"""
    pt=PageTemplateFile('Products/zogiLib/zpt/addZogiLibForm').__of__(self)
    return pt()

def manage_addZogiLib(self,id,title,digilibBaseUrl, localFileBase,version="book",RESPONSE=None):
    """add dgilib"""
    newObj=zogiLib(id,title,digilibBaseUrl, localFileBase, version)
    self.Destination()._setObject(id,newObj)
    if RESPONSE is not None:
        RESPONSE.redirect('manage_main')

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>