merge branch master

This commit is contained in:
Helmut Merz 2012-10-15 08:20:14 +02:00
commit d50498bdaf
17 changed files with 114 additions and 40 deletions

View file

@ -413,7 +413,7 @@ class ConceptView(BaseView):
if r.order != pos: if r.order != pos:
r.order = pos r.order = pos
def resources(self): def getResources(self):
form = self.request.form form = self.request.form
#if form.get('loops.viewName') == 'index.html' and self.editable: #if form.get('loops.viewName') == 'index.html' and self.editable:
if self.editable: if self.editable:
@ -430,6 +430,9 @@ class ConceptView(BaseView):
if fv.check(r.first): if fv.check(r.first):
yield ResourceRelationView(r, self.request, contextIsSecond=True) yield ResourceRelationView(r, self.request, contextIsSecond=True)
def resources(self):
return self.getResources()
@Lazy @Lazy
def resourcesList(self): def resourcesList(self):
from loops.browser.resource import ResourceRelationView from loops.browser.resource import ResourceRelationView

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2011 Helmut Merz helmutm@cy55.de # Copyright (c) 2012 Helmut Merz helmutm@cy55.de
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -98,7 +98,7 @@ class AdapterBase(object):
adapts(IConcept) adapts(IConcept)
_adapterAttributes = ('context', '__parent__') _adapterAttributes = ('context', '__parent__', 'request')
_contextAttributes = list(IConcept) _contextAttributes = list(IConcept)
_noexportAttributes = () _noexportAttributes = ()
_textIndexAttributes = () _textIndexAttributes = ()
@ -106,6 +106,7 @@ class AdapterBase(object):
__is_dummy__ = False __is_dummy__ = False
__type__ = None __type__ = None
request = None
languageInfo = None languageInfo = None
def __init__(self, context): def __init__(self, context):

View file

@ -77,6 +77,30 @@ class SectionView(Base, ConceptView):
def sectionType(self): def sectionType(self):
return self.conceptManager['section'] return self.conceptManager['section']
def getResources(self):
relViews = super(SectionView, self).getResources()
return relViews
@Lazy
def textResources(self):
self.images = [[]]
result = []
idx = 0
for rv in self.getResources():
if rv.context.contentType.startswith('text/'):
idx += 1
result.append(rv)
self.images.append([])
else:
self.registerDojoLightbox()
url = self.nodeView.getUrlForTarget(rv.context)
src = '%s/mediaasset.html?v=small' % url
fullSrc = '%s/mediaasset.html?v=medium' % url
img = dict(src=src, fullImageUrl=fullSrc, title=rv.title,
description=rv.description, url=url, object=rv)
self.images[idx].append(img)
return result
def getCssClassForResource(self, r): def getCssClassForResource(self, r):
for c in r.context.getConcepts([self.defaultPredicate]): for c in r.context.getConcepts([self.defaultPredicate]):
if c.conceptType == self.documentTypeType: if c.conceptType == self.documentTypeType:

View file

