'Expand the parent of a leaf in a GtkTree

In a C and GTK program I have a function which is called when an element in a tree is activated:

g_signal_connect(G_OBJECT(tree), "row-activated", _CALLBACK(tree_row_activated_presets), NULL);
static void tree_row_activated_presets(GtkTreeView *tree, GtkTreePath *path, GtkTreeViewColumn *column, gpointer data)
{
  GtkTreeIter iter;
  GtkTreeModel *model = gtk_tree_view_get_model(tree);

  gtk_tree_model_get_iter(model, &iter, path);

  if(gtk_tree_model_iter_has_child(model, &iter))
  {
    ..... (actions if a branch is activated)
  }
  else
  {
    // leaf node
    gint rowid;
    gchar *name, *operation;
    GdkPixbuf *editable;
    gtk_tree_model_get(model, &iter, P_ROWID_COLUMN, &rowid, P_NAME_COLUMN, &name, P_OPERATION_COLUMN, &operation, P_EDITABLE_COLUMN, &editable, -1);
    if(editable != NULL)
    {
      GtkTreeIter parent_iter;
      gtk_tree_model_iter_parent(model, &parent_iter, &iter);
      edit_preset(tree, rowid, name, operation); // this function resets the tree, all branches get closed 
      ... MISSING CODE CALCULATING parent_path ...
      gtk_tree_view_expand_row(tree, parent_path, FALSE);
    }
    g_free(name);
    g_free(operation);
  }
}

How do I get the parent_path corresponding to parent_iter?



Solution 1:[1]

I might be misinterpreting what your desired outcome is, but it sounds like you want the top level parent for a child (e.g. "parent", "grand-parent", "great-grand-parent", and so forth) along with all of the intermediate ancestors to construct a genealogical path. From my experience in engineering with multi-level bills of materials, we would call the output you are after an "end item where-used" inquiry.

At your statement where you have "... MISSING CODE CALCULATING parent_path ...", one would probably insert a call to a recursive function that works back up through the tree view to ultimately get to the top parent, storing the name of the parent at each generation level. Alternatively, before recursive functions were common, one could replicate recursive calls by storing parent/child information in an array where each array entry was a level associated with the parent/child path.

Using the finite level array process, here is a snippet of code you might use as an example. I added this to a sample program that presents a tree view of programming languages and places the selected language into the status footer. The additional code snippet adds in the parental path. The block of code you may be interested in would inside the "if ((gtk_tree_model_iter_has_child(model, &iter)) == FALSE)" block.

void on_changed(GtkWidget *widget, gpointer statusbar)
{
    GtkTreeIter     iter;
    GtkTreeIter     parent;
    GtkTreeIter     work_iter;
    GtkTreeModel    *model;
    gchar           *value;
    gchar           status_text[256];
    gchar           status_work[256] [99];  /* To hold up to 99 parent/child levels */
    gboolean        loop_check = TRUE;
    gint            lvl = 0;

    if (gtk_tree_selection_get_selected(GTK_TREE_SELECTION(widget), &model, &iter))
    {
        gtk_tree_model_get(model, &iter, COLUMN, &value, -1);
        strcpy(status_text, value);
        strcpy(status_work[lvl], value);
        g_free(value);
    
        if ((gtk_tree_model_iter_has_child(model, &iter)) == FALSE)
        {
            strcat(status_text, "  Path: ");
            work_iter = iter;  /* This is a GtkTreeIter */
            while(loop_check)
            {
                if(gtk_tree_model_iter_parent(model, &parent, &work_iter)) /* See if this iter has a parent */
                {
                    gtk_tree_model_get(model, &parent, COLUMN, &value, -1);
                    lvl++;  /* This is just an array index for the parent/child level */
                    strcpy(status_work[lvl], value);
                    work_iter = parent;  /* Prepare to see if this iter has a parent */
                    g_free(value);
                }
                else
                {
                    loop_check = FALSE;  /* This gets us out of the loop */
                }
            }
            while(lvl > 0)
            {
                strcat(status_text, status_work[lvl]);
                strcat(status_text, "/");
                lvl--;
            }
            strcat(status_text, status_work[lvl]);
        }
        gtk_statusbar_push(GTK_STATUSBAR(statusbar), gtk_statusbar_get_context_id(GTK_STATUSBAR(statusbar), status_text), status_text);
    }
}
    

With that extra bit of code chasing down parents for children, I was able to add the path to the status bar of the sample program.

Parent_Child path

Granted, my example only has two levels; however, the logic should work for multiple parent/child levels. Hopefully, this sample portrays what type of logic you were after and did not waste your time reading this.

Regards.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 NoDakker