Re: [Zope3-Users] MultiWidget

2009-01-22 Thread Christian Lück
Hi Roger,

Roger Ineichen wrote:
 Hi Christian
 
 Betreff: [Zope3-Users] MultiWidget

 Hi,

 the new MultiWidget in z3c.form is great! I like the way 
 input errors are reported. Thank you for this!

 To help the users of my app a little I was thinking about 
 conditions for the the add and remove buttons. I think the 
 old tuple-sequence widget in zope.app.form had such a 
 feature.  I want the add button to appear only if the number 
 of subwidgets is below the max_length in the schema. And the 
 remove button (and even the select boxes) should only appear 
 if the number of subwidgets exceeds the min_length of the 
 schema or zero. -- Well, OK, one might run into an inregular 
 state when selecting several widgets for removal so that the 
 min_length is violated. But, at least there should not be a 
 remove button if the number of subwidgets equals zero, and no 
 add button should appear if the number of subwidgets equals 
 (or exceeds) max_length.

 To achive this I started with conditions for the buttons. But 
 the problem is that the button conditions are checked very 
 early during the setup of the widget when one can't yet get 
 the number of subwidgets form '_value'-attribute or 
 'widgets'-attribute of the MultiWidget instance.
 So the more general question is: How would one check button 
 conditions that depend on a widget's state (number of 
 subwidgets, values...)?

 Do you have you a hint for me?
 
 Try to call updateActions *again* after action.execute get called.
 
 def update(self):
 self.updateWidgets()
 self.updateActions()
 self.actions.execute()
 # update action conditions they get probably changed by execute
 self.updateActions()
 

thanks for your answer. I think it has put me on the right track. But
I've not arrived yet.

With calling self.updateActions() on the end of the update process the
conditions are correctly handled. Great!
But I've run into new problems with the actions now. I'm totally stuck
there and doen't even know how to describe the problem well. Sorry, it
is more a phenemological description than a good analysis... Hm, the
actions are not correctly bound to the button events.
1) With the update-method you suggested: When the remove-button is
present, the add-button is not bound to the add-action. Information on
all other multiwidgets in the form is lost (zero subwidgets).
2) Alternatively I've tried

def update(self):
super(MyMultiWidget, self).update()
self.updateActions()

This seems better: We don't loose information on other multiwidgets in
the form any more. But now the remove-button is not bound to the
remove-action (while adding works fine).


I also noticed that checking the length of the widgets-attribute instead
of the value_-attribute is the way to go. For no value is added on an
add-action but a widget. (And I noticed that min_length is not an
attribute of the field.value_type but of the field-attribute itself.) So
the code is now

import zope.interface
from z3c.form import widget, button, interfaces
from z3c.form.browser import multi
from zope.i18n import translate
import zope.i18nmessageid

_ = zope.i18nmessageid.MessageFactory(zope)


class MultiWidget(multi.MultiWidget):

buttons = button.Buttons() # reset buttons

showLabel = False

def addButtonLabel(self):
button_label = _('Add %s')
button_label = translate(button_label, context=self.request,
 default=button_label)
title = getattr(self.field.value_type, 'title', _(uan item))
title = translate(title, context=self.request)
return button_label % title

@button.buttonAndHandler(_(uAdd an item),
 name = add,
 condition = lambda form: form.needAdd(),
 )
def handleAdd(self, action):
self.appendAddingWidget()

def needAdd(self):
max_length = getattr(self.field, 'max_length', None)
if max_length is None:
return True
else:
return len(self.widgets)  max_length

@button.buttonAndHandler(_(remove-selected-items,
   uRemove selected items),
 name = remove,
 condition = lambda form: form.needRemove(),
 )
def handleRemove(self, action):
see z3c.form.browser.multi.MultiWidget.handleRemove()
self.widgets = [widget for widget in self.widgets
if ('%s.remove' % (widget.name)) not in
self.request]
self.value = [widget.value for widget in self.widgets]

