GNOME Data Access 5 manual: Trees

## Trees

Libgda supports data organized hierarchically in a tree. The specific aspect of this object is that one does not actually create nodes in it directly, but rather specifies the tree structure (ie. what top level nodes represent, whan their children represent, ...) using GdaTreeManager objects: any node in the tree is managed by one and only one such object. This approach makes it very easy to produce trees organized around repetitive data coming from a database. So again, one does not create or remove nodes in a tree, but asks that the tree be specifically updated, in part or starting from a specific node (note that nodes can also be added and removed on events depending on each GdaTreeManager object).

A tree is represented by a unique GdaTree object, in which each node is represented by a GdaTreeNode object. As mentioned previously, any GdaTreeNode in a GdaTree is created (and destroyed) by a GdaTreeManager object: the nodes hierarchy itself is represented by a hierarchy of GdaTreeManager objects (with the one(s) managing the nodes immediately under the tree root attached to the GdaTree itself and the others attached to the GdaTreeManager which act as their parent).

When populating a tree (or updating a part of it), a GdaTreeManager is requested to create (or update) nodes below a parent node. For any node it creates (or updates), and for any sub tree managers it has, it requests those sub managers to populate (or update) the sub nodes of that node; this is a recursive process. Note that the tree manager itself does not store any information about the nodes it has created (this information is stored in the GdaTreeNode themselves): it is stateless (much in the same way as the GtkCellRenderer objects are stateless in a GtkTreeView widget).

The following figure illustrates a simple tree:

The tree has 3 top level nodes (labelled "Node 0", "Node 1" and "Node 2" in the schema), which have been created by the GdaTreeManager labelled "GdaTreeManager 0". These top level nodes have sub nodes (two for the "Node 0" and "Node 1", and none for "Node 2") which have been created by the GdaTreeManager labelled "GdaTreeManager 1"

The following figure illustrates a mode complicated tree which, when dumped is (truncated here for readability):

    .
    |-- information_schema
    |   |-- sql_features
    |   |   |-- feature_name
    |   |   `-- feature_id
    |   `-- sql_parts
    |       |-- comments
    |       `-- feature_id
    |-- public
    |   |-- customers
    |   |   |-- name
    |   |   `-- id
    |   `-- products
    |       |-- name
    |       `-- ref
    |-- customers
    |   |-- name
    |   `-- id
    `-- products
        |-- name
        `-- ref

The tree has 4 top level nodes ("information_schema", "public" which in fact represent schemas in a PostgreSQL database and "customers" and "products" which are the tables in the "public" schema). Two GdaTreeManager objects are associated to the GdaTree object: the GdaTreeMgrSchemas manager (which creates nodes for each schema in a database) and the GdaTreeMgrTables manager (which creates nodes for each table in a schema, or, if no schema is specified creates nodes for each table visible by default). Here the GdaTreeMgrSchemas manager created the "information_schema" and "public" top level nodes and the GdaTreeMgrTables manager created the "customers" and "products" top level nodes.

The topmost GdaTreeMgrSchemas tree manager object has a child tree manager which is also a GdaTreeManagerTables (and which here is the same object as the GdaTreeManagerTables object which created two of the top level nodes to avoid the unnecessary complication of creating too many tree manager objects). This GdaTreeManagerTables object created the "sql_features", "sql_parts" nodes below the "information_schema" node and the "customers" and "products" nodes below the "public" node.

As the GdaTreeManagerTables object also has a child tree manager, the GdaTreeMgrColumns manager, some nodes are created below the "customers" nodes and below the "products" nodes (some of these nodes are not represented in the figure above for clarity).

As illustrated on the figure above, tree nodes can be assigned named attributes as GValue values. For instance the GdaTreeMgrSchemas manager sets the "schema" attribute to the nodes it creates, the GdaTreeMgrTables manager sets the "table_name" attribute (and the "schema" attribute if the node has been created as a table which is visible by default) and the GdaTreeMgrColumns manager sets the "column_name" attribute to the nodes it creates.

Node attributes can be read and changed at will by the programmer, and are used extensively by the tree manager objects themselves to determine the nodes they nees to create as children of a given node. For example the GdaTreeMgrTables manager, uses gda_tree_node_fetch_attribute() to get the "schema" attribute from the node below which it has to create children nodes. If the attribute exists, it then creates a node for each table in the mentioned schema, and otherwise creates a node for each table visible by default.

The code to set up this tree would be the following one:

    GdaConnection *cnc = ...
    GdaTree *tree;
    GdaTreeManager *schemas_mgr, *tables_mgr, *columns_mgr;

    tree = gda_tree_new ();

    schemas_mgr = gda_tree_mgr_schemas_new (cnc);
    tables_mgr = gda_tree_mgr_tables_new (cnc, NULL);
    columns_mgr = gda_tree_mgr_columns_new (cnc, NULL, NULL);

    gda_tree_manager_add_manager (schemas_mgr, tables_mgr);
    gda_tree_manager_add_manager (tables_mgr, columns_mgr);

    gda_tree_add_manager (tree, schemas_mgr);
    gda_tree_add_manager (tree, tables_mgr);

    g_object_unref (schemas_mgr);
    g_object_unref (tables_mgr);
    g_object_unref (columns_mgr);

    if (!gda_tree_update_all (tree, NULL)) {
            /* ERROR */
    }
    else {
            gda_tree_dump (tree, NULL, NULL);
    }
    g_object_unref (tree);