dee

Merge lp:~mhr3/dee/add-changesets into lp:dee

Proposed by Michal Hruby
Status: Merged
Approved by: Paweł Stołowski
Approved revision: 430
Merged at revision: 429
Proposed branch: lp:~mhr3/dee/add-changesets
Merge into: lp:dee
Diff against target: 956 lines (+510/-21)
15 files modified
configure.ac (+1/-1)
debian/changelog (+6/-0)
debian/libdee-1.0-4.symbols (+2/-0)
src/dee-filter-model.c (+55/-0)
src/dee-model.c (+111/-0)
src/dee-model.h (+12/-4)
src/dee-proxy-model.c (+61/-1)
src/dee-sequence-model.c (+3/-3)
src/dee-serializable-model.c (+52/-0)
src/dee-shared-model.c (+5/-2)
tests/test-client-server.c (+15/-0)
tests/test-filter-model.c (+138/-8)
tests/test-model-interactions.c (+15/-0)
tests/test-resource-manager.c (+30/-2)
vapi/dee-1.0.vapi (+4/-0)
To merge this branch: bzr merge lp:~mhr3/dee/add-changesets
Reviewer Review Type Date Requested Status
Paweł Stołowski (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+185111@code.launchpad.net

Commit message

Add support for changesets to DeeModel API.

Description of the change

Add support for changesets to DeeModel API.

This will allow us to make dee models more compatible with the way Qt models work and therefore enable us to implement more efficient Qt model wrapper for DeeModel.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Paweł Stołowski (stolowski) wrote :

Great stuff, looks good, some suggestions though:

1) I think it would make sense to implement a rudimentary check for dee_model_begin_changeset / dee_model_end_changeset calls to ensure they're called in a sequence, e.g. by maintaining an internal flag, so that calling end/begin or begin/begin etc. would give a warning.

2) Can you extend the tests to check that "started" signal arrives before "end"?

review: Needs Fixing
lp:~mhr3/dee/add-changesets updated
430. By Michal Hruby

Act on review comments

Revision history for this message
Michal Hruby (mhr3) wrote :

> Great stuff, looks good, some suggestions though:
>
> 1) I think it would make sense to implement a rudimentary check for
> dee_model_begin_changeset / dee_model_end_changeset calls to ensure they're
> called in a sequence, e.g. by maintaining an internal flag, so that calling
> end/begin or begin/begin etc. would give a warning.
>
> 2) Can you extend the tests to check that "started" signal arrives before
> "end"?

Done.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Paweł Stołowski (stolowski) wrote :