def needRemove(self):
min_length = getattr(self.field, 'min_length', 0)
return len(self.widgets)  min_length

def updateActions(self):
Use as a hook to make a nice add button label.
self.buttons['add'].title = self.addButtonLabel()
super(MultiWidget, self).updateActions()

def update(self

Re: [Zope3-Users] MultiWidget

2009-01-22 Thread Christian Lück
Christian Lück wrote:
 Hi Roger,
 
 Roger Ineichen wrote:
 Hi Christian

 Betreff: [Zope3-Users] MultiWidget

 Hi,

 the new MultiWidget in z3c.form is great! I like the way 
 input errors are reported. Thank you for this!

 To help the users of my app a little I was thinking about 
 conditions for the the add and remove buttons. I think the 
 old tuple-sequence widget in zope.app.form had such a 
 feature.  I want the add button to appear only if the number 
 of subwidgets is below the max_length in the schema. And the 
 remove button (and even the select boxes) should only appear 
 if the number of subwidgets exceeds the min_length of the 
 schema or zero. -- Well, OK, one might run into an inregular 
 state when selecting several widgets for removal so that the 
 min_length is violated. But, at least there should not be a 
 remove button if the number of subwidgets equals zero, and no 
 add button should appear if the number of subwidgets equals 
 (or exceeds) max_length.

 To achive this I started with conditions for the buttons. But 
 the problem is that the button conditions are checked very 
 early during the setup of the widget when one can't yet get 
 the number of subwidgets form '_value'-attribute or 
 'widgets'-attribute of the MultiWidget instance.
 So the more general question is: How would one check button 
 conditions that depend on a widget's state (number of 
 subwidgets, values...)?

 Do you have you a hint for me?
 Try to call updateActions *again* after action.execute get called.

 def update(self):
 self.updateWidgets()
 self.updateActions()
 self.actions.execute()
 # update action conditions they get probably changed by execute
 self.updateActions()

 
 thanks for your answer. I think it has put me on the right track. But
 I've not arrived yet.
 
 With calling self.updateActions() on the end of the update process the
 conditions are correctly handled. Great!
 But I've run into new problems with the actions now. I'm totally stuck
 there and doen't even know how to describe the problem well. Sorry, it
 is more a phenemological description than a good analysis... Hm, the
 actions are not correctly bound to the button events.

Ok, here comes the analysis:

 1) With the update-method you suggested: When the remove-button is
 present, the add-button is not bound to the add-action. Information on
 all other multiwidgets in the form is lost (zero subwidgets).

The reason for losing all info is simply that the update-method of
z3c.form.widget.Widget is never called.

 2) Alternatively I've tried
 
 def update(self):
   super(MyMultiWidget, self).update()
   self.updateActions()
 
 This seems better: We don't loose information on other multiwidgets in
 the form any more. But now the remove-button is not bound to the
 remove-action (while adding works fine).
 

There is a button but no action. I guess it is still a runtime problem.
The actions, too, are created early in the setup process and the
condition for the button fails at this time. So there is probably no
action created. I guess there problem occurs as a consequence of line
260 of z3c.form/z3c/form/button.py:
Only if the condition is fullfilled an action is created.
I played around with the code and changed continue to pass. But that
then, I get a button all time, even if the condition fails. Arrg

