Back to index

plone3  3.1.7
Widget.py
Go to the documentation of this file.
00001 from copy import deepcopy
00002 from types import DictType, FileType, ListType, StringTypes
00003 from DateTime import DateTime
00004 
00005 from Products.CMFCore.utils import getToolByName
00006 from Products.CMFCore.Expression import Expression
00007 from Products.CMFCore.Expression import createExprContext
00008 
00009 from Products.Archetypes.utils import className
00010 from Products.Archetypes.utils import unique
00011 from Products.Archetypes.utils import capitalize
00012 from Products.Archetypes.generator import macrowidget
00013 from Products.Archetypes.debug import log
00014 from Products.Archetypes.Registry import registerPropertyType
00015 from Products.Archetypes.Registry import registerWidget
00016 
00017 from ExtensionClass import Base
00018 from AccessControl import ClassSecurityInfo
00019 from Globals import InitializeClass
00020 from Acquisition import aq_base
00021 
00022 _marker = []
00023 
00024 class TypesWidget(macrowidget, Base):
00025     _properties = macrowidget._properties.copy()
00026     _properties.update({
00027         'modes' : ('view', 'edit'),
00028         'populate' : True,  # should this field be populated in edit and view?
00029         'postback' : True,  # should this field be repopulated with POSTed
00030                          # value when an error occurs?
00031         'show_content_type' : False,
00032         'helper_js': (),
00033         'helper_css': (),
00034         'blurrable': False,
00035         })
00036 
00037     security = ClassSecurityInfo()
00038 
00039     security.declarePublic('getName')
00040     def getName(self):
00041         return self.__class__.__name__
00042 
00043     security.declarePublic('getType')
00044     def getType(self):
00045         """Return the type of this field as a string"""
00046         return className(self)
00047 
00048     security.declarePublic('bootstrap')
00049     def bootstrap(self, instance):
00050         """Override if your widget needs data from the instance."""
00051         return
00052 
00053     security.declarePublic('populateProps')
00054     def populateProps(self, field):
00055         """This is called when the field is created."""
00056         name = field.getName()
00057         if not self.label:
00058             self.label = capitalize(name)
00059 
00060     security.declarePublic('isVisible')
00061     def isVisible(self, instance, mode='view'):
00062         """decide if a field is visible in a given mode -> 'state'
00063 
00064         Return values are visible, hidden, invisible
00065 
00066         The value for the attribute on the field may either be a dict with a
00067         mapping for edit and view::
00068 
00069             visible = { 'edit' :'hidden', 'view' : 'invisible' }
00070 
00071         Or a single value for all modes::
00072 
00073             True/1:  'visible'
00074             False/0: 'invisible'
00075             -1:      'hidden'
00076             
00077         visible: The field is shown in the view/edit screen
00078         invisible: The field is skipped when rendering the view/edit screen
00079         hidden: The field is added as <input type="hidden" />
00080 
00081         The default state is 'visible'.
00082         """
00083         vis_dic = getattr(aq_base(self), 'visible', _marker)
00084         state = 'visible'
00085         if vis_dic is _marker:
00086             return state
00087         if type(vis_dic) is DictType:
00088             state = vis_dic.get(mode, state)
00089         elif not vis_dic:
00090             state = 'invisible'
00091         elif vis_dic < 0:
00092             state = 'hidden'
00093         return state
00094 
00095     security.declarePublic('setCondition')
00096     def setCondition(self, condition):
00097         """Set the widget expression condition."""
00098         self.condition = condition
00099 
00100     security.declarePublic('getCondition')
00101     def getCondition(self):
00102         """Return the widget text condition."""
00103         return self.condition
00104 
00105     security.declarePublic('testCondition')
00106     def testCondition(self, folder, portal, object):
00107         """Test the widget condition."""
00108         try:
00109             if self.condition:
00110                 __traceback_info__ = (folder, portal, object, self.condition)
00111                 ec = createExprContext(folder, portal, object)
00112                 return Expression(self.condition)(ec)
00113             else:
00114                 return True
00115         except AttributeError:
00116             return True
00117 
00118     security.declarePublic('process_form')
00119     def process_form(self, instance, field, form, empty_marker=None,
00120                      emptyReturnsMarker=False, validating=True):
00121         """Basic impl for form processing in a widget"""
00122         value = form.get(field.getName(), empty_marker)
00123         if value is empty_marker:
00124             return empty_marker
00125         if emptyReturnsMarker and value == '':
00126             return empty_marker
00127         return value, {}
00128 
00129     security.declarePublic('copy')
00130     def copy(self):
00131         """
00132         Return a copy of widget instance, consisting of field name and
00133         properties dictionary.
00134         """
00135         cdict = dict(vars(self))
00136         properties = deepcopy(cdict)
00137         return self.__class__(**properties)
00138 
00139 InitializeClass(TypesWidget)
00140 
00141 class StringWidget(TypesWidget):
00142     _properties = TypesWidget._properties.copy()
00143     _properties.update({
00144         'macro' : "widgets/string",
00145         'size' : '30',
00146         'maxlength' : '255',
00147         'blurrable' : True,
00148         })
00149 
00150     security = ClassSecurityInfo()
00151 
00152 class DecimalWidget(TypesWidget):
00153     _properties = TypesWidget._properties.copy()
00154     _properties.update({
00155         'macro' : "widgets/decimal",
00156         'size' : '5',
00157         'maxlength' : '255',
00158         'dollars_and_cents' : False,
00159         'whole_dollars' : False,
00160         'thousands_commas' : False,
00161         'blurrable' : True,
00162         })
00163 
00164     security = ClassSecurityInfo()
00165 
00166 class IntegerWidget(TypesWidget):
00167     _properties = TypesWidget._properties.copy()
00168     _properties.update({
00169         'macro' : "widgets/integer",
00170         'size' : '5',
00171         'maxlength' : '255',
00172         'blurrable' : True,
00173         })
00174 
00175     security = ClassSecurityInfo()
00176 
00177 class ReferenceWidget(TypesWidget):
00178     _properties = TypesWidget._properties.copy()
00179     _properties.update({
00180         'macro' : "widgets/reference",
00181         'checkbox_bound': 5,
00182 
00183         'addable' : False, # create createObject link for every addable type
00184         'destination_types' : None,
00185         'destination' : None, # may be:
00186                               # - ".", context object;
00187                               # - None, any place where
00188                               #   Field.allowed_types can be added;
00189                               # - string path;
00190                               # - name of method on instance
00191                               #   (it can be a combination list);
00192                               # - a list, combining all item above;
00193                               # - a dict, where
00194                               #   {portal_type:<combination of the items above>}
00195                               # destination is relative to portal root
00196         'helper_css' : ('content_types.css',),
00197         })
00198 
00199     security = ClassSecurityInfo()
00200 
00201     def lookupDestinationsFor(self, typeinfo, tool, purl, destination_types=None):
00202         """
00203         search where the user can add a typeid instance
00204         """
00205         searchFor = []
00206 
00207         # first, discover who can contain the type
00208         if destination_types is not None:
00209             if type(destination_types) in (type(()), type([])):
00210                 searchFor += list(destination_types[:])
00211             else:
00212                 searchFor.append(destination_types)
00213         else:
00214             for regType in tool.listTypeInfo():
00215                 if typeinfo.globalAllow():
00216                     searchFor.append(regType.getId())
00217                 elif regType.filter_content_types and regType.allowed_content_types:
00218                     act_dict = dict([ (act, 0) for act in regType.allowed_content_types ])
00219                     if act_dict.has_key(typeinfo.getId()):
00220                         searchFor.append(regType.getId())
00221 
00222         catalog = getToolByName(purl, 'portal_catalog')
00223         containers = []
00224         portal_path = "/".join(purl.getPortalObject().getPhysicalPath())
00225         for wanted in searchFor:
00226             for brain in catalog(portal_type=wanted):
00227                 relative_path = brain.getPath().replace(portal_path + '/', '')
00228                 containers.append(relative_path)
00229 
00230         return containers
00231 
00232     security.declarePublic('addableTypes')
00233     def addableTypes(self, instance, field):
00234         """ Returns a list of dictionaries which maps portal_type
00235             to a human readable form.
00236         """
00237         tool = getToolByName(instance, 'portal_types')
00238         purl = getToolByName(instance, 'portal_url')
00239 
00240         lookupDestinationsFor = self.lookupDestinationsFor
00241         getRelativeContentURL = purl.getRelativeContentURL
00242 
00243         # if destination_types is None (by default) it will do
00244         # N-portal_types queries to the catalog which is horribly inefficient
00245 
00246         destination_types = getattr(self, 'destination_types', None)
00247         destination = self.destination
00248         types = []
00249 
00250         options = {}
00251         for typeid in field.allowed_types:
00252             _info = tool.getTypeInfo(typeid)
00253             if _info is None:
00254                 # The portal_type asked for was not
00255                 # installed/has been removed.
00256                 log("Warning: in Archetypes.Widget.lookupDestinationsFor: " \
00257                     "portal type %s not found" % typeid )
00258                 continue
00259 
00260             if destination == None:
00261                 options[typeid]=[None]
00262             elif isinstance(destination, DictType):
00263                 options[typeid]=destination.get(typeid, [None])
00264                 if not isinstance(options[typeid], ListType):
00265                     options[typeid] = [options[typeid]]
00266             elif isinstance(destination, ListType):
00267                 options[typeid]=destination
00268             else:
00269                 place = getattr(aq_base(instance), destination, destination)
00270                 if callable(place):
00271                     #restore acq.wrapper
00272                     place = getattr(instance, destination)
00273                     place = place()
00274                 if isinstance(place, ListType):
00275                     options[typeid] = place
00276                 else:
00277                     options[typeid] = [place]
00278 
00279             value = {}
00280             value['id'] = typeid
00281             value['name'] = _info.Title()
00282             value['destinations'] = []
00283 
00284             for option in options.get(typeid):
00285                 if option == None:
00286                     value['destinations'] = value['destinations'] + \
00287                         lookupDestinationsFor(_info, tool, purl,
00288                                           destination_types=destination_types)
00289                 elif option == '.':
00290                     value['destinations'].append(getRelativeContentURL(instance))
00291                 else:
00292                     try:
00293                         place = getattr(aq_base(instance), option, option)
00294                     except TypeError:
00295                         place = option
00296                     if callable(place):
00297                         #restore acq.wrapper
00298                         place = getattr(instance, option)
00299                         place = place()
00300                     if isinstance(place, ListType):
00301                         value['destinations'] = place + value['destinations']
00302                     else:
00303                         #TODO Might as well check for type, doing it everywhere else
00304                         value['destinations'].append(place)
00305 
00306             if value['destinations']:
00307                 types.append(value)
00308 
00309         return types
00310 
00311 class ComputedWidget(TypesWidget):
00312     _properties = TypesWidget._properties.copy()
00313     _properties.update({
00314         'macro' : "widgets/computed",
00315         })
00316 
00317     security = ClassSecurityInfo()
00318 
00319 class TextAreaWidget(TypesWidget):
00320     _properties = TypesWidget._properties.copy()
00321     _properties.update({
00322         'macro' : "widgets/textarea",
00323         'rows'  : 5,
00324         'cols'  : 40,
00325         'format': 0,
00326         'append_only': False,
00327         'timestamp' : False,        
00328         'divider':"\n\n========================\n\n",
00329         'timestamp': False,
00330         'maxlength' : False,
00331         'helper_js': ('widgets/js/textcount.js',),        
00332         })
00333 
00334     security = ClassSecurityInfo()
00335 
00336     security.declarePublic('process_form')
00337     def process_form(self, instance, field, form, empty_marker=None,
00338                      emptyReturnsMarker=False, validating=True):
00339         """handle text formatting"""
00340         text_format = None
00341         value = None
00342         # text field with formatting
00343         value = form.get(field.getName(), empty_marker)
00344 
00345         if value is empty_marker:
00346             return empty_marker
00347 
00348         if emptyReturnsMarker and value == '':
00349             return empty_marker
00350 
00351         format_field = "%s_text_format" % field.getName()
00352         text_format = form.get(format_field, empty_marker)
00353         kwargs = {}
00354 
00355         if text_format is not empty_marker and text_format:
00356             kwargs['mimetype'] = text_format
00357 
00358         """ handle append_only """
00359         # Don't append if the existing data is empty or nothing was passed in
00360         if getattr(field.widget, 'append_only', None):
00361             if field.getEditAccessor(instance)():
00362                 if (value and not value.isspace()):
00363                     
00364                     divider = field.widget.divider
00365                     
00366                     # Add a datestamp along with divider if desired.
00367                     if getattr(field.widget, 'timestamp', None):
00368 
00369                         divider = "\n\n" + str(DateTime()) + divider
00370                         
00371                     # using default_output_type caused a recursive transformation
00372                     # that sucked, thus mimetype= here to keep it in line
00373                     value = value + divider + \
00374                             field.getEditAccessor(instance)()
00375                 else:
00376                     # keep historical entries
00377                     value = field.getEditAccessor(instance)()
00378         return value, kwargs
00379 
00380 class LinesWidget(TypesWidget):
00381     _properties = TypesWidget._properties.copy()
00382     _properties.update({
00383         'macro' : "widgets/lines",
00384         'rows'  : 5,
00385         'cols'  : 40,
00386         })
00387 
00388     security = ClassSecurityInfo()
00389 
00390 class BooleanWidget(TypesWidget):
00391     _properties = TypesWidget._properties.copy()
00392     _properties.update({
00393         'macro' : "widgets/boolean",
00394         })
00395 
00396     security = ClassSecurityInfo()
00397 
00398 class CalendarWidget(TypesWidget):
00399     _properties = TypesWidget._properties.copy()
00400     _properties.update({
00401         'macro' : "widgets/calendar",
00402         'format' : '', # time.strftime string
00403         'show_hm' : True, 
00404         'show_ymd' : True,
00405         'starting_year' : None,
00406         'ending_year' : None,
00407         'future_years' : None,
00408         'helper_js': ('jscalendar/calendar_stripped.js',
00409                       'jscalendar/calendar-en.js'),
00410         'helper_css': ('jscalendar/calendar-system.css',),
00411         })
00412 
00413     security = ClassSecurityInfo()
00414 
00415     security.declarePublic('process_form')
00416     def process_form(self, instance, field, form, empty_marker=None,
00417                      emptyReturnsMarker=False, validating=True):
00418         """Basic impl for form processing in a widget"""
00419 
00420         fname = field.getName()
00421         value = form.get(fname, empty_marker)
00422         if value is empty_marker:
00423             return empty_marker
00424         # If JS support is unavailable, the value
00425         # in the request may be missing or incorrect
00426         # since it won't have been assembled from the
00427         # input components. Instead of relying on it,
00428         # assemble the date/time from its input components.
00429         year = form.get('%s_year' % fname, '0000')
00430         month = form.get('%s_month' % fname, '00')
00431         day = form.get('%s_day' % fname, '00')
00432         hour = form.get('%s_hour' % fname, '00')
00433         minute = form.get('%s_minute' % fname, '00')
00434         ampm = form.get('%s_ampm' % fname, '')
00435         if (year != '0000') and (day != '00') and (month != '00'):
00436             value = "%s-%s-%s %s:%s" % (year, month, day, hour, minute)
00437             if ampm:
00438                 value = '%s %s' % (value, ampm)
00439         else:
00440             value = ''
00441         if emptyReturnsMarker and value == '':
00442             return empty_marker
00443         # stick it back in request.form
00444         form[fname] = value
00445         return value, {}
00446 
00447 class SelectionWidget(TypesWidget):
00448     _properties = TypesWidget._properties.copy()
00449     _properties.update({
00450         'format': "flex", # possible values: flex, select, radio
00451         'macro' : "widgets/selection",
00452         'blurrable' : True,
00453         })
00454 
00455     security = ClassSecurityInfo()
00456 
00457 class LanguageWidget(TypesWidget):
00458     _properties = TypesWidget._properties.copy()
00459     _properties.update({
00460         'format': "flex", # possible values: flex, select, radio
00461         'macro' : "widgets/languagewidget",
00462         'blurrable' : True,
00463         })
00464 
00465     security = ClassSecurityInfo()
00466 
00467 class MultiSelectionWidget(TypesWidget):
00468     _properties = TypesWidget._properties.copy()
00469     _properties.update({
00470         'format': "select", # possible values: select, checkbox
00471         'macro' : "widgets/multiselection",
00472         'size'  : 5,
00473         'blurrable' : True,
00474         })
00475 
00476     security = ClassSecurityInfo()
00477 
00478     security.declarePublic('process_form')
00479     def process_form(self, instance, field, form, empty_marker=None,
00480                      emptyReturnsMarker=False, validating=True):
00481         """Basic impl for form processing in a widget"""
00482         value = form.get(field.getName(), empty_marker)
00483         if value is empty_marker:
00484             return empty_marker
00485         if emptyReturnsMarker and value == '':
00486             return empty_marker
00487         if isinstance(value, StringTypes):
00488             values = [v.strip() for v in value.split('\n')]
00489         elif isinstance(value, ListType):
00490             values = value
00491         else:
00492             values = []
00493         return values, {}
00494 
00495 class KeywordWidget(TypesWidget):
00496     _properties = TypesWidget._properties.copy()
00497     _properties.update({
00498         'format': "select", # possible values: select, checkbox
00499         'macro' : "widgets/keyword",
00500         'size'  : 5,
00501         'vocab_source' : 'portal_catalog',
00502         'roleBasedAdd' : True,
00503         })
00504 
00505     security = ClassSecurityInfo()
00506 
00507     security.declarePublic('process_form')
00508     def process_form(self, instance, field, form, empty_marker=None,
00509                      emptyReturnsMarker=False, validating=True):
00510         """process keywords from form where this widget has a list of
00511         available keywords and any new ones"""
00512         name = field.getName()
00513         existing_keywords = form.get('%s_existing_keywords' % name, empty_marker)
00514         if existing_keywords is empty_marker:
00515             existing_keywords = []
00516         new_keywords = form.get('%s_keywords' % name, empty_marker)
00517         if new_keywords is empty_marker:
00518             new_keywords = []
00519 
00520         value = existing_keywords + new_keywords
00521         value = [k for k in list(unique(value)) if k]
00522 
00523         if not value and emptyReturnsMarker: return empty_marker
00524 
00525         return value, {}
00526 
00527 
00528 class FileWidget(TypesWidget):
00529     _properties = TypesWidget._properties.copy()
00530     _properties.update({
00531         'macro' : "widgets/file",
00532         'show_content_type' : True,
00533         })
00534 
00535     security = ClassSecurityInfo()
00536 
00537     security.declarePublic('process_form')
00538     def process_form(self, instance, field, form, empty_marker=None,
00539                      emptyReturnsMarker=False, validating=True):
00540         """form processing that deals with binary data"""
00541 
00542         delete = form.get('%s_delete' % field.getName(), empty_marker)
00543         if delete=='delete': return "DELETE_FILE", {}
00544         if delete=='nochange' : return empty_marker
00545 
00546         value = None
00547 
00548         fileobj = form.get('%s_file' % field.getName(), empty_marker)
00549 
00550         if fileobj is empty_marker: return empty_marker
00551 
00552         filename = getattr(fileobj, 'filename', '')
00553         if not filename:
00554             filename = getattr(fileobj, 'name', '')
00555 
00556         if filename:
00557             value = fileobj
00558 
00559         if not value: return None
00560 
00561         return value, {}
00562 
00563 
00564 class RichWidget(TypesWidget):
00565     _properties = TypesWidget._properties.copy()
00566     _properties.update({
00567         'macro' : "widgets/rich",
00568         'rows'  : 5,
00569         'cols'  : 40,
00570         'format': 1,
00571         'allow_file_upload': True,
00572         })
00573 
00574     security = ClassSecurityInfo()
00575 
00576     security.declarePublic('process_form')
00577     def process_form(self, instance, field, form, empty_marker=None,
00578                      emptyReturnsMarker=False, validating=True):
00579         """complex form processing, includes handling for text
00580         formatting and file objects"""
00581         # This is basically the old processing chain from base object
00582         text_format = None
00583         isFile = False
00584         value = None
00585 
00586         # was a mimetype specified
00587         format_field = "%s_text_format" % field.getName()
00588         text_format = form.get(format_field, empty_marker)
00589 
00590         # or a file?
00591         fileobj = form.get('%s_file' % field.getName(), empty_marker)
00592 
00593         if fileobj is not empty_marker:
00594 
00595             filename = getattr(fileobj, 'filename', '') or \
00596                        (isinstance(fileobj, FileType) and \
00597                         getattr(fileobj, 'name', ''))
00598 
00599             if filename:
00600                 value = fileobj
00601                 isFile = True
00602 
00603         kwargs = {}
00604         if not value:
00605             value = form.get(field.getName(), empty_marker)
00606             if text_format is not empty_marker and text_format:
00607                 kwargs['mimetype'] = text_format
00608 
00609         if value is empty_marker: return empty_marker
00610 
00611         if value and not isFile:
00612             # Value filled, no file uploaded
00613             if kwargs.get('mimetype') == str(field.getContentType(instance)) \
00614                    and instance.isBinary(field.getName()):
00615                 # Was an uploaded file, same content type
00616                 del kwargs['mimetype']
00617 
00618         return value, kwargs
00619 
00620 
00621 class IdWidget(TypesWidget):
00622     _properties = TypesWidget._properties.copy()
00623     _properties.update({
00624         'macro' : "widgets/zid",
00625          # show IDs in edit boxes when they are autogenerated?
00626         'display_autogenerated' : True,
00627         # script used to determine if an ID is autogenerated
00628         'is_autogenerated' : 'isIDAutoGenerated',
00629         # ignore global or by-member setting for visible ids?
00630         'ignore_visible_ids': False,
00631         })
00632 
00633     security = ClassSecurityInfo()
00634 
00635     security.declarePublic('process_form')
00636     def process_form(self, instance, field, form, empty_marker=None,
00637                      emptyReturnsMarker=False, validating=True):
00638         """the id might be hidden by the widget and not submitted"""
00639         value = form.get('id', empty_marker)
00640         if not value or value is empty_marker or not value.strip():
00641             value = instance.getId()
00642         return value,  {}
00643 
00644 class RequiredIdWidget(IdWidget):
00645     _properties = IdWidget._properties.copy()
00646     _properties.update({
00647         })
00648 
00649     security = ClassSecurityInfo()
00650 
00651     security.declarePublic('process_form')
00652     def process_form(self, instance, field, form, empty_marker=None,
00653                      emptyReturnsMarker=False, validating=True):
00654         """Override IdWidget.process_form to require id."""
00655         return TypesWidget.process_form(self, instance, field, form, empty_marker)
00656 
00657 
00658 class ImageWidget(FileWidget):
00659     _properties = FileWidget._properties.copy()
00660     _properties.update({
00661         'macro' : "widgets/image",
00662         # only display if size <= threshold, otherwise show link
00663         'display_threshold': 102400,
00664         # use this scale for the preview in the edit form, default to 'preview'
00665         # if this scale isn't available then use the display_threshold
00666         'preview_scale': 'preview', 
00667         })
00668 
00669     security = ClassSecurityInfo()
00670 
00671     security.declarePublic('process_form')
00672     def process_form(self, instance, field, form, empty_marker=None,
00673                      emptyReturnsMarker=False, validating=True):
00674         """form processing that deals with image data (and its delete case)"""
00675         value = None
00676         ## check to see if the delete hidden was selected
00677         delete = form.get('%s_delete' % field.getName(), empty_marker)
00678         if delete=='delete': return "DELETE_IMAGE", {}
00679         if delete=='nochange' : return empty_marker
00680         
00681 
00682         fileobj = form.get('%s_file' % field.getName(), empty_marker)
00683 
00684         if fileobj is empty_marker: return empty_marker
00685 
00686         filename = getattr(fileobj, 'filename', '') or \
00687                    (isinstance(fileobj, FileType) and \
00688                     getattr(fileobj, 'name', ''))
00689 
00690         if filename:
00691             value = fileobj
00692 
00693         if not value: return None
00694         return value, {}
00695 
00696     security.declarePublic('preview_tag')
00697     def preview_tag(self, instance, field):
00698         """Return a tag for a preview image, or None if no preview is found."""
00699         img=field.get(instance)
00700         if not img:
00701             return None
00702 
00703         if self.preview_scale in field.sizes:
00704             return field.tag(instance, scale=self.preview_scale)
00705 
00706         if img.getSize()<=self.display_threshold:
00707             return field.tag(instance)
00708 
00709         return None
00710 
00711 # LabelWidgets are used to display instructions on a form.  The widget only
00712 # displays the label for a value -- no values and no form elements.
00713 class LabelWidget(TypesWidget):
00714     _properties = TypesWidget._properties.copy()
00715     _properties.update({
00716         'macro' : "widgets/label",
00717         })
00718 
00719     security = ClassSecurityInfo()
00720 
00721 class PasswordWidget(TypesWidget):
00722     _properties = TypesWidget._properties.copy()
00723     _properties.update({
00724         'macro' : 'widgets/password',
00725         'modes' : ('edit',),
00726         'populate' : False,
00727         'postback' : False,
00728         'size' : 20,
00729         'maxlength' : '255',
00730         })
00731 
00732     security = ClassSecurityInfo()
00733 
00734 class VisualWidget(TextAreaWidget):
00735     _properties = TextAreaWidget._properties.copy()
00736     _properties.update({
00737         'macro' : "widgets/visual",
00738         'rows'  : 25,      #rows of TextArea if VE is not available
00739         'cols'  : 80,      #same for cols
00740         'width' : '507px', #width of VE frame (if VE is avalilable)
00741         'height': '400px', #same for height
00742         'format': 0,
00743         'append_only': False, #creates a textarea you can only add to, not edit
00744         'divider': '\n\n<hr />\n\n', # default divider for append only divider
00745         })
00746 
00747     security = ClassSecurityInfo()
00748 
00749 class EpozWidget(TextAreaWidget):
00750     _properties = TextAreaWidget._properties.copy()
00751     _properties.update({
00752         'macro' : "widgets/epoz",
00753         })
00754 
00755     security = ClassSecurityInfo()
00756 
00757 class InAndOutWidget(ReferenceWidget):
00758     _properties = ReferenceWidget._properties.copy()
00759     _properties.update({
00760         'macro' : "widgets/inandout",
00761         'size' : '6',
00762         'helper_js': ('widgets/js/inandout.js',),
00763         })
00764 
00765     security = ClassSecurityInfo()
00766 
00767 class PicklistWidget(TypesWidget):
00768     _properties = TypesWidget._properties.copy()
00769     _properties.update({
00770         'macro' : "widgets/picklist",
00771         'size' : '6',
00772         'helper_js': ('widgets/js/picklist.js',),
00773         })
00774 
00775     security = ClassSecurityInfo()
00776 
00777 __all__ = ('StringWidget', 'DecimalWidget', 'IntegerWidget',
00778            'ReferenceWidget', 'ComputedWidget', 'TextAreaWidget',
00779            'LinesWidget', 'BooleanWidget', 'CalendarWidget',
00780            'SelectionWidget', 'MultiSelectionWidget', 'KeywordWidget',
00781            'RichWidget', 'FileWidget', 'IdWidget', 'ImageWidget',
00782            'LabelWidget', 'PasswordWidget', 'VisualWidget', 'EpozWidget',
00783            'InAndOutWidget', 'PicklistWidget', 'RequiredIdWidget',
00784            'LanguageWidget',
00785            )
00786 
00787 registerWidget(StringWidget,
00788                title='String',
00789                description=('Renders a HTML text input box which '
00790                             'accepts a single line of text'),
00791                used_for=('Products.Archetypes.Field.StringField',)
00792                )
00793 
00794 registerWidget(DecimalWidget,
00795                title='Decimal',
00796                description=('Renders a HTML text input box which '
00797                             'accepts a fixed point value'),
00798                used_for=('Products.Archetypes.Field.FixedPointField',)
00799                )
00800 
00801 registerWidget(IntegerWidget,
00802                title='Integer',
00803                description=('Renders a HTML text input box which '
00804                             'accepts a integer value'),
00805                used_for=('Products.Archetypes.Field.IntegerField',)
00806                )
00807 
00808 registerWidget(ReferenceWidget,
00809                title='Reference',
00810                description=('Renders a HTML text input box which '
00811                             'accepts a reference value'),
00812                used_for=('Products.Archetypes.Field.ReferenceField',)
00813                )
00814 
00815 registerWidget(ComputedWidget,
00816                title='Computed',
00817                description='Renders the computed value as HTML',
00818                used_for=('Products.Archetypes.Field.ComputedField',)
00819                )
00820 
00821 registerWidget(TextAreaWidget,
00822                title='Text Area',
00823                description=('Renders a HTML Text Area for typing '
00824                             'a few lines of text'),
00825                used_for=('Products.Archetypes.Field.StringField',
00826                          'Products.Archetypes.Field.TextField')
00827                )
00828 
00829 registerWidget(LinesWidget,
00830                title='Lines',
00831                description=('Renders a HTML textarea for a list '
00832                             'of values, one per line'),
00833                used_for=('Products.Archetypes.Field.LinesField',)
00834                )
00835 
00836 registerWidget(BooleanWidget,
00837                title='Boolean',
00838                description='Renders a HTML checkbox',
00839                used_for=('Products.Archetypes.Field.BooleanField',)
00840                )
00841 
00842 registerWidget(CalendarWidget,
00843                title='Calendar',
00844                description=('Renders a HTML input box with a helper '
00845                             'popup box for choosing dates'),
00846                used_for=('Products.Archetypes.Field.DateTimeField',)
00847                )
00848 
00849 registerWidget(SelectionWidget,
00850                title='Selection',
00851                description=('Renders a HTML selection widget, which '
00852                             'can be represented as a dropdown, or as '
00853                             'a group of radio buttons'),
00854                used_for=('Products.Archetypes.Field.StringField',
00855                          'Products.Archetypes.Field.LinesField',)
00856                )
00857 
00858 registerWidget(LanguageWidget,
00859               title='Language',
00860               description=('Renders a HTML selection widget for choosing '
00861                            'a language from a vocabulary. The widget can be '
00862                            'represented as a dropdown, or as a group of'
00863                            'of radio buttons'),
00864               used_for=('Products.Archetypes.Field.StringField')
00865               )
00866 
00867 registerWidget(MultiSelectionWidget,
00868                title='Multi Selection',
00869                description=('Renders a HTML selection widget, where '
00870                             'you can be choose more than one value'),
00871                used_for=('Products.Archetypes.Field.LinesField',)
00872                )
00873 
00874 registerWidget(KeywordWidget,
00875                title='Keyword',
00876                description='Renders a HTML widget for choosing keywords',
00877                used_for=('Products.Archetypes.Field.LinesField',)
00878                )
00879 
00880 registerWidget(RichWidget,
00881                title='Rich Widget',
00882                description=('Renders a HTML widget that allows you to '
00883                             'type some content, choose formatting '
00884                             'and/or upload a file'),
00885                used_for=('Products.Archetypes.Field.TextField',)
00886                )
00887 
00888 registerWidget(FileWidget,
00889                title='File',
00890                description='Renders a HTML widget upload a file',
00891                used_for=('Products.Archetypes.Field.FileField',)
00892                )
00893 
00894 registerWidget(IdWidget,
00895                title='ID',
00896                description='Renders a HTML widget for typing an Id',
00897                used_for=('Products.Archetypes.Field.StringField',)
00898                )
00899 
00900 registerWidget(RequiredIdWidget,
00901                title='ID',
00902                description='Renders a HTML widget for typing an required Id',
00903                used_for=('Products.Archetypes.Field.StringField',)
00904                )
00905 
00906 registerWidget(ImageWidget,
00907                title='Image',
00908                description=('Renders a HTML widget for '
00909                             'uploading/displaying an image'),
00910                used_for=('Products.Archetypes.Field.ImageField',)
00911                )
00912 
00913 registerWidget(LabelWidget,
00914                title='Label',
00915                description=('Renders a HTML widget that only '
00916                             'displays the label'),
00917                used_for=None
00918                )
00919 
00920 registerWidget(PasswordWidget,
00921                title='Password',
00922                description='Renders a HTML password widget',
00923                used_for=('Products.Archetypes.Field.StringField',)
00924                )
00925 
00926 registerWidget(VisualWidget,
00927                title='Visual',
00928                description='Renders a HTML visual editing widget widget',
00929                used_for=('Products.Archetypes.Field.StringField',)
00930                )
00931 
00932 registerWidget(EpozWidget,
00933                title='Epoz',
00934                description='Renders a HTML Epoz widget',
00935                used_for=('Products.Archetypes.Field.StringField',)
00936                )
00937 
00938 registerWidget(InAndOutWidget,
00939                title='In & Out',
00940                description=('Renders a widget for moving items '
00941                             'from one list to another. Items are '
00942                             'removed from the first list.'),
00943                used_for=('Products.Archetypes.Field.LinesField',
00944                          'Products.Archetypes.Field.ReferenceField',)
00945                )
00946 
00947 registerWidget(PicklistWidget,
00948                title='Picklist',
00949                description=('Render a widget to pick from one '
00950                             'list to populate another.  Items '
00951                             'stay in the first list.'),
00952                used_for=('Products.Archetypes.Field.LinesField',)
00953                )
00954 
00955 registerPropertyType('maxlength', 'integer', StringWidget)
00956 registerPropertyType('populate', 'boolean')
00957 registerPropertyType('postback', 'boolean')
00958 registerPropertyType('rows', 'integer', RichWidget)
00959 registerPropertyType('cols', 'integer', RichWidget)
00960 registerPropertyType('rows', 'integer', TextAreaWidget)
00961 registerPropertyType('cols', 'integer', TextAreaWidget)
00962 registerPropertyType('append_only', 'boolean', TextAreaWidget)
00963 registerPropertyType('divider', 'string', TextAreaWidget)
00964 registerPropertyType('timestamp', 'boolean', TextAreaWidget)
00965 registerPropertyType('rows', 'integer', LinesWidget)
00966 registerPropertyType('cols', 'integer', LinesWidget)
00967 registerPropertyType('rows', 'integer', VisualWidget)
00968 registerPropertyType('cols', 'integer', VisualWidget)