q tree model bindings: recursively insert rows

On rowsMoved and modelReset recursively insert all the existing children
of the top nodes. This is because rowsMoved is handled by deleting
all of the moved rows during the rowsAboutToBeMoved signal and then
re-inserting them on the rowsMoved signal. In this case, any children
of the moved rows must be re-inserted as well.

Issue: #80698
Change-Id: Ice7c8d453039acd91a55652c802fdf3e427f96e0
diff --git a/src/models/gtkqsortfiltertreemodel.cpp b/src/models/gtkqsortfiltertreemodel.cpp
index 329fefc..484bf73 100644
--- a/src/models/gtkqsortfiltertreemodel.cpp
+++ b/src/models/gtkqsortfiltertreemodel.cpp
@@ -237,6 +237,30 @@
 }
 
 /**
+ * helper method which recursively adds all the children of the given QModelIndex
+ */
+static void
+insert_children(const QModelIndex &idx_given, GtkQSortFilterTreeModel *gtk_model)
+{
+    const auto children = gtk_model->priv->given_model->rowCount(idx_given);
+    for (int i = 0; i < children; ++i) {
+        GtkTreeIter iter_child;
+        auto idx_child_given = gtk_model->priv->given_model->index(i, 0, idx_given);
+        if (idx_child_given.isValid()) {
+            auto idx_child_original = gtk_model->priv->given_model->mapToSource(idx_child_given);
+            auto idx_child_access = gtk_model->priv->access_model->mapFromSource(idx_child_original);
+            iter_child.stamp = gtk_model->priv->stamp;
+            qmodelindex_to_iter(idx_child_access, &iter_child);
+            if (auto path_child = gtk_q_sort_filter_tree_model_get_path(GTK_TREE_MODEL(gtk_model), &iter_child)) {
+                gtk_tree_model_row_inserted(GTK_TREE_MODEL(gtk_model), path_child, &iter_child);
+                gtk_tree_path_free(path_child);
+            }
+            insert_children(idx_child_given, gtk_model);
+        }
+    }
+}
+
+/**
  * gtk_q_sort_filter_tree_model_new:
  * @model: QAbstractItemModel to which this model will bind.
  * @n_columns: number of columns in the list store
@@ -365,6 +389,7 @@
                 GtkTreePath *path_new = gtk_q_sort_filter_tree_model_get_path(GTK_TREE_MODEL(retval), &iter_new);
                 gtk_tree_model_row_inserted(GTK_TREE_MODEL(retval), path_new, &iter_new);
                 gtk_tree_path_free(path_new);
+                insert_children(idx_given, retval);
                 destinationRow++;
             }
         }
@@ -464,20 +489,8 @@
         &QAbstractItemModel::modelReset,
         [=] () {
             // g_debug("model reset");
-            /* now add all the (new) rows */
-            int row_count = retval->priv->given_model->rowCount();
-            for (int row = 0; row < row_count; ++row) {
-                // g_debug("adding row %d", row);
-                GtkTreeIter iter_new;
-                QModelIndex idx_given = retval->priv->given_model->index(row, 0);
-                QModelIndex idx_original = retval->priv->given_model->mapToSource(idx_given);
-                QModelIndex idx_access = retval->priv->access_model->mapFromSource(idx_original);
-                iter_new.stamp = stamp;
-                qmodelindex_to_iter(idx_access, &iter_new);
-                GtkTreePath *path_new = gtk_q_sort_filter_tree_model_get_path(GTK_TREE_MODEL(retval), &iter_new);
-                gtk_tree_model_row_inserted(GTK_TREE_MODEL(retval), path_new, &iter_new);
-                gtk_tree_path_free(path_new);
-            }
+            /* now recursively add all the (new) rows */
+            insert_children(QModelIndex(), retval);
         }
     );
 
diff --git a/src/models/gtkqtreemodel.cpp b/src/models/gtkqtreemodel.cpp
index 0a18e77..c6a4a22 100644
--- a/src/models/gtkqtreemodel.cpp
+++ b/src/models/gtkqtreemodel.cpp
@@ -229,6 +229,28 @@
 }
 
 /**
+ * helper method which recursively adds all the children of the given QModelIndex
+ */
+static void
+insert_children(const QModelIndex &idx, GtkQTreeModel *gtk_model)
+{
+    const auto children = gtk_model->priv->model->rowCount(idx);
+    for (int i = 0; i < children; ++i) {
+        GtkTreeIter iter_child;
+        auto idx_child = gtk_model->priv->model->index(i, 0, idx);
+        if (idx_child.isValid()) {
+            iter_child.stamp = gtk_model->priv->stamp;
+            qmodelindex_to_iter(idx_child, &iter_child);
+            if (auto path_child = gtk_q_tree_model_get_path(GTK_TREE_MODEL(gtk_model), &iter_child)) {
+                gtk_tree_model_row_inserted(GTK_TREE_MODEL(gtk_model), path_child, &iter_child);
+                gtk_tree_path_free(path_child);
+            }
+            insert_children(idx_child, gtk_model);
+        }
+    }
+}
+
+/**
  * gtk_q_tree_model_new:
  * @model: QAbstractItemModel to which this model will bind.
  * @n_columns: number of columns in the list store
@@ -333,6 +355,7 @@
                 GtkTreePath *path_new = gtk_q_tree_model_get_path(GTK_TREE_MODEL(retval), &iter_new);
                 gtk_tree_model_row_inserted(GTK_TREE_MODEL(retval), path_new, &iter_new);
                 gtk_tree_path_free(path_new);
+                insert_children(idx, retval);
                 destinationRow++;
             }
         }
@@ -421,18 +444,8 @@
         &QAbstractItemModel::modelReset,
         [=] () {
             // g_debug("model reset");
-            /* now add all the (new) rows */
-            int row_count = proxy_model->rowCount();
-            for (int row = 0; row < row_count; row++) {
-                // g_debug("adding row %d", row);
-                GtkTreeIter iter_new;
-                QModelIndex idx = proxy_model->index(row, 0);
-                iter_new.stamp = stamp;
-                qmodelindex_to_iter(idx, &iter_new);
-                GtkTreePath *path_new = gtk_q_tree_model_get_path(GTK_TREE_MODEL(retval), &iter_new);
-                gtk_tree_model_row_inserted(GTK_TREE_MODEL(retval), path_new, &iter_new);
-                gtk_tree_path_free(path_new);
-            }
+            /* now recursively add all the (new) rows */
+            insert_children(QModelIndex(), retval);
         }
     );