@ -21,6 +21,7 @@ concept(u'issubtype', u'is Subtype', u'predicate', options=u'hide_children',
# document types # document types
concept(u'keyquestions', u'Leitfragen', u'documenttype') concept(u'keyquestions', u'Leitfragen', u'documenttype')
concept(u'textelement', u'Textabschnitt', u'documenttype') concept(u'textelement', u'Textabschnitt', u'documenttype')
concept(u'textelement2', u'Textabschnitt separat', u'documenttype')
concept(u'quote', u'Zitat', u'documenttype') concept(u'quote', u'Zitat', u'documenttype')
concept(u'story', u'Geschichte', u'documenttype') concept(u'story', u'Geschichte', u'documenttype')
concept(u'usecase', u'Fallbeispiel', u'documenttype') concept(u'usecase', u'Fallbeispiel', u'documenttype')

View file

@ -14,7 +14,7 @@
<metal:section define-macro="section"> <metal:section define-macro="section">
<metal:info use-macro="view/concept_macros/concepttitle" /> <metal:info use-macro="view/concept_macros/concepttitle" />
<div tal:repeat="related item/resources"> <div tal:repeat="related item/textResources">
<div class="span-4"> <div class="span-4">
<div tal:attributes="class python: <div tal:attributes="class python:
item.getCssClassForResource(related)" item.getCssClassForResource(related)"
@ -36,7 +36,8 @@
string:$resourceBase/cybertools.icons/vcard_edit.png" /></a> string:$resourceBase/cybertools.icons/vcard_edit.png" /></a>
<a i18n:translate="" i18n:attributes="title" <a i18n:translate="" i18n:attributes="title"
title="Edit with external editor." title="Edit with external editor."
tal:condition="related/xeditable" xxtal:condition="related/xeditable"
tal:condition="nothing"
tal:attributes="href string:$url/external_edit?version=this"> tal:attributes="href string:$url/external_edit?version=this">
<img tal:attributes="src <img tal:attributes="src
string:$resourceBase/cybertools.icons/application_edit.png" /></a> string:$resourceBase/cybertools.icons/application_edit.png" /></a>
@ -45,6 +46,15 @@
<a tal:content="parent/title" <a tal:content="parent/title"
tal:attributes="href python:view.getUrlForTarget(parent)" /> tal:attributes="href python:view.getUrlForTarget(parent)" />
</div> </div>
<div tal:repeat="image python:
item.images[repeat['related'].index() + 1]">
<a dojoType="dojox.image.Lightbox" group="mediasset"
i18n:attributes="title"
tal:attributes="href image/fullImageUrl;
title image/title">
<img tal:attributes="src image/src;
alt image/title" /></a>
</div>
</div> </div>
</div> </div>
</metal:section> </metal:section>

View file

@ -231,7 +231,7 @@ Extracting Document Properties from MS Office Files
>>> path = os.path.join(dataDir, 'office') >>> path = os.path.join(dataDir, 'office')
>>> fn = os.path.join(path, 'example.docx') >>> fn = os.path.join(path, 'example.docx')
>>> os.path.getsize(fn) >>> os.path.getsize(fn)
20337... 23561...
>>> officeFile = addAndConfigureObject(resources, Resource, 'test.docx', >>> officeFile = addAndConfigureObject(resources, Resource, 'test.docx',
... title=u'Example Word File', resourceType=tOfficeFile, ... title=u'Example Word File', resourceType=tOfficeFile,
@ -241,7 +241,7 @@ Extracting Document Properties from MS Office Files
>>> content = aOfficeFile.data >>> content = aOfficeFile.data
>>> len(content) >>> len(content)
17409 20327
Clean up: Clean up:
>>> shutil.copy(fn + '.sav', fn) >>> shutil.copy(fn + '.sav', fn)

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de # Copyright (c) 2012 Helmut Merz helmutm@cy55.de
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -18,8 +18,6 @@
""" """
View class(es) for integrating external objects. View class(es) for integrating external objects.
$Id$
""" """
from zope import interface, component from zope import interface, component
@ -42,7 +40,9 @@ class ExternalCollectionView(ConceptView):
def update(self): def update(self):
if 'update' in self.request.form: if 'update' in self.request.form:
cta = adapted(self.context) cta = adapted(self.context)
if cta is not None: cta.request = self.request
cta.update() cta.update()
if cta.updateMessage is not None:
self.request.form['message'] = cta.updateMessage
return True return True

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2009 Helmut Merz helmutm@cy55.de # Copyright (c) 2012 Helmut Merz helmutm@cy55.de
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -19,8 +19,6 @@
""" """
Concept adapter(s) for external collections, e.g. a directory in the Concept adapter(s) for external collections, e.g. a directory in the
file system. file system.
$Id$
""" """
from datetime import datetime from datetime import datetime
@ -62,10 +60,12 @@ class ExternalCollectionAdapter(AdapterBase):
implements(IExternalCollection) implements(IExternalCollection)
adapts(IConcept) adapts(IConcept)
_adapterAttributes = ('context', '__parent__', 'exclude', 'newResources') _adapterAttributes = AdapterBase._adapterAttributes + (
'exclude', 'newResources', 'updateMessage')
_contextAttributes = list(IExternalCollection) + list(IConcept) _contextAttributes = list(IExternalCollection) + list(IConcept)
newResources = None newResources = None
updateMessage = None
def getExclude(self): def getExclude(self):
return getattr(self.context, '_exclude', None) or [] return getattr(self.context, '_exclude', None) or []
@ -101,12 +101,17 @@ class ExternalCollectionAdapter(AdapterBase):
adobj = adapted(obj) adobj = adapted(obj)
directory = provider.getDirectory(self) directory = provider.getDirectory(self)
adobj.storageParams=dict(subdirectory=directory) adobj.storageParams=dict(subdirectory=directory)
adobj.request = self.request
adobj.externalAddress = addr adobj.externalAddress = addr
# collect error information
if adobj.processingErrors:
message = self.updateMessage or u''
message += u'<br />'.join(adobj.processingErrors)
self.updateMessage = message
# force reindexing # force reindexing
notify(ObjectModifiedEvent(obj)) notify(ObjectModifiedEvent(obj))
else: else:
new.append(addr) new.append(addr)
#print '*** new', new
if new: if new:
self.newResources = provider.createExtFileObjects(self, new) self.newResources = provider.createExtFileObjects(self, new)
for r in self.newResources: for r in self.newResources:
@ -205,7 +210,13 @@ class DirectoryCollectionProvider(object):
contentType=contentType, contentType=contentType,
) )
adobj = adapted(obj) adobj = adapted(obj)
adobj.request = client.request
adobj.externalAddress = addr # must be set last adobj.externalAddress = addr # must be set last
# collect error information
if adobj.processingErrors:
message = client.updateMessage or u''
message += u'<br />'.join(adobj.processingErrors)
client.updateMessage = message
yield obj yield obj
def getDirectory(self, client): def getDirectory(self, client):

View file

@ -7,6 +7,10 @@
<metal:block use-macro="view/concept_macros/conceptdata"> <metal:block use-macro="view/concept_macros/conceptdata">
<metal:fill tal:condition="item/editable" <metal:fill tal:condition="item/editable"
fill-slot="fields"> fill-slot="fields">
<div class="error"
tal:define="message view/message | request/message | nothing"
tal:condition="message"
tal:content="structure message" />
<metal:block use-macro="view/concept_macros/conceptfields" /> <metal:block use-macro="view/concept_macros/conceptfields" />
<form method="post"> <form method="post">
<input type="submit" name="update" value="Update Collection" /> <input type="submit" name="update" value="Update Collection" />

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2010 Helmut Merz helmutm@cy55.de # Copyright (c) 2012 Helmut Merz helmutm@cy55.de
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -18,8 +18,6 @@
""" """
Resource adapter(s) for MS Office files. Resource adapter(s) for MS Office files.
$Id$
""" """
from datetime import date, datetime, timedelta from datetime import date, datetime, timedelta
@ -56,6 +54,7 @@ class OfficeFile(ExternalFileAdapter):
propertyMap = {u'Revision:': 'version'} propertyMap = {u'Revision:': 'version'}
propFileName = 'docProps/custom.xml' propFileName = 'docProps/custom.xml'
corePropFileName = 'docProps/core.xml'
fileExtensions = ('.docm', '.docx', 'dotm', 'dotx', 'pptx', 'potx', 'ppsx', fileExtensions = ('.docm', '.docx', 'dotm', 'dotx', 'pptx', 'potx', 'ppsx',
'.xlsm', '.xlsx', '.xltm', '.xltx') '.xlsm', '.xlsx', '.xltm', '.xltx')
@ -88,20 +87,32 @@ class OfficeFile(ExternalFileAdapter):
from logging import getLogger from logging import getLogger
self.logger.warn(e) self.logger.warn(e)
return [] return []
if self.corePropFileName not in zf.namelist():
self.logger.warn('Core properties not found in file %s.' %
self.externalAddress)
if self.propFileName not in zf.namelist(): if self.propFileName not in zf.namelist():
self.logger.warn('Custom properties not found in file %s.' % self.logger.warn('Custom properties not found in file %s.' %
self.externalAddress) self.externalAddress)
propsXml = zf.read(self.propFileName) propsXml = zf.read(self.propFileName)
corePropsXml = zf.read(self.corePropFileName)
# TODO: read core.xml, return both trees in dictionary
zf.close() zf.close()
return etree.fromstring(propsXml) return {'custom': etree.fromstring(propsXml),
'core': etree.fromstring(corePropsXml)}
def getDocProperty(self, pname): def getDocProperty(self, pname):
for p in self.docPropertyDom: for p in self.docPropertyDom['custom']:
name = p.attrib.get('name') name = p.attrib.get('name')
if name == pname: if name == pname:
return p[0].text return p[0].text
return None return None
def getCoreProperty(self, pname):
for p in self.docPropertyDom['core']:
if p.tag.endswith(pname):
return p.text
return None
def processDocument(self): def processDocument(self):
changed = False changed = False
docVersion = None docVersion = None
@ -109,11 +120,14 @@ class OfficeFile(ExternalFileAdapter):
strType = ('{http://schemas.openxmlformats.org/' strType = ('{http://schemas.openxmlformats.org/'
'officeDocument/2006/docPropsVTypes}lpwstr') 'officeDocument/2006/docPropsVTypes}lpwstr')
attributes = {} attributes = {}
dom = self.docPropertyDom # get dc:description from core.xml
desc = self.getCoreProperty('description')
if desc is not None:
attributes['comments'] = desc
dom = self.docPropertyDom['custom']
for p in dom: for p in dom:
name = p.attrib.get('name') name = p.attrib.get('name')
value = p[0].text value = p[0].text
#print '***', self.externalAddress, name, value, p[0].tag
attr = self.propertyMap.get(name) attr = self.propertyMap.get(name)
if attr == 'version': if attr == 'version':
docVersion = value docVersion = value
@ -136,7 +150,9 @@ class OfficeFile(ExternalFileAdapter):
newZf.writestr(self.propFileName, etree.tostring(dom)) newZf.writestr(self.propFileName, etree.tostring(dom))
newZf.close() newZf.close()
shutil.move(newFn, fn) shutil.move(newFn, fn)
self.update(attributes) errors = self.update(attributes)
if errors:
self.processingErrors = errors
def update(self, attributes): def update(self, attributes):
# to be implemented by subclass # to be implemented by subclass
@ -146,10 +162,10 @@ class OfficeFile(ExternalFileAdapter):
def parseDate(s): def parseDate(s):
if not s: if not s:
return None return None
tt = strptime(s, '%Y-%m-%dT%H:%M:%SZ') try:
#try: tt = strptime(s, '%Y-%m-%dT%H:%M:%SZ')
# tt = strptime(s, '%Y-%m-%dT%H:%M:%SZ') except ValueError:
#except ValueError: return None
# try: # try:
# tt = strptime(s, '%d.%m.%y') # tt = strptime(s, '%d.%m.%y')
# except ValueError: # except ValueError:

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: $Id$\n" "Project-Id-Version: $Id$\n"
"POT-Creation-Date: 2007-05-22 12:00 CET\n" "POT-Creation-Date: 2007-05-22 12:00 CET\n"
"PO-Revision-Date: 2012-08-20 12:00 CET\n" "PO-Revision-Date: 2012-09-17 12:00 CET\n"
"Last-Translator: Helmut Merz <helmutm@cy55.de>\n" "Last-Translator: Helmut Merz <helmutm@cy55.de>\n"
"Language-Team: loops developers <helmutm@cy55.de>\n" "Language-Team: loops developers <helmutm@cy55.de>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@ -758,6 +758,9 @@ msgstr "Kommentare"
msgid "Add Comment" msgid "Add Comment"
msgstr "Kommentar hinzufügen" msgstr "Kommentar hinzufügen"
msgid "Subject"
msgstr "Thema"
msgid "Selection using: $targets" msgid "Selection using: $targets"
msgstr "Auswahl über: $targets" msgstr "Auswahl über: $targets"

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de # Copyright (c) 2012 Helmut Merz helmutm@cy55.de
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -18,8 +18,6 @@
""" """
Definition of view classes and other browser related stuff for comments. Definition of view classes and other browser related stuff for comments.
$Id$
""" """
from zope import interface, component from zope import interface, component
@ -52,6 +50,8 @@ class CommentsView(NodeView):
@Lazy @Lazy
def allowed(self): def allowed(self):
if self.isAnonymous:
return False
return (self.virtualTargetObject is not None and return (self.virtualTargetObject is not None and
self.globalOptions('organize.allowComments')) self.globalOptions('organize.allowComments'))
@ -120,8 +120,8 @@ class CreateComment(EditObject):
def update(self): def update(self):
form = self.request.form form = self.request.form
subject = form.get('subject') subject = form.get('subject')
text = form.get('text') text = form.get('text') or u''
if not subject or not text or self.personId is None or self.object is None: if not subject or self.personId is None or self.object is None:
return True return True
#contentType = form.get('contentType') or 'text/restructured' #contentType = form.get('contentType') or 'text/restructured'
rm = self.view.loopsRoot.getRecordManager() rm = self.view.loopsRoot.getRecordManager()

View file

@ -58,7 +58,7 @@
</div> </div>
<div class="buttons"> <div class="buttons">
<input value="Save" type="submit" <input value="Save" type="submit"
onClick="return closeDialog(true)" onClick="if (not this.validate()) return False; return closeDialog(true)"
i18n:attributes="value"> i18n:attributes="value">
<input type="button" value="Cancel" <input type="button" value="Cancel"
onClick="return closeDialog(false)" onClick="return closeDialog(false)"

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2011 Helmut Merz helmutm@cy55.de # Copyright (c) 2012 Helmut Merz helmutm@cy55.de
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -18,8 +18,6 @@
""" """
Definition of the Concept class. Definition of the Concept class.
$Id$
""" """
from cStringIO import StringIO from cStringIO import StringIO
@ -352,7 +350,10 @@ class ExternalFileAdapter(FileAdapter):
implements(IExternalFile) implements(IExternalFile)
_adapterAttributes = (FileAdapter._adapterAttributes _adapterAttributes = (FileAdapter._adapterAttributes
+ ('storageParams', 'externalAddress', 'uniqueAddress')) + ('storageParams', 'externalAddress', 'uniqueAddress',
'processingErrors'))
processingErrors = []
def getStorageParams(self): def getStorageParams(self):
params = getattr(self.context, '_storageParams', None) params = getattr(self.context, '_storageParams', None)