class IntegerValidator(StringBaseValidator):
    property_names = StringBaseValidator.property_names +\
                   ['start', 'end']
    message_names = StringBaseValidator.message_names +\
                  ['not_integer', 'integer_out_of_range']

    start = fields.IntegerField(
        'start',
        title='Start',
        description=(
            "The integer entered by the user must be larger than or equal to "
            "this value. If left empty, there is no minimum."),
        default="",
        required=0)
    end = fields.IntegerField(
        'end',
        title='End',
        description=(
            "The integer entered by the user must be smaller than this "
            "value. If left empty, there is no maximum."),
        default="",
        required=0)

    not_integer = _('You did not enter an integer.')
    integer_out_of_range = _('The integer you entered was out of range.')

    def check(self, field, value, failover=False):
        if value == "":
            if not failover and field.get_value('required'):
                self.raise_error('required_not_found', field)
            return ""

        if not isinstance(value, int):
            self.raise_error('not_integer', field)

        if not failover:
            start = field.get_value('start')
            end = field.get_value('end')
            if start != "" and value < start:
                self.raise_error('integer_out_of_range', field)
            if end != "" and value >= end:
                self.raise_error('integer_out_of_range', field)
        return value

    def validate(self, field, key, REQUEST):
        value = REQUEST.get(key, "").strip()
        if value:
            try:
                value = int(value)
            except ValueError:
                self.raise_error('not_integer', field)

        return self.check(field, value, key + '_novalidate' in REQUEST)

    def serializeValue(self, field, value, producer):
        value_string = str(value)
        producer.characters(value_string)
Exemple #2
0
class TextWidget(Widget):
    """Text widget
    """
    property_names = Widget.property_names +\
                     ['display_width', 'display_maxwidth', 'extra']

    default = fields.StringField(
        'default',
        title='Default',
        description=(
            "You can place text here that will be used as the default "
            "value of the field, unless the programmer supplies an override "
            "when the form is being generated."),
        default="",
        required=0)

    display_width = fields.IntegerField(
        'display_width',
        title='Display width',
        description=("The width in characters. Required."),
        default=20,
        required=1)

    display_maxwidth = fields.IntegerField(
        'display_maxwidth',
        title='Maximum input',
        description=(
            "The maximum input in characters that the widget will allow. "
            "Required. If set to 0 or is left empty, there is no maximum. "
            "Note that is client side behavior only."),
        default="",
        required=0)

    def render(self, field, key, value, REQUEST):
        """Render text input field.
        """
        extra = field.get_value('extra')
        css_class = field.get_value('css_class')
        kw = {
            'type': "text",
            'name': key,
            'css_class': css_class,
            'value': value,
            'size': field.get_value('display_width'),
            'extra': extra
        }
        if not extra or not id_value_re.search(extra):
            kw['id'] = field.generate_field_html_id(key)
        display_maxwidth = field.get_value('display_maxwidth') or 0
        if display_maxwidth > 0:
            kw['maxlength'] = display_maxwidth
        contents = render_element("input", **kw)
        return render_element("div", contents=contents, css_class=css_class)

    def render_view(self, field, value):
        return render_value(value)
Exemple #3
0
class TextAreaWidget(Widget):
    """Textarea widget
    """
    property_names = Widget.property_names +\
                     ['width', 'height', 'extra']

    default = fields.TextAreaField(
        'default',
        title='Default',
        description=("Default value of the text in the widget."),
        default="",
        width=20,
        height=3,
        required=0)

    width = fields.IntegerField(
        'width',
        title='Width',
        description=("The width (columns) in characters. Required."),
        default=40,
        required=1)

    height = fields.IntegerField(
        'height',
        title="Height",
        description=("The height (rows) in characters. Required."),
        default=5,
        required=1)

    def render(self, field, key, value, REQUEST):
        width = field.get_value('width')
        height = field.get_value('height')
        extra = field.get_value('extra')
        css_class = field.get_value('css_class')
        kw = {
            'name': key,
            'css_class': css_class,
            'cols': width,
            'rows': height,
            'contents': cgi.escape(value)
        }
        if not extra or not id_value_re.search(extra):
            kw['id'] = field.generate_field_html_id(key)
        contents = render_element("textarea", **kw)
        return render_element("div", contents=contents, css_class=css_class)

    def render_view(self, field, value):
        return render_value(value)
class StringValidator(StringBaseValidator):
    property_names = StringBaseValidator.property_names +\
                   ['unicode', 'max_length', 'truncate']
    message_names = StringBaseValidator.message_names +\
                  ['too_long']

    unicode = fields.CheckBoxField(
        'unicode',
        title='Unicode',
        description=(
            "Checked if the field delivers a unicode string instead of an "
            "8-bit string."),
        default=0)
    max_length = fields.IntegerField(
        'max_length',
        title='Maximum length',
        description=(
            "The maximum amount of characters that can be entered in this "
            "field. If set to 0 or is left empty, there is no maximum. "
            "Note that this is server side validation."),
        default="",
        required=0)
    truncate = fields.CheckBoxField(
        'truncate',
        title='Truncate',
        description=(
            "If checked, truncate the field if it receives more input than is "
            "allowed. The behavior in this case is to raise a validation "
            "error, but the text can be silently truncated instead."),
        default=0)

    too_long = _('Too much input was given.')

    def check(self, field, value, failover=False):
        value = StringBaseValidator.check(self, field, value, failover)

        # Verify encoding (using form setting)
        value = ensure_unicode(value,
                               convert=field.get_value('unicode'),
                               encoding=field.get_form_encoding())

        if not failover:
            max_length = field.get_value('max_length') or 0
            if max_length > 0 and len(value) > max_length:
                if field.get_value('truncate'):
                    value = value[:max_length]
                else:
                    self.raise_error('too_long', field)

        return value
Exemple #5
0
class MultiListWidget(MultiItemsWidget):
    """List widget with multiple select.
    """
    property_names = Widget.property_names +\
                     ['items', 'size', 'view_separator', 'extra', 'extra_item']

    size = fields.IntegerField(
        'size',
        title='Size',
        description=(
            "The display size in rows of the field. If set to 1, the "
            "widget will be displayed as a drop down box by many browsers, "
            "if set to something higher, a list will be shown. Required."),
        default=5,
        required=1)

    def render(self, field, key, value, REQUEST):
        rendered_items = self.render_items(field, key, value, REQUEST)

        extra = field.get_value('extra')
        kw = {
            'name': key,
            'multiple': None,
            'css_class': field.get_value('css_class'),
            'size': field.get_value('size'),
            'contents': string.join(rendered_items, "\n"),
            'extra': extra
        }
        if not extra or not id_value_re.search(extra):
            kw['id'] = field.generate_field_html_id(key)
        return render_element('select', **kw)

    def render_item(self, text, value, key, css_class, extra_item, html_id):
        return render_element('option',
                              contents=text,
                              value=value,
                              extra=extra_item)

    def render_selected_item(self, text, value, key, css_class, extra_item,
                             html_id):
        return render_element('option',
                              contents=text,
                              value=value,
                              selected=None,
                              extra=extra_item)
