1 /*
2 * Copyright (C) 2009 Canonical, Ltd.
3 *
4 * This library is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License
6 * version 3.0 as published by the Free Software Foundation.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License version 3.0 for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library. If not, see
15 * <http://www.gnu.org/licenses/>.
16 *
17 * Authored by:
18 * Neil Jagdish Patel <neil.patel@canonical.com>
19 * Mikkel Kamstrup Erlandsen <mikkel.kamstrup@canonical.com>
20 *
21 * NB: Inspiration for column storage taken from GtkListStore
22 * API inspired by ClutterModel by Matthew Allumn <mallum@openedhand.com>
23 * Neil Patel <njp@o-hand.com>
24 * Emmanuele Bassi <ebassi@openedhand.com>
25 */
26 /**
27 * SECTION:dee-model
28 * @short_description: A generic table model interface
29 * @include: dee.h
30 *
31 * #DeeModel is a generic table model that can holds #GVariant<!-- -->s as
32 * column values. Each column is restricted to hold variants with some
33 * predefined type signature. This is known as the
34 * <emphasis>column schema</emphasis>.
35 *
36 * <refsect2 id="dee-1.0-DeeModel.on_indexes">
37 * <title>Indexes - Access by Key or Full Text Analysis</title>
38 * <para>
39 * Instead of forcing you to search the rows and columns for given values
40 * or patterns #DeeModel is integrated with a powerful #DeeIndex that allows
41 * you to create custom indexes over the model content that are updated
42 * automatically as the model changes.
43 * </para>
44 * <para>
45 * Indexes can be created for integer keys, string keys (fx. URIs), or for
46 * full text search into the model contents. The indexing API is flexible
47 * and extensible and can provide huge optimizations in terms of access times
48 * if you find yourself iterating over the model searching for something.
49 * </para>
50 * </refsect2>
51 *
52 * <refsect2 id="dee-1.0-DeeModel.on_sorting">
53 * <title>Sorting</title>
54 * <para>
55 * As a simpler alternative to using indexes you can rely on sorted models.
56 * This is done by using the dee_model_insert_sorted() and
57 * dee_model_find_sorted() family of APIs. Some model classes have
58 * accelerated implementations of sorted inserts and lookups.
59 * Notably #DeeSequenceModel.
60 * </para>
61 * </refsect2>
62 *
63 * <refsect2 id="dee-1.0-DeeModel.on_tags">
64 * <title>Tags - Attach Arbitrary Data to Rows</title>
65 * <para>
66 * It's a very common pattern that you want to render a #DeeModel into some
67 * view in a classinc MVC pattern. If the view needs to reflect changes in the
68 * model dynamically you often find yourself creating ad-hoc mappings between
69 * the rows of the model and the widgets in your view.
70 * </para>
71 * <para>
72 * In situations where you need to pair the rows in a model with some external
73 * data structure the <emphasis>tags API</emphasis> may come in handy.
74 * It consists of the functions dee_model_register_tag(), dee_model_set_tag(),
75 * dee_model_get_tag(), and dee_model_clear_tag().
76 * </para>
77 * </refsect2>
78 *
79 */
80 #ifdef HAVE_CONFIG_H
81 #include <config.h>
82 #endif
83
84 #include <memory.h>
85 #include <time.h>
86 #include <unistd.h>
87
88 #include "dee-model.h"
89 #include "dee-marshal.h"
90 #include "trace-log.h"
91
92 typedef DeeModelIface DeeModelInterface;
93 G_DEFINE_INTERFACE (DeeModel, dee_model, G_TYPE_OBJECT)
94
95 enum
96 {
97 /* Public signals */
98 DEE_MODEL_SIGNAL_ROW_ADDED,
99 DEE_MODEL_SIGNAL_ROW_REMOVED,
100 DEE_MODEL_SIGNAL_ROW_CHANGED,
101 DEE_MODEL_SIGNAL_CHANGESET_STARTED,
102 DEE_MODEL_SIGNAL_CHANGESET_FINISHED,
103
104 DEE_MODEL_LAST_SIGNAL
105 };
106
107 static guint32 dee_model_signals[DEE_MODEL_LAST_SIGNAL] = { 0 };
108
109 #define CHECK_SCHEMA(self,out_num_cols,return_expression) \
110 if (G_UNLIKELY (dee_model_get_schema (self, out_num_cols) == NULL)) \
111 { \
112 g_critical ("The model %s@%p doesn't have a schema", \
113 G_OBJECT_TYPE_NAME (self), self); \
114 return_expression; \
115 }
116
117 static void dee_model_set_schema_valist (DeeModel *self,
118 va_list *args);
119
120 static void dee_model_set_column_names_valist (DeeModel *self,
121 const gchar *first_column_name,
122 va_list *args);
123
124 static DeeModelIter* dee_model_append_valist (DeeModel *self,
125 va_list *args);
126
127 static DeeModelIter* dee_model_prepend_valist (DeeModel *self,
128 va_list *args);
129
130 static DeeModelIter* dee_model_insert_valist (DeeModel *self,
131 guint pos,
132 va_list *args);
133
134 static DeeModelIter* dee_model_insert_before_valist (DeeModel *self,
135 DeeModelIter *iter,
136 va_list *args);
137
138 static void dee_model_set_valist (DeeModel *self,
139 DeeModelIter *iter,
140 va_list *args);
141
142 static void dee_model_get_valist (DeeModel *self,
143 DeeModelIter *iter,
144 va_list args);
145
146 static GVariant** dee_model_build_row_valist (DeeModel *self,
147 GVariant **out_row_members,
148 va_list *args);
149
150 /*
151 * We provide here a couple of DeeModelIter functions, so that they're usable
152 * from introspected languages.
153 */
154
155 static gpointer
dee_model_iter_copy(gpointer boxed)156 dee_model_iter_copy (gpointer boxed)
157 {
158 /* FIXME: this implementation will work fine with DeeSequenceModel, but what
159 * about others? */
160 return boxed;
161 }
162
163 static void
dee_model_iter_free(gpointer boxed)164 dee_model_iter_free (gpointer boxed)
165 {
166 }
167
dee_model_iter_get_type(void)168 GType dee_model_iter_get_type (void)
169 {
170 static GType dee_model_iter_type = 0;
171
172 if (dee_model_iter_type == 0)
173 {
174 dee_model_iter_type = g_boxed_type_register_static ("DeeModelIter",
175 dee_model_iter_copy,
176 dee_model_iter_free);
177 }
178
179 return dee_model_iter_type;
180 }
181
182 static void
dee_model_default_init(DeeModelInterface * klass)183 dee_model_default_init (DeeModelInterface *klass)
184 {
185 /**
186 * DeeModel::row-added:
187 * @self: the #DeeModel on which the signal is emitted
188 * @iter: (transfer none) (type Dee.ModelIter): a #DeeModelIter pointing to the newly added row
189 *
190 * Connect to this signal to be notified when a row is added to @self.
191 **/
192 dee_model_signals[DEE_MODEL_SIGNAL_ROW_ADDED] =
193 g_signal_new ("row-added",
194 DEE_TYPE_MODEL,
195 G_SIGNAL_RUN_LAST,
196 G_STRUCT_OFFSET (DeeModelIface,row_added),
197 NULL, NULL,
198 g_cclosure_marshal_VOID__BOXED,
199 G_TYPE_NONE, 1,
200 DEE_TYPE_MODEL_ITER);
201 /**
202 * DeeModel::row-removed:
203 * @self: the #DeeModel on which the signal is emitted
204 * @iter: (transfer none) (type Dee.ModelIter): a #DeeModelIter pointing to the removed row
205 *
206 * Connect to this signal to be notified when a row is removed from @self.
207 * The row is still valid while the signal is being emitted.
208 **/
209 dee_model_signals[DEE_MODEL_SIGNAL_ROW_REMOVED] =
210 g_signal_new ("row-removed",
211 DEE_TYPE_MODEL,
212 G_SIGNAL_RUN_LAST,
213 G_STRUCT_OFFSET (DeeModelIface,row_removed),
214 NULL, NULL,
215 g_cclosure_marshal_VOID__BOXED,
216 G_TYPE_NONE, 1,
217 DEE_TYPE_MODEL_ITER);
218 /**
219 * DeeModel::row-changed:
220 * @self: the #DeeModel on which the signal is emitted
221 * @iter: (transfer none) (type Dee.ModelIter): a #DeeModelIter pointing to the changed row
222 *
223 * Connect to this signal to be notified when a row is changed.
224 **/
225 dee_model_signals[DEE_MODEL_SIGNAL_ROW_CHANGED] =
226 g_signal_new ("row-changed",
227 DEE_TYPE_MODEL,
228 G_SIGNAL_RUN_LAST,
229 G_STRUCT_OFFSET (DeeModelIface,row_changed),
230 NULL, NULL,
231 g_cclosure_marshal_VOID__BOXED,
232 G_TYPE_NONE, 1,
233 DEE_TYPE_MODEL_ITER);
234
235 /**
236 * DeeModel::changeset-started
237 * @self: the #DeeModel on which the signal is emitted
238 *
239 * Connect to this signal to be notified when a changeset that can contain
240 * multiple row additions / changes / removals is about to be committed
241 * to the model.
242 * Note that not all model implementations use the changeset approach and
243 * you might still get a row change signal outside of changeset-started and
244 * changeset-finished signals. It also isn't guaranteed that a changeset
245 * would always be non-empty.
246 */
247 dee_model_signals[DEE_MODEL_SIGNAL_CHANGESET_STARTED] =
248 g_signal_new ("changeset-started",
249 DEE_TYPE_MODEL,
250 G_SIGNAL_RUN_LAST,
251 G_STRUCT_OFFSET (DeeModelIface, changeset_started),
252 NULL, NULL,
253 g_cclosure_marshal_VOID__VOID,
254 G_TYPE_NONE, 0);
255
256 /**
257 * DeeModel::changeset-finished
258 * @self: the #DeeModel on which the signal is emitted
259 *
260 * Connect to this signal to be notified when a changeset that can contain
261 * multiple row additions / changes / removals has been committed
262 * to the model.
263 */
264 dee_model_signals[DEE_MODEL_SIGNAL_CHANGESET_FINISHED] =
265 g_signal_new ("changeset-finished",
266 DEE_TYPE_MODEL,
267 G_SIGNAL_RUN_LAST,
268 G_STRUCT_OFFSET (DeeModelIface, changeset_finished),
269 NULL, NULL,
270 g_cclosure_marshal_VOID__VOID,
271 G_TYPE_NONE, 0);
272 }
273
274 /**
275 * dee_model_set_schema:
276 * @self: The #DeeModel to set the column layout for
277 * @VarArgs: A list of #GVariant type strings terminated by a %NULL
278 *
279 * Set the #GVariant types and the number of columns used by @self.
280 * This method must be called exactly once before using @self. Note that
281 * some constructors will do this for you.
282 *
283 * To create a model with three columns; a 32 bit integer, a string,
284 * and lastly an array of strings, you would do:
285 * <informalexample><programlisting>
286 * DeeModel *model;
287 * model = dee_sequence_model_new ();
288 * dee_model_set_schema (model, "i", "s", "as", NULL);
289 * </programlisting></informalexample>
290 */
291 void
dee_model_set_schema(DeeModel * self,...)292 dee_model_set_schema (DeeModel *self,
293 ...)
294 {
295 va_list args;
296
297 g_return_if_fail (DEE_IS_MODEL (self));
298
299 va_start (args, self);
300 dee_model_set_schema_valist(self, &args);
301 va_end (args);
302 }
303
304 /**
305 * dee_model_set_schema_valist: (skip)
306 * @self: The #DeeModel to change
307 * @VarArgs: A list of #GVariant type strings terminated by a %NULL
308 *
309 * Like dee_model_set_schema() but for language bindings.
310 */
311 static void
dee_model_set_schema_valist(DeeModel * self,va_list * args)312 dee_model_set_schema_valist (DeeModel *self,
313 va_list *args)
314 {
315 DeeModelIface *iface;
316 GSList *columns, *iter;
317 const gchar *column_schema;
318 gchar **column_schemas;
319 guint n_columns, i;
320
321 g_return_if_fail (DEE_IS_MODEL (self));
322
323 /* Extract and validate the column schema strings from the va_list */
324 column_schema = va_arg (*args, const gchar*);
325 n_columns = 0;
326 columns = NULL;
327 while (column_schema != NULL)
328 {
329 if (!g_variant_type_string_is_valid (column_schema))
330 {
331 g_critical ("When setting schema for DeeModel %p: '%s' is not a "
332 "valid GVariant type string", self, column_schema);
333 return;
334 }
335
336 columns = g_slist_prepend (columns, g_strdup (column_schema));
337 column_schema = va_arg (*args, const gchar*);
338 n_columns++;
339 }
340
341 /* Construct a string array with the validated column schemas */
342 columns = g_slist_reverse (columns);
343 column_schemas = g_new0 (gchar*, n_columns + 1);
344
345 for ((i = 0, iter = columns); iter; (i++, iter = iter->next))
346 {
347 column_schemas[i] = iter->data; // steal the duped type string
348 }
349
350 #ifdef ENABLE_TRACE_LOG
351 gchar* schema = g_strjoinv (", ", column_schemas);
352 trace_object (self, "Set schema: (%s)", schema);
353 g_free (schema);
354 #endif
355
356 iface = DEE_MODEL_GET_IFACE (self);
357 (* iface->set_schema_full) (self, (const gchar**) column_schemas, n_columns);
358
359 g_slist_free (columns);
360 g_strfreev (column_schemas);
361 }
362
363 /**
364 * dee_model_set_schema_full:
365 * @self: The #DeeModel to set the column layout for
366 * @column_schemas: (array length=num_columns zero-terminated=1) (element-type utf8) (transfer none): A list of #GVariant type strings terminated by a %NULL
367 * @num_columns: an integer specifying the array length for @VarArgs
368 *
369 * Set the #GVariant types and the number of columns used by @self.
370 * This method must be called exactly once before using @self. Note that
371 * some constructors will do this for you.
372 */
373 void
dee_model_set_schema_full(DeeModel * self,const gchar * const * column_schemas,guint num_columns)374 dee_model_set_schema_full (DeeModel *self,
375 const gchar* const *column_schemas,
376 guint num_columns)
377 {
378 DeeModelIface *iface;
379
380 g_return_if_fail (DEE_IS_MODEL (self));
381
382 if (dee_model_get_schema (self, NULL) != NULL)
383 {
384 g_critical ("The model %s@%p already has a schema set",
385 G_OBJECT_TYPE_NAME (self), self);
386 return;
387 }
388
389 iface = DEE_MODEL_GET_IFACE (self);
390
391 (* iface->set_schema_full) (self, column_schemas, num_columns);
392 }
393
394 void
dee_model_set_column_names(DeeModel * self,const gchar * first_column_name,...)395 dee_model_set_column_names (DeeModel *self, const gchar *first_column_name,
396 ...)
397 {
398 va_list args;
399
400 g_return_if_fail (DEE_IS_MODEL (self));
401
402 va_start (args, first_column_name);
403 dee_model_set_column_names_valist (self, first_column_name, &args);
404 va_end (args);
405 }
406
407 static void
dee_model_set_column_names_valist(DeeModel * self,const gchar * first_column_name,va_list * args)408 dee_model_set_column_names_valist (DeeModel *self,
409 const gchar *first_column_name,
410 va_list *args)
411 {
412 DeeModelIface *iface;
413 const gchar **column_names;
414 guint n_columns, i;
415
416 g_return_if_fail (DEE_IS_MODEL (self));
417
418 n_columns = dee_model_get_n_columns (self);
419
420 g_return_if_fail (n_columns != 0);
421
422 column_names = g_alloca (sizeof (gchar*) * n_columns);
423 column_names[0] = first_column_name;
424
425 i = 1;
426 /* Extract and validate the column schema strings from the va_list */
427 while (i < n_columns)
428 {
429 gchar *name = va_arg (*args, gchar*);
430 column_names[i++] = name;
431 if (name == NULL) break;
432 }
433
434 iface = DEE_MODEL_GET_IFACE (self);
435 (* iface->set_column_names_full) (self, column_names, i);
436 }
437
438 /**
439 * dee_model_set_column_names_full:
440 * @self: A #DeeModel.
441 * @column_names: (array length=num_columns zero-terminated=1) (element-type utf8) (transfer none): A list of column names terminated by a %NULL
442 * @num_columns: an integer specifying the array length for @annotations
443 *
444 * Set column names used by @self.
445 * This method must be called exactly once, but only after setting
446 * a schema of the model. Note that some constructors will do this for you.
447 */
448 void
dee_model_set_column_names_full(DeeModel * self,const gchar ** column_names,guint num_columns)449 dee_model_set_column_names_full (DeeModel *self,
450 const gchar **column_names,
451 guint num_columns)
452 {
453 DeeModelIface *iface;
454
455 g_return_if_fail (DEE_IS_MODEL (self));
456
457 if (dee_model_get_schema (self, NULL) == NULL)
458 {
459 g_critical ("The model %s@%p doesn't have a schema set",
460 G_OBJECT_TYPE_NAME (self), self);
461 return;
462 }
463
464 iface = DEE_MODEL_GET_IFACE (self);
465 (* iface->set_column_names_full) (self, column_names, num_columns);
466 }
467
468 /**
469 * dee_model_get_column_names:
470 * @self: The #DeeModel to get the the schema for
471 * @num_columns: (out) (allow-none): Address of an integer in which to store the
472 * number of columns in @self. Or %NULL to ignore the array length.
473 *
474 * Get a %NULL-terminated array of column names for the columns of @self.
475 * These names can be used in calls to dee_model_build_named_row().
476 *
477 * Returns: (array length=num_columns) (element-type utf8) (transfer none):
478 * A %NULL-terminated array of #GVariant type strings. The length of
479 * the returned array is written to @num_columns. The returned array
480 * should not be freed or modified. It is owned by the model.
481 */
482 const gchar**
dee_model_get_column_names(DeeModel * self,guint * num_columns)483 dee_model_get_column_names (DeeModel *self,
484 guint *num_columns)
485 {
486 DeeModelIface *iface;
487
488 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
489
490 iface = DEE_MODEL_GET_IFACE (self);
491
492 return (* iface->get_column_names) (self, num_columns);
493 }
494
495 /**
496 * dee_model_get_schema:
497 * @self: The #DeeModel to get the the schema for
498 * @num_columns: (out) (allow-none): Address of an integer in which to store the
499 * number of columns in @self. Or %NULL to ignore the array length.
500 *
501 * Get a %NULL-terminated array of #GVariant type strings that defines the
502 * required formats for the columns of @self.
503 *
504 * Returns: (array length=num_columns) (element-type utf8) (transfer none):
505 * A %NULL-terminated array of #GVariant type strings. The length of
506 * the returned array is written to @num_columns. The returned array
507 * should not be freed or modified. It is owned by the model.
508 */
509 const gchar* const*
dee_model_get_schema(DeeModel * self,guint * num_columns)510 dee_model_get_schema (DeeModel *self,
511 guint *num_columns)
512 {
513 DeeModelIface *iface;
514
515 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
516
517 iface = DEE_MODEL_GET_IFACE (self);
518
519 return (* iface->get_schema) (self, num_columns);
520 }
521
522 /**
523 * dee_model_get_column_schema:
524 * @self: a #DeeModel
525 * @column: the column to get retrieve the #GVariant type string of
526 *
527 * Get the #GVariant signature of a column
528 *
529 * Return value: the #GVariant signature of the column at index @column
530 */
531 const gchar*
dee_model_get_column_schema(DeeModel * self,guint column)532 dee_model_get_column_schema (DeeModel *self,
533 guint column)
534 {
535 DeeModelIface *iface;
536
537 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
538
539 iface = DEE_MODEL_GET_IFACE (self);
540
541 return (* iface->get_column_schema) (self, column);
542 }
543
544 /**
545 * dee_model_get_field_schema:
546 * @self: a #DeeModel
547 * @field_name: name of vardict field to get schema of
548 * @out_column: (out): column index of the associated vardict
549 *
550 * Get the #GVariant signature of field previously registered with
551 * dee_model_register_vardict_schema().
552 *
553 * Return value: the #GVariant signature for the field, or %NULL if given field
554 * wasn't registered with dee_model_register_vardict_schema().
555 */
556 const gchar*
dee_model_get_field_schema(DeeModel * self,const gchar * field_name,guint * out_column)557 dee_model_get_field_schema (DeeModel *self,
558 const gchar *field_name,
559 guint *out_column)
560 {
561 DeeModelIface *iface;
562
563 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
564
565 iface = DEE_MODEL_GET_IFACE (self);
566
567 return (* iface->get_field_schema) (self, field_name, out_column);
568 }
569
570 /**
571 * dee_model_get_column_index:
572 * @self: a #DeeModel
573 * @column_name: the column name to retrieve the index of
574 *
575 * Get the column index of a column.
576 *
577 * Return value: 0-based index of the column or -1 if column with this name
578 * wasn't found
579 */
580 gint
dee_model_get_column_index(DeeModel * self,const gchar * column_name)581 dee_model_get_column_index (DeeModel *self,
582 const gchar *column_name)
583 {
584 DeeModelIface *iface;
585
586 g_return_val_if_fail (DEE_IS_MODEL (self), -1);
587
588 iface = DEE_MODEL_GET_IFACE (self);
589
590 return (* iface->get_column_index) (self, column_name);
591 }
592
593 /**
594 * dee_model_register_vardict_schema:
595 * @self: a #DeeModel
596 * @column: the column index to register the schemas with
597 * @schemas: (element-type utf8 utf8): hashtable with keys specifying
598 * names of the fields and values defining their schema
599 *
600 * Register schema for fields in a model containing column with variant
601 * dictionary schema ('a{sv}').
602 * The keys registered with this function can be later used
603 * with dee_model_build_named_row() function, as well as
604 * dee_model_get_value_by_name(). Note that it is possible to register
605 * the same field name for multiple columns, in which case you need to use
606 * fully-qualified "column_name::field" name in the calls to
607 * dee_model_build_named_row() and dee_model_get_field_schema().
608 */
609 void
dee_model_register_vardict_schema(DeeModel * self,guint column,GHashTable * schemas)610 dee_model_register_vardict_schema (DeeModel *self,
611 guint column,
612 GHashTable *schemas)
613 {
614 DeeModelIface *iface;
615
616 g_return_if_fail (DEE_IS_MODEL (self));
617
618 iface = DEE_MODEL_GET_IFACE (self);
619
620 return (* iface->register_vardict_schema) (self, column, schemas);
621 }
622
623 /**
624 * dee_model_get_vardict_schema:
625 * @self: a #DeeModel
626 * @column: the column index to get the schemas for
627 *
628 * Get a schema for variant dictionary column previously registered using
629 * dee_model_register_vardict_schema().
630 *
631 * Return value: (transfer container) (element-type utf8 utf8): Hashtable
632 * containing a mapping from field names to schemas or NULL.
633 * Note that keys and values in the hashtable may be owned
634 * by the model, so you need to create a deep copy if you
635 * intend to keep the hashtable around.
636 */
637 GHashTable*
dee_model_get_vardict_schema(DeeModel * self,guint column)638 dee_model_get_vardict_schema (DeeModel *self, guint column)
639 {
640 DeeModelIface *iface;
641
642 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
643
644 iface = DEE_MODEL_GET_IFACE (self);
645
646 return (* iface->get_vardict_schema) (self, column);
647 }
648
649 /**
650 * dee_model_get_n_columns:
651 * @self: a #DeeModel
652 *
653 * Gets the number of columns in @self
654 *
655 * Return value: the number of columns per row in @self
656 **/
657 guint
dee_model_get_n_columns(DeeModel * self)658 dee_model_get_n_columns (DeeModel *self)
659 {
660 DeeModelIface *iface;
661
662 g_return_val_if_fail (DEE_IS_MODEL (self), 0);
663
664 iface = DEE_MODEL_GET_IFACE (self);
665
666 return (* iface->get_n_columns) (self);
667 }
668
669 /**
670 * dee_model_get_n_rows:
671 * @self: a #DeeModel
672 *
673 * Gets the number of rows in @self
674 *
675 * Return value: the number of rows in @self
676 **/
677 guint
dee_model_get_n_rows(DeeModel * self)678 dee_model_get_n_rows (DeeModel *self)
679 {
680 DeeModelIface *iface;
681
682 g_return_val_if_fail (DEE_IS_MODEL (self), 0);
683
684 iface = DEE_MODEL_GET_IFACE (self);
685
686 return (* iface->get_n_rows) (self);
687 }
688
689 /**
690 * dee_model_begin_changeset:
691 * @self: a #DeeModel
692 *
693 * Notify listeners that the model is about to be changed, which means that
694 * multiple row additions / changes / removals will follow.
695 * The default implementation of this method will emit
696 * the ::changeset-started signal.
697 *
698 * It is not stricly necessary to enclose every change to a model
699 * in a dee_model_begin_changeset() and dee_model_end_changeset() calls, but
700 * doing so is highly recommended and allows implementing various optimizations.
701 *
702 * The usual way to perform multiple changes to a model is as follows:
703 *
704 * <programlisting>
705 * void update_model (DeeModel *model)
706 * {
707 * GVariant **added_row_data1 = ...;
708 * GVariant **added_row_data2 = ...;
709 *
710 * dee_model_begin_changeset (model);
711 *
712 * dee_model_remove (model, dee_model_get_first_iter (model));
713 * dee_model_append_row (model, added_row_data1);
714 * dee_model_append_row (model, added_row_data2);
715 *
716 * dee_model_end_changeset (model);
717 * }
718 * </programlisting>
719 */
720 void
dee_model_begin_changeset(DeeModel * self)721 dee_model_begin_changeset (DeeModel *self)
722 {
723 DeeModelIface *iface;
724
725 g_return_if_fail (DEE_IS_MODEL (self));
726
727 iface = DEE_MODEL_GET_IFACE (self);
728
729 if (iface->begin_changeset)
730 (* iface->begin_changeset) (self);
731 else
732 g_signal_emit (self, dee_model_signals[DEE_MODEL_SIGNAL_CHANGESET_STARTED], 0);
733 }
734
735 /**
736 * dee_model_end_changeset:
737 * @self: a #DeeModel
738 *
739 * Notify listeners that all changes have been committed to the model.
740 * The default implementation of this method will emit
741 * the ::changeset-finished signal.
742 *
743 * See also dee_model_begin_changeset().
744 */
745 void
dee_model_end_changeset(DeeModel * self)746 dee_model_end_changeset (DeeModel *self)
747 {
748 DeeModelIface *iface;
749
750 g_return_if_fail (DEE_IS_MODEL (self));
751
752 iface = DEE_MODEL_GET_IFACE (self);
753
754 if (iface->end_changeset)
755 (* iface->end_changeset) (self);
756 else
757 g_signal_emit (self, dee_model_signals[DEE_MODEL_SIGNAL_CHANGESET_FINISHED], 0);
758 }
759
760 static GVariant*
collect_variant(const gchar * col_schema,va_list * args)761 collect_variant (const gchar* col_schema, va_list *args)
762 {
763 const gchar *col_string;
764 GVariant *result;
765
766 if (g_variant_type_is_basic (G_VARIANT_TYPE (col_schema)))
767 {
768 switch (col_schema[0])
769 {
770 case 's':
771 case 'o':
772 case 'g':
773 col_string = va_arg (*args, const gchar*);
774 result = g_variant_new (col_schema, col_string ? col_string : "");
775 break;
776 default:
777 result = g_variant_new_va (col_schema, NULL, args);
778 }
779 }
780 else
781 result = va_arg (*args, GVariant*);
782
783 return result;
784 }
785
786 /**
787 * dee_model_build_row:
788 * @self: The model to create a row for
789 * @out_row_members: An array to write the values to or %NULL to allocate
790 * a new array. If non-%NULL it must have a length
791 * that is longer or equal to the number of columns in @self
792 * @VarArgs: A list with values matching the column schemas of @self.
793 * Basic variant types are passed directly while any other
794 * types must be boxed in a #GVariant. It's important to note that
795 * any floating references on variants passed to this method will be
796 * <emphasis>not</emphasis> be consumed. A %NULL value for a string
797 * type column will be converted to the empty string.
798 *
799 * Build an array of #GVariant<!-- -->s with values from the variadic argument
800 * list according to the model schema for @self. The caller must call
801 * g_variant_ref_sink() and g_variant_unref() on all the returned variants and
802 * g_free() the array itself if %NULL was passed as @out_row_members.
803 *
804 * This is utility function and will not touch or modify @self in any way.
805 *
806 * Returns: If @out_row_members is %NULL a newly allocated array of variants
807 * will be returned and the array must be freed with g_free().
808 * If @out_row_members is non-%NULL it will be reused, and variants in
809 * the array may or may not have floating references, which means the
810 * caller must make sure that g_variant_ref_sink() and
811 * g_variant_unref() are called on them.
812 *
813 */
814 GVariant**
dee_model_build_row(DeeModel * self,GVariant ** out_row_members,...)815 dee_model_build_row (DeeModel *self,
816 GVariant **out_row_members,
817 ...)
818 {
819 va_list args;
820 GVariant **result;
821
822 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
823
824 CHECK_SCHEMA (self, NULL, return NULL);
825
826 va_start (args, out_row_members);
827 result = dee_model_build_row_valist (self, out_row_members, &args);
828 va_end (args);
829
830 return result;
831 }
832
833 /**
834 * dee_model_build_row_valist: (skip):
835 * @self: The model to build a row for
836 * @out_row_members: An array to write the values to or %NULL to allocate
837 * a new array
838 * @args: A %va_list of arguments as described in dee_model_build_row()
839 *
840 * Like dee_model_build_row() but intended for language bindings.
841 *
842 * Returns: See dee_model_build_row()
843 */
844 static GVariant**
dee_model_build_row_valist(DeeModel * self,GVariant ** out_row_members,va_list * args)845 dee_model_build_row_valist (DeeModel *self,
846 GVariant **out_row_members,
847 va_list *args)
848 {
849 guint i, n_cols;
850 const gchar *col_schema;
851 const gchar *const *schema;
852
853 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
854
855 schema = dee_model_get_schema (self, &n_cols);
856
857 if (out_row_members == NULL)
858 out_row_members = g_new0 (GVariant*, n_cols);
859
860 for (i = 0; i < n_cols; i++)
861 {
862 col_schema = schema[i];
863
864 out_row_members[i] = collect_variant (col_schema, args);
865
866 if (G_UNLIKELY (out_row_members[i] == NULL))
867 {
868 g_critical ("Trying to build a row with a NULL member on position"
869 " %i. This is probably an error in an application using"
870 " libdee", i);
871 return NULL;
872 }
873 }
874
875 return out_row_members;
876 }
877
878 /**
879 * dee_model_build_named_row:
880 * @self: The model to create a row for
881 * @out_row_members: An array to write the values to or %NULL to allocate
882 * a new array. If non-%NULL it must have a length
883 * that is longer or equal to the number of columns in @self
884 * @first_column_name: A column name
885 * @VarArgs: Value for given column, followed by more name/value pairs,
886 * followed by %NULL. The passed names have to match the column names
887 * (or field names registered with
888 * dee_model_register_vardict_schema()) and values have to be set
889 * according to schema of the given column or field.
890 * Basic variant types are passed directly while any other types
891 * must be boxed in a #GVariant, similar to dee_model_build_row().
892 *
893 * Build an array of #GVariant<!-- -->s with values from the variadic argument
894 * list according to the column names and model schema for @self.
895 * The caller must call g_variant_ref_sink() and g_variant_unref()
896 * on all the returned variants and g_free() the array itself if %NULL
897 * was passed as @out_row_members.
898 *
899 * This is utility function and will not touch or modify @self in any way.
900 *
901 * For example, to append a row to model with signature ("s", "u", "s") and
902 * column names set to ("uri", "count", "description") you could do:
903 * <informalexample><programlisting>
904 * GVariant *row_buf[3];
905 *
906 * dee_model_append_row (model,
907 * dee_model_build_named_row (model, row_buf,
908 * "uri", "http://example.org",
909 * "count", 435,
910 * "description", "Example.org site", NULL));
911 * </programlisting></informalexample>
912 *
913 * Returns: If @out_row_members is %NULL a newly allocated array of variants
914 * will be returned and the array must be freed with g_free().
915 * If @out_row_members is non-%NULL it will be reused, and variants in
916 * the array may or may not have floating references, which means the
917 * caller must make sure that g_variant_ref_sink() and
918 * g_variant_unref() are called on them.
919 *
920 */
921 GVariant**
dee_model_build_named_row(DeeModel * self,GVariant ** out_row_members,const gchar * first_column_name,...)922 dee_model_build_named_row (DeeModel *self,
923 GVariant **out_row_members,
924 const gchar *first_column_name,
925 ...)
926 {
927 va_list args;
928 GVariant **result;
929
930 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
931
932 CHECK_SCHEMA (self, NULL, return NULL);
933
934 va_start (args, first_column_name);
935 result = dee_model_build_named_row_valist (self, out_row_members,
936 first_column_name, &args);
937 va_end (args);
938
939 return result;
940 }
941
942 /**
943 * dee_model_build_named_row_sunk:
944 * @self: The model to create a row for
945 * @out_row_members: (array): An array to write the values to or %NULL to
946 * allocate a new array. If non-%NULL it must have a length
947 * that is longer or equal to the number of columns in @self
948 * @out_array_length: (out): Length of the returned variant array
949 * @first_column_name: A column name
950 * @VarArgs: Value for given column, followed by more name/value pairs,
951 * followed by %NULL. The passed names have to match the column names
952 * and values have to be set according to schema of @self.
953 * Basic variant types are passed directly while any other types
954 * must be boxed in a #GVariant, similar to dee_model_build_row().
955 *
956 * Version of dee_model_build_named_row() for language bindings - as opposed to
957 * dee_model_build_named_row(), the returned variants will be strong
958 * references, therefore you always have to call g_variant_unref() on the items
959 * and g_free() the array itself if %NULL was passed as @out_row_members.
960 *
961 * If @out_row_members is non-%NULL, g_variant_unref() will be called
962 * on its elements (if also non-%NULL), which allows easy reuse of the array
963 * memory in loops.
964 *
965 * This is utility function and will not touch or modify @self in any way.
966 *
967 * Example of memory management for model with schema ("s", "i") and
968 * column names ("uri", "count"):
969 * <informalexample><programlisting>
970 * GVariant **row_buf;
971 *
972 * row_buf = dee_model_build_named_row_sunk (model, NULL, "uri", "file:///",
973 * "count", 0, NULL);
974 * dee_model_append_row (model, row_buf);
975 *
976 * for (int i = 1; i < 100; i++)
977 * {
978 * dee_model_append_row (model,
979 * dee_model_build_named_row_sunk (model, row_buf, "uri", "file:///",
980 * "count", i, NULL));
981 * }
982 *
983 * g_variant_unref (row_buf[0]);
984 * g_variant_unref (row_buf[1]);
985 * g_free (row_buf);
986 * </programlisting></informalexample>
987 *
988 * Returns: (array length=out_array_length): If @out_row_members is %NULL
989 * a newly allocated array of variants will be returned and the array
990 * must be freed with g_free().
991 * If @out_row_members is non-%NULL it will be reused. Variants in
992 * the array will have strong references, which means the
993 * caller must make sure that g_variant_unref() is called on them.
994 *
995 */
996 GVariant**
dee_model_build_named_row_sunk(DeeModel * self,GVariant ** out_row_members,guint * out_array_length,const gchar * first_column_name,...)997 dee_model_build_named_row_sunk (DeeModel *self,
998 GVariant **out_row_members,
999 guint *out_array_length,
1000 const gchar *first_column_name,
1001 ...)
1002 {
1003 va_list args;
1004 guint num_columns, i;
1005 GVariant **result;
1006
1007 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
1008
1009 CHECK_SCHEMA (self, &num_columns, return NULL);
1010
1011 if (out_row_members)
1012 {
1013 for (i = 0; i < num_columns; i++)
1014 {
1015 if (out_row_members[i]) g_variant_unref (out_row_members[i]);
1016 }
1017 }
1018
1019 va_start (args, first_column_name);
1020 result = dee_model_build_named_row_valist (self, out_row_members,
1021 first_column_name, &args);
1022 va_end (args);
1023
1024 if (result)
1025 {
1026 for (i = 0; i < num_columns; i++)
1027 {
1028 g_variant_ref_sink (result[i]);
1029 }
1030 }
1031
1032 if (out_array_length)
1033 *out_array_length = result != NULL ? num_columns : 0;
1034
1035 return result;
1036 }
1037
1038 GVariant**
dee_model_build_named_row_valist(DeeModel * self,GVariant ** out_row_members,const gchar * first_column_name,va_list * args)1039 dee_model_build_named_row_valist (DeeModel *self,
1040 GVariant **out_row_members,
1041 const gchar *first_column_name,
1042 va_list *args)
1043 {
1044 DeeModelIface *iface;
1045 guint n_cols, i;
1046 gint col_idx, last_unset_col;
1047 gboolean *variant_set;
1048 GVariantBuilder **builders;
1049 const gchar *col_name, *col_schema;
1050 const gchar *const *schema;
1051
1052 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
1053
1054 schema = dee_model_get_schema (self, &n_cols);
1055
1056 if (out_row_members == NULL)
1057 out_row_members = g_new0 (GVariant*, n_cols);
1058
1059 variant_set = g_alloca (n_cols * sizeof (gboolean));
1060 memset (variant_set, 0, n_cols * sizeof (gboolean));
1061
1062 builders = g_alloca (n_cols * sizeof (GVariantBuilder*));
1063 memset (builders, 0, n_cols * sizeof (GVariantBuilder*));
1064
1065 iface = DEE_MODEL_GET_IFACE (self);
1066
1067 col_name = first_column_name;
1068 while (col_name != NULL)
1069 {
1070 col_idx = (* iface->get_column_index) (self, col_name);
1071 if (col_idx >= 0)
1072 {
1073 col_schema = schema[col_idx];
1074
1075 out_row_members[col_idx] = collect_variant (col_schema, args);
1076
1077 if (G_UNLIKELY (out_row_members[col_idx] == NULL))
1078 {
1079 g_critical ("Trying to build a row with a NULL member for column"
1080 " %s. This is probably an error in an application using"
1081 " libdee", col_name);
1082 break;
1083 }
1084 else
1085 {
1086 variant_set[col_idx] = TRUE;
1087 }
1088 }
1089 else
1090 {
1091 // check if we have hints
1092 col_schema = (* iface->get_field_schema) (self, col_name, (guint*) &col_idx);
1093 if (col_schema != NULL)
1094 {
1095 const gchar *key_name;
1096 if (builders[col_idx] == NULL)
1097 {
1098 builders[col_idx] = g_variant_builder_new (G_VARIANT_TYPE (schema[col_idx]));
1099 }
1100
1101 key_name = strstr (col_name, "::");
1102 key_name = key_name != NULL ? key_name + 2 : col_name;
1103 g_variant_builder_add (builders[col_idx], "{sv}",
1104 key_name,
1105 collect_variant (col_schema, args));
1106 }
1107 else
1108 {
1109 g_warning ("Unable to find column index for \"%s\"", col_name);
1110 /* need to break, cause there's no way to know size of the value */
1111 break;
1112 }
1113 }
1114 col_name = va_arg (*args, const gchar*);
1115 }
1116
1117 /* Finish builders */
1118 for (i = 0; i < n_cols; i++)
1119 {
1120 if (builders[i])
1121 {
1122 out_row_members[i] = g_variant_builder_end (builders[i]);
1123 g_variant_builder_unref (builders[i]);
1124 variant_set[i] = TRUE;
1125 }
1126 }
1127
1128 /* Check if all columns were set */
1129 last_unset_col = -1;
1130 for (i = 0; i < n_cols; i++)
1131 {
1132 if (!variant_set[i])
1133 {
1134 /* Create empty a{sv} if needed */
1135 if (g_variant_type_is_subtype_of (G_VARIANT_TYPE (schema[i]),
1136 G_VARIANT_TYPE_VARDICT))
1137 {
1138 GVariantBuilder builder;
1139 g_variant_builder_init (&builder, G_VARIANT_TYPE (schema[i]));
1140 out_row_members[i] = g_variant_builder_end (&builder);
1141 variant_set[i] = TRUE;
1142 }
1143 else
1144 {
1145 last_unset_col = i;
1146 }
1147 }
1148 }
1149
1150 if (last_unset_col >= 0)
1151 {
1152 /* Be nice and unref the variants we created */
1153 for (i = 0; i < n_cols; i++)
1154 {
1155 if (variant_set[i])
1156 {
1157 g_variant_unref (g_variant_ref_sink (out_row_members[i]));
1158 out_row_members[i] = NULL;
1159 }
1160 }
1161
1162 const gchar **names = dee_model_get_column_names (self, NULL);
1163 g_critical ("Unable to build row: Column %d '%s' wasn't set",
1164 last_unset_col, names ? names[last_unset_col] : "unnamed");
1165 return NULL;
1166 }
1167
1168 return out_row_members;
1169 }
1170
1171 /**
1172 * dee_model_append:
1173 * @self: a #DeeModel
1174 * @VarArgs: A list of values matching the column schemas of @self.
1175 * Any basic variant type is passed as the standard C type while
1176 * any other type must be boxed in a #GVariant. Any floating
1177 * references will be consumed. A %NULL value for a string
1178 * type column will be converted to the empty string.
1179 *
1180 * Creates and appends a new row to the end of a #DeeModel, setting the row
1181 * values upon creation.
1182 *
1183 * For and example see dee_model_insert_before().
1184 *
1185 * Returns: (transfer none) (type Dee.ModelIter): A #DeeModelIter pointing to the new row
1186 */
1187 DeeModelIter*
dee_model_append(DeeModel * self,...)1188 dee_model_append (DeeModel *self,
1189 ...)
1190 {
1191 DeeModelIter *iter;
1192 va_list args;
1193
1194 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
1195
1196 va_start (args, self);
1197 iter = dee_model_append_valist (self, &args);
1198 va_end (args);
1199
1200 return iter;
1201 }
1202
1203 /**
1204 * dee_model_append_valist: (skip):
1205 * @self: A #DeeModel
1206 * @args: A pointer to a variable argument list
1207 *
1208 * Returns: A #DeeModelIter pointing to the new row
1209 */
1210 static DeeModelIter*
dee_model_append_valist(DeeModel * self,va_list * args)1211 dee_model_append_valist (DeeModel *self,
1212 va_list *args)
1213 {
1214 DeeModelIface *iface;
1215 DeeModelIter *iter;
1216 GVariant **row_members;
1217 guint num_columns;
1218
1219 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
1220 CHECK_SCHEMA (self, &num_columns, return NULL);
1221
1222 iface = DEE_MODEL_GET_IFACE (self);
1223
1224 row_members = g_alloca (num_columns * sizeof (gpointer));
1225
1226 dee_model_build_row_valist (self, row_members, args);
1227
1228 iter = (* iface->append_row) (self, row_members);
1229 return iter;
1230 }
1231
1232 /**
1233 * dee_model_append_row:
1234 * @self: The model to prepend a row to
1235 * @row_members: (array zero-terminated=1): An array of #GVariants with type
1236 * signature matching those of the column schemas of @self.
1237 * If any of the variants have floating references they will be
1238 * consumed
1239 *
1240 * Like dee_model_append() but intended for language bindings or
1241 * situations where you work with models on a meta level and may not have
1242 * a prior knowledge of the column schemas of the models. See also
1243 * dee_model_build_row().
1244 *
1245 * Returns: (transfer none) (type Dee.ModelIter): A #DeeModelIter pointing to the new row
1246 */
1247 DeeModelIter*
dee_model_append_row(DeeModel * self,GVariant ** row_members)1248 dee_model_append_row (DeeModel *self,
1249 GVariant **row_members)
1250 {
1251 DeeModelIface *iface;
1252
1253 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
1254 CHECK_SCHEMA (self, NULL, return NULL);
1255
1256 iface = DEE_MODEL_GET_IFACE (self);
1257
1258 return (* iface->append_row) (self, row_members);
1259 }
1260
1261 /**
1262 * dee_model_prepend:
1263 * @self: a #DeeModel
1264 * @VarArgs: A list of values matching the column schemas of @self.
1265 * Any basic variant type is passed as the standard C type while
1266 * any other type must be boxed in a #GVariant. Any floating
1267 * references will be consumed. A %NULL value for a string
1268 * type column will be converted to the empty string.
1269 *
1270 * Creates and prepends a new row to the beginning of a #DeeModel, setting the
1271 * row values upon creation.
1272 *
1273 * Example:
1274 *
1275 * <informalexample><programlisting>
1276 * DeeModel *model;
1277 * model = ...
1278 * dee_model_set_schema (model, "i", "s", NULL);
1279 * dee_model_prepend (model, 10, "Rooney");
1280 * </programlisting></informalexample>
1281 *
1282 * Returns: (transfer none) (type Dee.ModelIter): A #DeeModelIter pointing to the new row
1283 */
1284 DeeModelIter*
dee_model_prepend(DeeModel * self,...)1285 dee_model_prepend (DeeModel *self,
1286 ...)
1287 {
1288 DeeModelIter *iter;
1289 va_list args;
1290
1291 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
1292
1293 va_start (args, self);
1294 iter = dee_model_prepend_valist (self, &args);
1295 va_end (args);
1296
1297 return iter;
1298 }
1299
1300 /**
1301 * dee_model_prepend_valist: (skip):
1302 * @self: A #DeeModel
1303 * @args: A pointer to a variable argument list
1304 *
1305 * Returns: A #DeeModelIter pointing to the new row
1306 */
1307 static DeeModelIter*
dee_model_prepend_valist(DeeModel * self,va_list * args)1308 dee_model_prepend_valist (DeeModel *self,
1309 va_list *args)
1310 {
1311 DeeModelIface *iface;
1312 DeeModelIter *iter;
1313 GVariant **row_members;
1314 guint num_columns;
1315
1316 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
1317 CHECK_SCHEMA (self, &num_columns, return NULL);
1318
1319 iface = DEE_MODEL_GET_IFACE (self);
1320
1321 row_members = g_alloca (num_columns * sizeof (gpointer));
1322
1323 dee_model_build_row_valist (self, row_members, args);
1324
1325 iter = (* iface->prepend_row) (self, row_members);
1326 return iter;
1327 }
1328
1329 /**
1330 * dee_model_prepend_row:
1331 * @self: The model to prepend a row to
1332 * @row_members: (array zero-terminated=1): An array of
1333 * #GVariants with type signature matching those of
1334 * the column schemas of @self. If any of the variants have
1335 * floating references they will be consumed.
1336 *
1337 * Like dee_model_prepend() but intended for language bindings or
1338 * situations where you work with models on a meta level and may not have
1339 * a priori knowledge of the column schemas of the models. See also
1340 * dee_model_build_row().
1341 *
1342 * Returns: (transfer none) (type Dee.ModelIter): A #DeeModelIter pointing to the new row
1343 */
1344 DeeModelIter*
dee_model_prepend_row(DeeModel * self,GVariant ** row_members)1345 dee_model_prepend_row (DeeModel *self,
1346 GVariant **row_members)
1347 {
1348 DeeModelIface *iface;
1349
1350 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
1351
1352 CHECK_SCHEMA (self, NULL, return NULL);
1353
1354 iface = DEE_MODEL_GET_IFACE (self);
1355
1356 return (* iface->prepend_row) (self, row_members);
1357 }
1358
1359 /**
1360 * dee_model_insert:
1361 * @self: a #DeeModel
1362 * @pos: The index to insert the row on. The existing row will be pushed down
1363 * @VarArgs: A list of values matching the column schemas of @self.
1364 * Any basic variant type is passed as the standard C type while
1365 * any other type must be boxed in a #GVariant. Any floating
1366 * references will be consumed. A %NULL value for a string
1367 * type column will be converted to the empty string.
1368 *
1369 * Creates and inserts a new row into a #DeeModel, pushing the existing
1370 * rows down.
1371 *
1372 * For and example see dee_model_insert_before().
1373 *
1374 * Returns: (transfer none) (type Dee.ModelIter): A #DeeModelIter pointing to the new row
1375 */
1376 DeeModelIter*
dee_model_insert(DeeModel * self,guint pos,...)1377 dee_model_insert (DeeModel *self,
1378 guint pos,
1379 ...)
1380 {
1381 DeeModelIter *iter;
1382 va_list args;
1383
1384 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
1385
1386 va_start (args, pos);
1387 iter = dee_model_insert_valist (self, pos, &args);
1388 va_end (args);
1389
1390 return iter;
1391 }
1392
1393 /**
1394 * dee_model_insert_valist: (skip):
1395 * @self: A #DeeModel
1396 * @pos: The index to insert the row on. The existing row will be pushed down
1397 * @args: A pointer to a variable argument list
1398 *
1399 * Returns: A #DeeModelIter pointing to the new row
1400 */
1401 static DeeModelIter*
dee_model_insert_valist(DeeModel * self,guint pos,va_list * args)1402 dee_model_insert_valist (DeeModel *self,
1403 guint pos,
1404 va_list *args)
1405 {
1406 DeeModelIface *iface;
1407 DeeModelIter *iter;
1408 GVariant **row_members;
1409 guint num_columns;
1410
1411 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
1412 CHECK_SCHEMA (self, &num_columns, return NULL);
1413
1414 iface = DEE_MODEL_GET_IFACE (self);
1415
1416 row_members = g_alloca (num_columns * sizeof (gpointer));
1417
1418 dee_model_build_row_valist (self, row_members, args);
1419
1420 iter = (* iface->insert_row) (self, pos, row_members);
1421 return iter;
1422 }
1423
1424 /**
1425 * dee_model_insert_row:
1426 * @self: a #DeeModel
1427 * @pos: The index to insert the row on. The existing row will be pushed down.
1428 * @row_members: (array zero-terminated=1): An array of
1429 * #GVariants with type signature matching those of
1430 * the column schemas of @self. If any of the variants have
1431 * floating references they will be consumed.
1432 *
1433 * As dee_model_insert(), but intended for language bindings or
1434 * situations where you work with models on a meta level and may not have
1435 * a priori knowledge of the column schemas of the models. See also
1436 * dee_model_build_row().
1437 *
1438 * Returns: (transfer none) (type Dee.ModelIter): A #DeeModelIter pointing to the new row
1439 */
1440 DeeModelIter*
dee_model_insert_row(DeeModel * self,guint pos,GVariant ** row_members)1441 dee_model_insert_row (DeeModel *self,
1442 guint pos,
1443 GVariant **row_members)
1444 {
1445 DeeModelIface *iface;
1446
1447 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
1448
1449 CHECK_SCHEMA (self, NULL, return NULL);
1450
1451 iface = DEE_MODEL_GET_IFACE (self);
1452
1453 return (* iface->insert_row) (self, pos, row_members);
1454 }
1455
1456 /**
1457 * dee_model_insert_before:
1458 * @self: a #DeeModel
1459 * @iter: An iter pointing to the row before which to insert the new one
1460 * @VarArgs: A list of values matching the column schemas of @self.
1461 * Any basic variant type is passed as the standard C type while
1462 * any other type must be boxed in a #GVariant. Any floating
1463 * references will be consumed. A %NULL value for a string
1464 * type column will be converted to the empty string.
1465 *
1466 * Creates and inserts a new row into a #DeeModel just before the row pointed
1467 * to by @iter.
1468 *
1469 * For example, to insert a new row in a model with schema ("u", "s", "as")
1470 * you would do:
1471 *
1472 * <informalexample><programlisting>
1473 * DeeModelIter *iter;
1474 * GVariantBuilder b;
1475 *
1476 * g_variant_builder_init (&b, "as");
1477 * g_variant_builder_add (&b, "s", "Hello");
1478 * g_variant_builder_add (&b, "s", "World");
1479 *
1480 * iter = find_my_special_row (model);
1481 * dee_model_insert_before (model, iter,
1482 * 27,
1483 * "Howdy",
1484 * g_variant_builder_end (&b));
1485 * </programlisting></informalexample>
1486 *
1487 * Returns: (transfer none) (type Dee.ModelIter): A #DeeModelIter pointing to the new row
1488 */
1489 DeeModelIter*
dee_model_insert_before(DeeModel * self,DeeModelIter * iter,...)1490 dee_model_insert_before (DeeModel *self,
1491 DeeModelIter *iter,
1492 ...)
1493 {
1494 va_list args;
1495
1496 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
1497
1498 va_start (args, iter);
1499 iter = dee_model_insert_before_valist (self, iter, &args);
1500 va_end (args);
1501
1502 return iter;
1503 }
1504
1505 /**
1506 * dee_model_insert_before_valist: (skip):
1507 * @self: a #DeeModel
1508 * @iter: An iter pointing to the row before which to insert the new one
1509 * @args: See dee_model_insert_before()
1510 *
1511 * As dee_model_insert_before(), but intended for language bindings.
1512 *
1513 * Returns: A #DeeModelIter pointing to the new row
1514 */
1515 static DeeModelIter*
dee_model_insert_before_valist(DeeModel * self,DeeModelIter * iter,va_list * args)1516 dee_model_insert_before_valist (DeeModel *self,
1517 DeeModelIter *iter,
1518 va_list *args)
1519 {
1520 DeeModelIface *iface;
1521 GVariant **row_members;
1522 guint num_columns;
1523
1524 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
1525 CHECK_SCHEMA (self, &num_columns, return NULL);
1526
1527 iface = DEE_MODEL_GET_IFACE (self);
1528
1529 row_members = g_alloca (num_columns * sizeof (gpointer));
1530
1531 dee_model_build_row_valist (self, row_members, args);
1532
1533 iter = (* iface->insert_row_before) (self, iter, row_members);
1534 return iter;
1535 }
1536
1537 /**
1538 * dee_model_insert_row_before:
1539 * @self: a #DeeModel
1540 * @iter: An iter pointing to the row before which to insert the new one
1541 * @row_members: (array zero-terminated=1): An array of
1542 * #GVariants with type signature matching those of the
1543 * column schemas of @self. If any of the variants have floating
1544 * references they will be consumed.
1545 *
1546 * As dee_model_insert_before(), but intended for language bindings or
1547 * situations where you work with models on a meta level and may not have
1548 * a priori knowledge of the column schemas of the models. See also
1549 * dee_model_build_row().
1550 *
1551 * Returns: (transfer none) (type Dee.ModelIter): A #DeeModelIter pointing to the new row
1552 **/
1553 DeeModelIter*
dee_model_insert_row_before(DeeModel * self,DeeModelIter * iter,GVariant ** row_members)1554 dee_model_insert_row_before (DeeModel *self,
1555 DeeModelIter *iter,
1556 GVariant **row_members)
1557 {
1558 DeeModelIface *iface;
1559
1560 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
1561
1562 CHECK_SCHEMA (self, NULL, return NULL);
1563
1564 iface = DEE_MODEL_GET_IFACE (self);
1565
1566 return (* iface->insert_row_before) (self, iter, row_members);
1567 }
1568
1569 /* Translates DeeCompareRowFunc callback into DeeCompareRowSizedFunc */
1570 static gint
dee_model_cmp_func_translate_func(GVariant ** row1,GVariant ** row2,gpointer data)1571 dee_model_cmp_func_translate_func (GVariant **row1,
1572 GVariant **row2,
1573 gpointer data)
1574 {
1575 gpointer *all_data = (gpointer*) data;
1576 DeeCompareRowSizedFunc cmp_func = (DeeCompareRowSizedFunc) all_data[0];
1577 gpointer user_data = all_data[1];
1578 guint array_length = GPOINTER_TO_UINT (all_data[2]);
1579
1580 return cmp_func (row1, array_length, row2, array_length, user_data);
1581 }
1582
1583 /**
1584 * dee_model_insert_row_sorted:
1585 * @self: The model to do a sorted insert on
1586 * @row_members: (array zero-terminated=1): An array of
1587 * #GVariants with type signature matching those of the
1588 * column schemas of @self. If any of the variants have floating
1589 * references they will be consumed.
1590 * @cmp_func: (scope call): Callback used for comparison or rows
1591 * @user_data: (closure): Arbitrary pointer passed to @cmp_func during search
1592 *
1593 * Inserts a row in @self according to the sorting specified by @cmp_func.
1594 * If you use this method for insertion you should not use other methods as this
1595 * method assumes the model to be already sorted by @cmp_func.
1596 *
1597 * Returns: (transfer none) (type Dee.ModelIter): A #DeeModelIter pointing to the new row
1598 */
1599 DeeModelIter*
dee_model_insert_row_sorted(DeeModel * self,GVariant ** row_members,DeeCompareRowFunc cmp_func,gpointer user_data)1600 dee_model_insert_row_sorted (DeeModel *self,
1601 GVariant **row_members,
1602 DeeCompareRowFunc cmp_func,
1603 gpointer user_data)
1604 {
1605 DeeModelIface *iface;
1606
1607 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
1608
1609 CHECK_SCHEMA (self, NULL, return NULL);
1610
1611 iface = DEE_MODEL_GET_IFACE (self);
1612
1613 return (* iface->insert_row_sorted) (self, row_members, cmp_func, user_data);
1614 }
1615
1616 /**
1617 * dee_model_insert_row_sorted_with_sizes:
1618 * @self: The model to do a sorted insert on
1619 * @row_members: (array zero-terminated=1): An array of
1620 * #GVariants with type signature matching those of the
1621 * column schemas of @self. If any of the variants have floating
1622 * references they will be consumed.
1623 * @cmp_func: (scope call): Callback used for comparison or rows
1624 * @user_data: (closure): Arbitrary pointer passed to @cmp_func during search
1625 *
1626 * Inserts a row in @self according to the sorting specified by @cmp_func.
1627 * If you use this method for insertion you should not use other methods as this
1628 * method assumes the model to be already sorted by @cmp_func.
1629 *
1630 * Returns: (transfer none) (type Dee.ModelIter): A #DeeModelIter pointing to the new row
1631 */
1632 DeeModelIter*
dee_model_insert_row_sorted_with_sizes(DeeModel * self,GVariant ** row_members,DeeCompareRowSizedFunc cmp_func,gpointer user_data)1633 dee_model_insert_row_sorted_with_sizes (DeeModel *self,
1634 GVariant **row_members,
1635 DeeCompareRowSizedFunc cmp_func,
1636 gpointer user_data)
1637 {
1638 gpointer all_data[3];
1639
1640 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
1641
1642 all_data[0] = cmp_func;
1643 all_data[1] = user_data;
1644 all_data[2] = GUINT_TO_POINTER (dee_model_get_n_columns (self));
1645
1646 return dee_model_insert_row_sorted (self, row_members,
1647 dee_model_cmp_func_translate_func,
1648 all_data);
1649 }
1650
1651 /**
1652 * dee_model_insert_sorted:
1653 * @self: The model to do a sorted insert on
1654 * @cmp_func: (scope call): Callback used for comparison or rows
1655 * @user_data: (closure): Arbitrary pointer passed to @cmp_func during search
1656 * @VarArgs: Specifies the row to insert. A collection of #GVariant<!-- -->s
1657 * matching the number of columns @self
1658 *
1659 * Convenience function for calling dee_model_insert_row_sorted().
1660 * Inserts a row in @self according to the sorting specified by @cmp_func.
1661 * If you use this method for insertion you should not use other methods as this
1662 * method assumes the model to be already sorted by @cmp_func.
1663 *
1664 * Returns: (transfer none) (type Dee.ModelIter): A #DeeModelIter pointing to the new row
1665 */
1666 DeeModelIter*
dee_model_insert_sorted(DeeModel * self,DeeCompareRowFunc cmp_func,gpointer user_data,...)1667 dee_model_insert_sorted (DeeModel *self,
1668 DeeCompareRowFunc cmp_func,
1669 gpointer user_data,
1670 ...)
1671 {
1672 DeeModelIface *iface;
1673 DeeModelIter *iter;
1674 GVariant **row_members;
1675 guint num_columns;
1676 va_list args;
1677
1678 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
1679
1680 CHECK_SCHEMA (self, &num_columns, return NULL);
1681
1682 iface = DEE_MODEL_GET_IFACE (self);
1683
1684 row_members = g_alloca (num_columns * sizeof (gpointer));
1685
1686 va_start (args, user_data);
1687 dee_model_build_row_valist (self, row_members, &args);
1688 va_end (args);
1689
1690 iter = (* iface->insert_row_sorted) (self, row_members, cmp_func, user_data);
1691 return iter;
1692 }
1693
1694 /**
1695 * dee_model_find_row_sorted:
1696 * @self: The model to search
1697 * @row_spec: (array zero-terminated=1): An array of
1698 * #GVariants with type signature matching those of the
1699 * column schemas of @self. No references will be taken on the variants.
1700 * @cmp_func: (scope call): Callback used for comparison or rows
1701 * @user_data: (closure): Arbitrary pointer passed to @cmp_func during search
1702 * @out_was_found: (out): A place to store a boolean value that will be set when
1703 * this method returns. If %TRUE then an exact match was found.
1704 * If %FALSE then the returned iter points to a row just after
1705 * where @row_spec would have been inserted.
1706 * Pass %NULL to ignore.
1707 *
1708 * Finds a row in @self according to the sorting specified by @cmp_func.
1709 * This method will assume that @self is already sorted by @cmp_func.
1710 *
1711 * If you use this method for searching you should only use
1712 * dee_model_insert_row_sorted() to insert rows in the model.
1713 *
1714 * Returns: (transfer none) (type Dee.ModelIter): If @out_was_found is set to
1715 * %TRUE then a #DeeModelIter pointing to the last matching row.
1716 * If it is %FALSE then the iter pointing to the row just after where
1717 * @row_spec_would have been inserted.
1718 */
1719 DeeModelIter*
dee_model_find_row_sorted(DeeModel * self,GVariant ** row_spec,DeeCompareRowFunc cmp_func,gpointer user_data,gboolean * out_was_found)1720 dee_model_find_row_sorted (DeeModel *self,
1721 GVariant **row_spec,
1722 DeeCompareRowFunc cmp_func,
1723 gpointer user_data,
1724 gboolean *out_was_found)
1725 {
1726 DeeModelIface *iface;
1727
1728 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
1729
1730 CHECK_SCHEMA (self, NULL, return NULL);
1731
1732 iface = DEE_MODEL_GET_IFACE (self);
1733
1734 return (* iface->find_row_sorted) (self, row_spec, cmp_func,
1735 user_data, out_was_found);
1736 }
1737
1738 /**
1739 * dee_model_find_row_sorted_with_sizes:
1740 * @self: The model to search
1741 * @row_spec: (array zero-terminated=1): An array of
1742 * #GVariants with type signature matching those of the
1743 * column schemas of @self. No references will be taken on the variants.
1744 * @cmp_func: (scope call): Callback used for comparison or rows
1745 * @user_data: (closure): Arbitrary pointer passed to @cmp_func during search
1746 * @out_was_found: (out): A place to store a boolean value that will be set when
1747 * this method returns. If %TRUE then an exact match was found.
1748 * If %FALSE then the returned iter points to a row just after
1749 * where @row_spec would have been inserted.
1750 * Pass %NULL to ignore.
1751 *
1752 * Like dee_model_find_row_sorted(), but uses DeeCompareRowSizedFunc and
1753 * therefore doesn't cause trouble when used from introspected languages.
1754 *
1755 * Finds a row in @self according to the sorting specified by @cmp_func.
1756 * This method will assume that @self is already sorted by @cmp_func.
1757 *
1758 * If you use this method for searching you should only use
1759 * dee_model_insert_row_sorted() (or dee_model_insert_row_sorted_with_sizes())
1760 * to insert rows in the model.
1761 *
1762 * Returns: (transfer none) (type Dee.ModelIter): If @out_was_found is set to
1763 * %TRUE then a #DeeModelIter pointing to the last matching row.
1764 * If it is %FALSE then the iter pointing to the row just after where
1765 * @row_spec_would have been inserted.
1766 */
1767 DeeModelIter*
dee_model_find_row_sorted_with_sizes(DeeModel * self,GVariant ** row_spec,DeeCompareRowSizedFunc cmp_func,gpointer user_data,gboolean * out_was_found)1768 dee_model_find_row_sorted_with_sizes (DeeModel *self,
1769 GVariant **row_spec,
1770 DeeCompareRowSizedFunc cmp_func,
1771 gpointer user_data,
1772 gboolean *out_was_found)
1773 {
1774 gpointer all_data[3];
1775
1776 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
1777
1778 all_data[0] = cmp_func;
1779 all_data[1] = user_data;
1780 all_data[2] = GUINT_TO_POINTER (dee_model_get_n_columns (self));
1781
1782 return dee_model_find_row_sorted (self, row_spec,
1783 dee_model_cmp_func_translate_func,
1784 all_data, out_was_found);
1785 }
1786
1787 /**
1788 * dee_model_find_sorted:
1789 * @self: The model to search
1790 * @cmp_func: (scope call): Callback used for comparison or rows
1791 * @user_data: (closure): Arbitrary pointer passed to @cmp_func during search
1792 * @out_was_found: (out): A place to store a boolean value that will be set when
1793 * this method returns. If %TRUE then an exact match was found.
1794 * If %FALSE then the returned iter points to a row just after
1795 * where @row_spec would have been inserted.
1796 * Pass %NULL to ignore.
1797 * @VarArgs: A sequence of variables with type signature matching those of the
1798 * column schemas of @self.
1799 *
1800 * Finds a row in @self according to the sorting specified by @cmp_func.
1801 * This method will assume that @self is already sorted by @cmp_func.
1802 *
1803 * If you use this method for searching you should only use
1804 * dee_model_insert_row_sorted() to insert rows in the model.
1805 *
1806 * Returns: (transfer none) (type Dee.ModelIter): If @out_was_found is set to
1807 * %TRUE then a #DeeModelIter pointing to the last matching row.
1808 * If it is %FALSE then the iter pointing to the row just after where
1809 * @row_spec_would have been inserted.
1810 */
1811 DeeModelIter*
dee_model_find_sorted(DeeModel * self,DeeCompareRowFunc cmp_func,gpointer user_data,gboolean * out_was_found,...)1812 dee_model_find_sorted (DeeModel *self,
1813 DeeCompareRowFunc cmp_func,
1814 gpointer user_data,
1815 gboolean *out_was_found,
1816 ...)
1817 {
1818 DeeModelIface *iface;
1819 DeeModelIter *iter;
1820 GVariant **row_members;
1821 guint num_columns;
1822 va_list args;
1823
1824 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
1825
1826 CHECK_SCHEMA (self, &num_columns, return NULL);
1827
1828 iface = DEE_MODEL_GET_IFACE (self);
1829
1830 row_members = g_alloca (num_columns * sizeof (gpointer));
1831
1832 va_start (args, out_was_found);
1833 dee_model_build_row_valist (self, row_members, &args);
1834 va_end (args);
1835
1836 iter = (* iface->find_row_sorted) (self, row_members, cmp_func,
1837 user_data, out_was_found);
1838
1839 return iter;
1840 }
1841
1842 /**
1843 * dee_model_remove:
1844 * @self: a #DeeModel
1845 * @iter: a #DeeModelIter pointing to the row to remove
1846 *
1847 * Removes the row at the given position from the model.
1848 */
1849 void
dee_model_remove(DeeModel * self,DeeModelIter * iter)1850 dee_model_remove (DeeModel *self,
1851 DeeModelIter *iter)
1852 {
1853 DeeModelIface *iface;
1854
1855 g_return_if_fail (DEE_IS_MODEL (self));
1856
1857 CHECK_SCHEMA (self, NULL, return);
1858
1859 iface = DEE_MODEL_GET_IFACE (self);
1860
1861 (* iface->remove) (self, iter);
1862 }
1863
1864 /**
1865 * dee_model_clear:
1866 * @self: a #DeeModel object to clear
1867 *
1868 * Removes all rows in the model. Signals are emitted for each row in the model
1869 */
1870 void
dee_model_clear(DeeModel * self)1871 dee_model_clear (DeeModel *self)
1872 {
1873 DeeModelIface *iface;
1874
1875 g_return_if_fail (DEE_IS_MODEL (self));
1876
1877 CHECK_SCHEMA (self, NULL, return);
1878
1879 iface = DEE_MODEL_GET_IFACE (self);
1880
1881 return (* iface->clear) (self);
1882 }
1883
1884 /**
1885 * dee_model_set:
1886 * @self: a #DeeModel
1887 * @iter: a #DeeModelIter
1888 * @VarArgs: A list of values to set matching the column schemas.
1889 * Any basic variant type is passed as the standard C type while
1890 * any other type must be boxed in a #GVariant. Any floating
1891 * references will be consumed. A %NULL value for a string
1892 * type column will be converted to the empty string.
1893 *
1894 * Sets all values across the entire row referenced by @iter. The
1895 * variable argument list should contain values that match the column schemas
1896 * for the model. All basic variant type (see g_variant_type_is_basic()) are
1897 * passed in as their raw C type while all other types are passed in boxed in
1898 * a #GVariant. Any floating references on variants passed to this method are
1899 * consumed.
1900 *
1901 * For example, to set the values for a row on model with the schema
1902 * ("u", "s", "as"):
1903 * <informalexample><programlisting>
1904 * GVariantBuilder b;
1905 *
1906 * g_variant_builder_init (&b, "as");
1907 * g_variant_builder_add (&b, "Hello");
1908 * g_variant_builder_add (&b, "World");
1909 *
1910 * dee_model_set (model, iter, 27, "foo", g_variant_builder_end (&b));
1911 * </programlisting></informalexample>
1912 **/
1913 void
dee_model_set(DeeModel * self,DeeModelIter * iter,...)1914 dee_model_set (DeeModel *self,
1915 DeeModelIter *iter,
1916 ...)
1917 {
1918 va_list args;
1919
1920 g_return_if_fail (DEE_IS_MODEL (self));
1921
1922 /* Update data */
1923 va_start (args, iter);
1924 dee_model_set_valist (self, iter, &args);
1925 va_end (args);
1926 }
1927
1928 /**
1929 * dee_model_set_valist: (skip):
1930 * @self: a #DeeModel
1931 * @iter: a #DeeModelIter
1932 * @args: See dee_model_set()
1933 *
1934 * See dee_model_set(). This version takes a va_list for language bindings.
1935 */
1936 static void
dee_model_set_valist(DeeModel * self,DeeModelIter * iter,va_list * args)1937 dee_model_set_valist (DeeModel *self,
1938 DeeModelIter *iter,
1939 va_list *args)
1940 {
1941 DeeModelIface *iface;
1942 GVariant **row_members;
1943 guint num_columns;
1944
1945 g_return_if_fail (DEE_IS_MODEL (self));
1946
1947 iface = DEE_MODEL_GET_IFACE (self);
1948 num_columns = dee_model_get_n_columns (self);
1949 row_members = g_alloca (num_columns * sizeof (gpointer));
1950
1951 dee_model_build_row_valist (self, row_members, args);
1952
1953 (* iface->set_row) (self, iter, row_members);
1954 }
1955
1956 /**
1957 * dee_model_set_value:
1958 * @self: a #DeeModel
1959 * @iter: a #DeeModelIter
1960 * @column: column number to set the value
1961 * @value: New value for cell. If @value is a floating reference the model
1962 * will assume ownership of the variant
1963 *
1964 * Sets the data in @column for the row @iter points to, to @value. The type
1965 * of @value must be convertible to the type of the column.
1966 *
1967 * When this method call completes the model will emit ::row-changed. You can
1968 * edit the model in place without triggering the change signals by calling
1969 * dee_model_set_value_silently().
1970 */
1971 void
dee_model_set_value(DeeModel * self,DeeModelIter * iter,guint column,GVariant * value)1972 dee_model_set_value (DeeModel *self,
1973 DeeModelIter *iter,
1974 guint column,
1975 GVariant *value)
1976 {
1977 DeeModelIface *iface;
1978
1979 g_return_if_fail (DEE_IS_MODEL (self));
1980
1981 CHECK_SCHEMA (self, NULL, return);
1982
1983 iface = DEE_MODEL_GET_IFACE (self);
1984
1985 return (* iface->set_value) (self, iter, column, value);
1986 }
1987
1988 /**
1989 * dee_model_set_row:
1990 * @self: a #DeeModel
1991 * @iter: a #DeeModelIter
1992 * @row_members: (array): And array of
1993 * #GVariant<!-- -->s with type signature matching
1994 * those from the model schema. If any of the variants have
1995 * floating references these will be consumed
1996 *
1997 * Sets all columns in the row @iter points to, to those found in
1998 * @row_members. The variants in @row_members must match the types defined in
1999 * the model's schema.
2000 */
2001 void
dee_model_set_row(DeeModel * self,DeeModelIter * iter,GVariant ** row_members)2002 dee_model_set_row (DeeModel *self,
2003 DeeModelIter *iter,
2004 GVariant **row_members)
2005 {
2006 DeeModelIface *iface;
2007
2008 g_return_if_fail (DEE_IS_MODEL (self));
2009
2010 CHECK_SCHEMA (self, NULL, return);
2011
2012 iface = DEE_MODEL_GET_IFACE (self);
2013
2014 return (* iface->set_row) (self, iter, row_members);
2015 }
2016
2017 /**
2018 * dee_model_get:
2019 * @self: a #DeeModel
2020 * @iter: a #DeeModelIter
2021 * @VarArgs: a list of return locations matching the types defined in the
2022 * column schemas. To ignore the data in a specific column pass
2023 * a %NULL on that position
2024 *
2025 * Gets all the values across the entire row referenced by @iter. The
2026 * variable argument list should contain pointers to variables that match
2027 * the column schemas of this model.
2028 *
2029 * For all basic variant types (see g_variant_type_is_basic()) this method
2030 * expects pointers to their native C types while for all other types it
2031 * expects a pointer to a pointer to a #GVariant.
2032 *
2033 * For string values you are passed a constant reference which is owned by the
2034 * model, but any returned variants must be freed with g_variant_unref ().
2035 *
2036 * For example, to get all values a model with signature ("u", "s", "as") you
2037 * would do:
2038 * <informalexample><programlisting>
2039 * guint32 u;
2040 * const gchar *s;
2041 * GVariant *v;
2042 *
2043 * dee_model_get (model, iter, &u, &s, &v);
2044 *
2045 * // do stuff
2046 *
2047 * g_variant_unref (v);
2048 * </programlisting></informalexample>
2049 **/
2050 void
dee_model_get(DeeModel * self,DeeModelIter * iter,...)2051 dee_model_get (DeeModel *self,
2052 DeeModelIter *iter,
2053 ...)
2054 {
2055 va_list args;
2056
2057 g_return_if_fail (DEE_IS_MODEL (self));
2058 g_return_if_fail (iter);
2059
2060 va_start (args, iter);
2061 dee_model_get_valist (self, iter, args);
2062 va_end (args);
2063 }
2064
2065 /**
2066 * dee_model_get_valist: (skip):
2067 * @self: a #DeeModel
2068 * @iter: a #DeeModelIter
2069 * @args: a list of column/return location pairs, terminated by -1
2070 *
2071 * See #dee_model_get(). This version takes a va_list for language bindings.
2072 **/
2073 static void
dee_model_get_valist(DeeModel * self,DeeModelIter * iter,va_list args)2074 dee_model_get_valist (DeeModel *self,
2075 DeeModelIter *iter,
2076 va_list args)
2077 {
2078 GVariant *val;
2079 const GVariantType *val_t;
2080 guint col, n_cols;
2081 gpointer *col_data;
2082
2083 g_return_if_fail (DEE_IS_MODEL (self));
2084 g_return_if_fail (iter != NULL);
2085
2086 n_cols = dee_model_get_n_columns (self);
2087
2088 for (col = 0; col < n_cols; col++)
2089 {
2090 col_data = va_arg (args, gpointer*);
2091
2092 /* Skip past here if this column's data was not request */
2093 if (col_data == NULL)
2094 {
2095 continue;
2096 }
2097
2098 val = dee_model_get_value (self, iter, col);
2099 val_t = g_variant_get_type (val);
2100
2101 /* Basic types are passed back unboxed, and non-basic types are passed
2102 * back wrapped in variants. Strings are special because we pass them
2103 * back without copying them */
2104 if (g_variant_type_is_basic (val_t))
2105 {
2106 if (g_variant_type_equal (val_t, G_VARIANT_TYPE_SIGNATURE) ||
2107 g_variant_type_equal (val_t, G_VARIANT_TYPE_STRING) ||
2108 g_variant_type_equal (val_t, G_VARIANT_TYPE_OBJECT_PATH))
2109 {
2110 /* We need to cast away the constness */
2111 *col_data = (gpointer) g_variant_get_string (val, NULL);
2112 }
2113 else
2114 g_variant_get (val, dee_model_get_column_schema (self, col),
2115 col_data);
2116
2117 /* dee_model_get_value() returns a ref we need to free */
2118 g_variant_unref (val);
2119 }
2120 else
2121 {
2122 /* For complex types the ref on val is transfered to the caller */
2123 *col_data = val;
2124 }
2125 }
2126 }
2127
2128 /**
2129 * dee_model_get_row:
2130 * @self: A #DeeModel to get a row from
2131 * @iter: A #DeeModelIter pointing to the row to get
2132 * @out_row_members: (array) (out) (allow-none) (default NULL):
2133 * An array of variants with a length bigger than or equal to
2134 * the number of columns in @self, or %NULL. If you pass
2135 * %NULL here a new array will be allocated for you. The
2136 * returned variants will have a non-floating reference
2137 *
2138 * Returns: (array zero-terminated=1): @out_row_members if it was not %NULL
2139 * or a newly allocated array otherwise which you must free
2140 * with g_free(). The variants in the array will have a strong
2141 * reference and needs to be freed with g_variant_unref().
2142 */
2143 GVariant**
dee_model_get_row(DeeModel * self,DeeModelIter * iter,GVariant ** out_row_members)2144 dee_model_get_row (DeeModel *self,
2145 DeeModelIter *iter,
2146 GVariant **out_row_members)
2147 {
2148 DeeModelIface *iface;
2149
2150 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
2151
2152 iface = DEE_MODEL_GET_IFACE (self);
2153
2154 return (* iface->get_row) (self, iter, out_row_members);
2155 }
2156
2157 /**
2158 * dee_model_get_value:
2159 * @self: The #DeeModel to inspect
2160 * @iter: a #DeeModelIter pointing to the row to inspect
2161 * @column: column number to retrieve the value from
2162 *
2163 * Returns: (transfer full): A, guaranteed non-floating, reference to a
2164 * #GVariant containing the row data. Free with g_variant_unref().
2165 */
2166 GVariant*
dee_model_get_value(DeeModel * self,DeeModelIter * iter,guint column)2167 dee_model_get_value (DeeModel *self,
2168 DeeModelIter *iter,
2169 guint column)
2170 {
2171 DeeModelIface *iface;
2172
2173 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
2174
2175 iface = DEE_MODEL_GET_IFACE (self);
2176
2177 return (* iface->get_value) (self, iter, column);
2178 }
2179
2180 /**
2181 * dee_model_get_value_by_name:
2182 * @self: The #DeeModel to inspect
2183 * @iter: a #DeeModelIter pointing to the row to inspect
2184 * @column: column name to retrieve the value from
2185 *
2186 * Returns: (transfer full): A, guaranteed non-floating, reference to a
2187 * #GVariant containing the row data. Free with g_variant_unref().
2188 */
2189 GVariant*
dee_model_get_value_by_name(DeeModel * self,DeeModelIter * iter,const gchar * column_name)2190 dee_model_get_value_by_name (DeeModel *self,
2191 DeeModelIter *iter,
2192 const gchar *column_name)
2193 {
2194 DeeModelIface *iface;
2195
2196 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
2197
2198 iface = DEE_MODEL_GET_IFACE (self);
2199
2200 return (* iface->get_value_by_name) (self, iter, column_name);
2201 }
2202
2203 /**
2204 * dee_model_get_bool:
2205 * @self: a #DeeModel
2206 * @iter: a #DeeModelIter
2207 * @column: the column to retrieve a boolean from
2208 *
2209 * Return value: if @iter and @column are valid, the boolean stored at @column.
2210 * Otherwise %FALSE
2211 */
2212 gboolean
dee_model_get_bool(DeeModel * self,DeeModelIter * iter,guint column)2213 dee_model_get_bool (DeeModel *self,
2214 DeeModelIter *iter,
2215 guint column)
2216 {
2217 DeeModelIface *iface;
2218
2219 g_return_val_if_fail (DEE_IS_MODEL (self), FALSE);
2220
2221 iface = DEE_MODEL_GET_IFACE (self);
2222
2223 return (* iface->get_bool) (self, iter, column);
2224 }
2225
2226 /**
2227 * dee_model_get_uchar:
2228 * @self: a #DeeModel
2229 * @iter: a #DeeModelIter
2230 * @column: the column to retrieve a uchar from
2231 *
2232 * Return value: if @iter and @column are valid, the uchar stored at @column.
2233 * Otherwise 0.
2234 **/
2235 guchar
dee_model_get_uchar(DeeModel * self,DeeModelIter * iter,guint column)2236 dee_model_get_uchar (DeeModel *self,
2237 DeeModelIter *iter,
2238 guint column)
2239 {
2240 DeeModelIface *iface;
2241
2242 g_return_val_if_fail (DEE_IS_MODEL (self), '\0');
2243
2244 iface = DEE_MODEL_GET_IFACE (self);
2245
2246 return (* iface->get_uchar) (self, iter, column);
2247 }
2248
2249 /**
2250 * dee_model_get_int32:
2251 * @self: a #DeeModel
2252 * @iter: a #DeeModelIter
2253 * @column: the column to retrieve a int from
2254 *
2255 * Return value: if @iter and @column are valid, the int stored at @column.
2256 * Otherwise 0.
2257 **/
2258 gint32
dee_model_get_int32(DeeModel * self,DeeModelIter * iter,guint column)2259 dee_model_get_int32 (DeeModel *self,
2260 DeeModelIter *iter,
2261 guint column)
2262 {
2263 DeeModelIface *iface;
2264
2265 g_return_val_if_fail (DEE_IS_MODEL (self), 0);
2266
2267 iface = DEE_MODEL_GET_IFACE (self);
2268
2269 return (* iface->get_int32) (self, iter, column);
2270 }
2271
2272 /**
2273 * dee_model_get_uint32:
2274 * @self: a #DeeModel
2275 * @iter: a #DeeModelIter
2276 * @column: the column to retrieve a uint from
2277 *
2278 * Return value: if @iter and @column are valid, the uint stored at @column.
2279 * Otherwise 0.
2280 **/
2281 guint32
dee_model_get_uint32(DeeModel * self,DeeModelIter * iter,guint column)2282 dee_model_get_uint32 (DeeModel *self,
2283 DeeModelIter *iter,
2284 guint column)
2285 {
2286 DeeModelIface *iface;
2287
2288 g_return_val_if_fail (DEE_IS_MODEL (self), 0);
2289
2290 iface = DEE_MODEL_GET_IFACE (self);
2291
2292 return (* iface->get_uint32) (self, iter, column);
2293 }
2294
2295
2296 /**
2297 * dee_model_get_int64:
2298 * @self: a #DeeModel
2299 * @iter: a #DeeModelIter
2300 * @column: the column to retrieve a int64 from
2301 *
2302 * Return value: if @iter and @column are valid, the int64 stored at @column.
2303 * Otherwise 0.
2304 **/
2305 gint64
dee_model_get_int64(DeeModel * self,DeeModelIter * iter,guint column)2306 dee_model_get_int64 (DeeModel *self,
2307 DeeModelIter *iter,
2308 guint column)
2309 {
2310 DeeModelIface *iface;
2311
2312 g_return_val_if_fail (DEE_IS_MODEL (self), 0);
2313
2314 iface = DEE_MODEL_GET_IFACE (self);
2315
2316 return (* iface->get_int64) (self, iter, column);
2317 }
2318
2319
2320 /**
2321 * dee_model_get_uint64:
2322 * @self: a #DeeModel
2323 * @iter: a #DeeModelIter
2324 * @column: the column to retrieve a uint64 from
2325 *
2326 * Return value: if @iter and @column are valid, the uint64 stored at @column.
2327 * Otherwise 0.
2328 **/
2329 guint64
dee_model_get_uint64(DeeModel * self,DeeModelIter * iter,guint column)2330 dee_model_get_uint64 (DeeModel *self,
2331 DeeModelIter *iter,
2332 guint column)
2333 {
2334 DeeModelIface *iface;
2335
2336 g_return_val_if_fail (DEE_IS_MODEL (self), 0);
2337
2338 iface = DEE_MODEL_GET_IFACE (self);
2339
2340 return (* iface->get_uint64) (self, iter, column);
2341 }
2342
2343 /**
2344 * dee_model_get_double:
2345 * @self: a #DeeModel
2346 * @iter: a #DeeModelIter
2347 * @column: the column to retrieve a double from
2348 *
2349 * Return value: if @iter and @column are valid, the double stored at @column.
2350 * Otherwise 0.
2351 **/
2352 gdouble
dee_model_get_double(DeeModel * self,DeeModelIter * iter,guint column)2353 dee_model_get_double (DeeModel *self,
2354 DeeModelIter *iter,
2355 guint column)
2356 {
2357 DeeModelIface *iface;
2358
2359 g_return_val_if_fail (DEE_IS_MODEL (self), 0);
2360
2361 iface = DEE_MODEL_GET_IFACE (self);
2362
2363 return (* iface->get_double) (self, iter, column);
2364 }
2365
2366 /**
2367 * dee_model_get_string:
2368 * @self: a #DeeModel
2369 * @iter: a #DeeModelIter
2370 * @column: the column to retrieve a string from
2371 *
2372 * Return value: if @iter and @column are valid, the string stored at @column.
2373 * Otherwise %NULL.
2374 **/
2375 const gchar*
dee_model_get_string(DeeModel * self,DeeModelIter * iter,guint column)2376 dee_model_get_string (DeeModel *self,
2377 DeeModelIter *iter,
2378 guint column)
2379 {
2380 DeeModelIface *iface;
2381
2382 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
2383
2384 iface = DEE_MODEL_GET_IFACE (self);
2385
2386 return (* iface->get_string) (self, iter, column);
2387 }
2388
2389 /**
2390 * dee_model_get_first_iter:
2391 * @self: a #DeeModel
2392 *
2393 * Retrieves a #DeeModelIter representing the first row in @self.
2394 *
2395 * Return value: (transfer none): A #DeeModelIter (owned by @self, do not
2396 * free it)
2397 */
2398 DeeModelIter*
dee_model_get_first_iter(DeeModel * self)2399 dee_model_get_first_iter (DeeModel *self)
2400 {
2401 DeeModelIface *iface;
2402
2403 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
2404
2405 iface = DEE_MODEL_GET_IFACE (self);
2406
2407 return (* iface->get_first_iter) (self);
2408 }
2409
2410 /**
2411 * dee_model_get_last_iter:
2412 * @self: a #DeeModel
2413 *
2414 * Retrieves a #DeeModelIter pointing right <emphasis>after</emphasis> the
2415 * last row in @self. This is refered to also the the
2416 * <emphasis>end iter</emphasis>.
2417 *
2418 * As with other iters the end iter, in particular, is stable over inserts,
2419 * changes, or removals.
2420 *
2421 * Return value: (transfer none): A #DeeModelIter (owned by @self, do not
2422 * free it)
2423 **/
2424 DeeModelIter*
dee_model_get_last_iter(DeeModel * self)2425 dee_model_get_last_iter (DeeModel *self)
2426 {
2427 DeeModelIface *iface;
2428
2429 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
2430
2431 iface = DEE_MODEL_GET_IFACE (self);
2432
2433 return (* iface->get_last_iter) (self);
2434 }
2435
2436 /**
2437 * dee_model_get_iter_at_row:
2438 * @self: a #DeeModel
2439 * @row: position of the row to retrieve
2440 *
2441 * Retrieves a #DeeModelIter representing the row at the given index.
2442 *
2443 * Note that this method does not have any performance guarantees. In particular
2444 * it is not guaranteed to be <emphasis>O(1)</emphasis>.
2445 *
2446 * Return value: (transfer none): A new #DeeModelIter, or %NULL if @row
2447 * was out of bounds. The returned iter is owned by @self, so do not free it.
2448 **/
2449 DeeModelIter*
dee_model_get_iter_at_row(DeeModel * self,guint row)2450 dee_model_get_iter_at_row (DeeModel *self, guint row)
2451 {
2452 DeeModelIface *iface;
2453
2454 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
2455
2456 iface = DEE_MODEL_GET_IFACE (self);
2457
2458 return (* iface->get_iter_at_row) (self, row);
2459 }
2460
2461 /**
2462 * dee_model_next:
2463 * @self: a #DeeModel
2464 * @iter: a #DeeModelIter
2465 *
2466 * Returns a #DeeModelIter that points to the next position in the model.
2467 *
2468 * Return value: (transfer none): A #DeeModelIter, pointing to the next row in
2469 * the model. The iter is owned by @self, do not free it.
2470 **/
2471 DeeModelIter*
dee_model_next(DeeModel * self,DeeModelIter * iter)2472 dee_model_next (DeeModel *self,
2473 DeeModelIter *iter)
2474 {
2475 DeeModelIface *iface;
2476
2477 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
2478
2479 iface = DEE_MODEL_GET_IFACE (self);
2480
2481 return (* iface->next) (self, iter);
2482 }
2483
2484 /**
2485 * dee_model_prev:
2486 * @self: a #DeeModel
2487 * @iter: a #DeeModelIter
2488 *
2489 * Returns a #DeeModelIter that points to the previous position in the model.
2490 *
2491 * Return value: (transfer none): A #DeeModelIter, pointing to the previous
2492 * row in the model. The iter is owned by @self, do not free it.
2493 **/
2494 DeeModelIter *
dee_model_prev(DeeModel * self,DeeModelIter * iter)2495 dee_model_prev (DeeModel *self,
2496 DeeModelIter *iter)
2497 {
2498 DeeModelIface *iface;
2499
2500 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
2501
2502 iface = DEE_MODEL_GET_IFACE (self);
2503
2504 return (* iface->prev) (self, iter);
2505 }
2506
2507 /**
2508 * dee_model_is_first:
2509 * @self: a #DeeModel
2510 * @iter: a #DeeModelIter
2511 *
2512 * Checks if @iter is the very first iter @self.
2513 *
2514 * Return value: #TRUE if @iter is the first iter in the model
2515 */
2516 gboolean
dee_model_is_first(DeeModel * self,DeeModelIter * iter)2517 dee_model_is_first (DeeModel *self,
2518 DeeModelIter *iter)
2519 {
2520 DeeModelIface *iface;
2521
2522 g_return_val_if_fail (DEE_IS_MODEL (self), FALSE);
2523
2524 iface = DEE_MODEL_GET_IFACE (self);
2525
2526 return (* iface->is_first) (self, iter);
2527 }
2528
2529 /**
2530 * dee_model_is_last:
2531 * @self: a #DeeModel
2532 * @iter: a #DeeModelIter
2533 *
2534 * Whether @iter is the end iter of @self. Note that the end iter points
2535 * right <emphasis>after</emphasis> the last valid row in @self.
2536 *
2537 * Return value: #TRUE if @iter is the last iter in the model
2538 */
2539 gboolean
dee_model_is_last(DeeModel * self,DeeModelIter * iter)2540 dee_model_is_last (DeeModel *self,
2541 DeeModelIter *iter)
2542 {
2543 DeeModelIface *iface;
2544
2545 g_return_val_if_fail (DEE_IS_MODEL (self), FALSE);
2546
2547 iface = DEE_MODEL_GET_IFACE (self);
2548
2549 return (* iface->is_last) (self, iter);
2550 }
2551
2552 /**
2553 * dee_model_get_position:
2554 * @self: The model to inspect
2555 * @iter: The iter to get the position of
2556 *
2557 * Get the numeric offset of @iter into @self. Note that this method is
2558 * <emphasis>not</emphasis> guaranteed to be <emphasis>O(1)</emphasis>.
2559 *
2560 * Returns: The integer offset of @iter in @self
2561 */
2562 guint
dee_model_get_position(DeeModel * self,DeeModelIter * iter)2563 dee_model_get_position (DeeModel *self,
2564 DeeModelIter *iter)
2565 {
2566 DeeModelIface *iface;
2567
2568 g_return_val_if_fail (DEE_IS_MODEL (self), -1);
2569
2570 iface = DEE_MODEL_GET_IFACE (self);
2571
2572 return (* iface->get_position) (self, iter);
2573 }
2574
2575 /**
2576 * dee_model_register_tag:
2577 * @self: The model to register a tag on
2578 * @tag_destroy: Function called when a tagged row is removed from the model.
2579 * This function will also be called on all tagged rows when the
2580 * model is finalized.
2581 *
2582 * Register a new tag on a #DeeModel. A <emphasis>tag</emphasis> is an extra
2583 * value attached to a given row on a model. The tags are invisible to all
2584 * that doesn't have the tag handle returned by this method. #DeeModel
2585 * implementations must ensure that dee_model_get_tag() is an O(1) operation.
2586 *
2587 * Tags can be very useful in associating some extra data to a row in a model
2588 * and have that automatically synced when the model changes. If you're
2589 * writing a tiled view for a model you might want to tag each row with the
2590 * tile widget for that row. That way you have very convenient access to the
2591 * tile widget given any row in the model.
2592 *
2593 * The private nature of tags and the fact that you can store arbitrary pointers
2594 * and binary data in them also means that they are not serialized if you
2595 * utilize a model implementation that exposes the #DeeSerializable interface.
2596 *
2597 * Return value: (transfer none) (type Dee.ModelTag): A #DeeModelTag handle
2598 * that you can use to set and get tags with
2599 */
2600 DeeModelTag*
dee_model_register_tag(DeeModel * self,GDestroyNotify tag_destroy)2601 dee_model_register_tag (DeeModel *self,
2602 GDestroyNotify tag_destroy)
2603 {
2604 DeeModelIface *iface;
2605
2606 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
2607
2608 iface = DEE_MODEL_GET_IFACE (self);
2609
2610 return (* iface->register_tag) (self, tag_destroy);
2611 }
2612
2613 /**
2614 * dee_model_get_tag:
2615 * @self: The model to get a tag from
2616 * @iter: A #DeeModelIter pointing to the row to get the tag from
2617 * @tag: The tag handle to retrieve the tag value for
2618 *
2619 * Look up a tag value for a given row in a model. This method is guaranteed
2620 * to be O(1).
2621 *
2622 * Return value: (transfer none): Returns %NULL if @tag is unset otherwise the
2623 * value of the tag as it was set with dee_model_set_tag().
2624 */
2625 gpointer
dee_model_get_tag(DeeModel * self,DeeModelIter * iter,DeeModelTag * tag)2626 dee_model_get_tag (DeeModel *self,
2627 DeeModelIter *iter,
2628 DeeModelTag *tag)
2629 {
2630 DeeModelIface *iface;
2631
2632 g_return_val_if_fail (DEE_IS_MODEL (self), NULL);
2633
2634 iface = DEE_MODEL_GET_IFACE (self);
2635
2636 return (* iface->get_tag) (self, iter, tag);
2637 }
2638
2639 /**
2640 * dee_model_set_tag:
2641 * @self: The model to set a tag on
2642 * @iter: The row to set the tag on
2643 * @tag: The tag handle for the tag as obtained from dee_model_register_tag()
2644 * @value: The value to set for @tag. Note that %NULL represents an unset tag
2645 *
2646 * Set a tag on a row in a model. This function is guaranteed to be O(1).
2647 * See also dee_model_register_tag().
2648 *
2649 * If @tag is already set on this row the existing tag value will be destroyed
2650 * with the #GDestroyNotify passed to the dee_model_register_tag().
2651 */
2652 void
dee_model_set_tag(DeeModel * self,DeeModelIter * iter,DeeModelTag * tag,gpointer value)2653 dee_model_set_tag (DeeModel *self,
2654 DeeModelIter *iter,
2655 DeeModelTag *tag,
2656 gpointer value)
2657 {
2658 DeeModelIface *iface;
2659
2660 g_return_if_fail (DEE_IS_MODEL (self));
2661
2662 iface = DEE_MODEL_GET_IFACE (self);
2663
2664 (* iface->set_tag) (self, iter, tag, value);
2665 }
2666
2667 /**
2668 * dee_model_clear_tag:
2669 * @self: The model to clear a tag on
2670 * @iter: The row to clear the tag from
2671 * @tag: The tag to clear from @iter
2672 *
2673 * This method is purely syntactic sugar for calling dee_model_set_tag() with
2674 * a @value of %NULL. It's included in order to help developers write more
2675 * readable code.
2676 */
2677 void
dee_model_clear_tag(DeeModel * self,DeeModelIter * iter,DeeModelTag * tag)2678 dee_model_clear_tag (DeeModel *self,
2679 DeeModelIter *iter,
2680 DeeModelTag *tag)
2681 {
2682 DeeModelIface *iface;
2683
2684 g_return_if_fail (DEE_IS_MODEL (self));
2685
2686 iface = DEE_MODEL_GET_IFACE (self);
2687
2688 (* iface->set_tag) (self, iter, tag, NULL);
2689 }
2690
2691