title: QAbstractListModel dataChanged signal not updating ListView (QML)
body: <p>I have a QAbstractListModel connected to a ListView in QML, but I'm having an issue with updating the view from C++. This is with Qt 5.6 mingw, QtQuick 2.6, and QtQuick.Controls 1.5.</p>
  
  <p>Setup:
  The ListView uses a custom check box delegate with a property to store the value from the model. The delegate updates the model when a user clicks on the delegate. In my QML I also have a toggle button that calls a slot in my model which toggles the data in the model and emits the dataChanged() signal for all rows (sets all checkboxes to not checked or checked). </p>
  
  <p>Issue:
  The toggle button works just fine until a user interacts with any checkbox delegate. After a user does this, the dataChanged() signal no longer updates that specific delegate. I also verified that the data() function of my model is getting called for all rows before the user interaction and then it is only getting called on the rows the user didn't click after the user interaction. This leads me to believe somewhere behind the scenes the view is choosing not to update certain rows, but I can't figure out why.</p>
  
  <p>Possible Solution:
  Emitting layoutChanged() in the model does update the view for my toggle button regardless of user interaction, but this causes the entire view to be redrawn and is relatively slow.</p>
  
  <p>This issue was created using a checkbox, but it applies to any type of user interaction. Below is all of the code necessary to recreate my issue.</p>
  
  <p>main.qml</p>
  
  <pre><code>import QtQuick 2.6
  import QtQuick.Controls 1.5
  import QtQuick.Layouts 1.3
  
  ApplicationWindow {
      visible: true
      width: 640
      height: 480
  
      ColumnLayout {
          anchors.fill: parent
          spacing: 10
  
          Button {
              Layout.preferredHeight: 100
              Layout.preferredWidth: 100
              text: "Test!"
              onClicked: {
                  console.log("attempting to refresh qml")
                  testModel.refresh()
                  testModel.print()
              }
          }
  
  
          ScrollView {
              Layout.fillHeight: true
              Layout.fillWidth: true
  
              ListView {
                  id: view
                  anchors.fill: parent
                  spacing: 5
                  model: testModel
                  delegate: Rectangle {
  
                      height: 50
                      width: 100
                      color: "lightgray"
  
                      CheckBox {
                          id: checkBox
                          anchors.fill: parent
                          checked: valueRole
  
                          onClicked: {
                              valueRole = checked
                          }
                      }
                  }
              }
          }
      }
  }
  </code></pre>
  
  <p>TestModel.cpp</p>
  
  <pre><code>#include "testmodel.h"
  
  TestModel::TestModel(QObject *parent) : QAbstractListModel(parent) {
  
      roleVector &lt;&lt; TaskRoles::valueRole;
      testValue = false;
  }
  
  TestModel::~TestModel() {}
  
  void TestModel::setup(const QList&lt;bool&gt; &amp;inputList) {
  
      // Clear view
      removeRows(0, valueList.length());
  
      // Update value list
      valueList = inputList;
  
      // Add rows
      insertRows(0, valueList.length());
  }
  
  // Emits data changed for entire model
  void TestModel::refresh() {
  
      qDebug() &lt;&lt; "attempting to refresh c++";
  
      // Toggle all values in model
      for (int i=0; i &lt; valueList.length(); i++) {
          valueList[i] = testValue;
      }
  
      // Toggle test value
      testValue = !testValue;
  
      // Update view
      // this works but is slow
  //    layoutAboutToBeChanged();
  //    layoutChanged();
  
      // this doesn't work if the user clicked the checkbox already
      dataChanged(createIndex(0, 0), createIndex(rowCount()-1, 0), roleVector);
  }
  
  void TestModel::print() {
      qDebug() &lt;&lt; "Model:" &lt;&lt; valueList;
  }
  
  QHash&lt;int, QByteArray&gt; TestModel::roleNames() const {
  
      QHash&lt;int, QByteArray&gt; roles;
      roles[valueRole]         = "valueRole";
      return roles;
  }
  
  int TestModel::rowCount(const QModelIndex &amp; /*parent*/) const {
  
      return valueList.length();
  }
  
  QVariant TestModel::headerData(int /*section*/, Qt::Orientation /*orientation*/, int /*role*/) const {
  
      return QVariant();
  }
  
  Qt::ItemFlags TestModel::flags(const QModelIndex &amp; /*index*/) const {
  
      return static_cast&lt;Qt::ItemFlags&gt;(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable |  Qt::ItemIsEditable);
  }
  
  QVariant TestModel::data(const QModelIndex &amp;index, int role) const {
  
  //    qDebug() &lt;&lt; QString("Get Data - Row: %1, Col: %2, Role: %3").arg(index.row()).arg(index.column()).arg(role);
  
      int row = index.row();
  
      if (row &gt;= 0 &amp;&amp; row &lt; valueList.length()) {
  
          switch(role) {
              case valueRole:
              qDebug() &lt;&lt; QString("Get Data - Row: %1, Col: %2, Role: %3").arg(index.row()).arg(index.column()).arg(role);
                  return valueList.at(row);
              default:
                  return QVariant();
          }
      }
  
      return QVariant();
  }
  
  bool TestModel::setData(const QModelIndex &amp;index, const QVariant &amp;value, int role) {
  
      qDebug() &lt;&lt; QString("Set Data - Row: %1, Col: %2, Role: %3").arg(index.row()).arg(index.column()).arg(role);
  
      int row = index.row();
  
      if (row &gt;= 0 &amp;&amp; row &lt; valueList.length()) {
  
          switch(role) {
              case valueRole:
                  valueList[row] = value.toBool();
                  break;
              default:
                  break;
          }
  
          dataChanged(index, index, QVector&lt;int&gt;() &lt;&lt; role);
          print();
      }
  
      return true;
  }
  
  bool TestModel::insertRows(int row, int count, const QModelIndex &amp; /*parent*/) {
  
      // Check bounds
      if (row &lt; 0 || count &lt; 0) {
          return false;
      }
  
      if (count == 0) {
          return true;
      }
  
      if (row &gt; rowCount()) {
          row = rowCount();
      }
  
      beginInsertRows(QModelIndex(), row, row+count-1);
      endInsertRows();
  
      return true;
  }
  
  bool TestModel::removeRows(int row, int count, const QModelIndex &amp; /*parent*/) {
  
      // Check bounds
      if (row &lt; 0 || count &lt; 0 || rowCount() &lt;= 0) {
          return false;
      }
  
      if (count == 0) {
          return true;
      }
  
      if (row &gt;= rowCount()) {
          row = rowCount() - 1;
      }
  
      beginRemoveRows(QModelIndex(), row, row+count-1);
      endRemoveRows();
  
      return true;
  }
  </code></pre>
  
  <p>TestModel.h</p>
  
  <pre><code>#ifndef TESTMODEL_H
  #define TESTMODEL_H
  
  #include &lt;QAbstractListModel&gt;
  #include &lt;QDebug&gt;
  #include &lt;QVector&gt;
  
  
  class TestModel : public QAbstractListModel
  {
      Q_OBJECT
  public:
      explicit TestModel(QObject *parent = 0);
      ~TestModel();
  
      // Roles
      enum TaskRoles {
          valueRole = Qt::UserRole + 1,
      };
  
      // Row / Column Functions
      int rowCount(const QModelIndex &amp;parent = QModelIndex()) const ;
  
      // Header / Flag Functions
      QVariant headerData(int section, Qt::Orientation orientation, int role) const;
      Qt::ItemFlags flags(const QModelIndex &amp;index) const;
  
      // Model Get / Set Functions
      QVariant data(const QModelIndex &amp;index, int role = Qt::DisplayRole) const;
      bool setData(const QModelIndex &amp;index, const QVariant &amp;value, int role = Qt::EditRole);
  
      // Row Insertion / Deletion Functions
      bool insertRows(int row, int count, const QModelIndex &amp;parent = QModelIndex());
      bool removeRows(int row, int count, const QModelIndex &amp;parent = QModelIndex());
  
  protected:
      // Value List
      QList&lt;bool&gt; valueList;
      QVector&lt;int&gt; roleVector;
  public slots:
      QHash&lt;int, QByteArray&gt; roleNames() const;
      void setup(const QList&lt;bool&gt; &amp;inputList);
      void refresh();
      void print();
  };
  
  #endif // TESTMODEL_H
  </code></pre>
  
  <p>main.cpp</p>
  
  <pre><code>#include &lt;QGuiApplication&gt;
  #include &lt;QQmlApplicationEngine&gt;
  #include &lt;QtQml&gt;
  #include &lt;QQmlContext&gt;
  
  #include "testmodel.h"
  
  int main(int argc, char *argv[])
  {
      QGuiApplication app(argc, argv);
  
      TestModel testModel;
      testModel.setup(QList&lt;bool&gt;() &lt;&lt; true &lt;&lt; false &lt;&lt; true &lt;&lt; false &lt;&lt; true);
  
      QQmlApplicationEngine engine;
      engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
      engine.rootContext()-&gt;setContextProperty("testModel", &amp;testModel);
  
      return app.exec();
  }
  </code></pre>
  
  <p>Example debug output (notice how it goes from 5 get data calls to only 4 get data calls after the checkbox in the delegate is clicked):</p>
  
  <pre><code>qml: attempting to refresh qml
  attempting to refresh c++
  "Get Data - Row: 0, Col: 0, Role: 257"
  "Get Data - Row: 1, Col: 0, Role: 257"
  "Get Data - Row: 2, Col: 0, Role: 257"
  "Get Data - Row: 3, Col: 0, Role: 257"
  "Get Data - Row: 4, Col: 0, Role: 257"
  Model: (false, false, false, false, false)
  
  qml: clicked checkbox
  "Set Data - Row: 0, Col: 0, Role: 257"
  Model: (true, false, false, false, false)
  
  qml: attempting to refresh qml
  attempting to refresh c++
  "Get Data - Row: 1, Col: 0, Role: 257"
  "Get Data - Row: 2, Col: 0, Role: 257"
  "Get Data - Row: 3, Col: 0, Role: 257"
  "Get Data - Row: 4, Col: 0, Role: 257"
  Model: (true, true, true, true, true)
  
  qml: attempting to refresh qml
  attempting to refresh c++
  "Get Data - Row: 1, Col: 0, Role: 257"
  "Get Data - Row: 2, Col: 0, Role: 257"
  "Get Data - Row: 3, Col: 0, Role: 257"
  "Get Data - Row: 4, Col: 0, Role: 257"
  Model: (false, false, false, false, false)
  </code></pre>