--- documentViewer/documentViewer.py 2011/08/02 10:35:05 1.175.2.14 +++ documentViewer/documentViewer.py 2011/08/22 15:00:28 1.175.2.29 @@ -1,6 +1,8 @@ from OFS.Folder import Folder +from OFS.Image import File from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate -from Products.PageTemplates.PageTemplateFile import PageTemplateFile +from Products.PageTemplates.PageTemplateFile import PageTemplateFile +from Products.ZSimpleFile import ZSimpleFile from AccessControl import ClassSecurityInfo from AccessControl import getSecurityManager from Globals import package_home @@ -122,6 +124,8 @@ class documentViewer(Folder): """MetaDataFolder instance""" # templates and forms + viewer_text = PageTemplateFile('zpt/viewer_text', globals()) + viewer_images = PageTemplateFile('zpt/viewer_images', globals()) viewer_main = PageTemplateFile('zpt/viewer_main', globals()) toc_thumbs = PageTemplateFile('zpt/toc_thumbs', globals()) toc_text = PageTemplateFile('zpt/toc_text', globals()) @@ -134,8 +138,9 @@ class documentViewer(Folder): page_main_xml = PageTemplateFile('zpt/page_main_xml', globals()) page_main_pureXml = PageTemplateFile('zpt/page_main_pureXml', globals()) head_main = PageTemplateFile('zpt/head_main', globals()) - docuviewer_css = PageTemplateFile('css/docuviewer.css', globals()) info_xml = PageTemplateFile('zpt/info_xml', globals()) + # TODO: can this be nicer? + docuviewer_css = ZSimpleFile(content_type='text/css',filename='css/docuviewer.css', id='docuviewer_css',_prefix=globals()) thumbs_main_rss = PageTemplateFile('zpt/thumbs_main_rss', globals()) @@ -176,6 +181,9 @@ class documentViewer(Folder): except Exception, e: logging.error("Unable to find MetaDataFolder 'metadata': "+str(e)) + if digilibBaseUrl is not None: + self.digilibBaseUrl = digilibBaseUrl + # proxy text server methods to fulltextclient def getTextPage(self, **args): @@ -206,9 +214,9 @@ class documentViewer(Folder): """get all gis places """ return self.template.fulltextclient.getAllGisPlaces(**args) - def getTranslate(self, **args): + def getWordInfo(self, **args): """get translate""" - return self.template.fulltextclient.getTranslate(**args) + return self.template.fulltextclient.getWordInfo(**args) def getLemma(self, **args): """get lemma""" @@ -266,16 +274,17 @@ class documentViewer(Folder): security.declareProtected('View','index_html') - def index_html(self,url,mode="texttool",viewMode="auto",tocMode="thumbs",start=None,pn=1,mk=None): + def index_html(self,url,mode="texttool",viewMode="auto",viewType=None,tocMode="thumbs",start=1,pn=1): """ - view it - @param mode: defines how to access the document behind url + view page @param url: url which contains display information - @param viewMode: if images display images, if text display text, default is auto (text,images or auto) + @param mode: defines how to access the document behind url + @param viewMode: 'images': display images, 'text': display text, default is 'auto' + @param viewType: sub-type of viewMode, e.g. 'dict' for viewMode='text' @param tocMode: type of 'table of contents' for navigation (thumbs, text, figures, none) """ - logging.debug("documentViewer (index) mode: %s url:%s start:%s pn:%s"%(mode,url,start,pn)) + logging.debug("documentViewer(index_html) mode=%s url=%s viewMode=%s viewType=%s start=%s pn=%s"%(mode,url,viewMode,viewType,start,pn)) if not hasattr(self, 'template'): # this won't work @@ -291,24 +300,35 @@ class documentViewer(Folder): # get table of contents docinfo = self.getToc(mode=tocMode, docinfo=docinfo) - # auto viewMode: text_dict if text else images + # auto viewMode: text if there is a text else images if viewMode=="auto": if docinfo.get('textURL', None) or docinfo.get('textURLPath', None): - viewMode="text_dict" + viewMode = "text" + viewType = "dict" else: - viewMode="images" + viewMode = "images" - pageinfo = self.getPageinfo(start=start, current=pn, docinfo=docinfo, viewMode=viewMode, tocMode=tocMode) + elif viewMode == "text_dict": + # legacy fix + viewMode = "text" + viewType = "dict" + + # stringify viewType + if isinstance(viewType, list): + logging.debug("index_html: viewType is list:%s"%viewType) + viewType = ','.join([t for t in viewType if t]) + + pageinfo = self.getPageinfo(start=start, current=pn, docinfo=docinfo, viewMode=viewMode, viewType=viewType, tocMode=tocMode) + + # get template /template/viewer_$viewMode + pt = getattr(self.template, 'viewer_%s'%viewMode, None) + if pt is None: + logging.error("No template for viewMode=%s!"%viewMode) + # TODO: error page? + return "No template for viewMode=%s!"%viewMode - if viewMode != 'images' and docinfo.get('textURLPath', None): - # get full text page - page = self.getTextPage(mode=viewMode, pn=pn, docinfo=docinfo, pageinfo=pageinfo) - pageinfo['textPage'] = page - - # get template /template/viewer_main - pt = getattr(self.template, 'viewer_main') # and execute with parameters - return pt(docinfo=docinfo, pageinfo=pageinfo, viewMode=viewMode, mk=self.generateMarks(mk)) + return pt(docinfo=docinfo, pageinfo=pageinfo) def generateMarks(self,mk): ret="" @@ -331,61 +351,92 @@ class documentViewer(Folder): """try to get the digilib URL from zogilib""" url = self.template.zogilib.getDLBaseUrl() return url + + def getScalerUrl(self, fn=None, pn=None, dw=100, dh=100, docinfo=None): + """returns URL to digilib Scaler with params""" + url = None + if docinfo is not None: + url = docinfo.get('imageURL', None) + + if url is None: + url = "%s/servlet/Scaler?"%self.digilibBaseUrl + if fn is None and docinfo is not None: + fn = docinfo.get('imagePath','') + + url += "fn=%s"%fn + + if pn: + url += "&pn=%s"%pn + + url += "&dw=%s&dh=%s"%(dw,dh) + return url def getDocumentViewerURL(self): """returns the URL of this instance""" return self.absolute_url() def getStyle(self, idx, selected, style=""): - """returns a string with the given style and append 'sel' if path == selected.""" + """returns a string with the given style and append 'sel' if idx == selected.""" #logger("documentViewer (getstyle)", logging.INFO, "idx: %s selected: %s style: %s"%(idx,selected,style)) if idx == selected: return style + 'sel' else: return style - def getLink(self, param=None, val=None, params=None, baseUrl=None, paramSep='&'): - """returns URL to documentviewer with parameter param set to val or from dict params""" + def getParams(self, param=None, val=None, params=None, duplicates=None): + """returns dict with URL parameters. + + Takes URL parameters and additionally param=val or dict params. + Deletes key if value is None.""" # copy existing request params - urlParams=self.REQUEST.form.copy() + newParams=self.REQUEST.form.copy() # change single param if param is not None: if val is None: - if urlParams.has_key(param): - del urlParams[param] + if newParams.has_key(param): + del newParams[param] else: - urlParams[param] = str(val) + newParams[param] = str(val) # change more params if params is not None: - for k in params.keys(): - v = params[k] + for (k, v) in params.items(): if v is None: # val=None removes param - if urlParams.has_key(k): - del urlParams[k] + if newParams.has_key(k): + del newParams[k] else: - urlParams[k] = v + newParams[k] = v - # FIXME: does this belong here? - if urlParams.get("mode", None) == "filepath": #wenn beim erst Aufruf filepath gesetzt wurde aendere das nun zu imagepath - urlParams["mode"] = "imagepath" - urlParams["url"] = getParentPath(urlParams["url"]) - + if duplicates: + # eliminate lists (coming from duplicate keys) + for (k,v) in newParams.items(): + if isinstance(v, list): + if duplicates == 'comma': + # make comma-separated list of non-empty entries + newParams[k] = ','.join([t for t in v if t]) + elif duplicates == 'first': + # take first non-empty entry + newParams[k] = [t for t in v if t][0] + + return newParams + + def getLink(self, param=None, val=None, params=None, baseUrl=None, paramSep='&', duplicates='comma'): + """returns URL to documentviewer with parameter param set to val or from dict params""" + urlParams = self.getParams(param=param, val=val, params=params, duplicates=duplicates) # quote values and assemble into query string (not escaping '/') - ps = paramSep.join(["%s=%s"%(k,urllib.quote_plus(v,'/')) for (k, v) in urlParams.items()]) - #ps = urllib.urlencode(urlParams) + ps = paramSep.join(["%s=%s"%(k,urllib.quote_plus(unicode(v),'/')) for (k, v) in urlParams.items()]) if baseUrl is None: - baseUrl = self.REQUEST['URL1'] + baseUrl = self.getDocumentViewerURL() url = "%s?%s"%(baseUrl, ps) return url - - def getLinkAmp(self, param=None, val=None, params=None, baseUrl=None): + def getLinkAmp(self, param=None, val=None, params=None, baseUrl=None, duplicates='comma'): """link to documentviewer with parameter param set to val""" - return self.getLink(param, val, params, baseUrl, '&') + return self.getLink(param=param, val=val, params=params, baseUrl=baseUrl, paramSep='&', duplicates=duplicates) + def getInfo_xml(self,url,mode): """returns info about the document as XML""" @@ -434,6 +485,7 @@ class documentViewer(Folder): docinfo = {'mode': mode, 'url': url} # add self url docinfo['viewerUrl'] = self.getDocumentViewerURL() + docinfo['digilibBaseUrl'] = self.digilibBaseUrl # get index.meta DOM docUrl = None metaDom = None @@ -462,9 +514,8 @@ class documentViewer(Folder): docinfo['documentUrl'] = docUrl # process index.meta contents - if metaDom is not None: + if metaDom is not None and metaDom.tag == 'resource': # document directory name and path - logging.debug("RESOURCE: %s"%repr(self.metadataService.resource.getData(dom=metaDom,recursive=1))) resource = self.metadataService.getResourceData(dom=metaDom) if resource: docinfo = self.getDocinfoFromResource(docinfo, resource) @@ -503,7 +554,7 @@ class documentViewer(Folder): # image path if mode != 'texttool': - # override image path from texttool + # override image path from texttool with url docinfo['imagePath'] = url.replace('/mpiwg/online/', '', 1) # number of images from digilib @@ -565,9 +616,15 @@ class documentViewer(Folder): textUrl = texttool.get('text-url-path', None) if textUrl: docinfo['textURLPath'] = textUrl - #TODO: ugly: - #textUrlkurz = string.split(textUrl, ".")[0] - #docinfo['textURLPathkurz'] = textUrlkurz + + # page flow + docinfo['pageFlow'] = texttool.get('page-flow', 'ltr') + + # odd pages are left + docinfo['oddPage'] = texttool.get('odd-scan-position', 'left') + + # number of title page (0: not defined) + docinfo['titlePage'] = texttool.get('title-scan-no', 0) # old presentation stuff presentation = texttool.get('presentation', None) @@ -577,6 +634,7 @@ class documentViewer(Folder): else: docinfo['presentationUrl'] = os.path.join(docPath, presentation) + return docinfo def getDocinfoFromBib(self, docinfo, bib): @@ -661,63 +719,176 @@ class documentViewer(Folder): return docinfo - def getPageinfo(self, current, start=None, rows=None, cols=None, docinfo=None, viewMode=None, tocMode=None): + def getPageinfo(self, current=None, start=None, rows=None, cols=None, docinfo=None, viewMode=None, viewType=None, tocMode=None): """returns pageinfo with the given parameters""" + logging.debug("getPageInfo(current=%s, start=%s, rows=%s, cols=%s, viewMode=%s, viewType=%s, tocMode=%s)"%(current,start,rows,cols,viewMode,viewType,tocMode)) pageinfo = {} + pageinfo['viewMode'] = viewMode + pageinfo['viewType'] = viewType + pageinfo['tocMode'] = tocMode + current = getInt(current) - pageinfo['current'] = current + pageinfo['pn'] = current rows = int(rows or self.thumbrows) pageinfo['rows'] = rows cols = int(cols or self.thumbcols) pageinfo['cols'] = cols grpsize = cols * rows pageinfo['groupsize'] = grpsize - # what does this do? + # is start is empty use one around current start = getInt(start, default=(math.ceil(float(current)/float(grpsize))*grpsize-(grpsize-1))) # int(current / grpsize) * grpsize +1)) pageinfo['start'] = start - pageinfo['end'] = start + grpsize - if (docinfo is not None) and ('numPages' in docinfo): - np = int(docinfo['numPages']) - pageinfo['end'] = min(pageinfo['end'], np) - pageinfo['numgroups'] = int(np / grpsize) - if np % grpsize > 0: - pageinfo['numgroups'] += 1 + + np = int(docinfo.get('numPages', 0)) + if np == 0: + # numPages unknown - maybe we can get it from text page + if docinfo.get('textURLPath', None): + # cache text page as well + pageinfo['textPage'] = self.getTextPage(mode=viewType, pn=current, docinfo=docinfo, pageinfo=pageinfo) + np = int(docinfo.get('numPages', 0)) - pageinfo['viewMode'] = viewMode - pageinfo['tocMode'] = tocMode + pageinfo['numgroups'] = int(np / grpsize) + if np % grpsize > 0: + pageinfo['numgroups'] += 1 + + pageFlowLtr = docinfo.get('pageFlow', 'ltr') != 'rtl' + oddScanLeft = docinfo.get('oddPage', 'left') != 'right' + # add zeroth page for two columns + pageZero = (cols == 2 and (pageFlowLtr != oddScanLeft)) + pageinfo['pageZero'] = pageZero + pageinfo['pageBatch'] = self.getPageBatch(start=start, rows=rows, cols=cols, pageFlowLtr=pageFlowLtr, pageZero=pageZero, minIdx=1, maxIdx=np) + + # TODO: do we need this here? pageinfo['characterNormalization'] = self.REQUEST.get('characterNormalization','reg') - #pageinfo['optionToggle'] = self.REQUEST.get('optionToggle','1') pageinfo['query'] = self.REQUEST.get('query','') pageinfo['queryType'] = self.REQUEST.get('queryType','') pageinfo['querySearch'] =self.REQUEST.get('querySearch', 'fulltext') - pageinfo['textPN'] = self.REQUEST.get('textPN','1') pageinfo['highlightQuery'] = self.REQUEST.get('highlightQuery','') - pageinfo['tocPageSize'] = self.REQUEST.get('tocPageSize', '30') - pageinfo['queryPageSize'] =self.REQUEST.get('queryPageSize', '10') - pageinfo['tocPN'] = self.REQUEST.get('tocPN', '1') - # WTF?: - toc = int(pageinfo['tocPN']) - pageinfo['textPages'] =int(toc) + pageinfo['tocPageSize'] = getInt(self.REQUEST.get('tocPageSize', 30)) + pageinfo['queryPageSize'] = getInt(self.REQUEST.get('queryPageSize', 10)) + pageinfo['tocPN'] = getInt(self.REQUEST.get('tocPN', '1')) + pageinfo['searchPN'] = getInt(self.REQUEST.get('searchPN','1')) - # What does this do? + # limit tocPN if 'tocSize_%s'%tocMode in docinfo: - tocSize = int(docinfo['tocSize_%s'%tocMode]) - tocPageSize = int(pageinfo['tocPageSize']) + tocSize = docinfo['tocSize_%s'%tocMode] + tocPageSize = pageinfo['tocPageSize'] # cached toc if tocSize%tocPageSize>0: tocPages=tocSize/tocPageSize+1 else: tocPages=tocSize/tocPageSize - pageinfo['tocPN'] = min(tocPages,toc) + pageinfo['tocPN'] = min(tocPages,pageinfo['tocPN']) - pageinfo['searchPN'] =self.REQUEST.get('searchPN','1') - pageinfo['sn'] =self.REQUEST.get('sn','') return pageinfo + def getPageBatch(self, start=1, rows=10, cols=2, pageFlowLtr=True, pageZero=False, minIdx=1, maxIdx=0): + """returns dict with array of page informations for one screenfull of thumbnails""" + batch = {} + grpsize = rows * cols + if maxIdx == 0: + maxIdx = start + grpsize + + nb = int(math.ceil(maxIdx / float(grpsize))) + # list of all batch start and end points + batches = [] + if pageZero: + ofs = 0 + else: + ofs = 1 + + for i in range(nb): + s = i * grpsize + ofs + e = min((i + 1) * grpsize + ofs - 1, maxIdx) + batches.append({'start':s, 'end':e}) + + batch['batches'] = batches + + pages = [] + if pageZero and start == 1: + # correct beginning + idx = 0 + else: + idx = start + + for r in range(rows): + row = [] + for c in range(cols): + if idx < minIdx or idx > maxIdx: + page = {'idx':None} + else: + page = {'idx':idx} + + idx += 1 + if pageFlowLtr: + row.append(page) + else: + row.insert(0, page) + + pages.append(row) + + if start > 1: + batch['prevStart'] = max(start - grpsize, 1) + else: + batch['prevStart'] = None + + if start + grpsize < maxIdx: + batch['nextStart'] = start + grpsize + else: + batch['nextStart'] = None + + batch['pages'] = pages + return batch + + def getBatch(self, start=1, size=10, end=0, data=None, fullData=True): + """returns dict with information for one screenfull of data.""" + batch = {} + if end == 0: + end = start + size + + nb = int(math.ceil(end / float(size))) + # list of all batch start and end points + batches = [] + for i in range(nb): + s = i * size + 1 + e = min((i + 1) * size, end) + batches.append({'start':s, 'end':e}) + + batch['batches'] = batches + # list of elements in this batch + this = [] + j = 0 + for i in range(start, min(start+size, end)): + if data: + if fullData: + d = data[i] + else: + d = data[j] + j += 1 + + else: + d = i+1 + + this.append(d) + + batch['this'] = this + if start > 1: + batch['prevStart'] = max(start - size, 1) + else: + batch['prevStart'] = None + + if start + size < end: + batch['nextStart'] = start + size + else: + batch['nextStart'] = None + + return batch + + security.declareProtected('View management screens','changeDocumentViewerForm') changeDocumentViewerForm = PageTemplateFile('zpt/changeDocumentViewer', globals()) @@ -749,37 +920,3 @@ def manage_AddDocumentViewer(self,id,ima if RESPONSE is not None: RESPONSE.redirect('manage_main') - -## DocumentViewerTemplate class -class DocumentViewerTemplate(ZopePageTemplate): - """Template for document viewer""" - meta_type="DocumentViewer Template" - - -def manage_addDocumentViewerTemplateForm(self): - """Form for adding""" - pt=PageTemplateFile('zpt/addDocumentViewerTemplate', globals()).__of__(self) - return pt() - -def manage_addDocumentViewerTemplate(self, id='viewer_main', title=None, text=None, - REQUEST=None, submit=None): - "Add a Page Template with optional file content." - - self._setObject(id, DocumentViewerTemplate(id)) - ob = getattr(self, id) - txt=file(os.path.join(package_home(globals()),'zpt/viewer_main.zpt'),'r').read() - logging.info("txt %s:"%txt) - ob.pt_edit(txt,"text/html") - if title: - ob.pt_setTitle(title) - try: - u = self.DestinationURL() - except AttributeError: - u = REQUEST['URL1'] - - u = "%s/%s" % (u, urllib.quote(id)) - REQUEST.RESPONSE.redirect(u+'/manage_main') - return '' - - -