Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-89914

Q_OBJECT_COMPAT_PROPERTY binding removal inconsistent

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • P2: Important
    • 6.2
    • 6.0
    • Core: Object Model
    • None

    Description

      Setting a bindable property to some value should remove the binding.

      When using Q_OBJECT_COMPAT_PROPERTY it fails to do so if the setter is called inside of a signal handler of the signal emitted by the setter.

      The problem is the following:

      In QObjectCompatProperty there is logic to remove the binding when the setter is executed. But because QObjectCompatProperty calls the setter itself when evaluating the binding, this code is disabled during binding evaluation. When binding evaluation leads to a signal being emitted and that signal leads to user code calling the setter, it is still disabled.

      So correct logic would be: Binding removal is disabled if the setter is called directly by QObjectCompatProperty.

      Implemented logic is: Binding removal is disabled if the setter call is somewhere up the call stack.

      This problem could be solved by the proposal I already made in QTBUG-89890 :

      My proposal would be that any write to a bindable property just assigns the underlying QObjectCompatProperty. The old setters become private functions which are then, in turn, called by the QObjectCompatProperty.

       

      Source code for reproduction:

      #include <QObject>
      #include <QDebug>
      
      #include <private/qproperty_p.h>
      
      class Foo : public QObject {
          Q_OBJECT
          Q_PROPERTY(int a READ a WRITE setA NOTIFY aChanged BINDABLE bindableA)
      
      public:
          int a() const { return Adata; }
          void setA(int value) {
              int oldvalue = Adata;
              Adata = value;
              if (value != oldvalue)
                  emit aChanged(value);
          }
          QBindable<int> bindableA() { return &Adata; }
      
          signals:
          void aChanged(int);
      
      private:
          Q_OBJECT_COMPAT_PROPERTY(Foo, int, Adata, &Foo::setA)
      };
      
      int main(){
          QProperty<int> refvalue(5);
      
          Foo myfoo;
          myfoo.bindableA().setBinding([&](){ return refvalue.value(); });
      
          // once myfoo.a becomes 10 or greater, we want it to stop updating
          QObject::connect(&myfoo, &Foo::aChanged, [&](int value){
              if (value >= 10){
                  myfoo.setA(value);
              }
          });
      
          // change refvalue, myfoo.a follows
          refvalue = 6;
          assert(myfoo.a() == 6);
      
          refvalue = 8;
          assert(myfoo.a() == 8);
      
          refvalue = 10;
          assert(myfoo.a() == 10);
      
          refvalue = 12;
          assert(myfoo.a() == 10);
      }
      
      #include "main.moc"
      

      Attachments

        For Gerrit Dashboard: QTBUG-89914
        # Subject Branch Project Status CR V

        Activity

          People

            fabiankosmale Fabian Kosmale
            andreasbuhr Andreas Buhr
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:

              Gerrit Reviews

                There are no open Gerrit changes