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 (&amp;b, "as");
1477  *  g_variant_builder_add (&amp;b, "s", "Hello");
1478  *  g_variant_builder_add (&amp;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 (&amp;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 (&amp;b, "as");
1907  *   g_variant_builder_add (&amp;b, "Hello");
1908  *   g_variant_builder_add (&amp;b, "World");
1909  *
1910  *   dee_model_set (model, iter, 27, "foo", g_variant_builder_end (&amp;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