Exemple #6
0
class MultiRelationStringFieldWidget(Widget.LinesTextAreaWidget,
                                     Widget.TextWidget, Widget.ListWidget):
    """
  RelationStringField widget
  Works like a string field but includes one buttons
  - one search button which updates the field and sets a relation
  - creates object if not there
  """
    local_property_names = [
        'update_method',
        'jump_method',
        'allow_jump',
        'base_category',
        'portal_type',
        'allow_creation',
        'container_getter_id',
        'context_getter_id',
        'catalog_index',
        'relation_setter_id',
        'relation_form_id',
        'columns',
        'sort',
        'parameter_list',
        'list_method',
        'first_item',
        'items',
        'proxy_listbox_ids',
        'size',
        'extra_item',
    ]

    property_names = (
        lambda name_list, name_set=set():
        # delete double (but preserve order) in order to keep a usable ZMI...
        [x for x in name_list if not (x in name_set or name_set.add(x))]
    )(Widget.LinesTextAreaWidget.property_names +
      Widget.TextWidget.property_names + local_property_names)

    # XXX Field to remove...
    update_method = fields.StringField(
        'update_method',
        title='Update Method',
        description=("The method to call to set the relation. Required."),
        default="Base_validateRelation",
        required=1)

    jump_method = fields.StringField(
        'jump_method',
        title='Jump Method',
        description=("The method to call to jump to the relation. Required."),
        default="Base_jumpToRelatedDocument",
        required=1)

    allow_jump = fields.CheckBoxField(
        'allow_jump',
        title='Allow Jump',
        description=("Do we allow to jump to the relation ?"),
        default=1,
        required=0)

    base_category = fields.StringField(
        'base_category',
        title='Base Category',
        description=("The method to call to set the relation. Required."),
        default="",
        required=1)

    portal_type = fields.ListTextAreaField(
        'portal_type',
        title='Portal Type',
        description=("The method to call to set the relation. Required."),
        default="",
        required=0)

    allow_creation = fields.CheckBoxField(
        'allow_creation',
        title='Allow Creation',
        description=("Do we allow to create new objects ?"),
        default=1,
        required=0)

    container_getter_id = fields.StringField(
        'container_getter_id',
        title='Container Getter Method',
        description=("The method to call to get a container object."),
        default="",
        required=0)

    context_getter_id = fields.StringField(
        'context_getter_id',
        title='Context Getter Method',
        description=("The method to call to get the context."),
        default="",
        required=0)

    catalog_index = fields.StringField(
        'catalog_index',
        title='Catalog Index',
        description=("The method to call to set the relation. Required."),
        default="",
        required=1)

    # XXX Is it a good idea to keep such a field ??
    # User can redefine setter method with a script (and so, don't use the API)
    relation_setter_id = fields.StringField(
        'relation_setter_id',
        title='Relation Update Method',
        description=("The method to invoke in order to update the relation"),
        default="",
        required=0)

    relation_form_id = fields.StringField(
        'relation_form_id',
        title='Relation Form',
        description=("Form to display relation choices"),
        default="",
        required=0)

    size = fields.IntegerField(
        'size',
        title='Size',
        description=(
            "The display size in rows of the field. If set to 1, the "
            "widget will be displayed as a drop down box by many browsers, "
            "if set to something higher, a list will be shown. Required."),
        default=1,
        required=1)

    columns = fields.ListTextAreaField(
        'columns',
        title="Columns",
        description=("A list of attributes names to display."),
        default=[],
        required=0)

    sort = fields.ListTextAreaField(
        'sort',
        title='Default Sort',
        description=('The default sort keys and order'),
        default=[],
        required=0)

    parameter_list = fields.ListTextAreaField(
        'parameter_list',
        title="Parameter List",
        description=("A list of paramters used for the portal_catalog."),
        default=[],
        required=0)

    list_method = fields.MethodField('list_method',
                                     title='List Method',
                                     description=('The method to use to list'
                                                  'objects'),
                                     default='',
                                     required=0)

    proxy_listbox_ids = fields.ListTextAreaField(
        'proxy_listbox_ids',
        title='Proxy Listbox IDs',
        description=('A list of listbox that can be used as proxy'),
        default='',
        required=0)

    default_widget_rendering_instance = Widget.LinesTextAreaWidgetInstance

    def _getContextValue(self, field, REQUEST):
        """Return result of evaluated method
    defined by context_getter_id or here.
    """
        context_getter_id = field.get_value('context_getter_id')
        here = REQUEST['here']
        if context_getter_id:
            return getattr(here, context_getter_id)()
        return here

    def _generateRenderValueList(self, field, key, value_list, REQUEST):
        if isinstance(value_list, basestring):
            # Value is a string, reformat it correctly
            value_list = value_list.split("\n")
        else:
            # We get a list
            # rather than displaying nothing, display a marker when the
            # property is not set
            # XXX Translate ?
            value_list = [(x or NO_VALUE) for x in value_list]
        generate_subfield_key = field.generate_subfield_key
        need_validation = False
        result_list = []
        for index, value in enumerate(value_list):
            relation_item_list = REQUEST.get(
                generate_subfield_key(
                    "%s_%s" % (ITEM_ID, index),
                    key=key,
                ),
                None,
            )
            # If we get a empty string, display nothing !
            if value:
                need_validation |= relation_item_list is not None
                result_list.append((
                    Widget.TextWidgetInstance,
                    generate_subfield_key(
                        "%s_%s" % (SUB_FIELD_ID, index),
                        key=key,
                    ),
                    relation_item_list,
                    value,
                    index,
                ), )
        if need_validation:
            return result_list
        return [(Widget.LinesTextAreaWidgetInstance, None, [], value_list,
                 None)]

    def render(self, field, key, value, REQUEST, render_prefix=None):
        """
    Render text input field.
    """
        portal = self._getContextValue(field, REQUEST).getPortalObject()
        autocomplete_enabled = getattr(
            portal.portal_skins,
            'erp5_autocompletion_ui',
            None,
        ) is not None
        relation_field_index = REQUEST.get('_v_relation_field_index', 0)
        html_string_list = []
        for (widget_instance, relation_field_id, relation_item_list,
             value_instance, sub_index) in self._generateRenderValueList(
                 field,
                 key,
                 value,
                 REQUEST,
             ):
            sub_html_string = widget_instance.render(
                field,
                key,
                value_instance,
                REQUEST,
            )
            if autocomplete_enabled:
                sub_html_string += self.render_autocomplete(field, key)
            if relation_item_list is not None:
                if not autocomplete_enabled:
                    sub_html_string += self.render_wheel(
                        field,
                        value_instance,
                        REQUEST,
                        relation_index=relation_field_index,
                        sub_index=sub_index,
                    )
                if relation_item_list:
                    REQUEST['relation_item_list'] = relation_item_list
                    sub_html_string += NBSP + Widget.ListWidgetInstance.render(
                        field,
                        relation_field_id,
                        None,
                        REQUEST,
                    ) + NBSP
                    REQUEST['relation_item_list'] = None
            html_string_list.append(sub_html_string)
        html_string = '<br/>'.join(html_string_list)
        if (value == field.get_value('default')):
            # XXX Default rendering with value...
            relation_html_string = self.render_relation_link(
                field, value, REQUEST)
            if relation_html_string:
                html_string += NBSP + NBSP + relation_html_string
        REQUEST.set('_v_relation_field_index', relation_field_index + 1)
        return html_string

    def render_view(self, field, value, REQUEST=None, render_prefix=None):
        """
    Render read only field.
    """
        if (value not in ((), [], None, '')) and field.get_value('allow_jump'):
            if not isinstance(value, (list, tuple)):
                value = value,
            html_string = '<br />'.join(
                '<a class="relationfieldlink" href="%s">%s</a>' % (
                    escape(jump_reference.absolute_url()),
                    escape(display_value),
                ) for jump_reference, display_value in zip(
                    getattr(
                        self._getContextValue(field,
                                              REQUEST), 'get%sValueList' %
                        ''.join(part.capitalize() for part in field.get_value(
                            'base_category').split('_')))(
                                portal_type=[
                                    x[0]
                                    for x in field.get_value('portal_type')
                                ],
                                filter=dict(field.get_value('parameter_list')),
                            ),
                    value,
                ))
        else:
            html_string = self.default_widget_rendering_instance.render_view(
                field,
                value,
                REQUEST=REQUEST,
            )
            if REQUEST is None:
                REQUEST = get_request()
            relation_html_string = self.render_relation_link(
                field, value, REQUEST)
            if relation_html_string:
                html_string += NBSP + NBSP + relation_html_string
        extra = field.get_value('extra')
        if extra not in (None, ''):
            html_string = "<div %s>%s</div>" % (extra, html_string)
        css_class = field.get_value('css_class')
        if css_class not in ('', None):
            html_string = '<span class="%s">%s</span>' % (
                escape(css_class),
                html_string,
            )
        return html_string

    def render_autocomplete(self, field, key):
        """
    Use jquery-ui autocompletion for all relation fields by default, requiring
    only erp5_autocompletion_ui bt5 to be installed
    """
        # XXX: Allow to specify more parameters to jquery-ui autocomplete widget?
        return """
<script type="text/javascript">
$(document).ready(function() {
  $("input[name='%s']").ERP5Autocomplete({search_portal_type: %s,
                                          search_catalog_key: "%s"});
});
</script>""" % (
            escape(key),
            escape(json.dumps([x[0] for x in field.get_value('portal_type')])),
            escape(field.get_value('catalog_index')),
        )

    def render_wheel(self,
                     field,
                     value,
                     REQUEST,
                     relation_index=0,
                     sub_index=None,
                     render_prefix=None):
        """
    Render wheel used to display a listbox
    """
        here = self._getContextValue(field, REQUEST)
        portal_url = here.getPortalObject().portal_url
        if sub_index is None:
            sub_index_string = ''
        else:
            sub_index_string = '_%s' % sub_index
        return '&nbsp;<input type="image" ' \
          'src="%s/images/exec16.png" alt="update..." ' \
          'name="%s/viewSearchRelatedDocumentDialog%s%s' \
          ':method"/>' % (
          escape(portal_url()),
          escape(portal_url.getRelativeContentURL(here.portal_selections)),
          escape(str(relation_index)),
          escape(sub_index_string),
        )

    def render_relation_link(self, field, value, REQUEST, render_prefix=None):
        """
    Render link to the related object.
    """
        if value not in ((), [], None, '') and field.get_value('allow_jump'):
            # If we this relation field is used as a listbox/matrixbox editable
            # field, then the context of this cell is set in REQUEST. XXX this is not
            # 100% reliable way, maybe we need something to know that the field is
            # beeing rendered as an editable field.
            cell = REQUEST.get('cell')
            here = (cell if cell is not None else self._getContextValue(
                field, REQUEST))
            # Keep the selection name in the URL
            selection_name = REQUEST.get('selection_name')
            if selection_name is not None:
                selection_name_html = '&amp;selection_name=%s&amp;selection_index=%s' % (
                    escape(selection_name),
                    escape(str(REQUEST.get('selection_index', 0))),
                )
            else:
                selection_name_html = ''
            ignore_layout = REQUEST.get('ignore_layout')
            if ignore_layout is not None:
                selection_name_html += '&amp;ignore_layout:int=%s' % int(
                    ignore_layout)
            # Generate plan link
            return '<a href="%s/%s?field_id=%s&amp;form_id=%s%s">' \
              '<img src="%s/images/jump.png" alt="jump" />' \
            '</a>' % (
              escape(here.absolute_url()),
              escape(field.get_value('jump_method')),
              escape(field.id),
              escape(field.aq_parent.id),
              escape(selection_name_html),
              escape(here.getPortalObject().portal_url()),
            )
        return ''
Exemple #7
0
class VideoWidget(Widget.TextWidget):
    """
  A widget that displays a Video HTML element.
  This widget is intended to be used in
  conjunction with WebSite.
  """
    property_names = Widget.TextWidget.property_names + \
            ['video_controls', 'video_error_message', 'video_loop', \
                'video_width', 'video_height', 'video_preload', \
                'video_autoplay', 'js_enabled', 'video_player']

    video_controls = fields.CheckBoxField(
        'video_controls',
        title='Video Controls',
        description=("Controls to be used in Video Player."),
        default=1,
        required=0)

    video_error_message = fields.StringField(
        'video_error_message',
        title='Video Error Message',
        description=("Error message to be showed when \
          user's browser does not support the video tag."),
        default='Your browser does not support video tag.',
        required=0)

    video_loop = fields.CheckBoxField(
        'video_loop',
        title='Video Loop',
        description=("Specifies that the video file \
          will start over again, every time it is finished."),
        default=0,
        required=0)

    video_width = fields.IntegerField(
        'video_width',
        title='Video Width',
        description=("The width to be used when playing the video."),
        default=160,
        required=0)

    video_height = fields.IntegerField(
        'video_height',
        title='Video Height',
        description=("The height to be used when playing the video."),
        default=85,
        required=0)

    video_preload = fields.CheckBoxField(
        'video_preload',
        title='Video Preload',
        description=("Configure that you would like to \
      start downloading the video file as soon as possible."),
        default=1,
        required=0)

    video_autoplay = fields.CheckBoxField(
        'video_autoplay',
        title='Video Autoplay',
        description=("Configure that you would like to \
      start downloading and playing the video file as soon as possible."),
        default=0,
        required=0)

    js_enabled = fields.CheckBoxField(
        'js_enabled',
        title='Enable on the fly video player change (based on java script)',
        description=
        'Define if javascript is enabled or not on the current Video',
        default=1,
        required=0)

    video_player = fields.ListField(
        'video_player',
        title='Video Player',
        description=("The video player to be used to show video."),
        default="html5_video",
        required=1,
        size=1,
        items=[
            ('HTML5 Video', 'html5_video'),
            ('Flowplayer', 'flowplayer'),
        ])

    def render(self, field, key, value, REQUEST, render_prefix=None):
        return self.render_view(field, value, REQUEST, render_prefix)

    def render_view(self, field, value, REQUEST=None, render_prefix=None):
        if value is None:
            return ''
        video_player = field.get_value('video_player')
        if video_player == 'html5_video':
            extra_kw = {}
            if field.get_value('video_autoplay'):
                extra_kw['autoplay'] = 'autoplay'
            if field.get_value('video_controls'):
                extra_kw['controls'] = 'controls'
            if field.get_value('video_loop'):
                extra_kw['loop'] = 'loop'
            if field.get_value('video_preload'):
                extra_kw['preload'] = 'preload'
            return Widget.render_element(
                "video",
                src=value,
                extra=field.get_value('extra'),
                width=field.get_value('video_width'),
                height=field.get_value('video_height'),
                contents=field.get_value('video_error_message'),
                **extra_kw)
        elif video_player == 'flowplayer':
            a_element = Widget.render_element("a",
                              href="%s" % value,
                              style="display:block;width:%spx;height:%spx;" % \
                                              (field.get_value('video_width'),
                                               field.get_value('video_height'),),
                              id="player")

            script_element = """<script language="JavaScript">
                             flowplayer("player", "%s/flowplayer.swf");
                         </script>""" % self.getContext(
                field, REQUEST).getPortalObject().portal_url()
            return ' '.join([a_element, script_element])

    def get_javascript_list(self, field, REQUEST=None):
        """
    Returns list of javascript needed by the widget
    """
        if field.get_value('js_enabled'):
            video_player = field.get_value('video_player')
            context = self.getContext(field, REQUEST)
            if video_player == 'html5_video':
                # XXX Instead of harcoding library name
                # it should be better to call a python script, as
                # it is done on type base method.
                return ['%s/html5media.min.js' % context.portal_url()]
            elif video_player == 'flowplayer':
                return ['%s/flowplayer.min.js' % context.portal_url()]
        else:
            return []

    def getContext(self, field, REQUEST):
        """Return the context of rendering this Field.
    """
        value = REQUEST.get('here')
        if value is None:
            value = self.getForm(field).aq_parent
        return value

    def getForm(self, field):
        """Return the form which contains the Field.
    """
        return field.aq_parent