What should I do?

 
 I also noticed that checking the length of the widgets-attribute instead
 of the value_-attribute is the way to go. For no value is added on an
 add-action but a widget. (And I noticed that min_length is not an
 attribute of the field.value_type but of the field-attribute itself.) So
 the code is now
 
 import zope.interface
 from z3c.form import widget, button, interfaces
 from z3c.form.browser import multi
 from zope.i18n import translate
 import zope.i18nmessageid
 
 _ = zope.i18nmessageid.MessageFactory(zope)
 
 
 class MultiWidget(multi.MultiWidget):
 
 buttons = button.Buttons() # reset buttons
 
 showLabel = False
 
 def addButtonLabel(self):
 button_label = _('Add %s')
 button_label = translate(button_label, context=self.request,
  default=button_label)
 title = getattr(self.field.value_type, 'title', _(uan item))
 title = translate(title, context=self.request)
 return button_label % title
 
 @button.buttonAndHandler(_(uAdd an item),
  name = add,
  condition = lambda form: form.needAdd(),
  )
 def handleAdd(self, action):
 self.appendAddingWidget()
 
 def needAdd(self):
 max_length = getattr(self.field, 'max_length', None)
 if max_length is None:
 return True
 else:
 return len(self.widgets)  max_length
 
 @button.buttonAndHandler(_(remove-selected-items,
uRemove selected items),
  name

[Zope3-Users] MultiWidget

2009-01-18 Thread Christian Lück
Hi,

the new MultiWidget in z3c.form is great! I like the way input errors
are reported. Thank you for this!

To help the users of my app a little I was thinking about conditions for
the the add and remove buttons. I think the old tuple-sequence widget in
zope.app.form had such a feature.  I want the add button to appear only
if the number of subwidgets is below the max_length in the schema. And
the remove button (and even the select boxes) should only appear if the
number of subwidgets exceeds the min_length of the schema or zero. --
Well, OK, one might run into an inregular state when selecting several
widgets for removal so that the min_length is violated. But, at least
there should not be a remove button if the number of subwidgets equals
zero, and no add button should appear if the number of subwidgets equals
(or exceeds) max_length.

To achive this I started with conditions for the buttons. But the
problem is that the button conditions are checked very early during the
setup of the widget when one can't yet get the number of subwidgets form
'_value'-attribute or 'widgets'-attribute of the MultiWidget instance.
So the more general question is: How would one check button conditions
that depend on a widget's state (number of subwidgets, values...)?

Do you have you a hint for me?

I code I was trying:

import zope.interface
from z3c.form import widget, button, interfaces
from z3c.form.browser import multi
from zope.i18n import translate
import zope.i18nmessageid

_ = zope.i18nmessageid.MessageFactory(zope)


class MultiWidget(multi.MultiWidget):

buttons = button.Buttons() # reset buttons

showLabel = False

def addButtonLabel(self):
button_label = _('Add %s')
button_label = translate(button_label, context=self.request,
 default=button_label)
title = getattr(self.field.value_type, 'title', _(uan item))
title = translate(title, context=self.request)
return button_label % title

@button.buttonAndHandler(_(uAdd an item),
 name = add,
 condition = lambda form: form.needAdd(),
 )
def handleAdd(self, action):
self.appendAddingWidget()

def needAdd(self):
# TODO: this gets called before the widgets are updated and we
# still have self._value == []. So always True is returned
max_length = getattr(self.field.value_type, 'max_lenght', None)
if max_length is None:
return True
else:
return len(self._value)  max_length

@button.buttonAndHandler(_(remove-selected-items,
   uRemove selected items),
 name = remove,
 condition = lambda form: form.needRemove(),
 )
def handleRemove(self, action):
see z3c.form.browser.multi.MultiWidget.handleRemove()
self.widgets = [widget for widget in self.widgets
if ('%s.remove' % (widget.name)) not in
self.request]
self.value = [widget.value for widget in self.widgets]

def needRemove(self):
# TODO: This gets called before the widgets are updated and
# len(self._value) == 0.
min_length = getattr(self.field.value_type, 'min_length', 0)
return len(self._value)  min_length

def updateActions(self):
Use as a hook to make a nice add button label.
self.buttons['add'].title = self.addButtonLabel()
super(MultiWidget, self).updateActions()


@zope.interface.implementer(interfaces.IFieldWidget)
def multiFieldWidgetFactory(field, request):
return widget.FieldWidget(field, MultiWidget(request))


@zope.interface.implementer (interfaces.IFieldWidget)
def MultiFieldWidget(field, value_type, request):
return multiFieldWidgetFactory(field, request)


Regards,
Christian
___
Zope3-users mailing list
Zope3-users@zope.org
http://mail.zope.org/mailman/listinfo/zope3-users