2018-06-12 01:56:21 +00:00
|
|
|
|
/*
|
|
|
|
|
* Copyright © 2018 Benjamin Otte
|
|
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*
|
|
|
|
|
* Authors: Benjamin Otte <otte@gnome.org>
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
|
|
#include "gtktreelistmodel.h"
|
|
|
|
|
|
2019-01-07 04:37:32 +00:00
|
|
|
|
#include "gtkrbtreeprivate.h"
|
2018-06-12 01:56:21 +00:00
|
|
|
|
#include "gtkintl.h"
|
|
|
|
|
#include "gtkprivate.h"
|
|
|
|
|
|
2018-09-17 03:06:19 +00:00
|
|
|
|
/**
|
|
|
|
|
* SECTION:gtktreelistmodel
|
2019-02-24 20:29:08 +00:00
|
|
|
|
* @Short_description: A list model that can create child models on demand
|
2018-09-17 03:06:19 +00:00
|
|
|
|
* @Title: GtkTreeListModel
|
|
|
|
|
* @See_also: #GListModel
|
|
|
|
|
*
|
|
|
|
|
* #GtkTreeListModel is a #GListModel implementation that can expand rows
|
|
|
|
|
* by creating new child list models on demand.
|
|
|
|
|
*/
|
|
|
|
|
|
2018-06-12 01:56:21 +00:00
|
|
|
|
enum {
|
|
|
|
|
PROP_0,
|
|
|
|
|
PROP_AUTOEXPAND,
|
2018-09-01 16:48:38 +00:00
|
|
|
|
PROP_MODEL,
|
2018-09-01 02:59:06 +00:00
|
|
|
|
PROP_PASSTHROUGH,
|
2018-06-12 01:56:21 +00:00
|
|
|
|
NUM_PROPERTIES
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef struct _TreeNode TreeNode;
|
|
|
|
|
typedef struct _TreeAugment TreeAugment;
|
|
|
|
|
|
|
|
|
|
struct _TreeNode
|
|
|
|
|
{
|
|
|
|
|
GListModel *model;
|
2018-09-01 02:59:06 +00:00
|
|
|
|
GtkTreeListRow *row;
|
2019-01-07 04:37:32 +00:00
|
|
|
|
GtkRbTree *children;
|
2018-06-12 01:56:21 +00:00
|
|
|
|
union {
|
|
|
|
|
TreeNode *parent;
|
|
|
|
|
GtkTreeListModel *list;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
guint empty : 1;
|
|
|
|
|
guint is_root : 1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _TreeAugment
|
|
|
|
|
{
|
|
|
|
|
guint n_items;
|
|
|
|
|
guint n_local;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GtkTreeListModel
|
|
|
|
|
{
|
|
|
|
|
GObject parent_instance;
|
|
|
|
|
|
|
|
|
|
TreeNode root_node;
|
|
|
|
|
|
|
|
|
|
GtkTreeListModelCreateModelFunc create_func;
|
|
|
|
|
gpointer user_data;
|
|
|
|
|
GDestroyNotify user_destroy;
|
|
|
|
|
|
|
|
|
|
guint autoexpand : 1;
|
2018-09-01 02:59:06 +00:00
|
|
|
|
guint passthrough : 1;
|
2018-06-12 01:56:21 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GtkTreeListModelClass
|
|
|
|
|
{
|
|
|
|
|
GObjectClass parent_class;
|
|
|
|
|
};
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
struct _GtkTreeListRow
|
|
|
|
|
{
|
|
|
|
|
GObject parent_instance;
|
|
|
|
|
|
|
|
|
|
TreeNode *node; /* NULL when the row has been destroyed */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GtkTreeListRowClass
|
|
|
|
|
{
|
|
|
|
|
GObjectClass parent_class;
|
|
|
|
|
};
|
|
|
|
|
|
2018-06-12 01:56:21 +00:00
|
|
|
|
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
|
|
|
|
|
|
|
|
|
static GtkTreeListModel *
|
|
|
|
|
tree_node_get_tree_list_model (TreeNode *node)
|
|
|
|
|
{
|
|
|
|
|
for (; !node->is_root; node = node->parent)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
return node->list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static TreeNode *
|
|
|
|
|
tree_node_get_nth_child (TreeNode *node,
|
|
|
|
|
guint position)
|
|
|
|
|
{
|
2019-01-07 04:37:32 +00:00
|
|
|
|
GtkRbTree *tree;
|
2018-06-12 01:56:21 +00:00
|
|
|
|
TreeNode *child, *tmp;
|
|
|
|
|
TreeAugment *aug;
|
|
|
|
|
|
|
|
|
|
tree = node->children;
|
2019-01-07 04:37:32 +00:00
|
|
|
|
child = gtk_rb_tree_get_root (tree);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
2018-09-01 16:48:38 +00:00
|
|
|
|
while (child)
|
2018-06-12 01:56:21 +00:00
|
|
|
|
{
|
2019-01-14 01:12:02 +00:00
|
|
|
|
tmp = gtk_rb_tree_node_get_left (child);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
if (tmp)
|
|
|
|
|
{
|
2019-01-07 04:37:32 +00:00
|
|
|
|
aug = gtk_rb_tree_get_augment (tree, tmp);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
if (position < aug->n_local)
|
|
|
|
|
{
|
|
|
|
|
child = tmp;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
position -= aug->n_local;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (position == 0)
|
|
|
|
|
return child;
|
|
|
|
|
|
|
|
|
|
position--;
|
|
|
|
|
|
2019-01-14 01:12:02 +00:00
|
|
|
|
child = gtk_rb_tree_node_get_right (child);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-01 16:48:38 +00:00
|
|
|
|
return NULL;
|
2018-06-12 01:56:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static guint
|
|
|
|
|
tree_node_get_n_children (TreeNode *node)
|
|
|
|
|
{
|
|
|
|
|
TreeAugment *child_aug;
|
|
|
|
|
TreeNode *child_node;
|
|
|
|
|
|
|
|
|
|
if (node->children == NULL)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2019-01-07 04:37:32 +00:00
|
|
|
|
child_node = gtk_rb_tree_get_root (node->children);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
if (child_node == NULL)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2019-01-07 04:37:32 +00:00
|
|
|
|
child_aug = gtk_rb_tree_get_augment (node->children, child_node);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
|
|
|
|
return child_aug->n_items;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static guint
|
2019-01-07 04:37:32 +00:00
|
|
|
|
tree_node_get_local_position (GtkRbTree *tree,
|
|
|
|
|
TreeNode *node)
|
2018-06-12 01:56:21 +00:00
|
|
|
|
{
|
|
|
|
|
TreeNode *left, *parent;
|
|
|
|
|
TreeAugment *left_aug;
|
|
|
|
|
guint n;
|
|
|
|
|
|
2019-01-14 01:12:02 +00:00
|
|
|
|
left = gtk_rb_tree_node_get_left (node);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
if (left)
|
|
|
|
|
{
|
2019-01-07 04:37:32 +00:00
|
|
|
|
left_aug = gtk_rb_tree_get_augment (tree, left);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
n = left_aug->n_local;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
n = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-14 01:12:02 +00:00
|
|
|
|
for (parent = gtk_rb_tree_node_get_parent (node);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
parent;
|
2019-01-14 01:12:02 +00:00
|
|
|
|
parent = gtk_rb_tree_node_get_parent (node))
|
2018-06-12 01:56:21 +00:00
|
|
|
|
{
|
2019-01-14 01:12:02 +00:00
|
|
|
|
left = gtk_rb_tree_node_get_left (parent);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
if (left == node)
|
|
|
|
|
{
|
|
|
|
|
/* we are the left node, nothing changes */
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* we are the right node */
|
|
|
|
|
n++;
|
|
|
|
|
if (left)
|
|
|
|
|
{
|
2019-01-07 04:37:32 +00:00
|
|
|
|
left_aug = gtk_rb_tree_get_augment (tree, left);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
n += left_aug->n_local;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
node = parent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static guint
|
|
|
|
|
tree_node_get_position (TreeNode *node)
|
|
|
|
|
{
|
2019-01-07 04:37:32 +00:00
|
|
|
|
GtkRbTree *tree;
|
2018-06-12 01:56:21 +00:00
|
|
|
|
TreeNode *left, *parent;
|
|
|
|
|
TreeAugment *left_aug;
|
|
|
|
|
guint n;
|
|
|
|
|
|
|
|
|
|
for (n = 0;
|
|
|
|
|
!node->is_root;
|
|
|
|
|
node = node->parent, n++)
|
|
|
|
|
{
|
|
|
|
|
tree = node->parent->children;
|
|
|
|
|
|
2019-01-14 01:12:02 +00:00
|
|
|
|
left = gtk_rb_tree_node_get_left (node);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
if (left)
|
|
|
|
|
{
|
2019-01-07 04:37:32 +00:00
|
|
|
|
left_aug = gtk_rb_tree_get_augment (tree, left);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
n += left_aug->n_items;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-14 01:12:02 +00:00
|
|
|
|
for (parent = gtk_rb_tree_node_get_parent (node);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
parent;
|
2019-01-14 01:12:02 +00:00
|
|
|
|
parent = gtk_rb_tree_node_get_parent (node))
|
2018-06-12 01:56:21 +00:00
|
|
|
|
{
|
2019-01-14 01:12:02 +00:00
|
|
|
|
left = gtk_rb_tree_node_get_left (parent);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
if (left == node)
|
|
|
|
|
{
|
|
|
|
|
/* we are the left node, nothing changes */
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* we are the right node */
|
|
|
|
|
n += 1 + tree_node_get_n_children (parent);
|
|
|
|
|
if (left)
|
|
|
|
|
{
|
2019-01-07 04:37:32 +00:00
|
|
|
|
left_aug = gtk_rb_tree_get_augment (tree, left);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
n += left_aug->n_items;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
node = parent;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* the root isn't visible */
|
|
|
|
|
n--;
|
|
|
|
|
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tree_node_mark_dirty (TreeNode *node)
|
|
|
|
|
{
|
|
|
|
|
for (;
|
|
|
|
|
!node->is_root;
|
|
|
|
|
node = node->parent)
|
|
|
|
|
{
|
2019-01-14 01:12:02 +00:00
|
|
|
|
gtk_rb_tree_node_mark_dirty (node);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static TreeNode *
|
|
|
|
|
gtk_tree_list_model_get_nth (GtkTreeListModel *self,
|
|
|
|
|
guint position)
|
|
|
|
|
{
|
2019-01-07 04:37:32 +00:00
|
|
|
|
GtkRbTree *tree;
|
2018-06-12 01:56:21 +00:00
|
|
|
|
TreeNode *node, *tmp;
|
|
|
|
|
guint n_children;
|
|
|
|
|
|
|
|
|
|
n_children = tree_node_get_n_children (&self->root_node);
|
|
|
|
|
if (n_children <= position)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
tree = self->root_node.children;
|
2019-01-07 04:37:32 +00:00
|
|
|
|
node = gtk_rb_tree_get_root (tree);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
|
|
|
|
while (TRUE)
|
|
|
|
|
{
|
2019-01-14 01:12:02 +00:00
|
|
|
|
tmp = gtk_rb_tree_node_get_left (node);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
if (tmp)
|
|
|
|
|
{
|
2019-01-07 04:37:32 +00:00
|
|
|
|
TreeAugment *aug = gtk_rb_tree_get_augment (tree, tmp);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
if (position < aug->n_items)
|
|
|
|
|
{
|
|
|
|
|
node = tmp;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
position -= aug->n_items;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (position == 0)
|
|
|
|
|
return node;
|
|
|
|
|
|
|
|
|
|
position--;
|
|
|
|
|
|
|
|
|
|
n_children = tree_node_get_n_children (node);
|
|
|
|
|
if (position < n_children)
|
|
|
|
|
{
|
|
|
|
|
tree = node->children;
|
2019-01-07 04:37:32 +00:00
|
|
|
|
node = gtk_rb_tree_get_root (tree);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
position -= n_children;
|
|
|
|
|
|
2019-01-14 01:12:02 +00:00
|
|
|
|
node = gtk_rb_tree_node_get_right (node);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_return_val_if_reached (NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
static GListModel *
|
|
|
|
|
tree_node_create_model (GtkTreeListModel *self,
|
|
|
|
|
TreeNode *node)
|
2018-06-12 01:56:21 +00:00
|
|
|
|
{
|
2018-09-01 02:59:06 +00:00
|
|
|
|
TreeNode *parent = node->parent;
|
|
|
|
|
GListModel *model;
|
|
|
|
|
GObject *item;
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
item = g_list_model_get_item (parent->model,
|
|
|
|
|
tree_node_get_local_position (parent->children, node));
|
|
|
|
|
model = self->create_func (item, self->user_data);
|
|
|
|
|
g_object_unref (item);
|
|
|
|
|
if (model == NULL)
|
|
|
|
|
node->empty = TRUE;
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
return model;
|
2018-06-12 01:56:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gpointer
|
2018-09-01 02:59:06 +00:00
|
|
|
|
tree_node_get_item (TreeNode *node)
|
2018-06-12 01:56:21 +00:00
|
|
|
|
{
|
2018-09-01 02:59:06 +00:00
|
|
|
|
TreeNode *parent;
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
|
|
|
|
parent = node->parent;
|
|
|
|
|
return g_list_model_get_item (parent->model,
|
|
|
|
|
tree_node_get_local_position (parent->children, node));
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
static GtkTreeListRow *
|
|
|
|
|
tree_node_get_row (TreeNode *node)
|
2018-06-12 01:56:21 +00:00
|
|
|
|
{
|
2018-09-01 02:59:06 +00:00
|
|
|
|
if (node->row)
|
2018-06-12 01:56:21 +00:00
|
|
|
|
{
|
2018-09-01 02:59:06 +00:00
|
|
|
|
return g_object_ref (node->row);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
}
|
2018-09-01 02:59:06 +00:00
|
|
|
|
else
|
2018-06-12 01:56:21 +00:00
|
|
|
|
{
|
2018-09-01 02:59:06 +00:00
|
|
|
|
node->row = g_object_new (GTK_TYPE_TREE_LIST_ROW, NULL);
|
|
|
|
|
node->row->node = node;
|
|
|
|
|
|
|
|
|
|
return node->row;
|
2018-06-12 01:56:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static guint
|
|
|
|
|
gtk_tree_list_model_expand_node (GtkTreeListModel *self,
|
|
|
|
|
TreeNode *node);
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_tree_list_model_items_changed_cb (GListModel *model,
|
|
|
|
|
guint position,
|
|
|
|
|
guint removed,
|
|
|
|
|
guint added,
|
|
|
|
|
TreeNode *node)
|
|
|
|
|
{
|
|
|
|
|
GtkTreeListModel *self;
|
|
|
|
|
TreeNode *child;
|
|
|
|
|
guint i, tree_position, tree_removed, tree_added, n_local;
|
|
|
|
|
|
|
|
|
|
self = tree_node_get_tree_list_model (node);
|
|
|
|
|
n_local = g_list_model_get_n_items (model) - added + removed;
|
|
|
|
|
|
|
|
|
|
if (position < n_local)
|
|
|
|
|
{
|
|
|
|
|
child = tree_node_get_nth_child (node, position);
|
|
|
|
|
tree_position = tree_node_get_position (child);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
child = NULL;
|
|
|
|
|
tree_position = tree_node_get_position (node) + tree_node_get_n_children (node) + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (removed)
|
|
|
|
|
{
|
|
|
|
|
TreeNode *tmp;
|
|
|
|
|
|
|
|
|
|
g_assert (child != NULL);
|
|
|
|
|
if (position + removed < n_local)
|
|
|
|
|
{
|
|
|
|
|
TreeNode *end = tree_node_get_nth_child (node, position + removed);
|
|
|
|
|
tree_removed = tree_node_get_position (end) - tree_position;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tree_removed = tree_node_get_position (node) + tree_node_get_n_children (node) + 1 - tree_position;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < removed; i++)
|
|
|
|
|
{
|
|
|
|
|
tmp = child;
|
2019-01-14 01:12:02 +00:00
|
|
|
|
child = gtk_rb_tree_node_get_next (child);
|
2019-01-07 04:37:32 +00:00
|
|
|
|
gtk_rb_tree_remove (node->children, tmp);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tree_removed = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tree_added = added;
|
|
|
|
|
for (i = 0; i < added; i++)
|
|
|
|
|
{
|
2019-01-07 04:37:32 +00:00
|
|
|
|
child = gtk_rb_tree_insert_before (node->children, child);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
child->parent = node;
|
|
|
|
|
}
|
|
|
|
|
if (self->autoexpand)
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; i < added; i++)
|
|
|
|
|
{
|
|
|
|
|
tree_added += gtk_tree_list_model_expand_node (self, child);
|
2019-01-14 01:12:02 +00:00
|
|
|
|
child = gtk_rb_tree_node_get_next (child);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tree_node_mark_dirty (node);
|
|
|
|
|
|
|
|
|
|
g_list_model_items_changed (G_LIST_MODEL (self),
|
|
|
|
|
tree_position,
|
|
|
|
|
tree_removed,
|
|
|
|
|
tree_added);
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
static void gtk_tree_list_row_destroy (GtkTreeListRow *row);
|
|
|
|
|
|
2018-06-12 01:56:21 +00:00
|
|
|
|
static void
|
|
|
|
|
gtk_tree_list_model_clear_node (gpointer data)
|
|
|
|
|
{
|
|
|
|
|
TreeNode *node = data;
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
if (node->row)
|
|
|
|
|
gtk_tree_list_row_destroy (node->row);
|
|
|
|
|
|
2018-06-12 01:56:21 +00:00
|
|
|
|
if (node->model)
|
|
|
|
|
{
|
|
|
|
|
g_signal_handlers_disconnect_by_func (node->model,
|
|
|
|
|
gtk_tree_list_model_items_changed_cb,
|
|
|
|
|
node);
|
|
|
|
|
g_object_unref (node->model);
|
|
|
|
|
}
|
|
|
|
|
if (node->children)
|
2019-01-07 04:37:32 +00:00
|
|
|
|
gtk_rb_tree_unref (node->children);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
static void
|
2019-01-07 04:37:32 +00:00
|
|
|
|
gtk_tree_list_model_augment (GtkRbTree *tree,
|
|
|
|
|
gpointer _aug,
|
|
|
|
|
gpointer _node,
|
|
|
|
|
gpointer left,
|
|
|
|
|
gpointer right)
|
2018-09-01 02:59:06 +00:00
|
|
|
|
{
|
|
|
|
|
TreeAugment *aug = _aug;
|
|
|
|
|
|
|
|
|
|
aug->n_items = 1;
|
|
|
|
|
aug->n_items += tree_node_get_n_children (_node);
|
|
|
|
|
aug->n_local = 1;
|
|
|
|
|
|
|
|
|
|
if (left)
|
|
|
|
|
{
|
2019-01-07 04:37:32 +00:00
|
|
|
|
TreeAugment *left_aug = gtk_rb_tree_get_augment (tree, left);
|
2018-09-01 02:59:06 +00:00
|
|
|
|
aug->n_items += left_aug->n_items;
|
|
|
|
|
aug->n_local += left_aug->n_local;
|
|
|
|
|
}
|
|
|
|
|
if (right)
|
|
|
|
|
{
|
2019-01-07 04:37:32 +00:00
|
|
|
|
TreeAugment *right_aug = gtk_rb_tree_get_augment (tree, right);
|
2018-09-01 02:59:06 +00:00
|
|
|
|
aug->n_items += right_aug->n_items;
|
|
|
|
|
aug->n_local += right_aug->n_local;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-12 01:56:21 +00:00
|
|
|
|
static void
|
|
|
|
|
gtk_tree_list_model_init_node (GtkTreeListModel *list,
|
|
|
|
|
TreeNode *self,
|
|
|
|
|
GListModel *model)
|
|
|
|
|
{
|
|
|
|
|
gsize i, n;
|
|
|
|
|
TreeNode *node;
|
|
|
|
|
|
2018-09-18 01:58:56 +00:00
|
|
|
|
self->model = model;
|
2018-06-12 01:56:21 +00:00
|
|
|
|
g_signal_connect (model,
|
|
|
|
|
"items-changed",
|
|
|
|
|
G_CALLBACK (gtk_tree_list_model_items_changed_cb),
|
|
|
|
|
self);
|
2019-01-07 04:37:32 +00:00
|
|
|
|
self->children = gtk_rb_tree_new (TreeNode,
|
|
|
|
|
TreeAugment,
|
|
|
|
|
gtk_tree_list_model_augment,
|
|
|
|
|
gtk_tree_list_model_clear_node,
|
|
|
|
|
NULL);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
|
|
|
|
n = g_list_model_get_n_items (model);
|
|
|
|
|
node = NULL;
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
|
{
|
2019-01-07 04:37:32 +00:00
|
|
|
|
node = gtk_rb_tree_insert_after (self->children, node);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
node->parent = self;
|
|
|
|
|
if (list->autoexpand)
|
|
|
|
|
gtk_tree_list_model_expand_node (list, node);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
static guint
|
|
|
|
|
gtk_tree_list_model_expand_node (GtkTreeListModel *self,
|
|
|
|
|
TreeNode *node)
|
|
|
|
|
{
|
|
|
|
|
GListModel *model;
|
|
|
|
|
|
|
|
|
|
if (node->empty)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (node->model != NULL)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
model = tree_node_create_model (self, node);
|
|
|
|
|
|
|
|
|
|
if (model == NULL)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
gtk_tree_list_model_init_node (self, node, model);
|
|
|
|
|
|
|
|
|
|
tree_node_mark_dirty (node);
|
|
|
|
|
|
|
|
|
|
return tree_node_get_n_children (node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static guint
|
|
|
|
|
gtk_tree_list_model_collapse_node (GtkTreeListModel *self,
|
|
|
|
|
TreeNode *node)
|
|
|
|
|
{
|
|
|
|
|
guint n_items;
|
|
|
|
|
|
|
|
|
|
if (node->model == NULL)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
n_items = tree_node_get_n_children (node);
|
|
|
|
|
|
2019-01-07 04:37:32 +00:00
|
|
|
|
g_clear_pointer (&node->children, gtk_rb_tree_unref);
|
2018-09-01 02:59:06 +00:00
|
|
|
|
g_clear_object (&node->model);
|
|
|
|
|
|
|
|
|
|
tree_node_mark_dirty (node);
|
|
|
|
|
|
|
|
|
|
return n_items;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static GType
|
|
|
|
|
gtk_tree_list_model_get_item_type (GListModel *list)
|
|
|
|
|
{
|
|
|
|
|
GtkTreeListModel *self = GTK_TREE_LIST_MODEL (list);
|
|
|
|
|
|
|
|
|
|
if (self->passthrough)
|
2020-07-04 19:47:48 +00:00
|
|
|
|
return G_TYPE_OBJECT;
|
2018-09-18 03:51:57 +00:00
|
|
|
|
else
|
|
|
|
|
return GTK_TYPE_TREE_LIST_ROW;
|
2018-09-01 02:59:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static guint
|
|
|
|
|
gtk_tree_list_model_get_n_items (GListModel *list)
|
|
|
|
|
{
|
|
|
|
|
GtkTreeListModel *self = GTK_TREE_LIST_MODEL (list);
|
|
|
|
|
|
|
|
|
|
return tree_node_get_n_children (&self->root_node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gpointer
|
|
|
|
|
gtk_tree_list_model_get_item (GListModel *list,
|
|
|
|
|
guint position)
|
|
|
|
|
{
|
|
|
|
|
GtkTreeListModel *self = GTK_TREE_LIST_MODEL (list);
|
|
|
|
|
TreeNode *node;
|
|
|
|
|
|
|
|
|
|
node = gtk_tree_list_model_get_nth (self, position);
|
|
|
|
|
if (node == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (self->passthrough)
|
|
|
|
|
{
|
|
|
|
|
return tree_node_get_item (node);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return tree_node_get_row (node);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_tree_list_model_model_init (GListModelInterface *iface)
|
|
|
|
|
{
|
|
|
|
|
iface->get_item_type = gtk_tree_list_model_get_item_type;
|
|
|
|
|
iface->get_n_items = gtk_tree_list_model_get_n_items;
|
|
|
|
|
iface->get_item = gtk_tree_list_model_get_item;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
G_DEFINE_TYPE_WITH_CODE (GtkTreeListModel, gtk_tree_list_model, G_TYPE_OBJECT,
|
|
|
|
|
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_tree_list_model_model_init))
|
|
|
|
|
|
2018-06-12 01:56:21 +00:00
|
|
|
|
static void
|
|
|
|
|
gtk_tree_list_model_set_property (GObject *object,
|
|
|
|
|
guint prop_id,
|
|
|
|
|
const GValue *value,
|
|
|
|
|
GParamSpec *pspec)
|
|
|
|
|
{
|
|
|
|
|
GtkTreeListModel *self = GTK_TREE_LIST_MODEL (object);
|
|
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
|
{
|
|
|
|
|
case PROP_AUTOEXPAND:
|
|
|
|
|
gtk_tree_list_model_set_autoexpand (self, g_value_get_boolean (value));
|
|
|
|
|
break;
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
case PROP_PASSTHROUGH:
|
|
|
|
|
self->passthrough = g_value_get_boolean (value);
|
|
|
|
|
break;
|
|
|
|
|
|
2018-06-12 01:56:21 +00:00
|
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_tree_list_model_get_property (GObject *object,
|
|
|
|
|
guint prop_id,
|
|
|
|
|
GValue *value,
|
|
|
|
|
GParamSpec *pspec)
|
|
|
|
|
{
|
|
|
|
|
GtkTreeListModel *self = GTK_TREE_LIST_MODEL (object);
|
|
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
|
{
|
|
|
|
|
case PROP_AUTOEXPAND:
|
|
|
|
|
g_value_set_boolean (value, self->autoexpand);
|
|
|
|
|
break;
|
|
|
|
|
|
2018-09-01 16:48:38 +00:00
|
|
|
|
case PROP_MODEL:
|
|
|
|
|
g_value_set_object (value, self->root_node.model);
|
2018-09-01 02:59:06 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2018-09-01 16:48:38 +00:00
|
|
|
|
case PROP_PASSTHROUGH:
|
|
|
|
|
g_value_set_boolean (value, self->passthrough);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_tree_list_model_finalize (GObject *object)
|
|
|
|
|
{
|
|
|
|
|
GtkTreeListModel *self = GTK_TREE_LIST_MODEL (object);
|
|
|
|
|
|
|
|
|
|
gtk_tree_list_model_clear_node (&self->root_node);
|
|
|
|
|
if (self->user_destroy)
|
|
|
|
|
self->user_destroy (self->user_data);
|
|
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (gtk_tree_list_model_parent_class)->finalize (object);
|
2019-01-07 04:37:32 +00:00
|
|
|
|
}
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_tree_list_model_class_init (GtkTreeListModelClass *class)
|
|
|
|
|
{
|
|
|
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
|
|
|
|
|
|
|
|
|
|
gobject_class->set_property = gtk_tree_list_model_set_property;
|
|
|
|
|
gobject_class->get_property = gtk_tree_list_model_get_property;
|
|
|
|
|
gobject_class->finalize = gtk_tree_list_model_finalize;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* GtkTreeListModel:autoexpand:
|
|
|
|
|
*
|
|
|
|
|
* If all rows should be expanded by default
|
|
|
|
|
*/
|
|
|
|
|
properties[PROP_AUTOEXPAND] =
|
|
|
|
|
g_param_spec_boolean ("autoexpand",
|
|
|
|
|
P_("autoexpand"),
|
|
|
|
|
P_("If all rows should be expanded by default"),
|
|
|
|
|
FALSE,
|
|
|
|
|
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
|
|
|
|
|
2018-09-01 16:48:38 +00:00
|
|
|
|
/**
|
|
|
|
|
* GtkTreeListModel:model:
|
|
|
|
|
*
|
|
|
|
|
* The root model displayed
|
|
|
|
|
*/
|
|
|
|
|
properties[PROP_MODEL] =
|
|
|
|
|
g_param_spec_object ("model",
|
|
|
|
|
P_("Model"),
|
|
|
|
|
P_("The root model displayed"),
|
|
|
|
|
G_TYPE_LIST_MODEL,
|
|
|
|
|
GTK_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY);
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
/**
|
|
|
|
|
* GtkTreeListModel:passthrough:
|
|
|
|
|
*
|
|
|
|
|
* If %FALSE, the #GListModel functions for this object return custom
|
|
|
|
|
* #GtkTreeListRow objects.
|
|
|
|
|
* If %TRUE, the values of the child models are pass through unmodified.
|
|
|
|
|
*/
|
|
|
|
|
properties[PROP_PASSTHROUGH] =
|
|
|
|
|
g_param_spec_boolean ("passthrough",
|
|
|
|
|
P_("passthrough"),
|
|
|
|
|
P_("If child model values are passed through"),
|
|
|
|
|
FALSE,
|
|
|
|
|
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
|
|
|
|
|
|
2018-06-12 01:56:21 +00:00
|
|
|
|
g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_tree_list_model_init (GtkTreeListModel *self)
|
|
|
|
|
{
|
|
|
|
|
self->root_node.list = self;
|
|
|
|
|
self->root_node.is_root = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* gtk_tree_list_model_new:
|
2020-07-26 20:38:53 +00:00
|
|
|
|
* @root: (transfer full): The #GListModel to use as root
|
2018-09-01 02:59:06 +00:00
|
|
|
|
* @passthrough: %TRUE to pass through items from the models
|
2018-06-12 01:56:21 +00:00
|
|
|
|
* @autoexpand: %TRUE to set the autoexpand property and expand the @root model
|
|
|
|
|
* @create_func: Function to call to create the #GListModel for the children
|
|
|
|
|
* of an item
|
2020-01-13 01:26:50 +00:00
|
|
|
|
* @user_data: (closure): Data to pass to @create_func
|
2018-06-12 01:56:21 +00:00
|
|
|
|
* @user_destroy: Function to call to free @user_data
|
|
|
|
|
*
|
|
|
|
|
* Creates a new empty #GtkTreeListModel displaying @root with all rows collapsed.
|
2020-07-26 20:38:53 +00:00
|
|
|
|
*
|
|
|
|
|
* Returns: a newly created #GtkTreeListModel.
|
2018-06-12 01:56:21 +00:00
|
|
|
|
**/
|
|
|
|
|
GtkTreeListModel *
|
2020-07-26 20:38:53 +00:00
|
|
|
|
gtk_tree_list_model_new (GListModel *root,
|
|
|
|
|
gboolean passthrough,
|
2018-06-12 01:56:21 +00:00
|
|
|
|
gboolean autoexpand,
|
|
|
|
|
GtkTreeListModelCreateModelFunc create_func,
|
|
|
|
|
gpointer user_data,
|
|
|
|
|
GDestroyNotify user_destroy)
|
|
|
|
|
{
|
|
|
|
|
GtkTreeListModel *self;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (G_IS_LIST_MODEL (root), NULL);
|
|
|
|
|
g_return_val_if_fail (create_func != NULL, NULL);
|
|
|
|
|
|
|
|
|
|
self = g_object_new (GTK_TYPE_TREE_LIST_MODEL,
|
|
|
|
|
"autoexpand", autoexpand,
|
2018-09-01 02:59:06 +00:00
|
|
|
|
"passthrough", passthrough,
|
2018-06-12 01:56:21 +00:00
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
self->create_func = create_func;
|
|
|
|
|
self->user_data = user_data;
|
|
|
|
|
self->user_destroy = user_destroy;
|
|
|
|
|
|
2020-07-26 20:38:53 +00:00
|
|
|
|
gtk_tree_list_model_init_node (self, &self->root_node, root);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-01 16:48:38 +00:00
|
|
|
|
/**
|
|
|
|
|
* gtk_tree_list_model_get_model:
|
|
|
|
|
* @self: a #GtkTreeListModel
|
|
|
|
|
*
|
|
|
|
|
* Gets the root model that @self was created with.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer none): the root model
|
|
|
|
|
**/
|
|
|
|
|
GListModel *
|
|
|
|
|
gtk_tree_list_model_get_model (GtkTreeListModel *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (GTK_IS_TREE_LIST_MODEL (self), NULL);
|
|
|
|
|
|
|
|
|
|
return self->root_node.model;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
/**
|
|
|
|
|
* gtk_tree_list_model_get_passthrough:
|
|
|
|
|
* @self: a #GtkTreeListModel
|
|
|
|
|
*
|
|
|
|
|
* If this function returns %FALSE, the #GListModel functions for @self
|
|
|
|
|
* return custom #GtkTreeListRow objects. You need to call
|
|
|
|
|
* gtk_tree_list_row_get_item() on these objects to get the original
|
|
|
|
|
* item.
|
|
|
|
|
*
|
|
|
|
|
* If %TRUE, the values of the child models are passed through in their
|
|
|
|
|
* original state. You then need to call gtk_tree_list_model_get_row()
|
|
|
|
|
* to get the custom #GtkTreeListRows.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the model is passing through original row items
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
|
|
|
|
gtk_tree_list_model_get_passthrough (GtkTreeListModel *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (GTK_IS_TREE_LIST_MODEL (self), FALSE);
|
|
|
|
|
|
|
|
|
|
return self->passthrough;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-12 01:56:21 +00:00
|
|
|
|
/**
|
|
|
|
|
* gtk_tree_list_model_set_autoexpand:
|
|
|
|
|
* @self: a #GtkTreeListModel
|
|
|
|
|
* @autoexpand: %TRUE to make the model autoexpand its rows
|
|
|
|
|
*
|
|
|
|
|
* If set to %TRUE, the model will recursively expand all rows that
|
|
|
|
|
* get added to the model. This can be either rows added by changes
|
|
|
|
|
* to the underlying models or via gtk_tree_list_model_set_expanded().
|
|
|
|
|
**/
|
|
|
|
|
void
|
|
|
|
|
gtk_tree_list_model_set_autoexpand (GtkTreeListModel *self,
|
|
|
|
|
gboolean autoexpand)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (GTK_IS_TREE_LIST_MODEL (self));
|
|
|
|
|
|
|
|
|
|
if (self->autoexpand == autoexpand)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
self->autoexpand = autoexpand;
|
|
|
|
|
|
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_AUTOEXPAND]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* gtk_tree_list_model_get_autoexpand:
|
|
|
|
|
* @self: a #GtkTreeListModel
|
|
|
|
|
*
|
|
|
|
|
* Gets whether the model is set to automatically expand new rows
|
|
|
|
|
* that get added. This can be either rows added by changes to the
|
|
|
|
|
* underlying models or via gtk_tree_list_model_set_expanded().
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the model is set to autoexpand
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
|
|
|
|
gtk_tree_list_model_get_autoexpand (GtkTreeListModel *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (GTK_IS_TREE_LIST_MODEL (self), FALSE);
|
|
|
|
|
|
|
|
|
|
return self->autoexpand;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
/**
|
|
|
|
|
* gtk_tree_list_model_get_row:
|
|
|
|
|
* @self: a #GtkTreeListModel
|
|
|
|
|
* @position: the position of the row to fetch
|
|
|
|
|
*
|
|
|
|
|
* Gets the row object for the given row. If @position is greater than
|
|
|
|
|
* the number of items in @self, %NULL is returned.
|
|
|
|
|
*
|
|
|
|
|
* The row object can be used to expand and collapse rows as well as
|
|
|
|
|
* to inspect its position in the tree. See its documentation for details.
|
|
|
|
|
*
|
|
|
|
|
* This row object is persistent and will refer to the current item as
|
|
|
|
|
* long as the row is present in @self, independent of other rows being
|
|
|
|
|
* added or removed.
|
|
|
|
|
*
|
|
|
|
|
* If @self is set to not be passthrough, this function is equivalent
|
|
|
|
|
* to calling g_list_model_get_item().
|
|
|
|
|
*
|
2018-09-18 05:50:33 +00:00
|
|
|
|
* Do not confuse this function with gtk_tree_list_model_get_child_row().
|
2018-09-01 16:48:38 +00:00
|
|
|
|
*
|
|
|
|
|
* Returns: (nullable) (transfer full): The row item
|
2018-09-01 02:59:06 +00:00
|
|
|
|
**/
|
|
|
|
|
GtkTreeListRow *
|
|
|
|
|
gtk_tree_list_model_get_row (GtkTreeListModel *self,
|
|
|
|
|
guint position)
|
2018-06-12 01:56:21 +00:00
|
|
|
|
{
|
|
|
|
|
TreeNode *node;
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
g_return_val_if_fail (GTK_IS_TREE_LIST_MODEL (self), NULL);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
|
|
|
|
node = gtk_tree_list_model_get_nth (self, position);
|
|
|
|
|
if (node == NULL)
|
2018-09-01 02:59:06 +00:00
|
|
|
|
return NULL;
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
return tree_node_get_row (node);
|
|
|
|
|
}
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
2018-09-01 16:48:38 +00:00
|
|
|
|
/**
|
2018-09-18 05:50:33 +00:00
|
|
|
|
* gtk_tree_list_model_get_child_row:
|
2018-09-01 16:48:38 +00:00
|
|
|
|
* @self: a #GtkTreeListModel
|
|
|
|
|
* @position: position of the child to get
|
|
|
|
|
*
|
|
|
|
|
* Gets the row item corresponding to the child at index @position for
|
|
|
|
|
* @self's root model.
|
|
|
|
|
*
|
|
|
|
|
* If @position is greater than the number of children in the root model,
|
|
|
|
|
* %NULL is returned.
|
|
|
|
|
*
|
|
|
|
|
* Do not confuse this function with gtk_tree_list_model_get_row().
|
|
|
|
|
*
|
|
|
|
|
* Returns: (nullable) (transfer full): the child in @position
|
|
|
|
|
**/
|
|
|
|
|
GtkTreeListRow *
|
2018-09-18 05:50:33 +00:00
|
|
|
|
gtk_tree_list_model_get_child_row (GtkTreeListModel *self,
|
|
|
|
|
guint position)
|
2018-09-01 16:48:38 +00:00
|
|
|
|
{
|
|
|
|
|
TreeNode *child;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (GTK_IS_TREE_LIST_MODEL (self), NULL);
|
|
|
|
|
|
|
|
|
|
child = tree_node_get_nth_child (&self->root_node, position);
|
|
|
|
|
if (child == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return tree_node_get_row (child);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-13 06:45:57 +00:00
|
|
|
|
/**
|
|
|
|
|
* SECTION:gtktreelistrow
|
2019-12-19 03:41:41 +00:00
|
|
|
|
* @Short_description: A row in a GtkTreeListModel
|
2019-12-13 06:45:57 +00:00
|
|
|
|
* @Title: GtkTreeListRow
|
|
|
|
|
* @See_also: #GtkTreeListModel
|
|
|
|
|
*
|
|
|
|
|
* #GtkTreeListRow is the object used by #GtkTreeListModel to
|
|
|
|
|
* represent items. It allows navigating the model as a tree and
|
|
|
|
|
* modify the state of rows.
|
|
|
|
|
*
|
|
|
|
|
* #GtkTreeListRow instances are created by a #GtkTreeListModel only
|
2019-12-19 03:41:41 +00:00
|
|
|
|
* when the #GtkTreeListModel:passthrough property is not set.
|
2019-12-13 06:45:57 +00:00
|
|
|
|
*
|
|
|
|
|
* There are various support objects that can make use of #GtkTreeListRow
|
|
|
|
|
* objects, such as the #GtkTreeExpander widget that allows displaying
|
|
|
|
|
* an icon to expand or collapse a row or #GtkTreeListRowSorter that makes
|
|
|
|
|
* it possible to sort trees properly.
|
|
|
|
|
*/
|
2018-09-01 02:59:06 +00:00
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
ROW_PROP_0,
|
2018-09-01 16:48:38 +00:00
|
|
|
|
ROW_PROP_CHILDREN,
|
2018-09-01 02:59:06 +00:00
|
|
|
|
ROW_PROP_DEPTH,
|
|
|
|
|
ROW_PROP_EXPANDABLE,
|
|
|
|
|
ROW_PROP_EXPANDED,
|
|
|
|
|
ROW_PROP_ITEM,
|
|
|
|
|
NUM_ROW_PROPERTIES
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static GParamSpec *row_properties[NUM_ROW_PROPERTIES] = { NULL, };
|
|
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (GtkTreeListRow, gtk_tree_list_row, G_TYPE_OBJECT)
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_tree_list_row_destroy (GtkTreeListRow *self)
|
|
|
|
|
{
|
|
|
|
|
g_object_freeze_notify (G_OBJECT (self));
|
|
|
|
|
|
|
|
|
|
/* FIXME: We could check some properties to avoid excess notifies */
|
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), row_properties[ROW_PROP_DEPTH]);
|
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), row_properties[ROW_PROP_EXPANDABLE]);
|
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), row_properties[ROW_PROP_EXPANDED]);
|
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), row_properties[ROW_PROP_ITEM]);
|
|
|
|
|
|
|
|
|
|
self->node = NULL;
|
2018-09-18 01:41:27 +00:00
|
|
|
|
g_object_thaw_notify (G_OBJECT (self));
|
2018-06-12 01:56:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
static void
|
|
|
|
|
gtk_tree_list_row_set_property (GObject *object,
|
|
|
|
|
guint prop_id,
|
|
|
|
|
const GValue *value,
|
|
|
|
|
GParamSpec *pspec)
|
2018-06-12 01:56:21 +00:00
|
|
|
|
{
|
2018-09-01 02:59:06 +00:00
|
|
|
|
GtkTreeListRow *self = GTK_TREE_LIST_ROW (object);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
switch (prop_id)
|
|
|
|
|
{
|
|
|
|
|
case ROW_PROP_EXPANDED:
|
|
|
|
|
gtk_tree_list_row_set_expanded (self, g_value_get_boolean (value));
|
|
|
|
|
break;
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2018-06-12 01:56:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
static void
|
|
|
|
|
gtk_tree_list_row_get_property (GObject *object,
|
|
|
|
|
guint prop_id,
|
|
|
|
|
GValue *value,
|
|
|
|
|
GParamSpec *pspec)
|
2018-06-12 01:56:21 +00:00
|
|
|
|
{
|
2018-09-01 02:59:06 +00:00
|
|
|
|
GtkTreeListRow *self = GTK_TREE_LIST_ROW (object);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
switch (prop_id)
|
|
|
|
|
{
|
2018-09-01 16:48:38 +00:00
|
|
|
|
case ROW_PROP_CHILDREN:
|
|
|
|
|
g_value_set_object (value, gtk_tree_list_row_get_children (self));
|
|
|
|
|
break;
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
case ROW_PROP_DEPTH:
|
|
|
|
|
g_value_set_uint (value, gtk_tree_list_row_get_depth (self));
|
|
|
|
|
break;
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
case ROW_PROP_EXPANDABLE:
|
|
|
|
|
g_value_set_boolean (value, gtk_tree_list_row_is_expandable (self));
|
|
|
|
|
break;
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
case ROW_PROP_EXPANDED:
|
|
|
|
|
g_value_set_boolean (value, gtk_tree_list_row_get_expanded (self));
|
|
|
|
|
break;
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
case ROW_PROP_ITEM:
|
|
|
|
|
g_value_take_object (value, gtk_tree_list_row_get_item (self));
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2018-06-12 01:56:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2018-09-01 02:59:06 +00:00
|
|
|
|
gtk_tree_list_row_dispose (GObject *object)
|
|
|
|
|
{
|
|
|
|
|
GtkTreeListRow *self = GTK_TREE_LIST_ROW (object);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
if (self->node)
|
|
|
|
|
self->node->row = NULL;
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
G_OBJECT_CLASS (gtk_tree_list_row_parent_class)->dispose (object);
|
2019-01-07 04:37:32 +00:00
|
|
|
|
}
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
static void
|
|
|
|
|
gtk_tree_list_row_class_init (GtkTreeListRowClass *class)
|
|
|
|
|
{
|
|
|
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
gobject_class->set_property = gtk_tree_list_row_set_property;
|
|
|
|
|
gobject_class->get_property = gtk_tree_list_row_get_property;
|
|
|
|
|
gobject_class->dispose = gtk_tree_list_row_dispose;
|
|
|
|
|
|
2018-09-01 16:48:38 +00:00
|
|
|
|
/**
|
|
|
|
|
* GtkTreeListRow:children:
|
|
|
|
|
*
|
|
|
|
|
* The model holding the row's children.
|
|
|
|
|
*/
|
|
|
|
|
row_properties[ROW_PROP_CHILDREN] =
|
|
|
|
|
g_param_spec_object ("children",
|
|
|
|
|
P_("Children"),
|
2018-09-20 17:01:14 +00:00
|
|
|
|
P_("Model holding the row’s children"),
|
2018-09-01 16:48:38 +00:00
|
|
|
|
G_TYPE_LIST_MODEL,
|
|
|
|
|
GTK_PARAM_READABLE);
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
/**
|
|
|
|
|
* GtkTreeListRow:depth:
|
|
|
|
|
*
|
|
|
|
|
* The depth in the tree of this row
|
|
|
|
|
*/
|
|
|
|
|
row_properties[ROW_PROP_DEPTH] =
|
|
|
|
|
g_param_spec_uint ("depth",
|
|
|
|
|
P_("Depth"),
|
|
|
|
|
P_("Depth in the tree"),
|
|
|
|
|
0, G_MAXUINT, 0,
|
|
|
|
|
GTK_PARAM_READABLE);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* GtkTreeListRow:expandable:
|
|
|
|
|
*
|
|
|
|
|
* If this row can ever be expanded
|
|
|
|
|
*/
|
|
|
|
|
row_properties[ROW_PROP_EXPANDABLE] =
|
|
|
|
|
g_param_spec_boolean ("expandable",
|
|
|
|
|
P_("Expandable"),
|
|
|
|
|
P_("If this row can ever be expanded"),
|
|
|
|
|
FALSE,
|
|
|
|
|
GTK_PARAM_READABLE);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* GtkTreeListRow:expanded:
|
|
|
|
|
*
|
|
|
|
|
* If this row is currently expanded
|
|
|
|
|
*/
|
|
|
|
|
row_properties[ROW_PROP_EXPANDED] =
|
|
|
|
|
g_param_spec_boolean ("expanded",
|
|
|
|
|
P_("Expanded"),
|
|
|
|
|
P_("If this row is currently expanded"),
|
|
|
|
|
FALSE,
|
|
|
|
|
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
/**
|
|
|
|
|
* GtkTreeListRow:item:
|
|
|
|
|
*
|
|
|
|
|
* The item held in this row
|
|
|
|
|
*/
|
|
|
|
|
row_properties[ROW_PROP_ITEM] =
|
|
|
|
|
g_param_spec_object ("item",
|
|
|
|
|
P_("Item"),
|
|
|
|
|
P_("The item held in this row"),
|
|
|
|
|
G_TYPE_OBJECT,
|
|
|
|
|
GTK_PARAM_READABLE);
|
|
|
|
|
|
|
|
|
|
g_object_class_install_properties (gobject_class, NUM_ROW_PROPERTIES, row_properties);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
static void
|
|
|
|
|
gtk_tree_list_row_init (GtkTreeListRow *self)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-01 16:48:38 +00:00
|
|
|
|
/**
|
|
|
|
|
* gtk_tree_list_row_get_position:
|
|
|
|
|
* @self: a #GtkTreeListRow
|
|
|
|
|
*
|
|
|
|
|
* Returns the position in the #GtkTreeListModel that @self occupies
|
|
|
|
|
* at the moment.
|
|
|
|
|
*
|
|
|
|
|
* Returns: The position in the model
|
|
|
|
|
**/
|
|
|
|
|
guint
|
|
|
|
|
gtk_tree_list_row_get_position (GtkTreeListRow *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (GTK_IS_TREE_LIST_ROW (self), 0);
|
|
|
|
|
|
|
|
|
|
if (self->node == NULL)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return tree_node_get_position (self->node);
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
/**
|
|
|
|
|
* gtk_tree_list_row_get_depth:
|
|
|
|
|
* @self: a #GtkTreeListRow
|
|
|
|
|
*
|
|
|
|
|
* Gets the depth of this row. Rows that correspond to items in
|
|
|
|
|
* the root model have a depth of zero, rows corresponding to items
|
|
|
|
|
* of models of direct children of the root model have a depth of
|
|
|
|
|
* 1 and so on.
|
|
|
|
|
*
|
|
|
|
|
* The depth of a row never changes until the row is destroyed.
|
|
|
|
|
*
|
|
|
|
|
* Returns: The depth of this row
|
|
|
|
|
**/
|
|
|
|
|
guint
|
|
|
|
|
gtk_tree_list_row_get_depth (GtkTreeListRow *self)
|
2018-06-12 01:56:21 +00:00
|
|
|
|
{
|
|
|
|
|
TreeNode *node;
|
2018-09-01 02:59:06 +00:00
|
|
|
|
guint depth;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (GTK_IS_TREE_LIST_ROW (self), 0);
|
|
|
|
|
|
|
|
|
|
if (self->node == NULL)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
depth = 0;
|
|
|
|
|
for (node = self->node->parent;
|
|
|
|
|
!node->is_root;
|
|
|
|
|
node = node->parent)
|
|
|
|
|
depth++;
|
|
|
|
|
|
|
|
|
|
return depth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* gtk_tree_list_row_set_expanded:
|
|
|
|
|
* @self: a #GtkTreeListRow
|
|
|
|
|
* @expanded: %TRUE if the row should be expanded
|
|
|
|
|
*
|
|
|
|
|
* Expands or collapses a row.
|
|
|
|
|
*
|
|
|
|
|
* If a row is expanded, the model of calling the
|
|
|
|
|
* #GtkTreeListModelCreateModelFunc for the row's item will
|
|
|
|
|
* be inserted after this row. If a row is collapsed, those
|
|
|
|
|
* items will be removed from the model.
|
|
|
|
|
*
|
|
|
|
|
* If the row is not expandable, this function does nothing.
|
|
|
|
|
**/
|
|
|
|
|
void
|
|
|
|
|
gtk_tree_list_row_set_expanded (GtkTreeListRow *self,
|
|
|
|
|
gboolean expanded)
|
|
|
|
|
{
|
|
|
|
|
GtkTreeListModel *list;
|
|
|
|
|
gboolean was_expanded;
|
2018-06-12 01:56:21 +00:00
|
|
|
|
guint n_items;
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
g_return_if_fail (GTK_IS_TREE_LIST_ROW (self));
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
if (self->node == NULL)
|
2018-06-12 01:56:21 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
was_expanded = self->node->children != NULL;
|
|
|
|
|
if (was_expanded == expanded)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
list = tree_node_get_tree_list_model (self->node);
|
|
|
|
|
|
2018-06-12 01:56:21 +00:00
|
|
|
|
if (expanded)
|
|
|
|
|
{
|
2018-09-01 02:59:06 +00:00
|
|
|
|
n_items = gtk_tree_list_model_expand_node (list, self->node);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
if (n_items > 0)
|
2018-09-01 02:59:06 +00:00
|
|
|
|
g_list_model_items_changed (G_LIST_MODEL (list), tree_node_get_position (self->node) + 1, 0, n_items);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-09-01 02:59:06 +00:00
|
|
|
|
n_items = gtk_tree_list_model_collapse_node (list, self->node);
|
|
|
|
|
if (n_items > 0)
|
|
|
|
|
g_list_model_items_changed (G_LIST_MODEL (list), tree_node_get_position (self->node) + 1, n_items, 0);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
}
|
2018-09-01 02:59:06 +00:00
|
|
|
|
|
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), row_properties[ROW_PROP_EXPANDED]);
|
2018-09-01 16:48:38 +00:00
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), row_properties[ROW_PROP_CHILDREN]);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
/**
|
|
|
|
|
* gtk_tree_list_row_get_expanded:
|
|
|
|
|
* @self: a #GtkTreeListRow
|
|
|
|
|
*
|
|
|
|
|
* Gets if a row is currently expanded.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the row is expanded
|
|
|
|
|
**/
|
2018-06-12 01:56:21 +00:00
|
|
|
|
gboolean
|
2018-09-01 02:59:06 +00:00
|
|
|
|
gtk_tree_list_row_get_expanded (GtkTreeListRow *self)
|
2018-06-12 01:56:21 +00:00
|
|
|
|
{
|
2018-09-01 02:59:06 +00:00
|
|
|
|
g_return_val_if_fail (GTK_IS_TREE_LIST_ROW (self), FALSE);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
if (self->node == NULL)
|
2018-06-12 01:56:21 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
return self->node->children != NULL;
|
2018-06-12 01:56:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
/**
|
|
|
|
|
* gtk_tree_list_row_is_expandable:
|
|
|
|
|
* @self: a #GtkTreeListRow
|
|
|
|
|
*
|
|
|
|
|
* Checks if a row can be expanded. This does not mean that the
|
|
|
|
|
* row is actually expanded, this can be checked with
|
|
|
|
|
* gtk_tree_list_row_get_expanded()
|
|
|
|
|
*
|
|
|
|
|
* If a row is expandable never changes until the row is destroyed.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the row is expandable
|
|
|
|
|
**/
|
2018-06-12 01:56:21 +00:00
|
|
|
|
gboolean
|
2018-09-01 02:59:06 +00:00
|
|
|
|
gtk_tree_list_row_is_expandable (GtkTreeListRow *self)
|
2018-06-12 01:56:21 +00:00
|
|
|
|
{
|
2018-09-01 02:59:06 +00:00
|
|
|
|
GtkTreeListModel *list;
|
2018-06-12 01:56:21 +00:00
|
|
|
|
GListModel *model;
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
g_return_val_if_fail (GTK_IS_TREE_LIST_ROW (self), FALSE);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
if (self->node == NULL)
|
2018-06-12 01:56:21 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
if (self->node->empty)
|
2018-06-12 01:56:21 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
if (self->node->model)
|
2018-06-12 01:56:21 +00:00
|
|
|
|
return TRUE;
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
list = tree_node_get_tree_list_model (self->node);
|
|
|
|
|
model = tree_node_create_model (list, self->node);
|
2018-06-12 01:56:21 +00:00
|
|
|
|
if (model)
|
|
|
|
|
{
|
|
|
|
|
g_object_unref (model);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
|
/**
|
|
|
|
|
* gtk_tree_list_row_get_item:
|
|
|
|
|
* @self: a #GtkTreeListRow
|
|
|
|
|
*
|
|
|
|
|
* Gets the item corresponding to this row,
|
|
|
|
|
*
|
|
|
|
|
* The value returned by this function never changes until the
|
|
|
|
|
* row is destroyed.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (nullable) (type GObject) (transfer full): The item of this row
|
|
|
|
|
* or %NULL when the row was destroyed
|
|
|
|
|
**/
|
|
|
|
|
gpointer
|
|
|
|
|
gtk_tree_list_row_get_item (GtkTreeListRow *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (GTK_IS_TREE_LIST_ROW (self), NULL);
|
|
|
|
|
|
|
|
|
|
if (self->node == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return tree_node_get_item (self->node);
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-01 16:48:38 +00:00
|
|
|
|
/**
|
|
|
|
|
* gtk_tree_list_row_get_children:
|
|
|
|
|
* @self: a #GtkTreeListRow
|
|
|
|
|
*
|
|
|
|
|
* If the row is expanded, gets the model holding the children of @self.
|
|
|
|
|
*
|
|
|
|
|
* This model is the model created by the #GtkTreeListModelCreateModelFunc
|
|
|
|
|
* and contains the original items, no matter what value
|
|
|
|
|
* #GtkTreeListModel:passthrough is set to.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (nullable) (transfer none): The model containing the children
|
|
|
|
|
**/
|
|
|
|
|
GListModel *
|
|
|
|
|
gtk_tree_list_row_get_children (GtkTreeListRow *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (GTK_IS_TREE_LIST_ROW (self), NULL);
|
|
|
|
|
|
|
|
|
|
if (self->node == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return self->node->model;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* gtk_tree_list_row_get_parent:
|
|
|
|
|
* @self: a #GtkTreeListRow
|
|
|
|
|
*
|
|
|
|
|
* Gets the row representing the parent for @self. That is the row that would
|
|
|
|
|
* need to be collapsed to make this row disappear.
|
|
|
|
|
*
|
|
|
|
|
* If @self is a row corresponding to the root model, %NULL is returned.
|
|
|
|
|
*
|
|
|
|
|
* The value returned by this function never changes until the
|
|
|
|
|
* row is destroyed.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (nullable) (transfer full): The parent of @self
|
|
|
|
|
**/
|
|
|
|
|
GtkTreeListRow *
|
|
|
|
|
gtk_tree_list_row_get_parent (GtkTreeListRow *self)
|
|
|
|
|
{
|
|
|
|
|
TreeNode *parent;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (GTK_IS_TREE_LIST_ROW (self), NULL);
|
|
|
|
|
|
|
|
|
|
if (self->node == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
parent = self->node->parent;
|
|
|
|
|
if (parent->is_root)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return tree_node_get_row (parent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2018-09-18 05:50:33 +00:00
|
|
|
|
* gtk_tree_list_row_get_child_row:
|
2018-09-01 16:48:38 +00:00
|
|
|
|
* @self: a #GtkTreeListRow
|
|
|
|
|
* @position: position of the child to get
|
|
|
|
|
*
|
|
|
|
|
* If @self is not expanded or @position is greater than the number of
|
|
|
|
|
* children, %NULL is returned.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (nullable) (transfer full): the child in @position
|
|
|
|
|
**/
|
|
|
|
|
GtkTreeListRow *
|
2018-09-18 05:50:33 +00:00
|
|
|
|
gtk_tree_list_row_get_child_row (GtkTreeListRow *self,
|
|
|
|
|
guint position)
|
2018-09-01 16:48:38 +00:00
|
|
|
|
{
|
|
|
|
|
TreeNode *child;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (GTK_IS_TREE_LIST_ROW (self), NULL);
|
|
|
|
|
|
|
|
|
|
if (self->node == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (self->node->children == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
child = tree_node_get_nth_child (self->node, position);
|
|
|
|
|
if (child == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return tree_node_get_row (child);
|
|
|
|
|
}
|
|
|
|
|
|