Yay, awesome! +1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'configure.ac'
2--- configure.ac 2013-07-19 10:13:05 +0000
3+++ configure.ac 2013-09-16 18:51:54 +0000
4@@ -5,7 +5,7 @@
5 # Don't forget to check also GIR_VERSION
6 m4_define([dee_major], [1])
7 m4_define([dee_minor], [2])
8-m4_define([dee_micro], [6])
9+m4_define([dee_micro], [7])
10 m4_define([dee_api],
11 [dee_major.dee_minor])
12 m4_define([dee_version],
13
14=== modified file 'debian/changelog'
15--- debian/changelog 2013-09-04 02:32:11 +0000
16+++ debian/changelog 2013-09-16 18:51:54 +0000
17@@ -1,3 +1,9 @@
18+dee (1.2.7-0ubuntu1) UNRELEASED; urgency=low
19+
20+ * Added begin and end changeset API.
21+
22+ -- Michal Hruby <michal.hruby@canonical.com> Tue, 10 Sep 2013 11:59:21 +0100
23+
24 dee (1.2.6+13.10.20130904-0ubuntu1) saucy; urgency=low
25
26 [ Michal Hruby ]
27
28=== modified file 'debian/libdee-1.0-4.symbols'
29--- debian/libdee-1.0-4.symbols 2013-05-31 04:30:18 +0000
30+++ debian/libdee-1.0-4.symbols 2013-09-16 18:51:54 +0000
31@@ -54,12 +54,14 @@
32 dee_index_lookup_one@Base 0.5.16
33 dee_model_append@Base 0.5.2
34 dee_model_append_row@Base 0.5.2
35+ dee_model_begin_changeset@Base 0replaceme
36 dee_model_build_named_row@Base 1.2.0daily12.12.05
37 dee_model_build_named_row_sunk@Base 1.2.0daily12.12.05
38 dee_model_build_named_row_valist@Base 1.2.0daily12.12.05
39 dee_model_build_row@Base 0.5.2
40 dee_model_clear@Base 0.5.2
41 dee_model_clear_tag@Base 0.5.12
42+ dee_model_end_changeset@Base 0replaceme
43 dee_model_find_row_sorted@Base 1.0.0
44 dee_model_find_row_sorted_with_sizes@Base 1.0.14
45 dee_model_find_sorted@Base 1.0.0
46
47=== modified file 'src/dee-filter-model.c'
48--- src/dee-filter-model.c 2013-01-04 17:53:43 +0000
49+++ src/dee-filter-model.c 2013-09-16 18:51:54 +0000
50@@ -97,6 +97,8 @@
51 gulong on_orig_row_added_id;
52 gulong on_orig_row_removed_id;
53 gulong on_orig_row_changed_id;
54+ gulong on_orig_changeset_started_id;
55+ gulong on_orig_changeset_finished_id;
56 };
57
58 enum
59@@ -162,6 +164,12 @@
60 static void on_orig_model_row_changed (DeeFilterModel *self,
61 DeeModelIter *iter);
62
63+static void on_orig_model_changeset_started (DeeFilterModel *self,
64+ DeeModel *iter);
65+
66+static void on_orig_model_changeset_finished (DeeFilterModel *self,
67+ DeeModel *iter);
68+
69 /* GObject stuff */
70 static void
71 dee_filter_model_finalize (GObject *object)
72@@ -192,10 +200,16 @@
73 g_signal_handler_disconnect (priv->orig_model, priv->on_orig_row_removed_id);
74 if (priv->on_orig_row_changed_id != 0)
75 g_signal_handler_disconnect (priv->orig_model, priv->on_orig_row_changed_id);
76+ if (priv->on_orig_changeset_started_id != 0)
77+ g_signal_handler_disconnect (priv->orig_model, priv->on_orig_changeset_started_id);
78+ if (priv->on_orig_changeset_finished_id != 0)
79+ g_signal_handler_disconnect (priv->orig_model, priv->on_orig_changeset_finished_id);
80
81 priv->on_orig_row_added_id = 0;
82 priv->on_orig_row_removed_id = 0;
83 priv->on_orig_row_changed_id = 0;
84+ priv->on_orig_changeset_started_id = 0;
85+ priv->on_orig_changeset_finished_id = 0;
86
87 if (priv->orig_model)
88 {
89@@ -242,6 +256,16 @@
90 g_signal_connect_swapped (priv->orig_model, "row-changed",
91 G_CALLBACK (on_orig_model_row_changed), object);
92
93+ priv->on_orig_changeset_started_id =
94+ g_signal_connect_swapped (priv->orig_model, "changeset-started",
95+ G_CALLBACK (on_orig_model_changeset_started),
96+ object);
97+
98+ priv->on_orig_changeset_finished_id =
99+ g_signal_connect_swapped (priv->orig_model, "changeset-finished",
100+ G_CALLBACK (on_orig_model_changeset_finished),
101+ object);
102+
103 if (G_OBJECT_CLASS (dee_filter_model_parent_class)->constructed)
104 G_OBJECT_CLASS (dee_filter_model_parent_class)->constructed (object);
105 }
106@@ -327,6 +351,8 @@
107 priv->on_orig_row_added_id = 0;
108 priv->on_orig_row_removed_id = 0;
109 priv->on_orig_row_changed_id = 0;
110+ priv->on_orig_changeset_started_id = 0;
111+ priv->on_orig_changeset_finished_id = 0;
112 }
113
114 static void
115@@ -681,6 +707,35 @@
116 }
117 }
118
119+static void
120+on_orig_model_changeset_started (DeeFilterModel *self,
121+ DeeModel *model)
122+{
123+ DeeFilterModelPrivate *priv;
124+
125+ priv = self->priv;
126+
127+ if (priv->ignore_orig_signals)
128+ return;
129+
130+ /* this can end up being an empty changeset, but that's ok */
131+ g_signal_emit_by_name (self, "changeset-started");
132+}
133+
134+static void
135+on_orig_model_changeset_finished (DeeFilterModel *self,
136+ DeeModel *model)
137+{
138+ DeeFilterModelPrivate *priv;
139+
140+ priv = self->priv;
141+
142+ if (priv->ignore_orig_signals)
143+ return;
144+
145+ g_signal_emit_by_name (self, "changeset-finished");
146+}
147+
148 /*
149 * DeeModel Interface Implementation
150 */
151
152=== modified file 'src/dee-model.c'
153--- src/dee-model.c 2013-03-08 15:03:27 +0000
154+++ src/dee-model.c 2013-09-16 18:51:54 +0000
155@@ -98,6 +98,8 @@
156 DEE_MODEL_SIGNAL_ROW_ADDED,
157 DEE_MODEL_SIGNAL_ROW_REMOVED,
158 DEE_MODEL_SIGNAL_ROW_CHANGED,
159+ DEE_MODEL_SIGNAL_CHANGESET_STARTED,
160+ DEE_MODEL_SIGNAL_CHANGESET_FINISHED,
161
162 DEE_MODEL_LAST_SIGNAL
163 };
164@@ -229,6 +231,44 @@
165 g_cclosure_marshal_VOID__BOXED,
166 G_TYPE_NONE, 1,
167 DEE_TYPE_MODEL_ITER);
168+
169+ /**
170+ * DeeModel::changeset-started
171+ * @self: the #DeeModel on which the signal is emitted
172+ *
173+ * Connect to this signal to be notified when a changeset that can contain
174+ * multiple row additions / changes / removals is about to be committed
175+ * to the model.
176+ * Note that not all model implementations use the changeset approach and
177+ * you might still get a row change signal outside of changeset-started and
178+ * changeset-finished signals. It also isn't guaranteed that a changeset
179+ * would always be non-empty.
180+ */
181+ dee_model_signals[DEE_MODEL_SIGNAL_CHANGESET_STARTED] =
182+ g_signal_new ("changeset-started",
183+ DEE_TYPE_MODEL,
184+ G_SIGNAL_RUN_LAST,
185+ G_STRUCT_OFFSET (DeeModelIface, changeset_started),
186+ NULL, NULL,
187+ g_cclosure_marshal_VOID__VOID,
188+ G_TYPE_NONE, 0);
189+
190+ /**
191+ * DeeModel::changeset-finished
192+ * @self: the #DeeModel on which the signal is emitted
193+ *
194+ * Connect to this signal to be notified when a changeset that can contain
195+ * multiple row additions / changes / removals has been committed
196+ * to the model.
197+ */
198+ dee_model_signals[DEE_MODEL_SIGNAL_CHANGESET_FINISHED] =
199+ g_signal_new ("changeset-finished",
200+ DEE_TYPE_MODEL,
201+ G_SIGNAL_RUN_LAST,
202+ G_STRUCT_OFFSET (DeeModelIface, changeset_finished),
203+ NULL, NULL,
204+ g_cclosure_marshal_VOID__VOID,
205+ G_TYPE_NONE, 0);
206 }
207
208 /**
209@@ -646,6 +686,77 @@
210 return (* iface->get_n_rows) (self);
211 }
212
213+/**
214+ * dee_model_begin_changeset:
215+ * @self: a #DeeModel
216+ *
217+ * Notify listeners that the model is about to be changed, which means that
218+ * multiple row additions / changes / removals will follow.
219+ * The default implementation of this method will emit
220+ * the ::changeset-started signal.
221+ *
222+ * It is not stricly necessary to enclose every change to a model
223+ * in a dee_model_begin_changeset() and dee_model_end_changeset() calls, but
224+ * doing so is highly recommended and allows implementing various optimizations.
225+ *
226+ * The usual way to perform multiple changes to a model is as follows:
227+ *
228+ * <programlisting>
229+ * void update_model (DeeModel *model)
230+ * {
231+ * GVariant **added_row_data1 = ...;
232+ * GVariant **added_row_data2 = ...;
233+ *
234+ * dee_model_begin_changeset (model);
235+ *
236+ * dee_model_remove (model, dee_model_get_first_iter (model));
237+ * dee_model_append_row (model, added_row_data1);
238+ * dee_model_append_row (model, added_row_data2);
239+ *
240+ * dee_model_end_changeset (model);
241+ * }
242+ * </programlisting>
243+ */
244+void
245+dee_model_begin_changeset (DeeModel *self)
246+{
247+ DeeModelIface *iface;
248+
249+ g_return_if_fail (DEE_IS_MODEL (self));
250+
251+ iface = DEE_MODEL_GET_IFACE (self);
252+
253+ if (iface->begin_changeset)
254+ (* iface->begin_changeset) (self);
255+ else
256+ g_signal_emit (self, dee_model_signals[DEE_MODEL_SIGNAL_CHANGESET_STARTED], 0);
257+}
258+
259+/**
260+ * dee_model_end_changeset:
261+ * @self: a #DeeModel
262+ *
263+ * Notify listeners that all changes have been committed to the model.
264+ * The default implementation of this method will emit
265+ * the ::changeset-finished signal.
266+ *
267+ * See also dee_model_begin_changeset().
268+ */
269+void
270+dee_model_end_changeset (DeeModel *self)
271+{
272+ DeeModelIface *iface;
273+
274+ g_return_if_fail (DEE_IS_MODEL (self));
275+
276+ iface = DEE_MODEL_GET_IFACE (self);
277+
278+ if (iface->end_changeset)
279+ (* iface->end_changeset) (self);
280+ else
281+ g_signal_emit (self, dee_model_signals[DEE_MODEL_SIGNAL_CHANGESET_FINISHED], 0);
282+}
283+
284 static GVariant*
285 collect_variant (const gchar* col_schema, va_list *args)
286 {
287
288=== modified file 'src/dee-model.h'
289--- src/dee-model.h 2012-11-27 17:49:57 +0000
290+++ src/dee-model.h 2013-09-16 18:51:54 +0000
291@@ -266,14 +266,18 @@
292 DeeModelIter *iter,
293 GVariant **out_row_members);
294
295+ void (*begin_changeset) (DeeModel *self);
296+
297+ void (*end_changeset) (DeeModel *self);
298+
299+ void (*changeset_started) (DeeModel *self);
300+
301+ void (*changeset_finished) (DeeModel *self);
302+
303 /*< private >*/
304 void (*_dee_model_1) (void);
305 void (*_dee_model_2) (void);
306 void (*_dee_model_3) (void);
307- void (*_dee_model_4) (void);
308- void (*_dee_model_5) (void);
309- void (*_dee_model_6) (void);
310- void (*_dee_model_7) (void);
311 };
312
313 GType dee_model_iter_get_type (void);
314@@ -494,6 +498,10 @@
315 DeeModelIter *iter,
316 DeeModelTag *tag);
317
318+void dee_model_begin_changeset (DeeModel *self);
319+
320+void dee_model_end_changeset (DeeModel *self);
321+
322 GVariant** dee_model_build_row (DeeModel *self,
323 GVariant **out_row_members,
324 ...);
325
326=== modified file 'src/dee-proxy-model.c'
327--- src/dee-proxy-model.c 2013-01-04 17:53:43 +0000
328+++ src/dee-proxy-model.c 2013-09-16 18:51:54 +0000
329@@ -81,6 +81,8 @@
330 gulong row_added_handler;
331 gulong row_removed_handler;
332 gulong row_changed_handler;
333+ gulong changeset_started_handler;
334+ gulong changeset_finished_handler;
335 };
336
337 #define DEE_PROXY_MODEL_BACK_END(model) (DEE_PROXY_MODEL(model)->priv->back_end)
338@@ -233,6 +235,10 @@
339 DeeModelTag *tag,
340 gpointer value);
341
342+static void dee_proxy_model_begin_changeset (DeeModel *self);
343+
344+static void dee_proxy_model_end_changeset (DeeModel *self);
345+
346 /*
347 * Callbacks for relaying signals from the back end model
348 */
349@@ -245,6 +251,12 @@
350 static void on_back_end_row_changed (DeeProxyModel *self,
351 DeeModelIter *iter);
352
353+static void on_back_end_changeset_started (DeeProxyModel *self,
354+ DeeModel *model);
355+
356+static void on_back_end_changeset_finished (DeeProxyModel *self,
357+ DeeModel *model);
358+
359 /*
360 * Overrides for DeeSerializableModel
361 */
362@@ -270,6 +282,10 @@
363 g_signal_handler_disconnect (priv->back_end, priv->row_removed_handler);
364 if (priv->row_changed_handler != 0)
365 g_signal_handler_disconnect (priv->back_end, priv->row_changed_handler);
366+ if (priv->changeset_started_handler != 0)
367+ g_signal_handler_disconnect (priv->back_end, priv->changeset_started_handler);
368+ if (priv->changeset_finished_handler != 0)
369+ g_signal_handler_disconnect (priv->back_end, priv->changeset_finished_handler);
370
371 g_object_unref (priv->back_end);
372 }
373@@ -302,6 +318,16 @@
374 priv->row_changed_handler =
375 g_signal_connect_swapped (priv->back_end, "row-changed",
376 G_CALLBACK (on_back_end_row_changed), object);
377+
378+ priv->changeset_started_handler =
379+ g_signal_connect_swapped (priv->back_end, "changeset-started",
380+ G_CALLBACK (on_back_end_changeset_started),
381+ object);
382+
383+ priv->changeset_finished_handler =
384+ g_signal_connect_swapped (priv->back_end, "changeset-finished",
385+ G_CALLBACK (on_back_end_changeset_finished),
386+ object);
387 }
388
389 /* GObjectClass has NULL 'constructed' member, but we add this check for
390@@ -407,7 +433,7 @@
391 * from the back end model.
392 * You will most likely want to set this property to false
393 * if the implementation manipulates with the rows in the model and keep
394- * track of seqnums.
395+ * track of seqnums yourself.
396 **/
397 pspec = g_param_spec_boolean ("inherit-seqnums", "Inherit seqnums",
398 "Whether or not to inherit seqnums",
399@@ -462,6 +488,8 @@
400 iface->register_tag = dee_proxy_model_register_tag;
401 iface->get_tag = dee_proxy_model_get_tag;
402 iface->set_tag = dee_proxy_model_set_tag;
403+ iface->begin_changeset = dee_proxy_model_begin_changeset;
404+ iface->end_changeset = dee_proxy_model_end_changeset;
405
406 iface->register_vardict_schema = dee_proxy_model_register_vardict_schema;
407 iface->get_vardict_schema = dee_proxy_model_get_vardict_schema;
408@@ -479,6 +507,8 @@
409 priv->row_added_handler = 0;
410 priv->row_removed_handler = 0;
411 priv->row_changed_handler = 0;
412+ priv->changeset_started_handler = 0;
413+ priv->changeset_finished_handler = 0;
414 }
415
416 /*
417@@ -891,6 +921,22 @@
418 return dee_model_set_tag (DEE_PROXY_MODEL_BACK_END (self), iter, tag, value);
419 }
420
421+static void
422+dee_proxy_model_begin_changeset (DeeModel *self)
423+{
424+ g_return_if_fail (DEE_IS_PROXY_MODEL (self));
425+
426+ dee_model_begin_changeset (DEE_PROXY_MODEL_BACK_END (self));
427+}
428+
429+static void
430+dee_proxy_model_end_changeset (DeeModel *self)
431+{
432+ g_return_if_fail (DEE_IS_PROXY_MODEL (self));
433+
434+ dee_model_end_changeset (DEE_PROXY_MODEL_BACK_END (self));
435+}
436+
437 /*
438 * Relay signals from back end
439 */
440@@ -916,6 +962,20 @@
441 g_signal_emit_by_name (self, "row-changed", iter);
442 }
443
444+static void
445+on_back_end_changeset_started (DeeProxyModel *self,
446+ DeeModel *model)
447+{
448+ g_signal_emit_by_name (self, "changeset-started");
449+}
450+
451+static void
452+on_back_end_changeset_finished (DeeProxyModel *self,
453+ DeeModel *model)
454+{
455+ g_signal_emit_by_name (self, "changeset-finished");
456+}
457+
458 /*
459 * Overrides for DeeSerializableModel
460 */
461
462=== modified file 'src/dee-sequence-model.c'
463--- src/dee-sequence-model.c 2012-02-28 00:34:40 +0000
464+++ src/dee-sequence-model.c 2013-09-16 18:51:54 +0000
465@@ -280,9 +280,9 @@
466 obj_class->get_property = dee_sequence_model_get_property;
467
468 /* Find signal ids for the model modification signals */
469- sigid_row_added = g_signal_lookup ("row-added", DEE_TYPE_SEQUENCE_MODEL);
470- sigid_row_removed = g_signal_lookup ("row-removed", DEE_TYPE_SEQUENCE_MODEL);
471- sigid_row_changed = g_signal_lookup ("row-changed", DEE_TYPE_SEQUENCE_MODEL);
472+ sigid_row_added = g_signal_lookup ("row-added", DEE_TYPE_MODEL);
473+ sigid_row_removed = g_signal_lookup ("row-removed", DEE_TYPE_MODEL);
474+ sigid_row_changed = g_signal_lookup ("row-changed", DEE_TYPE_MODEL);
475
476 /* Add private data */
477 g_type_class_add_private (obj_class, sizeof (DeeSequenceModelPrivate));
478
479=== modified file 'src/dee-serializable-model.c'
480--- src/dee-serializable-model.c 2013-07-21 22:29:56 +0000
481+++ src/dee-serializable-model.c 2013-09-16 18:51:54 +0000
482@@ -77,6 +77,7 @@
483 gchar **column_names; // NULL terminated
484 guint32 *column_name_hashes;
485 GHashTable *field_schemas;
486+ gboolean inside_changeset;
487 };
488
489 typedef struct _FieldSchemaInfo FieldSchemaInfo;
490@@ -238,6 +239,13 @@
491 static gboolean dee_serializable_model_is_last (DeeModel *self,
492 DeeModelIter *iter);
493
494+static void dee_serializable_model_begin_changeset (DeeModel *self);
495+
496+static void dee_serializable_model_end_changeset (DeeModel *self);
497+
498+static guint sigid_changeset_started = 0;
499+static guint sigid_changeset_finished = 0;
500+
501 /* FieldSchemaInfo methods */
502 static FieldSchemaInfo*
503 field_schema_info_new (const gchar *schema, guint column)
504@@ -352,6 +360,9 @@
505 klass->set_seqnum = dee_serializable_model_set_seqnum_real;
506 klass->inc_seqnum = dee_serializable_model_inc_seqnum_real;
507
508+ sigid_changeset_started = g_signal_lookup ("changeset-started", DEE_TYPE_MODEL);
509+ sigid_changeset_finished = g_signal_lookup ("changeset-finished", DEE_TYPE_MODEL);
510+
511 /* Add private data */
512 g_type_class_add_private (obj_class, sizeof (DeeSerializableModelPrivate));
513 }
514@@ -1328,6 +1339,44 @@
515 }
516 }
517
518+static void
519+dee_serializable_model_begin_changeset (DeeModel *self)
520+{
521+ DeeSerializableModelPrivate *priv;
522+
523+ priv = DEE_SERIALIZABLE_MODEL (self)->priv;
524+
525+ if (!priv->inside_changeset)
526+ {
527+ priv->inside_changeset = TRUE;
528+ g_signal_emit (self, sigid_changeset_started, 0);
529+ }
530+ else
531+ {
532+ g_warning ("Ignored call to dee_model_begin_changeset, finish "
533+ "the current changeset using dee_model_end_changeset first");
534+ }
535+}
536+
537+static void
538+dee_serializable_model_end_changeset (DeeModel *self)
539+{
540+ DeeSerializableModelPrivate *priv;
541+
542+ priv = DEE_SERIALIZABLE_MODEL (self)->priv;
543+
544+ if (priv->inside_changeset)
545+ {
546+ priv->inside_changeset = FALSE;
547+ g_signal_emit (self, sigid_changeset_finished, 0);
548+ }
549+ else
550+ {
551+ g_warning ("Ignored call to dee_model_end_changeset, "
552+ "dee_model_begin_changeset has to be called first");
553+ }
554+}
555+
556 static DeeModelTag*
557 dee_serializable_model_register_tag (DeeModel *self,
558 GDestroyNotify tag_destroy)
559@@ -1635,6 +1684,9 @@
560 dee_serializable_model_register_vardict_schema;
561 iface->get_vardict_schema =
562 dee_serializable_model_get_vardict_schema;
563+
564+ iface->begin_changeset = dee_serializable_model_begin_changeset;
565+ iface->end_changeset = dee_serializable_model_end_changeset;
566 }
567
568 static void
569
570=== modified file 'src/dee-shared-model.c'
571--- src/dee-shared-model.c 2013-07-21 22:29:56 +0000
572+++ src/dee-shared-model.c 2013-09-16 18:51:54 +0000
573@@ -1477,6 +1477,7 @@
574 trace_object (self, "Applying transaction of %i rows", n_rows);
575
576 /* Phew. Finally. We're ready to merge the changes */
577+ g_signal_emit_by_name (self, "changeset-started");
578 g_signal_emit (self, _signals[BEGIN_TRANSACTION], 0, seqnum_before, seqnum_after);
579 priv->suppress_remote_signals = TRUE;
580 for (i = 0; i < n_rows; i++) /* Begin outer loop */
581@@ -1513,8 +1514,9 @@
582 g_critical ("Commit from %s contains rows of illegal length. "
583 "The model may have been left in a dirty state",
584 sender_name);
585- // FIXME: cleanup
586- return;
587+ /* cleanup */
588+ g_variant_unref (row);
589+ continue;
590 }
591
592 /* Read the row cells into our stack allocated row buffer.
593@@ -1570,6 +1572,7 @@
594 priv->last_committed_seqnum = seqnum_after;
595
596 g_signal_emit (self, _signals[END_TRANSACTION], 0, seqnum_before, seqnum_after);
597+ g_signal_emit_by_name (self, "changeset-finished");
598 }
599
600 static void
601
602=== modified file 'tests/test-client-server.c'
603--- tests/test-client-server.c 2012-02-28 10:56:27 +0000
604+++ tests/test-client-server.c 2013-09-16 18:51:54 +0000
605@@ -820,6 +820,12 @@
606 }
607
608 static void
609+changeset_signal (DeeModel *model, gboolean *value)
610+{
611+ *value = TRUE;
612+}
613+
614+static void
615 test_remote_append (Fixture *fix, gconstpointer data)
616 {
617 if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
618@@ -829,6 +835,13 @@
619 g_assert (dee_shared_model_is_leader (DEE_SHARED_MODEL (fix->model)));
620 g_assert_cmpuint (dee_model_get_n_rows (fix->model), ==, 0);
621
622+ gboolean got_changeset_start = FALSE;
623+ gboolean got_changeset_finish = FALSE;
624+ g_signal_connect (fix->model, "changeset-started",
625+ G_CALLBACK (changeset_signal), &got_changeset_start);
626+ g_signal_connect (fix->model, "changeset-finished",
627+ G_CALLBACK (changeset_signal), &got_changeset_finish);
628+
629 if (gtx_wait_for_command (TESTDIR,
630 MODEL_HELPER (append1, MODEL_NAME),
631 2000))
632@@ -838,6 +851,8 @@
633
634 /* There should be a new row in the model */
635 g_assert_cmpuint (dee_model_get_n_rows (fix->model), ==, 1);
636+ g_assert (got_changeset_start);
637+ g_assert (got_changeset_finish);
638 }
639
640 static void
641
642=== modified file 'tests/test-filter-model.c'
643--- tests/test-filter-model.c 2013-05-31 12:38:11 +0000
644+++ tests/test-filter-model.c 2013-09-16 18:51:54 +0000
645@@ -28,8 +28,16 @@
646
647 } FilterFixture;
648
649-static void setup (FilterFixture *fix, gconstpointer data);
650-static void teardown (FilterFixture *fix, gconstpointer data);
651+typedef struct
652+{
653+ gint first;
654+ gint second;
655+
656+} TwoIntsTuple;
657+
658+static void setup (FilterFixture *fix, gconstpointer data);
659+static void setup_empty (FilterFixture *fix, gconstpointer data);
660+static void teardown (FilterFixture *fix, gconstpointer data);
661
662 static void test_empty_orig (FilterFixture *fix,
663 gconstpointer data);
664@@ -54,6 +62,9 @@
665 static void test_regex (FilterFixture *fix,
666 gconstpointer data);
667
668+static void test_changesets (FilterFixture *fix,
669+ gconstpointer data);
670+
671 void
672 test_filter_model_create_suite (void)
673 {
674@@ -78,22 +89,35 @@
675 setup, test_any, teardown);
676 g_test_add (DOMAIN"/Regex", FilterFixture, 0,
677 setup, test_regex, teardown);
678+ g_test_add (DOMAIN"/Changesets", FilterFixture, 0,
679+ setup_empty, test_changesets, teardown);
680 }
681
682 static void
683-setup (FilterFixture *fix, gconstpointer data)
684+setup_empty (FilterFixture *fix, gconstpointer data)
685 {
686 fix->model = dee_sequence_model_new ();
687 dee_model_set_schema (fix->model, "i", "s", NULL);
688
689- dee_model_append (fix->model, 0, "Zero");
690- dee_model_append (fix->model, 1, "One");
691- dee_model_append (fix->model, 2, "Two");
692-
693 g_assert (DEE_IS_SEQUENCE_MODEL (fix->model));
694 }
695
696 static void
697+add_3rows(DeeModel *model)
698+{
699+ dee_model_append (model, 0, "Zero");
700+ dee_model_append (model, 1, "One");
701+ dee_model_append (model, 2, "Two");
702+}
703+
704+static void
705+setup (FilterFixture *fix, gconstpointer data)
706+{
707+ setup_empty (fix, data);
708+ add_3rows (fix->model);
709+}
710+
711+static void
712 teardown (FilterFixture *fix, gconstpointer data)
713 {
714 g_object_unref (fix->model);
715@@ -282,7 +306,28 @@
716 g_assert_cmpint (27, ==, dee_model_get_int32 (fix->model, iter, 0));
717 g_assert_cmpstr ("TwentySeven", ==, dee_model_get_string (m, iter, 1));
718 g_assert_cmpstr ("TwentySeven", ==, dee_model_get_string (fix->model, iter, 1));
719-
720+
721+ /* And append two more rows to the filtered model, to ensure the order */
722+ dee_model_prepend (m, -1, "MinusOne");
723+ dee_model_append (m, 39, "ThirtyNine");
724+ g_assert_cmpint (3, ==, filter_add_count);
725+ g_assert_cmpint (5, ==, orig_add_count);
726+ g_assert_cmpint (3, ==, dee_model_get_n_rows (m));
727+ g_assert_cmpint (8, ==, dee_model_get_n_rows (fix->model));
728+ g_assert_cmpuint (3, ==, dee_serializable_model_get_seqnum (m));
729+ iter = dee_model_prev (m, dee_model_get_last_iter (m));
730+ g_assert_cmpint (39, ==, dee_model_get_int32 (m, iter, 0));
731+ g_assert_cmpstr ("ThirtyNine", ==, dee_model_get_string (m, iter, 1));
732+ iter = dee_model_prev (m, iter);
733+ g_assert_cmpint (27, ==, dee_model_get_int32 (m, iter, 0));
734+ g_assert_cmpstr ("TwentySeven", ==, dee_model_get_string (m, iter, 1));
735+ iter = dee_model_prev (m, iter);
736+ g_assert_cmpint (-1, ==, dee_model_get_int32 (m, iter, 0));
737+ g_assert_cmpstr ("MinusOne", ==, dee_model_get_string (m, iter, 1));
738+ iter = dee_model_prev (fix->model, dee_model_get_last_iter (fix->model));
739+ g_assert_cmpint (39, ==, dee_model_get_int32 (fix->model, iter, 0));
740+ g_assert_cmpstr ("ThirtyNine", ==, dee_model_get_string (fix->model, iter, 1));
741+
742 g_object_unref (m);
743 }
744
745@@ -616,3 +661,88 @@
746 _test_orig_ordering (fix, &filter);
747 g_regex_unref (regex);
748 }
749+
750+static void
751+increment_first (TwoIntsTuple *tuple)
752+{
753+ tuple->first++;
754+ // first always has to be incremented before second
755+ g_assert (tuple->first > tuple->second);
756+}
757+
758+static void
759+increment_second (TwoIntsTuple *tuple)
760+{
761+ tuple->second++;
762+ // second needs to be incremented after first
763+ g_assert (tuple->second == tuple->first);
764+}
765+
766+static void
767+test_changesets (FilterFixture *fix, gconstpointer data)
768+{
769+ GRegex *regex;
770+ DeeFilter filter;
771+ DeeModel *filter_m1;
772+ DeeModel *filter_m2;
773+ DeeModel *filter_m3;
774+
775+ regex = g_regex_new ("^..[eo]", 0, 0, NULL);
776+ dee_filter_new_regex (1, regex, &filter);
777+ filter_m1 = dee_filter_model_new (fix->model, &filter);
778+ g_regex_unref (regex);
779+
780+ regex = g_regex_new ("^Z", 0, 0, NULL);
781+ dee_filter_new_regex (1, regex, &filter);
782+ filter_m2 = dee_filter_model_new (fix->model, &filter);
783+ g_regex_unref (regex);
784+
785+ regex = g_regex_new ("^X", 0, 0, NULL);
786+ dee_filter_new_regex (1, regex, &filter);
787+ filter_m3 = dee_filter_model_new (fix->model, &filter);
788+ g_regex_unref (regex);
789+
790+ g_assert_cmpuint (0, ==, dee_model_get_n_rows (fix->model));
791+ g_assert_cmpuint (0, ==, dee_model_get_n_rows (filter_m1));
792+ g_assert_cmpuint (0, ==, dee_model_get_n_rows (filter_m2));
793+ g_assert_cmpuint (0, ==, dee_model_get_n_rows (filter_m3));
794+
795+ TwoIntsTuple tuple_m0 = { 0, 0 };
796+ TwoIntsTuple tuple_m1 = { 0, 0 };
797+ TwoIntsTuple tuple_m2 = { 0, 0 };
798+ TwoIntsTuple tuple_m3 = { 0, 0 };
799+
800+ g_signal_connect_swapped (fix->model, "changeset-started",
801+ G_CALLBACK (increment_first), &tuple_m0);
802+ g_signal_connect_swapped (fix->model, "changeset-finished",
803+ G_CALLBACK (increment_second), &tuple_m0);
804+ g_signal_connect_swapped (filter_m1, "changeset-started",
805+ G_CALLBACK (increment_first), &tuple_m1);
806+ g_signal_connect_swapped (filter_m1, "changeset-finished",
807+ G_CALLBACK (increment_second), &tuple_m1);
808+ g_signal_connect_swapped (filter_m2, "changeset-started",
809+ G_CALLBACK (increment_first), &tuple_m2);
810+ g_signal_connect_swapped (filter_m2, "changeset-finished",
811+ G_CALLBACK (increment_second), &tuple_m2);
812+ g_signal_connect_swapped (filter_m3, "changeset-started",
813+ G_CALLBACK (increment_first), &tuple_m3);
814+ g_signal_connect_swapped (filter_m3, "changeset-finished",
815+ G_CALLBACK (increment_second), &tuple_m3);
816+
817+ dee_model_begin_changeset (fix->model);
818+ add_3rows (fix->model);
819+ dee_model_end_changeset (fix->model);
820+
821+ g_assert_cmpuint (3, ==, dee_model_get_n_rows (fix->model));
822+ g_assert_cmpuint (2, ==, dee_model_get_n_rows (filter_m1));
823+ g_assert_cmpuint (1, ==, dee_model_get_n_rows (filter_m2));
824+ g_assert_cmpuint (0, ==, dee_model_get_n_rows (filter_m3));
825+ g_assert_cmpint (tuple_m0.first, ==, 1);
826+ g_assert_cmpint (tuple_m0.second, ==, 1);
827+ g_assert_cmpint (tuple_m1.first, ==, 1);
828+ g_assert_cmpint (tuple_m1.second, ==, 1);
829+ g_assert_cmpint (tuple_m2.first, ==, 1);
830+ g_assert_cmpint (tuple_m2.second, ==, 1);
831+ g_assert_cmpint (tuple_m3.first, ==, 1);
832+ g_assert_cmpint (tuple_m3.second, ==, 1);
833+}
834
835=== modified file 'tests/test-model-interactions.c'
836--- tests/test-model-interactions.c 2013-07-16 08:32:59 +0000
837+++ tests/test-model-interactions.c 2013-09-16 18:51:54 +0000
838@@ -699,6 +699,12 @@
839 }
840
841 static void
842+changeset_signal (DeeModel *model, gboolean *value)
843+{
844+ *value = TRUE;
845+}
846+
847+static void
848 test_remote_append (Fixture *fix, gconstpointer data)
849 {
850 if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
851@@ -708,6 +714,13 @@
852 g_assert (dee_shared_model_is_leader (DEE_SHARED_MODEL (fix->model)));
853 g_assert_cmpuint (dee_model_get_n_rows (fix->model), ==, 0);
854
855+ gboolean got_changeset_start = FALSE;
856+ gboolean got_changeset_finish = FALSE;
857+ g_signal_connect (fix->model, "changeset-started",
858+ G_CALLBACK (changeset_signal), &got_changeset_start);
859+ g_signal_connect (fix->model, "changeset-finished",
860+ G_CALLBACK (changeset_signal), &got_changeset_finish);
861+
862 if (gtx_wait_for_command (TESTDIR,
863 MODEL_HELPER (append1, MODEL_NAME),
864 2000))
865@@ -717,6 +730,8 @@
866
867 /* There should be a new row in the model */
868 g_assert_cmpuint (dee_model_get_n_rows (fix->model), ==, 1);
869+ g_assert (got_changeset_start);
870+ g_assert (got_changeset_finish);
871 }
872
873 static void
874
875=== modified file 'tests/test-resource-manager.c'
876--- tests/test-resource-manager.c 2011-03-01 20:55:42 +0000
877+++ tests/test-resource-manager.c 2013-09-16 18:51:54 +0000
878@@ -38,17 +38,21 @@
879 static void shared_model_teardown (Fixture *fix, gconstpointer data);
880
881 static void test_model_persistence (Fixture *fix, gconstpointer data);
882+static void test_resource_manager_default (Fixture *fix, gconstpointer data);
883
884 void
885 test_resource_manager_create_suite (void)
886 {
887 #define DOMAIN "/ResourceManager"
888
889+ g_test_add (DOMAIN"/Default", Fixture, 0,
890+ NULL, test_resource_manager_default, NULL);
891+
892 g_test_add (DOMAIN"/SequenceModel", Fixture, 0,
893- sequence_model_setup, test_model_persistence, sequence_model_teardown);
894+ sequence_model_setup, test_model_persistence, sequence_model_teardown);
895
896 g_test_add (DOMAIN"/SharedModel", Fixture, 0,
897- shared_model_setup, test_model_persistence, shared_model_teardown);
898+ shared_model_setup, test_model_persistence, shared_model_teardown);
899 }
900
901 static void
902@@ -192,3 +196,27 @@
903
904 dee_assert_cmpmodel (fix->orig, fix->copy);
905 }
906+
907+static void
908+test_resource_manager_default (Fixture *fix, gconstpointer data)
909+{
910+ DeeResourceManager *manager;
911+ GError *error;
912+ GObject *result;
913+ gchar *primary_path;
914+
915+ error = NULL;
916+
917+ manager = dee_resource_manager_get_default ();
918+ g_object_get (manager, "primary-path", &primary_path, NULL);
919+ g_assert (g_str_has_suffix (primary_path, "resources"));
920+ g_free (primary_path);
921+
922+ result = dee_resource_manager_load (manager,
923+ "com.this.hopefully.doesnt.exist.com",
924+ &error);
925+ g_assert (result == NULL);
926+ /* loading non-existing resource just returns NULL, doesn't throw error */
927+ g_assert_no_error (error);
928+}
929+
930
931=== modified file 'vapi/dee-1.0.vapi'
932--- vapi/dee-1.0.vapi 2013-04-10 14:30:44 +0000
933+++ vapi/dee-1.0.vapi 2013-09-16 18:51:54 +0000
934@@ -212,11 +212,13 @@
935 public interface Model : GLib.Object {
936 public unowned Dee.ModelIter append (...);
937 public abstract unowned Dee.ModelIter append_row ([CCode (array_length = false, array_null_terminated = true)] GLib.Variant[] row_members);
938+ public abstract void begin_changeset ();
939 [CCode (array_length_pos = 1.33333, array_length_type = "guint", cname = "dee_model_build_named_row_sunk")]
940 public GLib.Variant[] build_named_row ([CCode (array_length = false)] GLib.Variant[]? out_row_members, string first_column_name, ...);
941 [CCode (array_length_pos = 1.33333, array_length_type = "guint", cname = "dee_model_build_named_row_sunk")]
942 public unowned GLib.Variant[] build_named_row_static ([CCode (array_length = false)] GLib.Variant[] out_row_members, string first_column_name, ...);
943 public abstract void clear ();
944+ public abstract void end_changeset ();
945 public abstract unowned Dee.ModelIter find_row_sorted ([CCode (array_length = false, array_null_terminated = true)] GLib.Variant[] row_spec, [CCode (delegate_target_pos = 2.5)] Dee.CompareRowFunc cmp_func, out bool out_was_found);
946 public unowned Dee.ModelIter find_row_sorted_with_sizes ([CCode (array_length = false, array_null_terminated = true)] GLib.Variant[] row_spec, [CCode (delegate_target_pos = 2.5)] Dee.CompareRowSizedFunc cmp_func, out bool out_was_found);
947 public unowned Dee.ModelIter find_sorted ([CCode (delegate_target_pos = 1.5)] Dee.CompareRowFunc cmp_func, out bool out_was_found, ...);
948@@ -271,6 +273,8 @@
949 public void set_schema (...);
950 public abstract void set_schema_full ([CCode (array_length_cname = "num_columns", array_length_pos = 1.1, array_length_type = "guint", array_null_terminated = true)] string[] column_schemas);
951 public abstract void set_value (Dee.ModelIter iter, uint column, GLib.Variant value);
952+ public virtual signal void changeset_finished ();
953+ public virtual signal void changeset_started ();
954 public virtual signal void row_added (Dee.ModelIter iter);
955 public virtual signal void row_changed (Dee.ModelIter iter);
956 public virtual signal void row_removed (Dee.ModelIter iter);

Subscribers

People subscribed via source and target branches

to all changes: