* Boston, MA 02111-1307, USA.
*/
-#include <config.h>
+#include "config.h"
#include <string.h>
#include <gobject/gvaluecollector.h>
#include "gtktreemodel.h"
#include "gtktreestore.h"
#include "gtktreedatalist.h"
#include "gtktreednd.h"
+#include "gtkbuildable.h"
#include "gtkintl.h"
-#include "gtkalias.h"
+
#define G_NODE(node) ((GNode *)node)
#define GTK_TREE_STORE_IS_SORTED(tree) (((GtkTreeStore*)(tree))->sort_column_id != GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
static void gtk_tree_store_drag_source_init(GtkTreeDragSourceIface *iface);
static void gtk_tree_store_drag_dest_init (GtkTreeDragDestIface *iface);
static void gtk_tree_store_sortable_init (GtkTreeSortableIface *iface);
+static void gtk_tree_store_buildable_init (GtkBuildableIface *iface);
static void gtk_tree_store_finalize (GObject *object);
static GtkTreeModelFlags gtk_tree_store_get_flags (GtkTreeModel *tree_model);
static gint gtk_tree_store_get_n_columns (GtkTreeModel *tree_model);
gint sort_column_id,
GtkTreeIterCompareFunc func,
gpointer data,
- GtkDestroyNotify destroy);
+ GDestroyNotify destroy);
static void gtk_tree_store_set_default_sort_func (GtkTreeSortable *sortable,
GtkTreeIterCompareFunc func,
gpointer data,
- GtkDestroyNotify destroy);
+ GDestroyNotify destroy);
static gboolean gtk_tree_store_has_default_sort_func (GtkTreeSortable *sortable);
+
+/* buildable */
+
+static gboolean gtk_tree_store_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data);
+static void gtk_tree_store_buildable_custom_finished (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer user_data);
+
static void validate_gnode (GNode *node);
static void gtk_tree_store_move (GtkTreeStore *tree_store,
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_DEST,
gtk_tree_store_drag_dest_init)
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE,
- gtk_tree_store_sortable_init))
+ gtk_tree_store_sortable_init)
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_tree_store_buildable_init))
static void
gtk_tree_store_class_init (GtkTreeStoreClass *class)
iface->has_default_sort_func = gtk_tree_store_has_default_sort_func;
}
+void
+gtk_tree_store_buildable_init (GtkBuildableIface *iface)
+{
+ iface->custom_tag_start = gtk_tree_store_buildable_custom_tag_start;
+ iface->custom_finished = gtk_tree_store_buildable_custom_finished;
+}
+
static void
gtk_tree_store_init (GtkTreeStore *tree_store)
{
while (tree_store->stamp == 0);
tree_store->sort_list = NULL;
- tree_store->sort_column_id = -2;
+ tree_store->sort_column_id = GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID;
tree_store->columns_dirty = FALSE;
}
GType type = va_arg (args, GType);
if (! _gtk_tree_data_list_check_type (type))
{
- g_warning ("%s: Invalid type %s passed to gtk_tree_store_new_with_types\n",
- G_STRLOC, g_type_name (type));
+ g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type));
g_object_unref (retval);
+ va_end (args);
return NULL;
}
gtk_tree_store_set_column_type (retval, i, type);
/**
* gtk_tree_store_newv:
* @n_columns: number of columns in the tree store
- * @types: an array of #GType types for the columns, from first to last
+ * @types: (array length=n_columns): an array of #GType types for the columns, from first to last
*
* Non vararg creation function. Used primarily by language bindings.
*
{
if (! _gtk_tree_data_list_check_type (types[i]))
{
- g_warning ("%s: Invalid type %s passed to gtk_tree_store_new_with_types\n",
- G_STRLOC, g_type_name (types[i]));
+ g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i]));
g_object_unref (retval);
return NULL;
}
* gtk_tree_store_set_column_types:
* @tree_store: A #GtkTreeStore
* @n_columns: Number of columns for the tree store
- * @types: An array of #GType types, one for each column
+ * @types: (array length=n_columns): An array of #GType types, one for each column
*
* This function is meant primarily for #GObjects that inherit from
* #GtkTreeStore, and should only be used when constructing a new
{
if (! _gtk_tree_data_list_check_type (types[i]))
{
- g_warning ("%s: Invalid type %s passed to gtk_tree_store_set_column_types\n", G_STRLOC, g_type_name (types[i]));
+ g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i]));
continue;
}
gtk_tree_store_set_column_type (tree_store, i, types[i]);
gtk_tree_store_set_n_columns (GtkTreeStore *tree_store,
gint n_columns)
{
- GType *new_columns;
+ int i;
if (tree_store->n_columns == n_columns)
return;
- new_columns = g_new0 (GType, n_columns);
- if (tree_store->column_headers)
- {
- /* copy the old header orders over */
- if (n_columns >= tree_store->n_columns)
- memcpy (new_columns, tree_store->column_headers, tree_store->n_columns * sizeof (gchar *));
- else
- memcpy (new_columns, tree_store->column_headers, n_columns * sizeof (GType));
-
- g_free (tree_store->column_headers);
- }
+ tree_store->column_headers = g_renew (GType, tree_store->column_headers, n_columns);
+ for (i = tree_store->n_columns; i < n_columns; i++)
+ tree_store->column_headers[i] = G_TYPE_INVALID;
+ tree_store->n_columns = n_columns;
if (tree_store->sort_list)
_gtk_tree_data_list_header_free (tree_store->sort_list);
tree_store->sort_list = _gtk_tree_data_list_header_new (n_columns, tree_store->column_headers);
-
- tree_store->column_headers = new_columns;
- tree_store->n_columns = n_columns;
}
/**
{
if (!_gtk_tree_data_list_check_type (type))
{
- g_warning ("%s: Invalid type %s passed to gtk_tree_store_new_with_types\n", G_STRLOC, g_type_name (type));
+ g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type));
return;
}
tree_store->column_headers[column] = type;
if (tree_store->default_sort_destroy)
{
- GtkDestroyNotify d = tree_store->default_sort_destroy;
+ GDestroyNotify d = tree_store->default_sort_destroy;
tree_store->default_sort_destroy = NULL;
d (tree_store->default_sort_data);
return TRUE;
}
else
- return FALSE;
+ {
+ iter->stamp = 0;
+ return FALSE;
+ }
}
static gboolean
return TRUE;
}
else
- return FALSE;
+ {
+ iter->stamp = 0;
+ return FALSE;
+ }
}
static gboolean
return TRUE;
}
else
- return FALSE;
+ {
+ iter->stamp = 0;
+ return FALSE;
+ }
}
static gboolean
return TRUE;
}
else
- return FALSE;
+ {
+ iter->stamp = 0;
+ return FALSE;
+ }
}
return func;
}
+static void
+gtk_tree_store_set_vector_internal (GtkTreeStore *tree_store,
+ GtkTreeIter *iter,
+ gboolean *emit_signal,
+ gboolean *maybe_need_sort,
+ gint *columns,
+ GValue *values,
+ gint n_values)
+{
+ gint i;
+ GtkTreeIterCompareFunc func = NULL;
+
+ func = gtk_tree_store_get_compare_func (tree_store);
+ if (func != _gtk_tree_data_list_compare_func)
+ *maybe_need_sort = TRUE;
+
+ for (i = 0; i < n_values; i++)
+ {
+ *emit_signal = gtk_tree_store_real_set_value (tree_store, iter,
+ columns[i], &values[i],
+ FALSE) || *emit_signal;
+
+ if (func == _gtk_tree_data_list_compare_func &&
+ columns[i] == tree_store->sort_column_id)
+ *maybe_need_sort = TRUE;
+ }
+}
+
static void
gtk_tree_store_set_valist_internal (GtkTreeStore *tree_store,
GtkTreeIter *iter,
GValue value = { 0, };
gchar *error = NULL;
- if (column >= tree_store->n_columns)
+ if (column < 0 || column >= tree_store->n_columns)
{
g_warning ("%s: Invalid column number %d added to iter (remember to end your list of columns with a -1)", G_STRLOC, column);
break;
}
}
+/**
+ * gtk_tree_store_set_valuesv:
+ * @tree_store: A #GtkTreeStore
+ * @iter: A valid #GtkTreeIter for the row being modified
+ * @columns: (array length=n_values): an array of column numbers
+ * @values: (array length=n_values): an array of GValues
+ * @n_values: the length of the @columns and @values arrays
+ *
+ * A variant of gtk_tree_store_set_valist() which takes
+ * the columns and values as two arrays, instead of varargs. This
+ * function is mainly intended for language bindings or in case
+ * the number of columns to change is not known until run-time.
+ *
+ * Since: 2.12
+ **/
+void
+gtk_tree_store_set_valuesv (GtkTreeStore *tree_store,
+ GtkTreeIter *iter,
+ gint *columns,
+ GValue *values,
+ gint n_values)
+{
+ gboolean emit_signal = FALSE;
+ gboolean maybe_need_sort = FALSE;
+
+ g_return_if_fail (GTK_IS_TREE_STORE (tree_store));
+ g_return_if_fail (VALID_ITER (iter, tree_store));
+
+ gtk_tree_store_set_vector_internal (tree_store, iter,
+ &emit_signal,
+ &maybe_need_sort,
+ columns, values, n_values);
+
+ if (maybe_need_sort && GTK_TREE_STORE_IS_SORTED (tree_store))
+ gtk_tree_store_sort_iter_changed (tree_store, iter, tree_store->sort_column_id, TRUE);
+
+ if (emit_signal)
+ {
+ GtkTreePath *path;
+
+ path = gtk_tree_store_get_path (GTK_TREE_MODEL (tree_store), iter);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (tree_store), path, iter);
+ gtk_tree_path_free (path);
+ }
+}
+
/**
* gtk_tree_store_set_valist:
* @tree_store: A #GtkTreeStore
* The list is terminated by a -1. For example, to set column 0 with type
* %G_TYPE_STRING to "Foo", you would write
* <literal>gtk_tree_store_set (store, iter, 0, "Foo", -1)</literal>.
+ *
+ * The value will be referenced by the store if it is a %G_TYPE_OBJECT, and it
+ * will be copied if it is a %G_TYPE_STRING or %G_TYPE_BOXED.
**/
void
gtk_tree_store_set (GtkTreeStore *tree_store,
/**
* gtk_tree_store_insert:
* @tree_store: A #GtkTreeStore
- * @iter: An unset #GtkTreeIter to set to the new row
- * @parent: A valid #GtkTreeIter, or %NULL
+ * @iter: (out): An unset #GtkTreeIter to set to the new row
+ * @parent: (allow-none): A valid #GtkTreeIter, or %NULL
* @position: position to insert the new row
*
* Creates a new row at @position. If parent is non-%NULL, then the row will be
/**
* gtk_tree_store_insert_before:
* @tree_store: A #GtkTreeStore
- * @iter: An unset #GtkTreeIter to set to the new row
- * @parent: A valid #GtkTreeIter, or %NULL
- * @sibling: A valid #GtkTreeIter, or %NULL
+ * @iter: (out): An unset #GtkTreeIter to set to the new row
+ * @parent: (allow-none): A valid #GtkTreeIter, or %NULL
+ * @sibling: (allow-none): A valid #GtkTreeIter, or %NULL
*
* Inserts a new row before @sibling. If @sibling is %NULL, then the row will
* be appended to @parent 's children. If @parent and @sibling are %NULL, then
/**
* gtk_tree_store_insert_after:
* @tree_store: A #GtkTreeStore
- * @iter: An unset #GtkTreeIter to set to the new row
- * @parent: A valid #GtkTreeIter, or %NULL
- * @sibling: A valid #GtkTreeIter, or %NULL
+ * @iter: (out): An unset #GtkTreeIter to set to the new row
+ * @parent: (allow-none): A valid #GtkTreeIter, or %NULL
+ * @sibling: (allow-none): A valid #GtkTreeIter, or %NULL
*
* Inserts a new row after @sibling. If @sibling is %NULL, then the row will be
* prepended to @parent 's children. If @parent and @sibling are %NULL, then
/**
* gtk_tree_store_insert_with_values:
* @tree_store: A #GtkTreeStore
- * @iter: An unset #GtkTreeIter to set the new row, or %NULL.
- * @parent: A valid #GtkTreeIter, or %NULL
+ * @iter: (out) (allow-none): An unset #GtkTreeIter to set the new row, or %NULL.
+ * @parent: (allow-none): A valid #GtkTreeIter, or %NULL
* @position: position to insert the new row
* @Varargs: pairs of column number and value, terminated with -1
*
* Calling
* <literal>gtk_tree_store_insert_with_values (tree_store, iter, position, ...)</literal>
* has the same effect as calling
- * <informalexample><programlisting>
+ * |[
* gtk_tree_store_insert (tree_store, iter, position);
* gtk_tree_store_set (tree_store, iter, ...);
- * </programlisting></informalexample>
+ * ]|
* with the different that the former will only emit a row_inserted signal,
* while the latter will emit row_inserted, row_changed and if the tree store
* is sorted, rows_reordered. Since emitting the rows_reordered signal
/**
* gtk_tree_store_insert_with_valuesv:
* @tree_store: A #GtkTreeStore
- * @iter: An unset #GtkTreeIter to set the new row, or %NULL.
- * @parent: A valid #GtkTreeIter, or %NULL
+ * @iter: (out) (allow-none): An unset #GtkTreeIter to set the new row, or %NULL.
+ * @parent: (allow-none): A valid #GtkTreeIter, or %NULL
* @position: position to insert the new row
* @columns: an array of column numbers
* @values: an array of GValues
GtkTreeIter tmp_iter;
gboolean changed = FALSE;
gboolean maybe_need_sort = FALSE;
- GtkTreeIterCompareFunc func = NULL;
- gint i;
g_return_if_fail (GTK_IS_TREE_STORE (tree_store));
iter->user_data = new_node;
g_node_insert (parent_node, position, new_node);
- func = gtk_tree_store_get_compare_func (tree_store);
- if (func != _gtk_tree_data_list_compare_func)
- maybe_need_sort = TRUE;
-
- for (i = 0; i < n_values; i++)
- {
- changed = gtk_tree_store_real_set_value (tree_store, iter,
- columns[i], &values[i],
- FALSE) || changed;
-
- if (func == _gtk_tree_data_list_compare_func &&
- columns[i] == tree_store->sort_column_id)
- maybe_need_sort = TRUE;
- }
+ gtk_tree_store_set_vector_internal (tree_store, iter,
+ &changed, &maybe_need_sort,
+ columns, values, n_values);
if (maybe_need_sort && GTK_TREE_STORE_IS_SORTED (tree_store))
gtk_tree_store_sort_iter_changed (tree_store, iter, tree_store->sort_column_id, FALSE);
/**
* gtk_tree_store_prepend:
* @tree_store: A #GtkTreeStore
- * @iter: An unset #GtkTreeIter to set to the prepended row
- * @parent: A valid #GtkTreeIter, or %NULL
+ * @iter: (out): An unset #GtkTreeIter to set to the prepended row
+ * @parent: (allow-none): A valid #GtkTreeIter, or %NULL
*
* Prepends a new row to @tree_store. If @parent is non-%NULL, then it will prepend
* the new row before the first child of @parent, otherwise it will prepend a row
/**
* gtk_tree_store_append:
* @tree_store: A #GtkTreeStore
- * @iter: An unset #GtkTreeIter to set to the appended row
- * @parent: A valid #GtkTreeIter, or %NULL
+ * @iter: (out): An unset #GtkTreeIter to set to the appended row
+ * @parent: (allow-none): A valid #GtkTreeIter, or %NULL
*
* Appends a new row to @tree_store. If @parent is non-%NULL, then it will append the
* new row after the last child of @parent, otherwise it will append a row to
* gtk_tree_store_move_before:
* @tree_store: A #GtkTreeStore.
* @iter: A #GtkTreeIter.
- * @position: A #GtkTreeIter or %NULL.
+ * @position: (allow-none): A #GtkTreeIter or %NULL.
*
* Moves @iter in @tree_store to the position before @position. @iter and
* @position should be in the same level. Note that this function only
* gtk_tree_store_move_after:
* @tree_store: A #GtkTreeStore.
* @iter: A #GtkTreeIter.
- * @position: A #GtkTreeIter.
+ * @position: (allow-none): A #GtkTreeIter.
*
* Moves @iter in @tree_store to the position after @position. @iter and
* @position should be in the same level. Note that this function only
gint sort_column_id,
GtkTreeIterCompareFunc func,
gpointer data,
- GtkDestroyNotify destroy)
+ GDestroyNotify destroy)
{
GtkTreeStore *tree_store = (GtkTreeStore *) sortable;
gtk_tree_store_set_default_sort_func (GtkTreeSortable *sortable,
GtkTreeIterCompareFunc func,
gpointer data,
- GtkDestroyNotify destroy)
+ GDestroyNotify destroy)
{
GtkTreeStore *tree_store = (GtkTreeStore *) sortable;
if (tree_store->default_sort_destroy)
{
- GtkDestroyNotify d = tree_store->default_sort_destroy;
+ GDestroyNotify d = tree_store->default_sort_destroy;
tree_store->default_sort_destroy = NULL;
d (tree_store->default_sort_data);
}
}
-#define __GTK_TREE_STORE_C__
-#include "gtkaliasdef.c"
+/* GtkBuildable custom tag implementation
+ *
+ * <columns>
+ * <column type="..."/>
+ * <column type="..."/>
+ * </columns>
+ */
+typedef struct {
+ GtkBuilder *builder;
+ GObject *object;
+ GSList *items;
+} GSListSubParserData;
+
+static void
+tree_model_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ gpointer user_data,
+ GError **error)
+{
+ guint i;
+ GSListSubParserData *data = (GSListSubParserData*)user_data;
+
+ for (i = 0; names[i]; i++)
+ {
+ if (strcmp (names[i], "type") == 0)
+ data->items = g_slist_prepend (data->items, g_strdup (values[i]));
+ }
+}
+
+static void
+tree_model_end_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ GSListSubParserData *data = (GSListSubParserData*)user_data;
+
+ g_assert(data->builder);
+
+ if (strcmp (element_name, "columns") == 0)
+ {
+ GSList *l;
+ GType *types;
+ int i;
+ GType type;
+
+ data = (GSListSubParserData*)user_data;
+ data->items = g_slist_reverse (data->items);
+ types = g_new0 (GType, g_slist_length (data->items));
+
+ for (l = data->items, i = 0; l; l = l->next, i++)
+ {
+ type = gtk_builder_get_type_from_name (data->builder, l->data);
+ if (type == G_TYPE_INVALID)
+ {
+ g_warning ("Unknown type %s specified in treemodel %s",
+ (const gchar*)l->data,
+ gtk_buildable_get_name (GTK_BUILDABLE (data->object)));
+ continue;
+ }
+ types[i] = type;
+
+ g_free (l->data);
+ }
+
+ gtk_tree_store_set_column_types (GTK_TREE_STORE (data->object), i, types);
+
+ g_free (types);
+ }
+}
+
+static const GMarkupParser tree_model_parser =
+ {
+ tree_model_start_element,
+ tree_model_end_element
+ };
+
+
+static gboolean
+gtk_tree_store_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data)
+{
+ GSListSubParserData *parser_data;
+
+ if (child)
+ return FALSE;
+
+ if (strcmp (tagname, "columns") == 0)
+ {
+ parser_data = g_slice_new0 (GSListSubParserData);
+ parser_data->builder = builder;
+ parser_data->items = NULL;
+ parser_data->object = G_OBJECT (buildable);
+
+ *parser = tree_model_parser;
+ *data = parser_data;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+gtk_tree_store_buildable_custom_finished (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer user_data)
+{
+ GSListSubParserData *data;
+
+ if (strcmp (tagname, "columns"))
+ return;
+
+ data = (GSListSubParserData*)user_data;
+
+ g_slist_free (data->items);
+ g_slice_free (GSListSubParserData, data);
+}