source: trunk/FieldsWidgets.py @ 1161

Revision 1161, 37.3 KB checked in by vahur, 13 years ago (diff)

getting historical value for one field only.
avoids RuntimeError?: maximum recursion depth exceeded in same rare cases

  • 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
23from Products.Archetypes.Widget import TextAreaWidget, StringWidget, SelectionWidget, TypesWidget, MultiSelectionWidget, VisualWidget
24from Products.Archetypes.ReferenceEngine import Reference
25from config import to_unicode
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
32
33from types import ListType, TupleType, StringType, UnicodeType, InstanceType
34
35import re
36
37STRING_TYPES = [StringType, UnicodeType]
38
39
40#StringWidget and TextAreaWidget need to update their macro, otherwise they try to use archetypes/skins/widgets -path only
41#Unfortunately this can't be done but by making new Widgets: LeStringWidget and LeTextAreaWidget
42
43class LeVisualWidget(VisualWidget):
44    _properties = VisualWidget._properties.copy()
45    _properties.update({
46        'macro' : 'widget_visual',
47        'rows'  : 18,      #rows of TextArea if VE is not available
48        'cols'  : 80,      #same for cols
49        'width' : '507px', #width of VE frame (if VE is avalilable)
50        'height': '260px', #same for height
51    })
52    # material types use versions of chapter_widgets and are not affected by this
53
54registerWidget(LeVisualWidget,
55    title='Visual Widget',
56    description='Visual Widget'
57)
58   
59
60class LeStringWidget(StringWidget):
61    _properties = StringWidget._properties.copy()
62    _properties.update({
63        'macro' : 'widget_string'
64    })
65
66registerWidget(LeStringWidget,
67    title='String Widget',
68    description='String Widget'
69)
70
71
72class LeTextAreaWidget(TextAreaWidget):
73    _properties = TextAreaWidget._properties.copy()
74    _properties.update({
75        'macro' : 'widget_textarea'
76    })
77
78#    security = ClassSecurityInfo()
79#
80#    # Copy-pasted from Archetypes/Widget.py/TextAreaWidget
81#    # removed a big chunks for supporting append_only and different text formats. We can take them back from original if needed.
82#    security.declarePublic('process_form')
83#    def process_form(self, instance, field, form, empty_marker=None,
84#                     emptyReturnsMarker=False):
85#        value = None
86#        # text field
87#        value = form.get(field.getName(), empty_marker)
88#
89#        if value is empty_marker:
90#            return empty_marker
91#
92#        if emptyReturnsMarker and value == '':
93#            return empty_marker
94#
95#        kwargs = {} # there be formats
96#
97#        #convert line breaks to <br />:s
98#        value= value.replace('\n','<br />')
99#
100#        return value, kwargs
101
102
103
104registerWidget(LeTextAreaWidget,
105    title='Textarea Widget',
106    description='Textarea Widget'
107)
108
109
110
111class WYSIWYMWidget(TextAreaWidget):
112    _properties = TextAreaWidget._properties.copy()
113    _properties.update({
114        'macro' : 'widget_wysiwym',
115        'helper_js' : ('js_helpers.js',),
116        'helper_css' : (),
117        'cols' : 40,
118        'rows' : 10,
119        'no_label' : True,
120    })
121
122registerWidget(WYSIWYMWidget,
123    title='WYSIWYM Widget',
124    description='WYSIWYM Widget',
125    used_for=('Products.LeMill.FieldsWidgets.WYSIWYMField',)
126)
127
128
129class TagsWidget(StringWidget):
130    _properties = StringWidget._properties.copy()
131    _properties.update({
132        'macro' : 'widget_tags',
133    })
134   
135registerWidget(TagsWidget,
136    title='Tags Widget',
137    description='Tags Widget',
138    used_for=('Products.LeMill.TagsField.TagsField',)
139)
140
141class HTMLLinkWidget(StringWidget):
142    _properties = StringWidget._properties.copy()
143    _properties.update({
144        'macro' : 'widget_htmllink',
145    })
146   
147registerWidget(HTMLLinkWidget,
148    title='HTML Link Widget',
149    description='Generated <a> tag Widget',
150    used_for=('Products.LeMill.FieldsWidgets.HTMLLinkWidget',)
151)
152
153class MessengerWidget(TypesWidget):
154    _properties = TypesWidget._properties.copy()
155    _properties.update({
156        'macro' : 'widget_messenger',
157    },)
158
159    security = ClassSecurityInfo()
160
161    security.declarePublic('process_form')
162    def process_form(self, instance, field, form, empty_marker=None,
163                     emptyReturnsMarker=False):
164        """Concatenates address + messenger type, but if address already contains something like prefix (word:) then removes it.
165        """
166        name = field.getName()
167        otherName = "%s_other" % name
168        value = form.get(name, empty_marker)
169        othervalue = form.get(otherName, empty_marker)
170        if (not value or value == empty_marker):
171            return empty_marker
172        if not othervalue == empty_marker:
173            value = "%s: %s" % (othervalue,value)
174        return value, {}
175
176
177registerWidget(MessengerWidget,
178    title='Messenger Widget',
179    description='Messenger Widget',
180    used_for=('Products.Archetypes.Field.StringField',)
181)
182
183
184class MobileWidget(StringWidget):
185    _properties = StringWidget._properties.copy()
186    _properties.update({
187        'macro' : 'widget_mobile',
188    })
189
190    security = ClassSecurityInfo()
191
192    security.declarePublic('process_form')
193    def process_form(self, instance, field, form, empty_marker=None,
194                     emptyReturnsMarker=False):
195        name = field.getName()
196        otherName = "%s_checkbox" % name
197        value = form.get(name, empty_marker)
198        othervalue = form.get(otherName, empty_marker)
199        if value == empty_marker and emptyReturnsMarker:
200            return empty_marker
201        if othervalue=="1":
202            value = "*SMS*%s" % value
203        return value, {}
204
205   
206registerWidget(MobileWidget,
207    title='Mobile Widget',
208    description='Mobile Widget',
209    used_for=('Products.Archetypes.Field.StringField',)
210)
211
212
213class CopyrightWidget(SelectionWidget):
214    _properties = SelectionWidget._properties.copy()
215    _properties.update({
216        'macro' : 'widget_copyright',
217    })
218   
219registerWidget(CopyrightWidget,
220    title='Copyright Widget',
221    description='Copyright selection Widget',
222    used_for=('Products.LeMill.StringField.StringField',)
223)
224
225class TwoColumnMultiSelectionWidget(MultiSelectionWidget):
226    _properties = MultiSelectionWidget._properties.copy()
227    _properties.update({
228        'macro' : 'widget_twocolumn',
229    })
230   
231registerWidget(TwoColumnMultiSelectionWidget,
232    title='Two column widget',
233    description='Two column multiselection widget',
234    used_for=('Products.Archetypes.Field.MultiSelectionField',)
235)
236
237
238class LinkLinesWidget(StringWidget):
239    _properties = StringWidget._properties.copy()
240    _properties.update({
241        'macro' : 'widget_linklines',
242        'empty_links' : 5
243    })
244   
245    security = ClassSecurityInfo()
246
247    security.declarePublic('process_form')
248    def process_form(self, instance, field, form, empty_marker=None,
249                     emptyReturnsMarker=False):
250        namebase = field.getName()
251        length = form.get("%s_last" % namebase, empty_marker)
252        if length==None or length==[]: length=4
253        result=[]
254        for n in range(0,int(length)):
255            url=form.get("%s%s_url" % (namebase, n))
256            text=form.get("%s%s" % (namebase, n))
257            if (url!='' and url!='http://'):
258                result.append((url,text))
259        return result, {}     
260
261class PieceWidget(SelectionWidget):
262    _properties = SelectionWidget._properties.copy()
263    _properties.update({
264        'macro' : 'widget_pieceselector',
265        'collections_only' : False,
266        'helper_js' : ('js_helpers.js',),
267        'fieldsToQuery' : ['material-piece-', 'material-file-'],
268        'show_added' : True,
269    })
270 
271    security = ClassSecurityInfo()
272
273    security.declarePublic('process_form')
274    def process_form(self, instance, field, form, empty_marker=None,
275            emptyReturnsMarker=False):
276        """ goes through the form and tries to find all references to pieces. """
277        value = []
278        pieces = []
279        for i in range(0,99):
280            tmp = []
281            for f in self._properties['fieldsToQuery']:
282                one = form.get(f+str(i), empty_marker)
283                if one and one is not empty_marker:
284                    if str(one) != '0':
285                        tmp.append(one)
286            if len(tmp)>0:
287                pieces.append(tmp)
288            tmp = []
289        for p in pieces:
290            uid = p[0]
291            if len(p)>1: # we have both uid and FileUpload instance. we're taking FilUpload
292                # upload piece, get uid
293                pass
294            value.append(uid)
295        if value == []:
296            return empty_marker
297        return value, {}
298
299registerWidget(PieceWidget,
300    title='Piece Widget',
301    description='Piece selection Widget',
302    used_for=('Products.LeMill.PieceField',)
303)
304
305class GroupWidget(SelectionWidget):
306    _properties = SelectionWidget._properties.copy()
307    _properties.update({
308        'macro' : 'widget_group',
309        'format' : 'radio',
310    })
311
312
313class refImagesWidget(SelectionWidget):
314    _properties = SelectionWidget._properties.copy()
315    _properties.update({
316        'macro' : 'widget_imageselection',
317        'helper_js' : ('js_helpers.js',),
318    })     
319
320class ImageSelectorWidget(SelectionWidget):
321    _properties = SelectionWidget._properties.copy()
322    _properties.update({
323        'macro' : 'widget_imageselector',
324        'helper_js' : ('js_helpers.js',),
325    })
326
327
328class ChapterWidget(SelectionWidget):
329    _properties = SelectionWidget._properties.copy()
330    _properties.update({
331        'macro' : 'widget_chapter',
332        'collections_only' : False,
333        'helper_js' : ('js_helpers.js',),
334        'show_added' : True,
335        'chapter_count' : 1,
336    })
337 
338    security = ClassSecurityInfo()
339
340    security.declarePublic('process_form')
341    def process_form(self, instance, field, form, empty_marker=None,
342            emptyReturnsMarker=False):
343        """ goes through the form and tries to find all texts and references to pieces. """
344        value = []
345        fieldname=field.getName()
346        file=form.get('%s_file' % fieldname)       
347        upload_pos=int(form.get('%s_uploaded' % fieldname))
348        for i in range(0,int(form.get('%s_count' % fieldname, 0))):
349            text= form.get('%s_%s' % (fieldname, i))
350            value.append(text)
351
352        if file and hasattr(file, 'filename') and upload_pos>-1:
353            value[upload_pos]=file
354        if value == []:
355            return empty_marker
356        return value, {}
357
358registerWidget(ChapterWidget,
359    title='Chapter Widget',
360    description='Chapter editor Widget',
361    used_for=('Products.LeMill.ChapterField',)
362)
363
364class SlideWidget(ChapterWidget):
365    _properties = ChapterWidget._properties.copy()
366    _properties.update({
367        'macro' : 'widget_slides',
368        'collections_only' : False,
369        'helper_js' : ('js_helpers.js',),
370        'show_added' : True,
371        'chapter_count' : 5,
372    })
373
374
375    security = ClassSecurityInfo()
376
377    security.declarePublic('process_form')
378    def process_form(self, instance, field, form, empty_marker=None,
379            emptyReturnsMarker=False):
380        """ goes through the form and tries to find all texts and references to pieces. """
381        fieldname=field.getName()
382        value = form.get(fieldname, empty_marker) # allow tests to create presentations from strings
383        if type(value)==str:
384            return['thisisamediapiecethisisamediapie', value], {} # simplest possible presentation
385        value = []
386        for i in range(0,int(form.get('%s_count' % fieldname, 1))):
387            text= form.get('%s_%s' % (fieldname, i))
388            file=form.get('%s_file_%s' % (fieldname, i))       
389            value.append(text)
390            if file and hasattr(file, 'filename'):
391                value[i]=file
392
393        if value == []:
394            return empty_marker
395        return value, {'allowed_types_sequence':['image','string']}
396
397
398registerWidget(SlideWidget,
399    title='Slide Widget',
400    description='Slide and caption editor Widget',
401    used_for=('Products.LeMill.ChapterField',)
402)
403
404class PilotWidget(ChapterWidget):
405    _properties = ChapterWidget._properties.copy()
406    _properties.update({
407        'macro' : 'widget_pilot',
408        'collections_only' : False,
409        'helper_js' : ('js_helpers.js',),
410        'show_added' : True,
411        'chapter_count' : 3,
412    })
413
414
415    security = ClassSecurityInfo()
416
417    security.declarePublic('process_form')
418    def process_form(self, instance, field, form, empty_marker=None,
419            emptyReturnsMarker=False):
420        """ 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. """
421        fieldname=field.getName()
422        value = []
423        edited = int(form.get('%s_last_edited' % fieldname, 1))
424        count= int(form.get('%s_count' % fieldname, 1))
425        y=3
426        for i in range(0,count):
427            text= form.get('%s_%s' % (fieldname, i))
428            if text!="" and text!=None:
429                if text.startswith('#keywords#!#'):
430                    text=text.split('#!#')[1:]
431                value.append(text)
432
433            if i >= edited and i<edited+3: 
434                # files
435                if i%3 != 2:
436                    file=form.get('%s_file_%s' % (fieldname, i))   
437                    if file and hasattr(file, 'filename'):
438                        value[i]=file
439                        continue
440                # keywords and questions
441                if i%3==2:               
442                    kw_counter=0
443                    kw=''
444                    target_len=3
445                    keywordlist=[]
446                    while(kw!=None and kw_counter<8):
447                        kw=form.get('%s_keyword_%s_%s' % (fieldname,i,kw_counter), None)
448                        if kw!=None:                     
449                            keywordlist.append(kw)
450                        kw_counter=kw_counter+1
451                    if i==count-1:
452                        target_len=7
453                    while len(keywordlist)<target_len:
454                        keywordlist.append('')
455                    value[i]=keywordlist
456        if value == []:
457            return empty_marker
458        return value, {'allowed_types_sequence':['image','audio','list']}
459
460    def merge_keywords(self, value):
461        """ allow lists to be stored in forms as hidden fields """
462        if type(value)==list or type(value)==tuple:
463            value='#!#'.join(value)
464            return ''.join(('#keywords#!#',value))
465         
466
467
468registerWidget(PilotWidget,
469    title='Pilot Widget',
470    description='Scene editor Widget',
471    used_for=('Products.LeMill.ChapterField',)
472)
473
474
475####                            ####
476####            FIELDS          ####
477####                            ####
478
479
480class PieceField(ReferenceField):
481    """ A field that stores references to pieces. Can be limited to images only etc. """
482    __implements__ = ReferenceField.__implements__
483    _properties = ReferenceField._properties.copy()
484    _properties.update({
485        'widget' : PieceWidget,
486        'multiValued' : True,
487        'piece_types' : 'all',
488        'allowed_types':('Piece',),
489       
490    })
491
492    security = ClassSecurityInfo()
493
494    security.declarePrivate('set')
495    def set(self, instance, value, **kwargs):
496        allowed = None
497        try:
498            allowed=kwargs[piece_types]
499        except NameError:
500            allowed = self._properties['piece_types']
501        # this is mostly copied from Archetypes.Field.ReferenceField.set with some additional checks and some shortcuts
502
503        # locating instances and creating pieces
504        new_values = []
505        for v in value:
506            if type(v) != InstanceType:
507                new_values.append(v)
508                continue
509            if v and v.filename:
510                id = instance.generateUniqueId('Piece')
511                portal_url = getToolByName(instance, 'portal_url')
512                new_id = portal_url.getPortalObject().content.invokeFactory('Piece', id, title=instance.Title()+'-image')
513                new_piece = getattr(instance.content, new_id)
514                uid = new_piece.UID()
515                new_piece.edit(image=v, file=v, language='')
516                new_values.append(uid)
517               
518                req = instance.REQUEST
519                ff = instance.getField('bodyText')
520                edit_chapter = req.get('edit_chapter', 1001)
521                ff.setPieces(instance, uid, int(edit_chapter))
522        old_values = value
523        value = new_values
524
525        tool = getToolByName(instance, 'reference_catalog')
526        targetUIDs = [ref.targetUID for ref in
527                      tool.getReferences(instance, self.relationship)]
528
529        if value is None:
530            value = ()
531
532        if not isinstance(value, (ListType, TupleType)):
533            value = value,
534        elif not self.multiValued and len(value) > 1:
535            value = value[0],
536
537        #convert objects to uids if necessary and check if they are correct subtype
538        uids = []
539        for v in value:
540            if type(v) in [StringType, UnicodeType]:
541                vobj=tool(UID=v)
542                # AttributeError: LazyCat instance has no attribute 'getObject'
543                #vobj=vobj.getObject()
544                if allowed=='all' or (allowed=='images' and vobj.isImage()):                 
545                    uids.append(v)
546            else:
547                if allowed=='all' or (allowed=='images' and v.isImage()): 
548                    uids.append(v.UID())
549
550        add = [v for v in uids if v and v not in targetUIDs]
551        sub = [t for t in targetUIDs if t not in uids]
552
553        # tweak keyword arguments for addReference
554        addRef_kw = kwargs.copy()
555        addRef_kw.setdefault('referenceClass', self.referenceClass)
556        if addRef_kw.has_key('schema'): del addRef_kw['schema']
557
558        for uid in add:
559            __traceback_info__ = (instance, uid, value, targetUIDs)
560            # throws IndexError if uid is invalid
561            tool.addReference(instance, uid, self.relationship, **addRef_kw)
562
563        for uid in sub:
564            tool.deleteReference(instance, uid, self.relationship)
565
566        if self.callStorageOnSet:
567            #if this option is set the reference fields's values get written
568            #to the storage even if the reference field never use the storage
569            #e.g. if i want to store the reference UIDs into an SQL field
570            ObjectField.set(self, instance, self.getRaw(instance), **kwargs)
571
572registerField(PieceField,
573               title='Piece Field',
574               description=('References to Pieces'),
575               )
576
577
578
579class TagsField(LinesField):
580    """ A field that stores tags """
581    __implements__ = LinesField.__implements__
582    _properties = LinesField._properties.copy()
583    _properties.update({
584        'widget' : TagsWidget,
585    })
586
587    security = ClassSecurityInfo()
588
589    def set(self, instance, value, **kwargs):
590        tags = []
591        tags_dirty = []
592    if isinstance(value,str):
593            value = value.lower()
594            tags_dirty = value.split(',')
595            value = tags_dirty
596            tags = []
597        if isinstance(value, tuple) or isinstance(value, list):
598            tags_dirty = value
599            [ tags.append(t.strip().lower()) for t in tags_dirty if t.strip().lower() not in tags ]
600            value = ','.join(tags)
601    if isinstance(value,str):
602        value = value.replace(',','\n')
603        LinesField.set(self, instance, value, **kwargs)
604                       
605    def getRaw(self, instance, **kwargs):
606        value = self.get(instance, **kwargs)
607        return ', '.join(value)
608
609    def get(self, instance, **kwargs):
610        return LinesField.get(self, instance, **kwargs)
611
612registerField(TagsField,
613               title='Tags Field',
614               description=('Tags Field'),
615               )
616
617class WYSIWYMField(StringField):
618    """A field that stores WYSIWYM strings"""
619    _properties = StringField._properties.copy()
620    _properties.update({
621        'widget' : WYSIWYMWidget,
622        'edit_accessor' :  "getRaw",
623        'default_output_type' : 'text/x-html-captioned',
624        'default_content_type' : 'text/html',
625    })   
626   
627    security = ClassSecurityInfo()
628   
629   
630    def getRaw(self, instance, **kwargs):
631        value = self.get_historical(instance,**kwargs)
632        return value
633   
634    def get_historical(self, instance, **kwargs):
635        """Special get method to handle history views as well."""
636        version = instance.REQUEST.get('version',None)
637        if not version:
638            return StringField.get(self,instance,**kwargs)
639        # Get old data from history
640        fields = instance.getHistoricalFields(version)
641        try:
642            value = fields[self.getName()]
643        except KeyError:
644            value = ''
645        return value
646
647    def get(self, instance, **kwargs):
648        ltool = getToolByName(instance, 'lemill_tool')
649        value = self.get_historical(instance,**kwargs)
650        return ltool.render(value)
651
652    # render -method has moved to LeMillTools, because it is needed also outside the wysiwym field.
653
654registerField(WYSIWYMField,
655               title='WYSIWYM Field',
656               description=('WYSIWYM Field'),
657               )
658
659class LinkLinesField(LinesField):
660    """ handles lists of links and their texts """
661    _properties = LinesField._properties.copy()
662    _properties.update({
663        'widget' : LinkLinesWidget,
664    })
665
666    security = ClassSecurityInfo()
667   
668    def get(self, instance, **kwargs):
669        """ Get a list of tuples, where [0] is url and [1] text """
670        values = LinesField.get(self, instance, **kwargs)
671        values = [tuple(x.split('###',1)) for x in values]
672        return values
673
674
675    security.declarePrivate('set')
676    def set(self, instance, value, **kwargs):
677        value= ['###'.join(x) for x in value]
678        LinesField.set(self, instance, value, **kwargs)
679
680registerField(LinkLinesField,
681               title='Link Lines Field',
682               description=('List of links'),
683               )
684
685
686
687class ChapterField(ObjectField):
688    """ chapters are stored as lists, where chapter can either be a string or UID. If UID, view widget should fetch the object. """
689    _properties = ObjectField._properties.copy()
690    _properties.update({
691        'widget' : ChapterWidget,
692        'relationship' : 'uses', # required
693        'referenceClass' : Reference,
694        'referenceReferences' : False,
695        'deleteEmptyChapters' : True
696    })
697   
698    security = ClassSecurityInfo()
699
700    def get(self, instance, **kwargs):
701        """Special get method to handle history views as well."""
702        version = instance.REQUEST.get('version',None)
703        if not version:
704            return ObjectField.get(self,instance,**kwargs)
705        # Get old data from history
706        #fields = instance.getHistoricalFields(version)
707        value = instance.getFieldHistory(self.getName(), version)
708        #value = fields[self.getName()]
709        if type(value) != type([]):
710            return [value,]
711        else:
712            return value
713
714    def set(self, instance, value, **kwargs):
715        tool = getToolByName(instance, REFERENCE_CATALOG)
716        targetUIDs = tool.getReferences(instance, self.relationship)
717        finalvalues=[]
718        allowed_types_sequence=['']
719        sequence_index=0
720        # widget cannot test file types with ease,
721        # so it sends requirement sequence as list f.ex ['image','string'] for Presentation 
722        if kwargs.has_key('allowed_types_sequence'):
723            allowed_types_sequence=kwargs['allowed_types_sequence']           
724        sequence_length=len(allowed_types_sequence)
725        ignore_type= allowed_types_sequence==['']
726        uids=[]
727        if value==None: value=['']
728        if type(value)==str: value=[value]       
729       
730        # tweak keyword arguments for addReference
731        addRef_kw = kwargs.copy()
732        addRef_kw.setdefault('referenceClass', self.referenceClass)
733        if addRef_kw.has_key('schema'): del addRef_kw['schema']
734
735        #assume that values are given in list   
736        for chapter in value:
737            if chapter and hasattr(chapter, 'filename'):
738                # This is a file, so create a piece from it, get its uid and give that to be the content of this chapter
739                id = instance.generateUniqueId('Piece')
740                portal_url = getToolByName(instance, 'portal_url')
741                new_id = portal_url.getPortalObject().content.invokeFactory('Piece', id, title='-'.join((instance.Title(),chapter.filename)))
742                new_piece = getattr(instance.content, new_id)
743                new_piece.edit(file=chapter)
744               
745                # file is uploaded and piece is made, but is it a piece of correct type?               
746                if new_piece.isImage() and (allowed_types_sequence[sequence_index]=='image' or ignore_type):
747                    new_piece.edit(image=chapter)
748                    chapter = new_piece.UID()
749                    fine_piece = True             
750                elif new_piece.isAudio() and (allowed_types_sequence[sequence_index]=='audio' or ignore_type):
751                    chapter = new_piece.UID()
752                    fine_piece = True               
753                else:
754                    fine_piece = False
755                    if allowed_types_sequence[sequence_index]=='image':
756                        chapter = 'thisisamediapiecethisisamediapie'
757                    elif allowed_types_sequence[sequence_index]=='audio':
758                        chapter = 'thisisaudiopiecethisisaudiopiece'
759                    else:
760                        chapter = None
761
762                # store UID in session so that we can edit these new pieces
763                if fine_piece:
764                    session=instance.REQUEST.SESSION
765                    if session.has_key('new_pieces'):
766                        session['new_pieces'].append(new_piece.UID())
767                    else:
768                        session['new_pieces']=[new_piece.UID()]
769
770            #try to set references
771            if type(chapter)==str:
772                if chapter.isalnum() and len(chapter)==32 and len(chapter)==len(chapter.strip()): # ok, it's a UID!
773                    uids.append(chapter) # collect list of good uids that should be there                 
774                    if chapter not in targetUIDs and chapter not in ['thisisamediapiecethisisamediapie', 'thisisaudiopiecethisisaudiopiece']: # if not there, add it
775                        __traceback_info__ = (instance, chapter, targetUIDs)
776                        tool.addReference(instance, chapter, self.relationship, **addRef_kw)
777
778            if chapter!=None or self.deleteEmptyChapters==False:
779                finalvalues.append(chapter)
780            sequence_index=sequence_index+1
781            if sequence_index==sequence_length:
782                sequence_index=0
783
784
785        for uid in targetUIDs: # delete bad references
786            if uid not in uids:
787                tool.deleteReference(instance, uid, self.relationship)           
788        # finally get it done
789        ObjectField.set(self, instance, finalvalues, **kwargs)
790
791    def add_new_chapter(self,instance, insert_point=-1):
792        """ adds new field/chapter """
793        value=ChapterField.get(self,instance)
794        value_end=[]
795        if insert_point!=-1:
796            value_end=value[insert_point:]
797            value=value[:insert_point]       
798        value.append((''))
799        value=value+value_end
800        ObjectField.set(self, instance, value)
801        if insert_point==-1:       
802            return len(value)-1
803        else:
804            return insert_point
805
806    def add_new_mediapiece(self,instance, insert_point=-1):
807        """ adds new field/mediapiece """
808        value=ChapterField.get(self,instance)
809        value_end=[]
810        if insert_point!=-1:
811            value_end=value[insert_point:]
812            value=value[:insert_point]           
813        value.append(('thisisamediapiecethisisamediapie')) # :) this looks like an UID
814        value=value+value_end
815        ObjectField.set(self, instance, value)
816        if insert_point==-1:       
817            return len(value)-1
818        else:
819            return insert_point
820
821    def add_new_slide(self, instance, insert_point=-1):
822        """ adds slide and caption (2 objects) to list """
823        value=ChapterField.get(self,instance)
824        value_end=[]
825        if insert_point!=-1:
826            value_end=value[insert_point:]
827            value=value[:insert_point]           
828        value.append(('thisisamediapiecethisisamediapie')) # :) this looks like an UID
829        value.append((''))
830        value=value+value_end
831        ObjectField.set(self, instance, value)
832        if insert_point==-1:       
833            return len(value)-2
834        else:
835            return insert_point
836
837    def add_new_scene(self, instance, insert_point=-1):
838        """ adds slide, voiceover and keywords (PILOT)"""
839        value=ChapterField.get(self,instance)
840        if insert_point==-1:
841            insert_point=len(value)-3
842        value_end=[]       
843        value_end=value[insert_point:]
844        value=value[:insert_point]           
845        value.append(('thisisamediapiecethisisamediapie')) # :) this looks like an UID
846        value.append(('thisisaudiopiecethisisaudiopiece'))
847        value.append(['','',''])
848        value=value+value_end
849        ObjectField.set(self, instance, value)
850        return insert_point
851       
852    def isUid(self, chapter):
853        """ Checks if chapter seems, smells and feels like UID """
854        if type(chapter) in STRING_TYPES:
855            if chapter.isalnum() and len(chapter)==32 and len(chapter)==len(chapter.strip()): # ok, it's an UID!
856                return chapter
857        elif type(chapter) in (list, tuple, int):
858            return False
859        else:
860#            try:
861                chapter=chapter.UID()
862                return chapter
863#            except:
864                return False
865               
866    def isAudioUID(self, chapter):
867        """ True if UID is audio placeholder """
868        if chapter=='thisisaudiopiecethisisaudiopiece':
869            return True
870
871    def isImageUID(self, chapter):
872        """ True if UID is audio placeholder """
873        if chapter=='thisisamediapiecethisisamediapie':
874            return True
875
876    def isKeywords(self, chapter):
877        """Keywords are lists of three strings, used in PILOT """
878        if type(chapter)==list and len(chapter)==3:
879            return True
880
881    def isQuestions(self, chapter):
882        """Questions are lists of seven strings, used in PILOT """
883        if type(chapter)==list and len(chapter)==7:
884            return True           
885               
886    def getObjectByUID(self, instance, uid):
887        """ Helper method for fetching mediapieces from references """
888        uid_catalog = getToolByName(instance, 'uid_catalog')
889        if uid=='thisisamediapiecethisisamediapie' or uid=='thisisaudiopiecethisisaudiopiece': return None # this is just a newly created placeholder
890        results=uid_catalog(UID=uid)
891        return results[0].getObject()
892
893    def getChapters(self, instance):
894        """ get a list of chapters with text. returning id's of chapters... eg. [1001, 1101, 1201] """
895        value=ChapterField.get(self,instance)
896        result=[]
897        for n in range(len(value)):
898            chapter=value[n]
899            if chapter.isalnum() and len(chapter)==32 and len(chapter)==len(chapter.strip()): # ok, it's an UID!
900                pass
901            else:
902                result.append(n)
903        return result
904
905    def getChapter(self, instance, chap_nr):
906        """ get a content of one chapter """
907        value=ChapterField.get(self, instance)
908        if len(value)<chap_nr:
909            return ''
910        else:
911            return value[chap_nr]
912
913    def getPieces(self, instance, chap_nr, as_objects=False):
914        """ return a list of pieces; uids or object list """
915        value=ChapterField.get(self,instance)
916        result=[]
917        for chapter in value:
918            if chapter.isalnum() and len(chapter)==32 and len(chapter)==len(chapter.strip()): # ok, it's an UID!
919                result.append(chapter)
920        if not as_objects:
921            return result
922        res = []
923        new_value = value
924        removed=[]
925        tool = getToolByName(instance, 'reference_catalog')
926        for uid in result:
927                v = tool.lookupObject(uid)
928                if not v:
929                    removed.append(uid)
930                else:
931                    res.append(v)
932        for chapclip in removed:
933            new_value.remove(chapclip)
934        if new_value!=value:
935            ObjectField.set(self, instance, new_value)
936        return res
937
938    def getFirstChapter(self, instance):
939        """ return first chapter """
940        return 0
941
942    def setChapter(self, instance, value, chap_nr):
943        """ set a chapter """
944        values=ChapterField.get(self,instance)
945        values[chap_nr]=value
946        ObjectField.set(self, instance, values)
947
948    def delChapter(self, instance, chap_nr):
949        """ delete chapter """
950        value=ChapterField.get(self,instance)
951        del value[chap_nr]
952        ObjectField.set(self, instance, value)       
953
954    def setPieces(self, instance, value, chap_nr):
955        """ set uids """
956        values=ChapterField.get(self,instance)
957        if type(value) not in STRING_TYPES:
958            value=value.UID()                   
959        values[chap_nr]=value
960        ObjectField.set(self, instance, values)
961
962    def delPiece(self, instance, chap_nr):
963        """ delete reference to piece """
964        values=ChapterField.get(self,instance)
965        tool = getToolByName(instance, REFERENCE_CATALOG)
966        tool.deleteReference(instance, values[chap_nr], self.relationship)
967        del values[chap_nr]
968        ObjectField.set(self, instance, values)       
969       
970    def delSlide(self, instance, chap_nr):
971        """ delete both chapter and caption """
972        values=ChapterField.get(self,instance)
973        tool = getToolByName(instance, REFERENCE_CATALOG)
974        tool.deleteReference(instance, values[chap_nr], self.relationship)
975        del values[chap_nr]
976        if len(values)>chap_nr:
977            del values[chap_nr]
978        ObjectField.set(self, instance, values)       
979
980    def delScene(self, instance, chap_nr):
981        """ delete image, audio and keywords/questions (PILOT)"""
982        values=ChapterField.get(self,instance)
983        tool = getToolByName(instance, REFERENCE_CATALOG)
984        tool.deleteReference(instance, values[chap_nr], self.relationship)
985        tool.deleteReference(instance, values[chap_nr+1], self.relationship)
986        for a in [1,2,3]:
987            if len(values)>chap_nr:
988                del values[chap_nr]
989        ObjectField.set(self, instance, values)
990       
991    def moveChapterUp(self, instance, chap_nr, granularity):
992        """ Move chapter chap_nr, chunk size is defined by int granularity """
993        values=ChapterField.get(self,instance)
994        if chap_nr-granularity<0:
995            return 0       
996        begin = values[:chap_nr-granularity] # minus the chunk before current chapter
997        moving_part = values[chap_nr-granularity:chap_nr] # the chunk before current chapter
998        end = values[chap_nr+granularity:]
999        chapter = values[chap_nr:chap_nr+granularity]
1000        ObjectField.set(self, instance, begin+chapter+moving_part+end)
1001       
1002    def moveChapterDown(self, instance, chap_nr, granularity):
1003        """ Move chapter chap_nr, chunk size is defined by int granularity """
1004        values=ChapterField.get(self,instance)
1005        if chap_nr+2*granularity>len(values):
1006            return 0     
1007        begin = values[:chap_nr]
1008        chapter = values[chap_nr:chap_nr+granularity]
1009        moving_part = values[chap_nr+granularity:chap_nr+granularity*2] # the chunk after current chapter
1010        end = values[chap_nr+granularity*2:] # the rest after current chapter and chunk after it
1011        ObjectField.set(self, instance, begin+moving_part+chapter+end)
1012
1013
1014
1015
1016registerField(ChapterField,
1017    title='Chapter field',
1018    description=('Chapter field'),
1019)
1020
1021
1022class DictField(LinesField):
1023    """ dictionary field """
1024    _properties = LinesField._properties.copy()
1025    _properties.update({
1026        'widget' : StringField,
1027    })
1028
1029    security = ClassSecurityInfo()
1030    def setValue(self, instance, key, value):
1031        i = aq_base(instance)
1032        if not shasattr(i, '_ivalues'):
1033            i._ivalues = PersistentMapping()
1034            i._p_changed = 1
1035        i._ivalues[key] = value
1036        i._ivalues._p_changed = 1
1037        i._p_changed = 1
1038
1039    def getKeys(self, instance):
1040        i = aq_base(instance)
1041        if not shasattr(i, '_ivalues'):
1042            return []
1043        else:
1044            return i._ivalues.keys()
1045
1046    def getValue(self, instance, key):
1047        i = aq_base(instance)
1048        if not shasattr(i, '_ivalues'):
1049            i._ivalues = PersistentMapping()
1050            i._p_changed = 1
1051            return ""
1052        if not i._ivalues.has_key(key):
1053            return ""
1054        return i._ivalues[key]
1055
Note: See TracBrowser for help on using the repository browser.