Exemple #8
0
def create_settings_form():
    """Create settings form for ZMIForm.
    """
    form = BasicForm('manage_settings')

    title = fields.StringField('title',
                               title="Title",
                               required=0,
                               default="")
    description = fields.TextAreaField('description',
                               title="Description",
                               required=0,
                               default="")
    row_length = fields.IntegerField('row_length',
                                     title='Number of groups in row (in order tab)',
                                     required=1,
                                     default=4)
    name = fields.StringField('name',
                              title="Form name",
                              required=0,
                              default="")
    pt = fields.StringField('pt',
                              title="Page Template",
                              required=0,
                              default="")
    action = fields.StringField('action',
                                title='Form action',
                                required=0,
                                default="")
    update_action = fields.StringField('update_action',
                                title='Form update action',
                                required=0,
                                default="")
    update_action_title = fields.StringField('update_action_title',
                               title="Update Action Title",
                               required=0,
                               default="")
    method = fields.ListField('method',
                              title='Form method',
                              items=[('POST', 'POST'),
                                     ('GET', 'GET')],
                              required=1,
                              size=1,
                              default='POST')
    enctype = fields.ListField('enctype',
                               title='Form enctype',
                               items=[('No enctype', ""),
                                      ('application/x-www-form-urlencoded',
                                       'application/x-www-form-urlencoded'),
                                      ('multipart/form-data',
                                       'multipart/form-data')],
                               required=0,
                               size=1,
                               default=None)
    encoding = fields.StringField('encoding',
                                  title='Encoding of pages the form is in',
                                  default="UTF-8",
                                  required=1)
    stored_encoding = fields.StringField('stored_encoding',
                                      title='Encoding of form properties',
                                      default='UTF-8',
                                      required=1)
    unicode_mode = fields.CheckBoxField('unicode_mode',
                                        title='Form properties are unicode',
                                        default=0,
                                        required=1)
    edit_order = fields.LinesField('edit_order',
                                   title='Setters for these properties should be'
                                   '<br /> called by edit() in the defined order')

    form.add_fields([title, description, row_length, name, pt, action, update_action, update_action_title,
                     method, enctype, encoding, stored_encoding, unicode_mode, edit_order])
    return form
class LinesValidator(StringBaseValidator):
    property_names = StringBaseValidator.property_names +\
                   ['unicode', 'max_lines', 'max_linelength', 'max_length']
    message_names = StringBaseValidator.message_names +\
                  ['too_many_lines', 'line_too_long', 'too_long']

    unicode = fields.CheckBoxField(
        'unicode',
        title='Unicode',
        description=(
            "Checked if the field delivers a unicode string instead of an "
            "8-bit string."),
        default=0)
    max_lines = fields.IntegerField(
        'max_lines',
        title='Maximum lines',
        description=(
            "The maximum amount of lines a user can enter. If set to 0, "
            "or is left empty, there is no maximum."),
        default="",
        required=0)
    max_linelength = fields.IntegerField(
        'max_linelength',
        title="Maximum length of line",
        description=(
            "The maximum length of a line. If set to 0 or is left empty, there "
            "is no maximum."),
        default="",
        required=0)
    max_length = fields.IntegerField(
        'max_length',
        title="Maximum length (in characters)",
        description=(
            "The maximum total length in characters that the user may enter. "
            "If set to 0 or is left empty, there is no maximum."),
        default="",
        required=0)

    too_many_lines = _('You entered too many lines.')
    line_too_long = _('A line was too long.')
    too_long = _('You entered too many characters.')

    def check(self, field, value, failover=False):
        if not isinstance(value, (list, tuple)):
            self.raise_error('not_a_list', field)

        result = []
        encoding = field.get_form_encoding()
        convert = field.get_value('unicode')
        whitespace_preserve = field.get_value('whitespace_preserve')
        if not failover:
            max_line_length = field.get_value('max_linelength') or 0
        else:
            max_line_length = 0
        for line in value:
            # Check each line
            if not whitespace_preserve:
                line = line.strip()
            if max_line_length and len(line) > max_line_length:
                self.raise_error('line_too_long', field)
            result.append(ensure_unicode(line, convert, encoding))

        # Check for input size
        if not failover:
            if not result and field.get_value('required'):
                self.raise_error('required_no_found', field)
            max_lines = field.get_value('max_lines') or 0
            if max_lines and len(result) > max_lines:
                self.raise_error('too_many_lines', field)
        return result

    def validate(self, field, key, REQUEST):
        value = REQUEST.get(key, "").strip()
        if isinstance(value, TaintedString):
            value = str(value)
        if not field.get_value('whitespace_preserve'):
            value = value.strip()

        # Check whether the entire input is too long
        max_length = field.get_value('max_length') or 0
        if max_length and len(value) > max_length:
            self.raise_error('too_long', field)

        # split input into separate lines
        value = value.split("\n")
        return self.check(field, value, key + '_novalidate' in REQUEST)

    def serializeValue(self, field, value, producer):
        value_string = '\n'.join(value)
        producer.characters(value_string)
