[scribus-dev] The handleSelectionChanged() thing again

Elvis Stansvik elvstone at gmail.com
Tue Jul 12 11:48:52 UTC 2011


2011/7/12 Andreas Vox <andreas.vox at googlemail.com>:
>
>
>> -----Ursprüngliche Nachricht-----
>> Von: Elvis Stansvik [mailto:elvstone at gmail.com]
>> Gesendet: Dienstag, 12. Juli 2011 10:59
>> An: Scribus Development Mailing List
>> Betreff: Re: [scribus-dev] The handleSelectionChanged() thing again
>>
>> 2011/7/12 Elvis Stansvik <elvstone at gmail.com>:
>> > Good morning,
>>
>> <snip>
>>
>> > This is what I'm trying to work around now in the best way possible.
>>
>> I guess that the best solution right now would be something like
>>
>> PropertiesPalette_Table::startEdit() { m_inEdit = true; }
>> PropertiesPalette_Table::endEdit() { m_inEdit = false; }
>> PropertiesPalette_Table::inEdit() { return m_inEdit; }
>> PropertiesPalette_Table::handleSelectionChanged()
>> {
>>     if (inEdit())
>>         return;
>>     // Update all controls et.c.
>> }
>> PropertiesPalette_Table::handleSomePropertyChange()
>> {
>>     startEdit();
>>     m_item->setSomeProperty();
>>     m_item->update();
>>     endEdit();
>> }
>>
>> But is update() blocking enough for that or could endEdit() possibly
>> be called before handleSelectionChanged()?
>
> I usually use a similar pattern when dealing with this situation:
>
>  private bool withinUpdate = false;
>
>  // event from Qt:
>  public void valueChanged(...)
>  {
>     try {
>        withinUpdate = true;
>        document->setNewValue(...);
>     }
>     finally {
>        withinUpdate = false;
>     }
>   }
>
>   // event from our model:
>   public void changed(...)
>   {
>      if (!withinUpdate)
>        ...
>   }

Ah. Good idea with the try/catch construct. I guess another approach
would be to use RAII and define an inner class to
PropertiesPalette_Table, like:

private bool withinUpdate = false;

class ChangeBlocker()
{
   public:
      ChangeBlocker(PropertiesPalette_Table *parent) : m_parent(parent)
      {
         m_parent->withinUpdate = true;
      }
      ~ChangeBlocker()
      {
         m_parent->withinUpdate = false;
      }
   private:
      PropertiesPalette_Table *m_parent;
};

The handler for event from Qt would then be reduced to

// event from Qt:
public void valueChanged(...)
{
   ChangeBlocker blocker(this);
   document->setNewValue(...);
}

(untested)

But now that I wrote that down I think your try/catch is prettier and
more explicit ;)

> I view the event chain from model -> UI as very important(*), so I'm
> hesitant to turn off all signals. So I just protect sections where UI code
> changes the model data by "withinUpdate = true" and ignore any events that
> come from the model during that time. That ensures other parts of Scribus
> still get the events and only the critical loop is broken.

Yep.

> (*) Having a robust mechanism that updates the view each time the model
> changes goes a long way to implement the model/view/controller pattern. Even
> if it seems round-about that the UI first sends the data to the model and
> then updates itself from the model, this architecture is very sound and
> makes developing and testing much easier. The resulting UI is also more
> stable and resilient to errors this way.

All valid points. I stand corrected!

Elvis



More information about the scribus-dev mailing list