source: trunk/FieldsWidgets.py @ 1902

Revision 1902, 33.3 KB checked in by jukka, 13 years ago (diff)

Deleting unused references didn't work. Refs #1468.

  • Property svn:eol-style set to native
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-1301  USA
18
19from AccessControl import ClassSecurityInfo
20from Products.Archetypes.config import REFERENCE_CATALOG
21from Products.Archetypes.Registry import registerField, registerWidget
22from Products.Archetypes.Field import StringField, LinesField, ReferenceField, ObjectField, FileField
23from Products.Archetypes.Widget import TextAreaWidget, StringWidget, SelectionWidget, TypesWidget, MultiSelectionWidget, VisualWidget, FileWidget
24from Products.Archetypes.ReferenceEngine import Reference
25from config import to_unicode, MIMETYPE_WHITELIST
26from Products.Archetypes import config
27from string import letters, punctuation
28from Products.CMFCore.utils import getToolByName
29from ZODB.PersistentMapping import PersistentMapping
30from Products.Archetypes.utils import shasattr
31from Acquisition import aq_base
32from mp3tool import get_length
33from types import ListType, TupleType, StringType, UnicodeType, InstanceType
34from Products.LeMill.Validators import remove_invalid_html_tags
35from Products.LeMill import LeMillMessageFactory as _
36
37import re
38
39STRING_TYPES = [StringType, UnicodeType]
40
41
42#StringWidget and TextAreaWidget need to update their macro, otherwise they try to use archetypes/skins/widgets -path only
43#Unfortunately this can't be done but by making new Widgets: LeStringWidget and LeTextAreaWidget
44
45class LeVisualWidget(VisualWidget):
46    _properties = VisualWidget._properties.copy()
47    _properties.update({
48        'macro' : 'widget_visual',
49        'rows'  : 18,      #rows of TextArea if VE is not available
50        'cols'  : 80,      #same for cols
51        'width' : '507px', #width of VE frame (if VE is avalilable)
52        'height': '260px', #same for height
53    })
54    # material types use versions of chapter_widgets and are not affected by this
55
56registerWidget(LeVisualWidget,
57    title='Visual Widget',
58    description='Visual Widget'
59)   
60
61class LeStringWidget(StringWidget):
62    _properties = StringWidget._properties.copy()
63    _properties.update({
64        'macro' : 'widget_string'
65    })
66
67registerWidget(LeStringWidget,
68    title='String Widget',
69    description='String Widget'
70)
71
72
73class LeTextAreaWidget(TextAreaWidget):
74    _properties = TextAreaWidget._properties.copy()
75    _properties.update({
76        'macro' : 'widget_textarea'
77    })
78
79registerWidget(LeTextAreaWidget,
80    title='Textarea Widget',
81    description='Textarea Widget'
82)
83
84
85
86class TagsWidget(StringWidget):
87    _properties = StringWidget._properties.copy()
88    _properties.update({
89        'macro' : 'widget_tags',
90    })
91   
92registerWidget(TagsWidget,
93    title='Tags Widget',
94    description='Tags Widget',
95    used_for=('Products.LeMill.TagsField.TagsField',)
96)
97
98class HTMLLinkWidget(StringWidget):
99    _properties = StringWidget._properties.copy()
100    _properties.update({
101        'macro' : 'widget_htmllink',
102    })
103
104    def getShortLinkName(self, link):
105        """Returns the shortened version of the link pointing to the reference's location. This shortened version goes into the content of the <a> tag."""     
106        lt = getToolByName(self, 'lemill_tool')
107        return lt.shorten_link_names(lt.htmlify(link))
108   
109registerWidget(HTMLLinkWidget,
110    title='HTML Link Widget',
111    description='Generated <a> tag Widget',
112    used_for=('Products.LeMill.FieldsWidgets.HTMLLinkWidget',)
113)
114
115class MessengerWidget(TypesWidget):
116    _properties = TypesWidget._properties.copy()
117    _properties.update({
118        'macro' : 'widget_messenger',
119    },)
120
121    security = ClassSecurityInfo()
122
123    security.declarePublic('process_form')
124    def process_form(self, instance, field, form, empty_marker=None,
125                     emptyReturnsMarker=False):
126        """Concatenates address + messenger type, but if address already contains something like prefix (word:) then removes it.
127        """
128        name = field.getName()
129        otherName = "%s_other" % name
130        value = form.get(name, empty_marker)
131        othervalue = form.get(otherName, empty_marker)
132        if not value:
133            return '', {}
134        if not othervalue == empty_marker:
135            value = "%s:%s" % (othervalue,value)
136        return value, {}
137
138
139registerWidget(MessengerWidget,
140    title='Messenger Widget',
141    description='Messenger Widget',
142    used_for=('Products.Archetypes.Field.StringField',)
143)
144
145
146class MobileWidget(StringWidget):
147    _properties = StringWidget._properties.copy()
148    _properties.update({
149        'macro' : 'widget_mobile',
150    })
151
152    security = ClassSecurityInfo()
153
154    security.declarePublic('process_form')
155    def process_form(self, instance, field, form, empty_marker=None,
156                     emptyReturnsMarker=False):
157        name = field.getName()
158        otherName = "%s_checkbox" % name
159        value = form.get(name, empty_marker)
160        othervalue = form.get(otherName, empty_marker)
161        if value == empty_marker and emptyReturnsMarker:
162            return empty_marker
163        if othervalue=="1":
164            value = "*SMS*%s" % value
165        return value, {}
166
167   
168registerWidget(MobileWidget,
169    title='Mobile Widget',
170    description='Mobile Widget',
171    used_for=('Products.Archetypes.Field.StringField',)
172)
173
174
175class CopyrightWidget(SelectionWidget):
176    _properties = SelectionWidget._properties.copy()
177    _properties.update({
178        'macro' : 'widget_copyright',
179    })
180   
181registerWidget(CopyrightWidget,
182    title='Copyright Widget',
183    description='Copyright selection Widget',
184    used_for=('Products.LeMill.StringField.StringField',)
185)
186
187class TwoColumnMultiSelectionWidget(MultiSelectionWidget):
188    _properties = MultiSelectionWidget._properties.copy()
189    _properties.update({
190        'macro' : 'widget_twocolumn',
191    })
192   
193registerWidget(TwoColumnMultiSelectionWidget,
194    title='Two column widget',
195    description='Two column multiselection widget',
196    used_for=('Products.Archetypes.Field.MultiSelectionField',)
197)
198
199
200class GroupWidget(SelectionWidget):
201    _properties = SelectionWidget._properties.copy()
202    _properties.update({
203        'macro' : 'widget_group',
204        'format' : 'radio',
205    })
206
207
208class refImagesWidget(SelectionWidget):
209    _properties = SelectionWidget._properties.copy()
210    _properties.update({
211        'macro' : 'widget_imageselection',
212        'helper_js' : ('js_helpers.js',),
213    })     
214
215class ImageSelectorWidget(SelectionWidget):
216    _properties = SelectionWidget._properties.copy()
217    _properties.update({
218        'macro' : 'widget_imageselector',
219        'helper_js' : ('js_helpers.js',),
220    })
221
222class ChapterWidget(SelectionWidget):
223    _properties = SelectionWidget._properties.copy()
224    _properties.update({
225        'macro' : 'widget_chapter',
226        'collections_only' : False,
227        'helper_js' : ('js_helpers.js','AC_RunActiveContent.js'),
228        'show_added' : True,
229        'chapter_count' : 1,
230    })
231 
232    security = ClassSecurityInfo()
233
234    security.declarePublic('process_form')
235    def process_form(self, instance, field, form, empty_marker=None,
236            emptyReturnsMarker=False):
237        """ goes through the form and tries to find all texts and references to pieces. """
238        value = []
239        fieldname=field.getName()
240        file=form.get('%s_file' % fieldname)       
241        upload_pos=int(form.get('%s_uploaded' % fieldname))
242        for i in range(0,int(form.get('%s_count' % fieldname, 0))):
243            text= form.get('%s_%s' % (fieldname, i))
244            text = remove_invalid_html_tags(text)
245            value.append(text)
246
247        if file and hasattr(file, 'filename') and upload_pos>-1:
248            value[upload_pos]=file
249        if value == []:
250            return empty_marker
251        return value, {}
252
253registerWidget(ChapterWidget,
254    title='Chapter Widget',
255    description='Chapter editor Widget',
256    used_for=('Products.LeMill.ChapterField',)
257)
258
259class SlideWidget(ChapterWidget):
260    _properties = ChapterWidget._properties.copy()
261    _properties.update({
262        'macro' : 'widget_slides',
263        'collections_only' : False,
264        'helper_js' : ('js_helpers.js',),
265        'show_added' : True,
266        'chapter_count' : 5,
267    })
268
269
270    security = ClassSecurityInfo()
271
272    security.declarePublic('process_form')
273    def process_form(self, instance, field, form, empty_marker=None,
274            emptyReturnsMarker=False):
275        """ goes through the form and tries to find all texts and references to pieces. """
276        fieldname=field.getName()
277        value = form.get(fieldname, empty_marker) # allow tests to create presentations from strings
278        if type(value)==str:
279            return['thisisamediapiecethisisamediapie', value], {} # simplest possible presentation
280        value = []
281        for i in range(0,int(form.get('%s_count' % fieldname, 1))):
282            text= form.get('%s_%s' % (fieldname, i))
283            text = remove_invalid_html_tags(text)
284            file=form.get('%s_file_%s' % (fieldname, i))
285            piece_uid=form.get('piece_uid_%s' % i, '')
286            if piece_uid=='0':
287                text=''       
288            value.append(text)
289            if file and hasattr(file, 'filename'):
290                value[i]=file
291
292        if value == []:
293            return empty_marker
294        return value, {'allowed_types_sequence':['image','string']}
295
296
297registerWidget(SlideWidget,
298    title='Slide Widget',
299    description='Slide and caption editor Widget',
300    used_for=('Products.LeMill.ChapterField',)
301)
302
303class PilotWidget(ChapterWidget):
304    _properties = ChapterWidget._properties.copy()
305    _properties.update({
306        'macro' : 'widget_pilot',
307        'collections_only' : False,
308        'helper_js' : ('js_helpers.js','AC_RunActiveContent.js'),
309        'show_added' : True,
310        'chapter_count' : 3,
311    })
312
313
314    security = ClassSecurityInfo()
315
316    security.declarePublic('process_form')
317    def process_form(self, instance, field, form, empty_marker=None,
318            emptyReturnsMarker=False):
319        """ goes through the form and tries to merge all text inputs to lists, find references to pieces and if file objects are uploaded, just send them forward to field. """
320        fieldname=field.getName()
321        value = []
322        edited = int(form.get('%s_last_edited' % fieldname, 1))
323        count= int(form.get('%s_count' % fieldname, 1))
324        y=3
325        for i in range(0,count):
326            text= form.get('%s_%s' % (fieldname, i))
327            if text!="" and text!=None:
328                if text.startswith('#keywords#!#'):
329                    text=text.split('#!#')[1:]
330                text = remove_invalid_html_tags(text)
331                value.append(text)
332
333            if i >= edited and i<edited+3: 
334                # files
335                if i%3 != 2:
336                    file=form.get('%s_file_%s' % (fieldname, i))   
337                    if file and hasattr(file, 'filename'):
338                        value[i]=file
339                        continue
340                # keywords and questions
341                if i%3==2:               
342                    kw_counter=0
343                    kw=''
344                    target_len=3
345                    keywordlist=[]
346                    while(kw!=None and kw_counter<8):
347                        kw=form.get('%s_keyword_%s_%s' % (fieldname,i,kw_counter), None)
348                        if kw!=None:                     
349                            keywordlist.append(kw)
350                        kw_counter=kw_counter+1
351                    if i==count-1:
352                        target_len=7
353                    while len(keywordlist)<target_len:
354                        keywordlist.append('')
355                    value[i]=keywordlist
356        if value == []:
357            return empty_marker
358        return value, {'allowed_types_sequence':['image','audio','list']}
359
360    def merge_keywords(self, value):
361        """ allow lists to be stored in forms as hidden fields """
362        if type(value)==list or type(value)==tuple:
363            value='#!#'.join(value)
364            return ''.join(('#keywords#!#',value))
365         
366
367
368registerWidget(PilotWidget,
369    title='Pilot Widget',
370    description='Scene editor Widget',
371    used_for=('Products.LeMill.ChapterField',)
372)
373
374
375class AudioWidget(FileWidget):
376    _properties = FileWidget._properties.copy()
377    _properties.update({
378    'macro' : 'widget_audio',
379    'helper_js' : ('AC_RunActiveContent.js',),
380    })
381
382registerWidget(AudioWidget,
383    title='Audio Widget',
384    description='Widget that uses flashplayer for mp3:s',
385    used_for=('Products.LeMill.ChapterField',)
386)
387
388
389
390
391####                            ####
392####            FIELDS          ####
393####                            ####
394
395
396class TagsField(LinesField):
397    """ A field that stores tags """
398    __implements__ = LinesField.__implements__
399    _properties = LinesField._properties.copy()
400    _properties.update({
401        'widget' : TagsWidget,
402    })
403
404    security = ClassSecurityInfo()
405
406    def set(self, instance, value, **kwargs):
407        tags = []
408        tags_dirty = []
409    if isinstance(value,str):
410            value = value.lower()
411            tags_dirty = value.split(',')
412            value = tags_dirty
413            tags = []
414        if isinstance(value, tuple) or isinstance(value, list):
415            tags_dirty = value
416            [ tags.append(t.strip().lower()) for t in tags_dirty if t.strip().lower() not in tags ]
417            value = ','.join(tags)
418    if isinstance(value,str):
419        value = value.replace(',','\n')
420        LinesField.set(self, instance, value, **kwargs)
421                       
422    def getRaw(self, instance, **kwargs):
423        value = self.get(instance, **kwargs)
424        return ', '.join(value)
425
426    def get(self, instance, **kwargs):
427        return LinesField.get(self, instance, **kwargs)
428
429registerField(TagsField,
430               title='Tags Field',
431               description=('Tags Field'),
432               )
433
434class WYSIWYMField(StringField):
435    """A field that stores WYSIWYM strings"""
436    _properties = StringField._properties.copy()
437    _properties.update({
438        'widget' : LeTextAreaWidget,
439        'edit_accessor' :  "getRaw",
440        'default_output_type' : 'text/x-html-captioned',
441        'default_content_type' : 'text/html',
442    })   
443   
444    security = ClassSecurityInfo()
445   
446   
447    def getRaw(self, instance, **kwargs):
448        value = self.get_historical(instance,**kwargs)
449        return value
450   
451    def get_historical(self, instance, **kwargs):
452        """Special get method to handle history views as well."""
453        version = instance.REQUEST.get('version',None)
454        if not version:
455            return StringField.get(self,instance,**kwargs)
456        # Get old data from history
457        #fields = instance.getHistoricalFields(version)
458        value = instance.getFieldHistory(self.getName(), version)
459        #try:
460        #    value = fields[self.getName()]
461        #except KeyError:
462        #    value = ''
463        return value
464
465    def get(self, instance, **kwargs):
466        ltool = getToolByName(instance, 'lemill_tool')
467        value = self.get_historical(instance,**kwargs)
468        #return ltool.render(value)
469        return value
470       
471
472    # render -method has moved to LeMillTools, because it is needed also outside the wysiwym field.
473
474registerField(WYSIWYMField,
475               title='WYSIWYM Field',
476               description=('WYSIWYM Field'),
477               )
478
479
480class ChapterField(ObjectField):
481    """ chapters are stored as lists, where chapter can either be a string or UID. If UID, view widget should fetch the object. """
482    _properties = ObjectField._properties.copy()
483    _properties.update({
484        'widget' : ChapterWidget,
485        'relationship' : 'uses', # required
486        'referenceClass' : Reference,
487        'referenceReferences' : False,
488        'deleteEmptyChapters' : True
489    })
490   
491    security = ClassSecurityInfo()
492
493    def get(self, instance, **kwargs):
494        """Special get method to handle history views as well."""
495        version = instance.REQUEST.get('version',None)
496        if not version:
497            return ObjectField.get(self,instance,**kwargs)
498        # Get old data from history
499        #fields = instance.getHistoricalFields(version)
500        value = instance.getFieldHistory(self.getName(), version)
501        #value = fields[self.getName()]
502        if type(value) != type([]):
503            return [value,]
504        else:
505            return value
506
507    def getCooked(self, instance, **kwargs):
508        """Get method that parses html as well."""
509        version = instance.REQUEST.get('version',None)
510        lt=getToolByName(self,'lemill_tool')
511        if not version:
512            raw=ObjectField.get(self,instance,**kwargs)
513        else:
514            # Get old data from history
515            #fields = instance.getHistoricalFields(version)
516            raw = instance.getFieldHistory(self.getName(), version)
517            #value = fields[self.getName()]
518            if type(raw) != type([]):
519                raw=[raw,]
520        return [lt.shorten_link_names(lt.htmlify(s)) for s in raw]
521
522
523    def set(self, instance, value, **kwargs):
524        tool = getToolByName(instance, REFERENCE_CATALOG)
525        portal_url = getToolByName(instance, 'portal_url')
526        plone_utils = getToolByName(instance, 'plone_utils')
527        lt = getToolByName(instance, 'lemill_tool')
528        targetUIDs = [x.targetUID for x in tool.getReferences(instance, self.relationship)]
529        finalvalues=[]
530        allowed_types_sequence=['']
531        sequence_index=0
532        # widget cannot test file types with ease,
533        # so it sends requirement sequence as list f.ex ['image','string'] for Presentation 
534        if kwargs.has_key('allowed_types_sequence'):
535            allowed_types_sequence=kwargs['allowed_types_sequence']           
536        sequence_length=len(allowed_types_sequence)
537        ignore_type= allowed_types_sequence==['']
538        uids=[]
539        if value==None: value=['']
540        if type(value)==str: value=[value]       
541       
542        # tweak keyword arguments for addReference
543        addRef_kw = kwargs.copy()
544        addRef_kw.setdefault('referenceClass', self.referenceClass)
545        if addRef_kw.has_key('schema'): del addRef_kw['schema']
546
547        #assume that values are given in list   
548        for chapter in value:
549            if chapter and hasattr(chapter, 'filename'):
550                # This is a file, so create a piece from it, get its uid and give that to be the content of this chapter
551                if chapter.headers['Content-Type'] not in MIMETYPE_WHITELIST:
552                    fine_piece=False
553                    if allowed_types_sequence[sequence_index]=='image' or ignore_type:
554                        chapter = 'thisisamediapiecethisisamediapie'
555                    elif allowed_types_sequence[sequence_index]=='audio':
556                        chapter = 'thisisaudiopiecethisisaudiopiece'
557                    else:
558                        chapter = None
559
560                else:               
561                    id = instance.generateUniqueId('Piece')
562                    filename=chapter.filename.split('/')[-1] # Windows brings in the whole path as filename, take only last part
563                    filename=filename.split('\\')[-1] # stupid windows                   
564                    if not lt.checkTitle(title=filename): # try with filename
565                        filename='-'.join((instance.Title(),filename)) # else use longer version
566                    new_id = portal_url.getPortalObject().content.invokeFactory('Piece', id, title=filename)
567                    new_piece = getattr(instance.content, new_id)
568                    new_piece.edit(file=chapter)                       
569                   
570                    # file is uploaded and piece is made, but is it a piece of correct type?               
571                    if new_piece.isImage() and (allowed_types_sequence[sequence_index]=='image' or ignore_type):
572                        new_piece.edit(image=chapter)
573                        chapter = new_piece.UID()
574                        fine_piece = True
575                        plone_utils.addPortalMessage(_(u'Image uploaded'))             
576                    elif new_piece.isAudio() and (allowed_types_sequence[sequence_index]=='audio' or ignore_type):
577                        chapter = new_piece.UID()
578                        fine_piece = True
579                        plone_utils.addPortalMessage(_(u'Audio clip uploaded'))             
580                    else:
581                        fine_piece = False               
582
583            #try to set references
584            if type(chapter)==str:
585                if chapter.isalnum() and len(chapter)==32 and len(chapter)==len(chapter.strip()): # ok, it's a UID!
586                    uids.append(chapter) # collect list of good uids that should be there                 
587                    if chapter not in targetUIDs and chapter not in ['thisisamediapiecethisisamediapie', 'thisisaudiopiecethisisaudiopiece']: # if not there, add it
588                        __traceback_info__ = (instance, chapter, targetUIDs)
589                        tool.addReference(instance, chapter, self.relationship, **addRef_kw)
590
591            if chapter!=None or self.deleteEmptyChapters==False:
592                finalvalues.append(chapter)
593            sequence_index=sequence_index+1
594            if sequence_index==sequence_length:
595                sequence_index=0
596
597
598        for uid in targetUIDs: # delete bad references       
599            if uid not in uids:
600                tool.deleteReference(instance, uid, self.relationship)           
601        # make sure there is item 0 in list
602        if finalvalues==[]:
603            if allowed_types_sequence[0]=='image':
604                finalvalues=['thisisamediapiecethisisamediapie']
605            elif allowed_types_sequence[0]=='audio':
606                finalvalues=['thisisaudiopiecethisisaudiopiece']
607            else:
608                finalvalues=['']               
609        # finally get it done
610        ObjectField.set(self, instance, finalvalues, **kwargs)
611
612
613    def add_new_chapter(self,instance, insert_point=-1):
614        """ adds new field/chapter """
615        value=ChapterField.get(self,instance)
616        value_end=[]
617        if insert_point!=-1:
618            value_end=value[insert_point:]
619            value=value[:insert_point]       
620        value.append((''))
621        value=value+value_end
622        ObjectField.set(self, instance, value)
623        if insert_point==-1:       
624            return len(value)-1
625        else:
626            return insert_point
627
628    def add_new_mediapiece(self,instance, insert_point=-1):
629        """ adds new field/mediapiece """
630        value=ChapterField.get(self,instance)
631        value_end=[]
632        if insert_point!=-1:
633            value_end=value[insert_point:]
634            value=value[:insert_point]           
635        value.append(('thisisamediapiecethisisamediapie')) # :) this looks like an UID
636        value=value+value_end
637        ObjectField.set(self, instance, value)
638        if insert_point==-1:       
639            return len(value)-1
640        else:
641            return insert_point
642
643    def add_new_slide(self, instance, insert_point=-1):
644        """ adds slide and caption (2 objects) to list """
645        value=ChapterField.get(self,instance)
646        value_end=[]
647        if insert_point!=-1:
648            value_end=value[insert_point:]
649            value=value[:insert_point]           
650        value.append(('thisisamediapiecethisisamediapie')) # :) this looks like an UID
651        value.append((''))
652        value=value+value_end
653        ObjectField.set(self, instance, value)
654        if insert_point==-1:       
655            return len(value)-2
656        else:
657            return insert_point
658
659    def add_new_scene(self, instance, insert_point=-1):
660        """ adds slide, voiceover and keywords (PILOT)"""
661        value=ChapterField.get(self,instance)
662        if insert_point==-1:
663            insert_point=len(value)-3
664        value_end=[]       
665        value_end=value[insert_point:]
666        value=value[:insert_point]           
667        value.append(('thisisamediapiecethisisamediapie')) # :) this looks like an UID
668        value.append(('thisisaudiopiecethisisaudiopiece'))
669        value.append(['','',''])
670        value=value+value_end
671        ObjectField.set(self, instance, value)
672        return insert_point
673       
674    def isUid(self, chapter):
675        """ Checks if chapter seems, smells and feels like UID """
676        if type(chapter) in STRING_TYPES:
677            if chapter.isalnum() and len(chapter)==32 and len(chapter)==len(chapter.strip()): # ok, it's an UID!
678                return chapter
679        elif type(chapter) in (list, tuple, int) or hasattr(chapter, 'filename'):
680            return False
681        else:
682#            try:
683                chapter=chapter.UID()
684                return chapter
685#            except:
686                return False
687               
688    def isAudioUID(self, chapter):
689        """ True if UID is audio placeholder """
690        if chapter=='thisisaudiopiecethisisaudiopiece':
691            return True
692
693    def isImageUID(self, chapter):
694        """ True if UID is audio placeholder """
695        if chapter=='thisisamediapiecethisisamediapie':
696            return True
697
698    def isKeywords(self, chapter):
699        """Keywords are lists of three strings, used in PILOT """
700        if type(chapter)==list and len(chapter)==3:
701            return True
702
703    def isQuestions(self, chapter):
704        """Questions are lists of seven strings, used in PILOT """
705        if type(chapter)==list and len(chapter)==7:
706            return True           
707               
708    def getObjectByUID(self, instance, uid):
709        """ Helper method for fetching mediapieces from references """
710        uid_catalog = getToolByName(instance, 'uid_catalog')
711        if uid=='thisisamediapiecethisisamediapie' or uid=='thisisaudiopiecethisisaudiopiece': return None # this is just a newly created placeholder
712        results=uid_catalog(UID=uid)
713        if results:
714            return results[0].getObject()
715        else:
716            return None
717
718    def getChapters(self, instance):
719        """ get a list of chapters with text. returning id's of chapters... eg. [1001, 1101, 1201] """
720        value=ChapterField.get(self,instance)
721        result=[]
722        for n in range(len(value)):
723            chapter=value[n]
724            if chapter.isalnum() and len(chapter)==32 and len(chapter)==len(chapter.strip()): # ok, it's an UID!
725                pass
726            else:
727                result.append(n)
728        return result
729
730    def getChapter(self, instance, chap_nr):
731        """ get a content of one chapter """
732        value=ChapterField.get(self, instance)
733        if len(value)<chap_nr:
734            return ''
735        else:
736            return value[chap_nr]
737
738    def getPieces(self, instance, chap_nr, as_objects=False):
739        """ return a list of pieces; uids or object list """
740        value=ChapterField.get(self,instance)
741        result=[]
742        for chapter in value:
743            if chapter.isalnum() and len(chapter)==32 and len(chapter)==len(chapter.strip()): # ok, it's an UID!
744                result.append(chapter)
745        if not as_objects:
746            return result
747        res = []
748        new_value = value
749        removed=[]
750        tool = getToolByName(instance, 'reference_catalog')
751        for uid in result:
752                v = tool.lookupObject(uid)
753                if not v:
754                    removed.append(uid)
755                else:
756                    res.append(v)
757        for chapclip in removed:
758            new_value.remove(chapclip)
759        if new_value!=value:
760            ObjectField.set(self, instance, new_value)
761        return res
762
763    def getFirstChapter(self, instance):
764        """ return first chapter """
765        return 0
766
767    def setChapter(self, instance, value, chap_nr):
768        """ set a chapter """
769        values=ChapterField.get(self,instance)
770        values[chap_nr]=value
771        ObjectField.set(self, instance, values)
772
773    def delChapter(self, instance, chap_nr):
774        """ delete chapter """
775        value=ChapterField.get(self,instance)
776        del value[chap_nr]
777        if value==[]: value=['']
778        ObjectField.set(self, instance, value)       
779
780    def setPieces(self, instance, value, chap_nr):
781        """ set uids """
782        values=ChapterField.get(self,instance)
783        if type(value) not in STRING_TYPES:
784            value=value.UID()                   
785        values[chap_nr]=value
786        ObjectField.set(self, instance, values)
787
788    def delPiece(self, instance, chap_nr):
789        """ delete reference to piece """
790        values=ChapterField.get(self,instance)
791        tool = getToolByName(instance, REFERENCE_CATALOG)
792        tool.deleteReference(instance, values[chap_nr], self.relationship)
793        del values[chap_nr]
794        if values==[]: values=['']
795        ObjectField.set(self, instance, values)       
796       
797    def delSlide(self, instance, chap_nr):
798        """ delete both chapter and caption """
799        values=ChapterField.get(self,instance)
800        tool = getToolByName(instance, REFERENCE_CATALOG)
801        tool.deleteReference(instance, values[chap_nr], self.relationship)
802        del values[chap_nr]
803        if len(values)>chap_nr:
804            del values[chap_nr]
805        if values==[]: values=['thisisamediapiecethisisamediapie', '']
806        ObjectField.set(self, instance, values)       
807
808    def delScene(self, instance, chap_nr):
809        """ delete image, audio and keywords/questions (PILOT)"""
810        values=ChapterField.get(self,instance)
811        tool = getToolByName(instance, REFERENCE_CATALOG)
812        tool.deleteReference(instance, values[chap_nr], self.relationship)
813        tool.deleteReference(instance, values[chap_nr+1], self.relationship)
814        for a in [1,2,3]:
815            if len(values)>chap_nr:
816                del values[chap_nr]
817        if values==[]: values=['']
818        ObjectField.set(self, instance, values)
819       
820    def moveChapterUp(self, instance, chap_nr, granularity):
821        """ Move chapter chap_nr, chunk size is defined by int granularity """
822        values=ChapterField.get(self,instance)
823        if chap_nr-granularity<0:
824            return 0       
825        begin = values[:chap_nr-granularity] # minus the chunk before current chapter
826        moving_part = values[chap_nr-granularity:chap_nr] # the chunk before current chapter
827        end = values[chap_nr+granularity:]
828        chapter = values[chap_nr:chap_nr+granularity]
829        ObjectField.set(self, instance, begin+chapter+moving_part+end)
830       
831    def moveChapterDown(self, instance, chap_nr, granularity):
832        """ Move chapter chap_nr, chunk size is defined by int granularity """
833        values=ChapterField.get(self,instance)
834        if chap_nr+2*granularity>len(values):
835            return 0     
836        begin = values[:chap_nr]
837        chapter = values[chap_nr:chap_nr+granularity]
838        moving_part = values[chap_nr+granularity:chap_nr+granularity*2] # the chunk after current chapter
839        end = values[chap_nr+granularity*2:] # the rest after current chapter and chunk after it
840        ObjectField.set(self, instance, begin+moving_part+chapter+end)
841
842
843    def getLength(self, piece):
844        as_time=piece.getLength()
845        return {'hour':as_time/3600,'minute':(as_time % 3600)/60,'second':as_time % 60}           
846
847    def getSlidesAsTuples(self, instance):
848        """ Helper method for slideshows, returns (slide, caption) -tuples """
849        chaps=ChapterField.get(self,instance)
850        chapters=[]
851        slide='thisisamediapiecethisisamediapie'
852        for c in range(len(chaps)):
853            if c%2==0:
854                # this should be UID
855                if self.isUid(chaps[c]):
856                    slide=chaps[c]       
857            else:
858                # this should be caption
859                caption=chaps[c]
860                chapters.append((slide, caption))
861                # nice side-effect is that if presentation has more captions than working slides,
862                # latest working slide is shown
863        return chapters
864
865
866
867registerField(ChapterField,
868    title='Chapter field',
869    description=('Chapter field'),
870)
871
872
873class AudioField(FileField):
874    """ field for mp3:s """
875    _properties = FileField._properties.copy()
876    _properties.update({
877        'widget' : AudioWidget,
878    })
879
880    def getLength(self, instance):
881        i = aq_base(instance)
882        file = AudioField.get(self,instance)
883        if not shasattr(i, '_mp3length'):
884                instance._mp3length=get_length(str(file))
885        print instance._mp3length
886        if instance._mp3length==0:
887                instance._mp3length=get_length(str(file))
888        return {'hour':instance._mp3length/3600,'minute':(instance._mp3length % 3600)/60,'second':instance._mp3length % 60}
889           
890    def set(self, instance, value, **kwargs):
891        """ allow only audio here """
892        FileField.set(self, instance, value, **kwargs)
893        file=self.get(instance)
894        if self.getContentType(instance).startswith('audio/'):
895            instance._mp3length=get_length(str(file))
896        elif str(file)!='':
897            FileField.set(self, instance, "DELETE_FILE", **kwargs)
898           
899
900registerField(AudioField,
901    title='Audio field',
902    description=('Field that accepts only mp3:s'),
903)
Note: See TracBrowser for help on using the repository browser.