Exemple #10
0
class OOoChartWidget(Widget.Widget):
  """
  This class is capabale of producing ODF
  charts based on data obtained through a
  listbox.
  Some properties are useless
  http://books.evc-cit.info/odbook/ch08.html#chart-plot-area-example
    - mean-value
    - error-margin
    - error-upper-limit
    - error-lower-limit
    - error-category
    - error-percentage
    - chart-japanese-candle-stick and stock-with-volume,chart:stock-updown-bars. These attributs are used with a chart:stock
  """

  property_names = list(Widget.Widget.property_names)

  # XXX The description says it's not used
  #     but removing 'default' breaks ODT/ODS rendering ...
  default = fields.StringField(
                              'default',
                              title='Default',
                              description=("A default value (not used)."),
                              default="",
                              required=0)

  listbox_form_id = fields.StringField(
                              'listbox_form_id',
                              title='ListBox Form ID',
                              description=("ID of the master form."),
                              default="",
                              required=0)
  property_names.append('listbox_form_id')

  listbox_id = fields.StringField(
                              'listbox_id',
                              title='ListBox ID',
                              description=("ID of the listbox in the master form."),
                              default="",
                              required=0)
  property_names.append('listbox_id')

  image_display = fields.ListField('image_display',
                              title='Image Display',
                              description=("Render size of this chart in HTML mode."),
                              default='medium',
                              items=[('thumbnail','thumbnail'),
                                    ('xsmall', 'xsmall'),
                                    ('small', 'small'),
                                    ('medium', 'medium'),
                                    ('large', 'large'),
                                    ('xlarge', 'xlarge'),
                                    ],
                              size=1)
  property_names.append('image_display')

  image_format = fields.StringField('image_format',
                              title='Image Format',
                              description=(
      "The format in which the chart should be converted to."),
                              default='png',
                              required=0)
  property_names.append('image_format')

  ooo_template = fields.StringField('ooo_template',
                              title='OOo Template',
                              description=('The ID of a OOo Page Template'
                                            'to render the ListBox'),
                              default='ERP5Site_viewChart',
                              required=0)
  property_names.append('ooo_template')


  chart_type = fields.ListField('chart_type',
                              title='Chart Type',
                              description=('Type of the Chart'),
                              default='chart:bar',
                              items=[('bar', 'chart:bar'),
                                    ('circle', 'chart:circle'),
                                    ('line', 'chart:line'),
                                    ('scatter', 'chart:scatter'),
                                    ('area', 'chart:area'),
                                    ],
                              size=0)
  property_names.append('chart_type')


  colour_column_list = fields.ListTextAreaField('colour_column_list',
                              title="Data Color",
                              description=(
    "A list of colors for each data associated to a column."),
                              default=[],
                              required=0)
  property_names.append('colour_column_list')

  # vertical ="true"
  chart_position = fields.ListField('chart_position',
                              title='Bar Position',
                              description=(
                    'Render the bar in horizontal position or vertical position'),
                              default='false',
                              items=[('horizontal', 'true'),
                                    ('vertical', 'false'),
                                    ],
                              size=0)
  property_names.append('chart_position')

  #legend of the chart or not
  chart_legend = fields.CheckBoxField('chart_legend',
                              title='Chart Legend',
                              description=('Show Chart Legend or no'),
                              default=1,
                              required=0)
  property_names.append('chart_legend')


  position_legend = fields.ListField('position_legend',
                              title='Legend Position',
                              description=(
                              'Legend Position according to the graph'),
                              default='end',
                              items=[('bottom', 'bottom'),
                                    ('end', 'end'),
                                    ('start', 'start'),
                                    ('top', 'top'),
                                    ],
                              size=1)
  property_names.append('position_legend')

  #legend of the chart or not
  chart_title_or_no = fields.CheckBoxField('chart_title_or_no',
                              title='Chart Title ',
                              description=('Show Title on Graph or no '),
                              default=1,
                              required=0)
  property_names.append('chart_title_or_no')

  # Axis
  x_axis_property_list = fields.ListTextAreaField('x_axis_property_list',
                              title="X-Axis Properties",
                              description="Examples of recognized properties:"
                                          " 'chart:visible',"
                                          " 'chart:display-label',"
                                          " 'chart:label-arrangement',"
                                          " 'chart:tick-marks-major-inner',"
                                          " 'chart:reverse-direction',"
                                          " 'chart:logarithmic',"
                                          " 'chart:text-overlap',"
                                          " 'chart:origin',"
                                          " 'text:line-break',"
                                          " 'style:rotation-angle'...",
                              default=(),
                              required=0)
  property_names.append('x_axis_property_list')

  y_axis_property_list = fields.ListTextAreaField('y_axis_property_list',
                              title="Y-Axis Properties",
                              default=(),
                              required=0)
  property_names.append('y_axis_property_list')

  #grid or not
  grid_graph = fields.CheckBoxField('grid_graph',
                              title='Chart Grid ',
                              description=('Show Grid or no'),
                              default=1,
                              required=0)
  property_names.append('grid_graph')


  grid_size = fields.ListField('grid_size',
                              title='Grid Size',
                              description=(
                              'Render a big grid size or a small grid size'),
                              default='major',
                              items=[('major', 'major'),
                                    ('minor', 'minor'),
                                    ],
                              size=0)
  property_names.append('grid_size')

  user_data_title = fields.StringField('user_data_title',
                              title="Overide Labelled Column ID",
                              description=(
    "Column Id choose by user to define the label."),
                              required=0)
  property_names.append('user_data_title')

  user_column_id_list = fields.ListTextAreaField('user_column_id_list',
                              title="Overide Column Ids",
                              description=(
    "A list of column Ids choose by user to draw the graph."),
                              default=[],
                              required=0)
  property_names.append('user_column_id_list')


  chart_stacked = fields.CheckBoxField('chart_stacked',
                              title='Stacked Data',
                              description=('stacked data or not'),
                              default=0,
                              required=0)
  property_names.append('chart_stacked')

  #connect-bars="false"
  connect_bars = fields.CheckBoxField('connect_bars',
                              title='Connect Bars',
                              description=(''),
                              default=0,
                              required=0)
  property_names.append('connect_bars')


  chart_three_dimensional = fields.CheckBoxField('chart_three_dimensional',
                              title='3D',
                              description=(
                      'Render the chart in three dimensions rather in flat mode'),
                              default=0,
                              required=0)
  property_names.append('chart_three_dimensional')

  #deep="false"
  deep = fields.CheckBoxField('deep',
                              title='Deep',
                              description=('Deep'),
                              default=0,
                              required=0)
  property_names.append('deep')

  # sector_pie_offset Default:0
  sector_pie_offset = fields.IntegerField('sector_pie_offset',
                              title='Sector Pie Offset',
                              description=(''),
                              default=0,
                              required=0)
  property_names.append('sector_pie_offset')


  #interpolation="none", cubic-spline, b-spline
  interpolation = fields.ListField('interpolation',
                              title='Interpolation',
                              description=(''),
                              default='none',
                              items=[('none', 'none'),
                                    ('cubic-spline', 'cubic-spline'),
                                    ('b-spline', 'b-spline')],
                              size=1)
  property_names.append('interpolation')

  #symbol-type="none", automatic
  symbol_type = fields.ListField('symbol_type',
                              title='Symbol Type',
                              description=(''),
                              default='none',
                              items=[('none', 'none'),
                                    ('automatic', 'automatic'),],
                              size=1)
  property_names.append('symbol_type')

  #lines-used="0"
  lines_used = fields.ListField('lines_used',
                              title='Lines Used',
                              description=(''),
                              default='0',
                              items=[('0', '0'),
                                      ('1', '1')],
                              size=1)
  property_names.append('lines_used')


  #series-source=columns or rows
  series_source = fields.ListField('series_source',
                              title='Series Source',
                              description=(''),
                              default='columns',
                              items=[('columns', 'columns'),
                                    ('rows', 'rows'),],
                              size=1)
  property_names.append('series_source')

  #regression-type="none" linear logarithmic exponential power
  regression_type = fields.ListField('regression_type',
                              title='Regression Type',
                              description=(''),
                              default='none',
                              items=[('none', 'none'),
                                    ('linear', 'linear'),
                                    ('logarithmic', 'logarithmic'),
                                    ('exponential', 'exponential'),
                                    ('power', 'power')],
                              size=1)
  property_names.append('regression_type')

  #data-label-number="none" value percentage
  data_label_number = fields.ListField('data_label_number',
                              title='Data Label Number',
                              description=(''),
                              default='none',
                              items=[('none', 'none'),
                                    ('value', 'value'),
                                    ('percentage', 'percentage')],
                              size=1)
  property_names.append('data_label_number')

  #data-label-text="false"
  data_label_text = fields.CheckBoxField('data_label_text',
                              title='Data Label Text',
                              description=(''),
                              default=0,
                              required=0)
  property_names.append('data_label_text')

  #data-label-symbol="false"
  data_label_symbol = fields.CheckBoxField('data_label_symbol',
                              title='Data Label Symbol',
                              description=(''),
                              default=0,
                              required=0)
  property_names.append('data_label_symbol')


  def getArgumentDict(self, field, REQUEST):
    """ Build argument Dict """
    def stringBoolean(value):
      return str(bool(value)).lower()
    form = field.aq_parent
    listbox_form_id = field.get_value('listbox_form_id')
    if listbox_form_id in ('', None):
      listbox_form_id = form.getId()
    listbox_id = field.get_value('listbox_id')
    if listbox_id in ('', None):
      listbox_id = 'listbox'
    render_prefix = REQUEST.get('render_prefix')
    extra_argument_dict = dict(
      render_prefix = render_prefix,
      chart_form_id = listbox_form_id,
      chart_field_id = listbox_id,
      chart_title = field.get_value('title'),
      chart_type = field.get_value('chart_type'),
      colour_column_list = field.get_value('colour_column_list'),
      user_column_id_list = field.get_value('user_column_id_list'),
      user_data_title= field.get_value('user_data_title'),
      chart_position = field.get_value('chart_position'),
      chart_legend = stringBoolean(field.get_value('chart_legend')),
      chart_title_or_no = stringBoolean(field.get_value('chart_title_or_no')),
      x_axis_property_dict = dict(field.get_value('x_axis_property_list')),
      y_axis_property_dict = dict(field.get_value('y_axis_property_list')),
      grid_graph = stringBoolean(field.get_value('grid_graph')),
      grid_size=field.get_value('grid_size'),
      chart_three_dimensional = stringBoolean(field.get_value('chart_three_dimensional')),
      deep = stringBoolean(field.get_value('deep')),
      chart_stacked = stringBoolean(field.get_value('chart_stacked')),
      sector_pie_offset = field.get_value('sector_pie_offset'),
      interpolation = field.get_value('interpolation'),
      symbol_type = field.get_value('symbol_type'),
      lines_used = field.get_value('lines_used'),
      connect_bars = stringBoolean(field.get_value('connect_bars')),
      series_source = field.get_value('series_source'),
      regression_type = field.get_value('regression_type'),
      data_label_number = field.get_value('data_label_number'),
      data_label_text = stringBoolean(field.get_value('data_label_text')),
      data_label_symbol = stringBoolean(field.get_value('data_label_symbol')),
      position_legend=field.get_value('position_legend'),
    )

    for k, v in extra_argument_dict.items():
      if REQUEST.get(k) is None:
        REQUEST.form[k] = v
    return extra_argument_dict


  def render_view(self, field, value, REQUEST=None, key=None, render_format='html', render_prefix=None):
    """
      Render a Chart in read-only.
    """
    if REQUEST is None: REQUEST=get_request()
    return self.render(field, key, value, REQUEST, render_format=render_format,
                       render_prefix=render_prefix)


  def render_odf(self, field, key, value, REQUEST, render_format='ooo',
                 render_prefix=None):
    """
      Render a Chart for ODT Style.
    """
    if REQUEST is None: REQUEST=get_request()
    form = field.aq_parent
    here = getattr(form, 'aq_parent', REQUEST)
    REQUEST.set('render_prefix', render_prefix)
    #needed to update REQUEST
    argument_dict = self.getArgumentDict(field, REQUEST)
    from xml.marshal.generic import dumps
    dump_args = dumps(argument_dict)
    #remove xml declaration (first processing node)
    dump_args = dump_args[dump_args.index('?>')+2:]
    content = '''<office:include path="%s/ERP5Site_buildChart"
                                 xlink:type="simple" xlink:actuate="onLoad"
                                 xlink:show="embed">%s</office:include>
                                 ''' % (here.getPath(), dump_args)
    return content


  def render(self, field, key, value, REQUEST, render_format='html', render_prefix=None):

    """
      Render a chart.

      render_format   -- If the format is set to html, render the chart
                         as a URL to ourselves with a png render_format

                         If the format is set to 'raw', render the chart
                         as raw XML.

                         If the format is set to an image type (ex. png)
                         render the chart using that format.
    """
    title = field.get_value('title')
    alt = field.get_value('description') or title
    form = field.aq_parent
    if not render_prefix:
      render_prefix = REQUEST.get('render_prefix')
    # Find the applicable context
    here = getattr(form, 'aq_parent', REQUEST)
    # Update the render format based on REQUEST parameters
    render_format = getattr(REQUEST, 'render_format', render_format)
    if render_format == 'html':
      css_class = field.get_value('css_class')
      format = field.get_value('image_format') or 'png'
      query_dict = dict(REQUEST.form.items())
      query_dict.update(render_format=format != 'raw' and format or '',
                        render_prefix=render_prefix,
                        display=field.get_value('image_display'))
      # XXX make_query does not handle tuples properly so listbox should be
      #     not editable (otherwise, REQUEST.form may contain listbox=()).
      url = '%s/%s/%s?%s' % (here.absolute_url(), form.getId(), field.getId(),
                             make_query(query_dict))
      if format in VALID_IMAGE_FORMAT_LIST:
        return '''<div class="OOoChartContent">
          <img class="%s" src="%s" title="%s" alt="%s"/">
          </div>''' % (css_class,
                       url,
                       title,
                       alt)
      elif format == 'raw':
        UrlIconOOo = '%s/misc_/ERP5OOo/OOo.png' % REQUEST['BASEPATH1']
        return '''<div class="OOoChartContent">
          <a href="%s"><img src="%s" alt="OOo"/></a>
          </div>''' % (url,
                       UrlIconOOo)
      elif format == 'pdf':
        UrlIconPdf = '%s/misc_/ERP5Form/PDF.png' % REQUEST['BASEPATH1']
        return '''<div class="OOoChartContent">
          <a href="%s"><img src="%s" alt="PDF" /></a>
          </div>''' % (url,
                       UrlIconPdf)
      else:
        raise NotImplementedError, 'Format: %s not handled' % format

    extra_context = self.getArgumentDict(field, REQUEST)

    method_id = field.get_value('ooo_template')

    # Find the page template
    ooo_template = getattr(here, method_id)

    # Render the chart
    return ooo_template(format=render_format, **extra_context)
