enabled_when listening outside model object

203 views Asked by At

I found a workaround to my original problem but I am hoping someone else can explain what is going on. I originally noticed that enabled_when, and I'd imagine visible_when also, appears to take effect in response to trait events originating from the model object only. If the event originates from some other object, even if the editor refers to it, it doesn't seem to be propagated correctly.

class DirectObjectPronoun(HasTraits):
    text=Str
    typable=Bool(False)

    traits_view=View(
        Item(name='typable'),
        Item(name='text',enabled_when='typable'))

class IndirectObjectPronoun(HasTraits):
    referent=Instance(DirectObjectPronoun,())

    traits_view=View(
        Item(name='typable',object='object.referent'),
        Item(name='text',object='object.referent',
            enabled_when='object.referent.typable'))

IndirectObjectPronoun().configure_traits()

The desired behavior is that the text window is enabled when typable is True and disabled otherwise. The observed behavior is that the text window is always disabled (though if the default value of typable is set to True then it is always enabled, so the problem must be in the listener.)

If a DirectObjectPronoun is edited directly, the disabling works as intended.

I found a workaroud that that I don't understand.

class IndirectObjectPronoun(HasTraits):
    stupid_listener=Bool
    referent=Instance(DirectObjectPronoun,())

    traits_view=View(
        Item(name='typable',object='object.referent'),
        Item(name='text',object='object.referent',
            enabled_when='object.referent.typable'))

    @on_trait_change('referent.typable')
    def _stupid_listener_listens_stupidly(self):
        self.stupid_listener=self.referent.typable

The idea is pretty simple: make a stupid variable that does nothing but listen to the condition, and then set that local variable to be the condition.

However, when I was testing this I forgot to change enabled_when but it worked correctly anyway. In some way, adding this listener seems to have reminded the IndirectObjectPronoun that it's supposed to listen to this variable anyway. It also appears that the content of the _stupid_listener_listens_stupidly function matters -- if you change this to pass or print 56 or whatever, it no longer works.

Does anyone know what's going on here?

1

There are 1 answers

1
Jonathan March On

Without studying the source, I don't know why it doesn't work; at very least, the inconsistency that you describe seems wrong.

A more intuitive workaround/solution is to use delegation:

class IndirectObjectPronoun(HasTraits):
    referent=Instance(DirectObjectPronoun,())
    typable = DelegatesTo('referent')

    traits_view=View(
        Item(name='typable',object='object.referent'),
        Item(name='text',object='object.referent',
             enabled_when='typable'))