source: trunk/PILOTMaterial.py @ 1889

Revision 1889, 10.0 KB checked in by gabor, 12 years ago (diff)

ref #1432

  • Property svn:keywords set to Id Revision
Line 
1# Copyright 2006 by the LeMill Team (see AUTHORS)
2#
3# This file is part of LeMill.
4#
5# LeMill is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# LeMill is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with LeMill; if not, write to the Free Software
17# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1
18
19from AccessControl import ClassSecurityInfo
20from Products.Archetypes.public import *
21from Products.CMFCore.utils import getToolByName
22
23from SharedMetadata import *
24from FieldsWidgets import *
25from config import PROJECTNAME, MODIFY_CONTENT, VIEW, to_unicode
26from Products.CMFPlone import PloneMessageFactory as PMF
27from Material import Material
28
29short_description = Schema((
30    StringField('shortDescription',
31        index="ZCTextIndex:schema",
32        searchable=True,
33        schemata = 'default',
34        widget = LeTextAreaWidget(
35            rows = 3,
36            label = 'Short description',
37            label_msgid = 'label_short_description',
38            i18n_domain="lemill",
39        ),
40    ),
41))
42
43full_description = Schema((
44    StringField('description',
45        index="ZCTextIndex:schema",
46        searchable=True,
47        schemata="metadata",
48        widget=LeTextAreaWidget(
49            rows = 8,
50            label="Full description",
51            label_msgid="label_full_description",
52            i18n_domain="lemill"),
53    )
54))
55
56bodyText = Schema((
57    ChapterField('bodyText',
58        accessor = 'getBodyText',
59        edit_accessor = 'getRawBodyText',
60        schemata = 'scenes',
61        mutator = "setBodyText",
62        index='ZCTextIndex:schema',
63        index_method = 'getOnlyText',
64        searchable = True,
65        allowable_content_types = ['text/html',],
66        allow_file_upload = False,
67        default_output_type = 'text/x-html-captioned',
68        default_content_type = 'text/html',
69        default=['thisisamediapiecethisisamediapie','thisisaudiopiecethisisaudiopiece',['','',''], 'thisisamediapiecethisisamediapie','thisisaudiopiecethisisaudiopiece',['','','','','','','']],
70        deleteEmptyChapters = False,
71        widget=PilotWidget(label = "",
72            label_msgid = "",
73            description = "Here you can compose a flash movie from images and audio pieces.",
74            description_msgid = "help_pilot_body_text",
75            i18n_domain = "lemill",
76            ),
77    ),
78))
79
80schema = BaseSchema + short_description + full_description + tags + group_sharing + coverImage + lemill_metadata_mods + language_schema + license_schema + author_schema + subject_area_schema + target_group_schema + deletionReason + version_schema + translation_schema + bodyText + ieee_lom_lre_ap + latest_edit_schema + score
81
82schema = schema.copy()
83schema['description'].isMetadata = False
84schema['description'].schemata = 'default'
85schema.moveField('shortDescription', after='bodyText')
86schema.moveField('description', after='shortDescription')
87schema['title'].required = True
88schema.moveField('rights', pos='bottom')
89
90
91class PILOTMaterial(Material):
92    """ PILOT Material """
93
94    schema = schema
95   
96    meta_type = 'PILOTMaterial'
97    archetype_name = 'PILOTMaterial'
98
99    security = ClassSecurityInfo()
100    security.declareObjectPublic()
101
102    security.declarePrivate('manage_afterAdd')
103    def manage_afterAdd(self, item, container):
104        Material.manage_afterAdd(self, item, container)
105        if not hasattr(item.aq_base, 'left_slots'):
106            self._setProperty('left_slots', ['here/portlet_material_actions/macros/portlet',], 'lines')
107        else:
108            self._updateProperty('left_slots', ['here/portlet_material_actions/macros/portlet',])
109
110    def getOnlyText(self):
111        """ bodyTexts index_method: goes through all text fields in body text and concatenates them to a mass of text suitable for indexing """
112        field=self.getField('bodyText')
113        values = field.get(self)
114        reslist=[]
115        for chap in values:
116            if chap==None:
117                continue
118            if type(chap)==list or type(chap)==tuple:
119                chap=to_unicode('\n'.join(chap))
120            reslist.append(chap)
121        return u'\n'.join(reslist)
122
123    def buildXML(self, only_validate=False):
124        """ builds the xml-blueprint from bodytext for flash engine """
125
126        def kw_cutter(k,maxlength):
127            """ method to add linebreaks to long keywords """
128            if len(k)>maxlength:
129                cutend=maxlength
130                cutbegin=0
131                resl=[]
132                while cutend<len(k):
133                    while k[cutend] not in ' +-':
134                        cutend=cutend-1
135                    resl.append(k[cutbegin:cutend])
136                    cutbegin=cutend
137                    cutend=cutend+maxlength
138                resl.append(k[cutbegin:])
139                k=' &amp;&amp;'.join(resl)
140            return k
141
142        plone_utils=getToolByName(self, 'plone_utils')
143
144        bodyfield=self.getField('bodyText')
145        bodytext=self.getBodyText()
146        title=self.title
147        failure=''
148        vc_url=[]
149        bg_url=[]
150        kw=[]
151        has_title=0
152        title_begin=''
153        maxlength=40 # how many characters of keyword fits on one line
154        msg=''
155        ### Collect and validate values ###
156        for f in range(len(bodytext)):
157            if f % 3 == 0:
158                # backgrounds
159                uid=bodytext[f]
160                obj=bodyfield.getObjectByUID(self, uid)
161                url='missing'
162                if obj!=None:
163                    if obj.isImage():
164                        url='/'.join((obj.absolute_url(),obj.getJpegVarName()))
165                    else:
166                        msg=msg+'Background image %s is missing, using blank instead.' % str((f/3)+1)
167                        failure='soft'
168                else:
169                    msg=msg+'Background image %s is missing, using blank instead.' % str((f/3)+1)                   
170                    failure='soft'
171                bg_url.append(url)
172
173            elif f % 3 == 1:
174                # voiceovers
175                uid=bodytext[f]
176                obj=bodyfield.getObjectByUID(self, uid)
177                url='missing'
178                length=30
179                if obj!=None:
180                    if obj.isAudio():
181                        url=obj.absolute_url()+'/file'
182                        length=obj.getLength()
183                    else:
184                        msg=msg+'Voiceover for scene %s is missing, using 15 seconds of ambient noise instead.' % str((f/3)+1)
185                        failure='soft'
186                else:
187                    msg=msg+'Voiceover for scene %s is missing, using 15 seconds of ambient noise instead.' % str((f/3)+1)                   
188                    failure='soft'
189                vc_url.append((url,length))
190           
191            elif f % 3 == 2:
192                # keywords
193                tkw=[to_unicode(x) for x in bodytext[f] if x!='']
194                if len(tkw)>3 and f<len(bodytext)-2:
195                    tkw=tkw[:3] # three keywords max unless final scene
196                if tkw==[]:
197                    tkw=['']
198                    msg=msg+'Keywords for scene %s are missing' % str((f/3)+1)
199                    failure='soft'
200                mplength=vc_url[-1][1] # length of latest voiceover
201                if f==2:
202                    has_title=1
203                cliplen = mplength/(len(tkw)+has_title)  # time reserved for each keyword
204                i=0
205                newlist=[]
206                if has_title==1:
207                    i=1
208                    title_begin='1'
209                    title_end=str(cliplen-2)
210                    has_title=0                   
211                for x in tkw:
212                    if len(x)>maxlength:
213                        x=kw_cutter(x,maxlength)
214                    newlist.append((x, i*cliplen+1, (i+1)*cliplen-2))
215                    i=i+1
216                kw.append(newlist)
217                # cliplen = time allocated for each keyword
218                # kw[n]=(keyword, startpoint, endpoint)
219
220        if len(vc_url)!=len(bg_url) or len(bg_url)!=len(kw):
221            failure='fatal'
222        if title_begin=='':
223            msg=msg+"Scene doesn't have enough components, keywords are missing."
224            failure='fatal'
225           
226        if only_validate==True:
227            if failure=='fatal' or failure=='soft':
228                valid=False
229            else:
230                valid=True
231           
232            return (valid,
233                bg_url,
234                [x[0] for x in vc_url],
235                [x[0][0] for x in kw])
236
237        if failure=='fatal':
238            print 'fatal failure'
239            print msg
240            plone_utils.addPortalMessage(PMF(u'Building flash failed. PILOT'))
241            plone_utils.addPortalMessage(PMF(msg))
242            return ''
243
244        ### Build xml ###
245
246        scene_type=' type="title"'
247        xml=u'<?xml version="1.0" encoding="utf-8"?>\n<pilot>\n'
248        xml=xml+u'<title begin="'+title_begin+u'" end="'+title_end+u'">'+title+u'</title>\n'
249        for i in range(len(bg_url)):
250            xml=xml+u'<scene'+scene_type+u'>\n'
251            xml=xml+u'   <voiceover src="'+vc_url[i][0]+u'" len="'+str(vc_url[i][1])+u'"/>\n'
252            xml=xml+u'   <backgroundimage src="'+bg_url[i]+'" />\n'
253            for k in range(len(kw[i])):           
254                xml=xml+u'   <keyword begin="'+str(kw[i][k][1])+u'" end="'+str(kw[i][k][2])+u'">'+kw[i][k][0]+u'</keyword>\n'
255            xml=xml+u'</scene> \n'
256            if i < len(bg_url)-2:
257                scene_type=''
258            else:
259                scene_type=u' type="questions"'
260        xml=xml+u'</pilot>'
261        # We use UTF-16 because that way we get the BOM, which Flash XML parser requires.
262        return xml.encode('utf-16')
263
264
265registerType(PILOTMaterial, PROJECTNAME)
Note: See TracBrowser for help on using the repository browser.