Exemple #11
0
class MultiRelationStringFieldWidget(Widget.LinesTextAreaWidget,
                                     Widget.TextWidget, Widget.ListWidget):
    """
  RelationStringField widget
  Works like a string field but includes one buttons
  - one search button which updates the field and sets a relation
  - creates object if not there
  """
    local_property_names = [
        'update_method',
        'jump_method',
        'allow_jump',
        'base_category',
        'portal_type',
        'allow_creation',
        'container_getter_id',
        'context_getter_id',
        'catalog_index',
        'relation_setter_id',
        'relation_form_id',
        'columns',
        'sort',
        'parameter_list',
        'list_method',
        'first_item',
        'items',
        'proxy_listbox_ids',
        'size',
        'extra_item',
    ]

    property_names = Widget.LinesTextAreaWidget.property_names + \
                     Widget.TextWidget.property_names + \
                     local_property_names

    # XXX Field to remove...
    update_method = fields.StringField(
        'update_method',
        title='Update Method',
        description=("The method to call to set the relation. Required."),
        default="Base_validateRelation",
        required=1)

    jump_method = fields.StringField(
        'jump_method',
        title='Jump Method',
        description=("The method to call to jump to the relation. Required."),
        default="Base_jumpToRelatedDocument",
        required=1)

    allow_jump = fields.CheckBoxField(
        'allow_jump',
        title='Allow Jump',
        description=("Do we allow to jump to the relation ?"),
        default=1,
        required=0)

    base_category = fields.StringField(
        'base_category',
        title='Base Category',
        description=("The method to call to set the relation. Required."),
        default="",
        required=1)

    portal_type = fields.ListTextAreaField(
        'portal_type',
        title='Portal Type',
        description=("The method to call to set the relation. Required."),
        default="",
        required=1)

    allow_creation = fields.CheckBoxField(
        'allow_creation',
        title='Allow Creation',
        description=("Do we allow to create new objects ?"),
        default=1,
        required=0)

    container_getter_id = fields.StringField(
        'container_getter_id',
        title='Container Getter Method',
        description=("The method to call to get a container object."),
        default="",
        required=0)

    context_getter_id = fields.StringField(
        'context_getter_id',
        title='Context Getter Method',
        description=("The method to call to get the context."),
        default="",
        required=0)

    catalog_index = fields.StringField(
        'catalog_index',
        title='Catalog Index',
        description=("The method to call to set the relation. Required."),
        default="",
        required=1)

    # XXX Is it a good idea to keep such a field ??
    # User can redefine setter method with a script (and so, don't use the API)
    relation_setter_id = fields.StringField(
        'relation_setter_id',
        title='Relation Update Method',
        description=("The method to invoke in order to update the relation"),
        default="",
        required=0)

    relation_form_id = fields.StringField(
        'relation_form_id',
        title='Relation Form',
        description=("Form to display relation choices"),
        default="",
        required=0)

    size = fields.IntegerField(
        'size',
        title='Size',
        description=(
            "The display size in rows of the field. If set to 1, the "
            "widget will be displayed as a drop down box by many browsers, "
            "if set to something higher, a list will be shown. Required."),
        default=1,
        required=1)

    columns = fields.ListTextAreaField(
        'columns',
        title="Columns",
        description=("A list of attributes names to display."),
        default=[],
        required=0)

    sort = fields.ListTextAreaField(
        'sort',
        title='Default Sort',
        description=('The default sort keys and order'),
        default=[],
        required=0)

    parameter_list = fields.ListTextAreaField(
        'parameter_list',
        title="Parameter List",
        description=("A list of paramters used for the portal_catalog."),
        default=[],
        required=0)

    list_method = fields.MethodField('list_method',
                                     title='List Method',
                                     description=('The method to use to list'
                                                  'objects'),
                                     default='',
                                     required=0)

    proxy_listbox_ids = fields.ListTextAreaField(
        'proxy_listbox_ids',
        title='Proxy Listbox IDs',
        description=('A list of listbox that can be used as proxy'),
        default='',
        required=0)

    # delete double in order to keep a usable ZMI...
    # XXX need to keep order !
    #property_names = dict([(i,0) for i in property_names]).keys()
    _v_dict = {}
    _v_property_name_list = []
    for property_name in property_names:
        if not _v_dict.has_key(property_name):
            _v_property_name_list.append(property_name)
            _v_dict[property_name] = 1
    property_names = _v_property_name_list

    default_widget_rendering_instance = Widget.LinesTextAreaWidgetInstance

    def _getContextValue(self, field, REQUEST):
        """Return result of evaluated method
    defined by context_getter_id or here.
    """
        context_getter_id = field.get_value('context_getter_id')
        here = REQUEST['here']
        if context_getter_id:
            return getattr(here, context_getter_id)()
        return here

    def _generateRenderValueList(self, field, key, value_list, REQUEST):
        result_list = []
        need_validation = 0
        ####################################
        # Check value
        ####################################
        if isinstance(value_list, StringType):
            # Value is a string, reformat it correctly
            value_list = value_list.split("\n")
        else:
            # We get a list
            # rather than displaying nothing, display a marker when the
            # property is not set
            # XXX Translate ?
            value_list = [(x or NO_VALUE) for x in value_list]
        # Check all relation
        for i in range(len(value_list)):
            ###################################
            # Sub field
            ###################################
            relation_field_id = field.generate_subfield_key("%s_%s" % \
                                                            (SUB_FIELD_ID, i),
                                                            key=key)
            relation_item_id = field.generate_subfield_key("%s_%s" % \
                                                           (ITEM_ID, i),
                                                           key=key)
            relation_item_list = REQUEST.get(relation_item_id, None)
            value = value_list[i]
            if (relation_item_list is not None) and \
               (value != ''):
                need_validation = 1
            # If we get a empty string, display nothing !
            if value != '':
                result_list.append(
                    (Widget.TextWidgetInstance, relation_field_id,
                     relation_item_list, value, i))
        if not need_validation:
            ###################################
            # Main field
            ###################################
            result_list = [(Widget.LinesTextAreaWidgetInstance, None, [],
                            value_list, None)]
        return result_list

    def render(self, field, key, value, REQUEST, render_prefix=None):
        """
    Render text input field.
    """
        html_string = ''
        relation_field_index = REQUEST.get('_v_relation_field_index', 0)
        render_parameter_list = self._generateRenderValueList(
            field, key, value, REQUEST)
        ####################################
        # Render subfield
        ####################################
        html_string_list = []
        for widget_instance, relation_field_id, relation_item_list, \
                                value_instance, sub_index in render_parameter_list:
            sub_html_string = widget_instance.render(field, key,
                                                     value_instance, REQUEST)

            here = self._getContextValue(field, REQUEST)
            portal = here.getPortalObject()
            autocomplete_enabled = getattr(portal.portal_skins,
                                           'erp5_autocompletion_ui', None)

            if autocomplete_enabled:
                sub_html_string += self.render_autocomplete(field, key)

            if relation_item_list is not None:
                ####################################
                # Render wheel
                ####################################
                if not autocomplete_enabled:
                    sub_html_string += self.render_wheel(
                        field,
                        value_instance,
                        REQUEST,
                        relation_index=relation_field_index,
                        sub_index=sub_index)

                if relation_item_list:
                    ####################################
                    # Render listfield
                    ####################################

                    REQUEST['relation_item_list'] = relation_item_list
                    sub_html_string += '&nbsp;%s&nbsp;' % \
                                          Widget.ListWidgetInstance.render(
                                          field, relation_field_id, None, REQUEST)
                    REQUEST['relation_item_list'] = None

            html_string_list.append(sub_html_string)
        ####################################
        # Generate html
        ####################################
        html_string = '<br/>'.join(html_string_list)
        ####################################
        # Render jump
        ####################################
        if (value == field.get_value('default')):
            # XXX Default rendering with value...
            relation_html_string = self.render_relation_link(
                field, value, REQUEST)
            if relation_html_string != '':
                html_string += '&nbsp;&nbsp;%s' % relation_html_string
        ####################################
        # Update relation field index
        ####################################
        REQUEST.set('_v_relation_field_index', relation_field_index + 1)
        return html_string

    def render_view(self, field, value, REQUEST=None, render_prefix=None):
        """
    Render read only field.
    """
        html_string = ''
        here = self._getContextValue(field, REQUEST)
        portal_url = here.getPortalObject().portal_url
        portal_url_string = portal_url()
        if (value not in ((), [], None, '')) and \
            field.get_value('allow_jump'):
            string_list = []
            base_category = field.get_value('base_category')
            portal_type = map(lambda x: x[0], field.get_value('portal_type'))
            kw = {}
            for k, v in field.get_value('parameter_list'):
                kw[k] = v
            accessor_name = 'get%sValueList' % ''.join(
                [part.capitalize() for part in base_category.split('_')])
            jump_reference_list = getattr(here, accessor_name)(
                portal_type=portal_type, filter=kw)
            if not isinstance(value, (list, tuple)):
                value = value,
            for jump_reference, display_value in zip(jump_reference_list,
                                                     value):
                string_list.append('<a class="relationfieldlink" href="%s">%s</a>' % \
                        (jump_reference.absolute_url(),
                         display_value))
            html_string = '<br />'.join(string_list)
        else:
            html_string = self.default_widget_rendering_instance.render_view(
                field, value, REQUEST=REQUEST)
            if REQUEST is None:
                REQUEST = get_request()
            relation_html_string = self.render_relation_link(
                field, value, REQUEST)
            if relation_html_string != '':
                html_string += '&nbsp;&nbsp;%s' % relation_html_string
        extra = field.get_value('extra')
        if extra not in (None, ''):
            html_string = "<div %s>%s</div>" % (extra, html_string)
        css_class = field.get_value('css_class')
        if css_class not in ('', None):
            # All strings should be escaped before rendering in HTML
            # except for editor field
            html_string = "<span class='%s'>%s</span>" % (css_class,
                                                          html_string)
        return html_string

    def render_autocomplete(self, field, key):
        """
    Use jquery-ui autocompletion for all relation fields by default, requiring
    only erp5_autocompletion_ui bt5 to be installed
    """
        # XXX: Allow to specify more parameters to jquery-ui autocomplete widget?
        import json
        return """
<script type="text/javascript">
$(document).ready(function() {
  $("input[name='%s']").ERP5Autocomplete({search_portal_type: %s,
                                          search_catalog_key: "%s"});
});
</script>""" % (key,
                json.dumps(map(lambda x: x[0],
                               field.get_value('portal_type'))),
                field.get_value('catalog_index'))

    def render_wheel(self,
                     field,
                     value,
                     REQUEST,
                     relation_index=0,
                     sub_index=None,
                     render_prefix=None):
        """
    Render wheel used to display a listbox
    """
        here = self._getContextValue(field, REQUEST)
        portal_url = here.getPortalObject().portal_url
        portal_url_string = portal_url()
        portal_selections_url_string = here.portal_url.getRelativeContentURL(
            here.portal_selections)
        if sub_index is None:
            sub_index_string = ''
        else:
            sub_index_string = '_%s' % sub_index
        return '&nbsp;<input type="image" ' \
             'src="%s/images/exec16.png" value="update..." ' \
             'name="%s/viewSearchRelatedDocumentDialog%s%s' \
             ':method"/>' % \
               (portal_url_string, portal_selections_url_string,
               relation_index, sub_index_string)

    def render_relation_link(self, field, value, REQUEST, render_prefix=None):
        """
    Render link to the related object.
    """
        html_string = ''
        here = REQUEST.get('cell', self._getContextValue(field, REQUEST))
        portal_url = here.getPortalObject().portal_url
        portal_url_string = portal_url()
        if (value not in ((), [], None, '')) and \
            field.get_value('allow_jump'):
            # Keep the selection name in the URL
            if REQUEST.get('selection_name') is not None:
                selection_name_html = '&amp;selection_name=%s&amp;selection_index=%s' % \
                      (REQUEST.get('selection_name'), REQUEST.get('selection_index'))
            else:
                selection_name_html = ''
            if REQUEST.get('ignore_layout') is not None:
                selection_name_html += '&amp;ignore_layout:int=%s' % int(
                    REQUEST.get('ignore_layout', 0))
            # Generate plan link
            html_string += '<a href="%s/%s?field_id=%s&amp;form_id=%s%s">' \
                             '<img src="%s/images/jump.png" alt="jump" />' \
                           '</a>' % \
                      (here.absolute_url(),
                       field.get_value('jump_method'),
                       field.id, field.aq_parent.id,
                       selection_name_html,
                       portal_url_string)
        return html_string
Exemple #12
0
class ImageFieldWidget(Widget.TextWidget):
    """ImageField widget.

    Renders an HTML <img> element where the src is the 'default' field value.
    The 'description' field value is used as 'alt' attribute.
    The image size is calculated using 'image_display'.
    """
    property_names = Widget.TextWidget.property_names + \
      ['image_display', 'image_format','image_quality', 'image_pre_converted_only']

    image_display = fields.StringField(
        'image_display',
        title='Image Display',
        description=
        ("The display size. See erp5.component.document.Image.default_displays_id_list "
         "for possible values. This is only used with ERP5 Images."),
        default='thumbnail',
        required=0)

    image_format = fields.StringField(
        'image_format',
        title='Image Format',
        description=("The format in which the image should be converted to. "
                     "This is only used with ERP5 Images."),
        default='',
        required=0)

    image_quality = fields.IntegerField(
        'image_quality',
        title='Image Quality',
        description=("The quality used when converting the image. "
                     "This is only used with ERP5 Images."),
        default=75,
        required=0)

    image_pre_converted_only = fields.CheckBoxField(
        'image_pre_converted_only',
        title='Image Pre Converted Only',
        description=(
            "Return image only if it is already pre converted in cache. "
            "This is only used with ERP5 Images."),
        default=False,
        required=0)

    def render(self, field, key, value, REQUEST, render_prefix=None):
        """Render image field as a link to the image
        """
        return self.render_view(field, value, REQUEST=REQUEST)

    def render_view(self, field, value, REQUEST=None, render_prefix=None):
        """Render image field as a link to the image
        """
        # Url is already defined in value
        if value is None:
            return ''
        image = value
        alt = field.get_value('description') or \
              field.get_value('title')
        css_class = field.get_value('css_class')
        extra = field.get_value('extra')
        options = {}
        options['display'] = field.get_value('image_display')
        options['format'] = field.get_value('image_format')
        options['quality'] = field.get_value('image_quality')
        pre_converted_only = field.get_value('image_pre_converted_only')
        if pre_converted_only:
            # only add if it's True as conversion machine assume that if it is missing
            # then conversion should happen "on the fly"
            options['pre_converted_only'] = pre_converted_only
        parameters = '&'.join(['%s=%s' % (k, v) for k, v in options.items() \
                               if v])
        if parameters:
            image = '%s?%s' % (image, parameters)
        return Widget.render_element(
            "img",
            alt=alt,
            src=image,
            css_class=css_class,
            extra=extra,
        )

    def render_odg_view(self, field, value, as_string, ooo_builder, REQUEST,
                        render_prefix, attr_dict, local_name):
        """
        return an image xml node rendered in odg format
        if as_string is True (default) the returned value is a string (xml
        reprensation of the node), if it's False, the value returned is the node
        object.
        attr_dict can be used for additional parameters (like style).
      """
        if attr_dict is None:
            attr_dict = {}
        draw_frame_node = None
        if value in ('', None):
            return None
        path = '/'.join(REQUEST.physicalPathFromURL(value))
        path = path.encode()
        image_object = field.getPortalObject().restrictedTraverse(path)
        display = field.get_value('image_display')
        format = field.get_value('image_format')
        quality = field.get_value('image_quality')
        image_parameter_dict = {'format': format}
        if display:
            image_parameter_dict['display'] = display
        if quality:
            image_parameter_dict['quality'] = quality
        # convert the image using fields parameters. In this way, if an image
        # is displayed in the form as a thumbnail, it will be added in the odg
        # document as thumbnail size/quality
        content_type, image_data = image_object.convert(**image_parameter_dict)
        image = OFSImage('', '', image_data)
        width = image.width
        height = image.height
        if image_data is None:
            return draw_frame_node

        # Big images are cut into smaller chunks, so it's required to cast to
        # str. See OFS/Image -> _read_data method for more information
        image_data = str(image_data)

        format = content_type.split('/')[-1]
        # add the image to the odg document
        picture_path = ooo_builder.addImage(image=image_data,
                                            format=format,
                                            content_type=content_type)

        # create the xml nodes related to the image
        draw_frame_tag_name = '{%s}%s' % (DRAW_URI, 'frame')
        draw_frame_node = Element(draw_frame_tag_name, nsmap=NSMAP)
        draw_frame_node.attrib.update(
            attr_dict.get(draw_frame_tag_name, {}).pop(0))

        # set the size of the image
        if display is not None:
            # if the image width and height are not on defined, use current
            # width and height
            if (image_object.getWidth(), image_object.getHeight()) not in \
              ((-1, -1), (0,0)):
                width, height = image_object._getAspectRatioSize(width, height)
                if draw_frame_node.attrib.get('{%s}width' % SVG_URI) and \
                  draw_frame_node.attrib.get('{%s}height' % SVG_URI):
                    # if a size already exist from attr_dict, try to resize the image to
                    # fit this size (image should not be biger than size from attr_dict)
                    # devide the value by 20 to have cm instead of px
                    width, height = self._getPictureSize(
                        width / 20.,
                        height / 20.,
                        target_width=draw_frame_node.attrib.get(
                            '{%s}width' % SVG_URI, ''),
                        target_height=draw_frame_node.attrib.get(
                            '{%s}height' % SVG_URI, ''))

                draw_frame_node.set('{%s}width' % SVG_URI, str(width))
                draw_frame_node.set('{%s}height' % SVG_URI, str(height))

        image_tag_name = '{%s}%s' % (DRAW_URI, 'image')
        image_node = Element(image_tag_name, nsmap=NSMAP)
        image_node.attrib.update(attr_dict.get(image_tag_name, []).pop())
        image_node.set('{%s}href' % XLINK_URI, picture_path)

        draw_frame_node.append(image_node)
        if as_string:
            return etree.tostring(draw_frame_node)
        return draw_frame_node

    def _getPictureSize(self, picture_width, picture_height, target_width,
                        target_height):
        # if not match causes exception
        width_tuple = re.match("(\d[\d\.]*)(.*)", target_width).groups()
        height_tuple = re.match("(\d[\d\.]*)(.*)", target_height).groups()
        unit = width_tuple[1]
        w = float(width_tuple[0])
        h = float(height_tuple[0])
        aspect_ratio = 1
        try:  # try image properties
            aspect_ratio = picture_width / picture_height
        except (TypeError, ZeroDivisionError):
            try:  # try Image Document API
                height = picture_height
                if height:
                    aspect_ratio = picture_width / height
            except AttributeError:  # fallback to Photo API
                height = float(picture_height)
                if height:
                    aspect_ratio = picture_width / height
        resize_w = h * aspect_ratio
        resize_h = w / aspect_ratio
        if resize_w < w:
            w = resize_w
        elif resize_h < h:
            h = resize_h
        return (str(w) + unit, str(h) + unit)