25
28
#include <string.h>
27
#include <bonobo/bonobo-exception.h>
28
#include "libedataserver/e-component-listener.h"
31
#include <dbus/dbus.h>
32
#include <dbus/dbus-glib.h>
33
#include <glib-object.h>
29
35
#include "e-cal-backend-sexp.h"
30
36
#include "e-data-cal-view.h"
35
GNOME_Evolution_Calendar_CalViewListener listener;
36
EComponentListener *component_listener;
38
gboolean notified_start;
39
gboolean notified_done;
42
/* Private part of the Query structure */
37
#include "e-data-cal-marshal.h"
39
extern DBusGConnection *connection;
41
static gboolean impl_EDataCalView_start (EDataCalView *query, GError **error);
42
#include "e-data-cal-view-glue.h"
43
46
struct _EDataCalViewPrivate {
44
47
/* The backend we are monitoring */
45
48
ECalBackend *backend;
49
GNOME_Evolution_Calendar_CallStatus done_status;
51
GHashTable *matched_objects;
53
/* The listener we report to */
52
EDataCalCallStatus done_status;
56
54
/* Sexp that defines the query */
57
55
ECalBackendSExp *sexp;
66
G_DEFINE_TYPE (EDataCalView, e_data_cal_view, G_TYPE_OBJECT);
67
#define E_DATA_CAL_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), E_DATA_CAL_VIEW_TYPE, EDataCalViewPrivate))
62
static void e_data_cal_view_class_init (EDataCalViewClass *class);
63
static void e_data_cal_view_init (EDataCalView *query, EDataCalViewClass *class);
69
static void e_data_cal_view_dispose (GObject *object);
64
70
static void e_data_cal_view_finalize (GObject *object);
66
static BonoboObjectClass *parent_class;
70
BONOBO_TYPE_FUNC_FULL (EDataCalView,
71
GNOME_Evolution_Calendar_CalView,
71
static void e_data_cal_view_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
72
static void e_data_cal_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
89
static guint signals[LAST_SIGNAL];
92
add_object_to_cache (EDataCalView *query, const gchar *calobj)
97
EDataCalViewPrivate *priv;
101
comp = e_cal_component_new_from_string (calobj);
105
e_cal_component_get_uid (comp, &uid);
107
g_object_unref (comp);
111
if (e_cal_component_is_instance (comp)) {
113
str = e_cal_component_get_recurid_as_string (comp);
114
real_uid = g_strdup_printf ("%s@%s", uid, str);
117
real_uid = g_strdup (uid);
119
if (g_hash_table_lookup (priv->matched_objects, real_uid))
120
g_hash_table_replace (priv->matched_objects, real_uid, g_strdup (calobj));
122
g_hash_table_insert (priv->matched_objects, real_uid, g_strdup (calobj));
125
g_object_unref (comp);
129
uncache_with_id_cb (gpointer key, gpointer value, gpointer user_data)
133
const gchar *this_uid;
135
gboolean remove = FALSE;
140
comp = e_cal_component_new_from_string (object);
142
e_cal_component_get_uid (comp, &this_uid);
143
if (this_uid && !strcmp (id->uid, this_uid)) {
144
if (id->rid && *id->rid) {
145
gchar *rid = e_cal_component_get_recurid_as_string (comp);
147
if (rid && !strcmp (id->rid, rid))
155
g_object_unref (comp);
162
remove_object_from_cache (EDataCalView *query, const ECalComponentId *id)
164
EDataCalViewPrivate *priv;
168
g_hash_table_foreach_remove (priv->matched_objects, (GHRFunc) uncache_with_id_cb, (gpointer) id);
172
listener_died_cb (EComponentListener *cl, gpointer data)
174
EDataCalView *query = QUERY (data);
175
EDataCalViewPrivate *priv;
180
for (l = priv->listeners; l != NULL; l = l->next) {
181
ListenerData *ld = l->data;
183
if (ld->component_listener == cl) {
184
g_object_unref (ld->component_listener);
185
ld->component_listener = NULL;
187
bonobo_object_release_unref (ld->listener, NULL);
190
priv->listeners = g_list_remove_link (priv->listeners, l);
194
if (priv->listeners == NULL)
195
g_signal_emit (query, signals[LAST_LISTENER_GONE], 0);
203
notify_matched_object_cb (gpointer key, gpointer value, gpointer user_data)
207
EDataCalViewPrivate *priv;
215
for (l = priv->listeners; l != NULL; l = l->next) {
216
ListenerData *ld = l->data;
218
if (!ld->notified_start) {
219
GNOME_Evolution_Calendar_stringlist obj_list;
220
CORBA_Environment ev;
222
obj_list._buffer = GNOME_Evolution_Calendar_stringlist_allocbuf (1);
223
obj_list._maximum = 1;
224
obj_list._length = 1;
225
obj_list._buffer[0] = CORBA_string_dup (object);
227
CORBA_exception_init (&ev);
228
GNOME_Evolution_Calendar_CalViewListener_notifyObjectsAdded (ld->listener, &obj_list, &ev);
229
CORBA_exception_free (&ev);
231
CORBA_free (obj_list._buffer);
237
impl_EDataCalView_start (PortableServer_Servant servant, CORBA_Environment *ev)
240
EDataCalViewPrivate *priv;
243
query = QUERY (bonobo_object_from_servant (servant));
247
g_hash_table_foreach (priv->matched_objects, (GHFunc) notify_matched_object_cb, query);
249
/* notify all listeners correctly if the query is already done */
250
for (l = priv->listeners; l != NULL; l = l->next) {
251
ListenerData *ld = l->data;
253
if (!ld->notified_start) {
254
ld->notified_start = TRUE;
256
if (priv->done && !ld->notified_done) {
258
ld->notified_done = TRUE;
260
CORBA_exception_init (ev);
261
GNOME_Evolution_Calendar_CalViewListener_notifyQueryDone (
262
ld->listener, priv->done_status, ev);
263
CORBA_exception_free (ev);
268
priv->started = TRUE;
269
e_cal_backend_start_query (priv->backend, query);
271
for (l = priv->listeners; l != NULL; l = l->next) {
272
ListenerData *ld = l->data;
274
ld->notified_start = TRUE;
280
e_data_cal_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
283
EDataCalViewPrivate *priv;
285
query = QUERY (object);
288
switch (property_id) {
290
priv->backend = E_CAL_BACKEND (g_value_dup_object (value));
293
e_data_cal_view_add_listener (query, g_value_get_pointer (value));
296
priv->sexp = E_CAL_BACKEND_SEXP (g_value_dup_object (value));
299
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
305
e_data_cal_view_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
308
EDataCalViewPrivate *priv;
310
query = QUERY (object);
313
switch (property_id) {
315
g_value_set_object (value, priv->backend);
318
if (priv->listeners) {
321
ld = priv->listeners->data;
322
g_value_set_pointer (value, ld->listener);
326
g_value_set_object (value, priv->sexp);
329
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
334
/* Class initialization function for the live search query */
91
static guint signals[LAST_SIGNAL] = { 0 };
336
95
e_data_cal_view_class_init (EDataCalViewClass *klass)
338
GObjectClass *object_class;
339
POA_GNOME_Evolution_Calendar_CalView__epv *epv = &klass->epv;
340
97
GParamSpec *param;
342
object_class = (GObjectClass *) klass;
344
parent_class = g_type_class_peek_parent (klass);
98
GObjectClass *object_class = G_OBJECT_CLASS (klass);
100
g_type_class_add_private (klass, sizeof (EDataCalViewPrivate));
346
102
object_class->set_property = e_data_cal_view_set_property;
347
103
object_class->get_property = e_data_cal_view_get_property;
104
object_class->dispose = e_data_cal_view_dispose;
348
105
object_class->finalize = e_data_cal_view_finalize;
350
epv->start = impl_EDataCalView_start;
352
107
param = g_param_spec_object ("backend", NULL, NULL, E_TYPE_CAL_BACKEND,
353
108
G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
354
109
g_object_class_install_property (object_class, PROP_BACKEND, param);
355
param = g_param_spec_pointer ("listener", NULL, NULL,
356
G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
357
g_object_class_install_property (object_class, PROP_LISTENER, param);
358
110
param = g_param_spec_object ("sexp", NULL, NULL, E_TYPE_CAL_BACKEND_SEXP,
359
111
G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
360
112
g_object_class_install_property (object_class, PROP_SEXP, param);
362
signals[LAST_LISTENER_GONE] =
363
g_signal_new ("last_listener_gone",
364
G_TYPE_FROM_CLASS (klass),
366
G_STRUCT_OFFSET (EDataCalViewClass, last_listener_gone),
368
g_cclosure_marshal_VOID__VOID,
371
klass->last_listener_gone = NULL;
374
/* Object initialization function for the live search query */
114
signals[OBJECTS_ADDED] =
115
g_signal_new ("objects-added",
116
G_OBJECT_CLASS_TYPE (klass),
119
g_cclosure_marshal_VOID__BOXED,
120
G_TYPE_NONE, 1, G_TYPE_STRV);
122
signals[OBJECTS_MODIFIED] =
123
g_signal_new ("objects-modified",
124
G_OBJECT_CLASS_TYPE (klass),
127
g_cclosure_marshal_VOID__BOXED,
128
G_TYPE_NONE, 1, G_TYPE_STRV);
130
signals[OBJECTS_REMOVED] =
131
g_signal_new ("objects-removed",
132
G_OBJECT_CLASS_TYPE (klass),
135
g_cclosure_marshal_VOID__BOXED,
136
G_TYPE_NONE, 1, G_TYPE_STRV);
139
g_signal_new ("progress",
140
G_OBJECT_CLASS_TYPE (klass),
143
e_data_cal_marshal_VOID__STRING_UINT,
144
G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_UINT);
147
g_signal_new ("done",
148
G_OBJECT_CLASS_TYPE (klass),
151
g_cclosure_marshal_VOID__UINT,
152
G_TYPE_NONE, 1, G_TYPE_UINT);
154
dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass), &dbus_glib_e_data_cal_view_object_info);
158
id_hash (gconstpointer key)
160
const ECalComponentId *id = key;
161
return g_str_hash (id->uid) ^ (id->rid ? g_str_hash (id->rid) : 0);
165
id_equal (gconstpointer a, gconstpointer b)
167
const ECalComponentId *id_a = a, *id_b = b;
168
return g_strcmp0 (id_a->uid, id_b->uid) == 0 && g_strcmp0 (id_a->rid, id_b->rid) == 0;
376
e_data_cal_view_init (EDataCalView *query, EDataCalViewClass *class)
173
e_data_cal_view_init (EDataCalView *view)
378
EDataCalViewPrivate *priv;
175
EDataCalViewPrivate *priv = E_DATA_CAL_VIEW_GET_PRIVATE (view);
380
priv = g_new0 (EDataCalViewPrivate, 1);
383
179
priv->backend = NULL;
384
180
priv->started = FALSE;
385
181
priv->done = FALSE;
386
priv->done_status = GNOME_Evolution_Calendar_Success;
387
priv->matched_objects = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
388
priv->listeners = NULL;
182
priv->done_status = Success;
183
priv->started = FALSE;
389
184
priv->sexp = NULL;
392
/* Finalize handler for the live search query */
394
e_data_cal_view_finalize (GObject *object)
397
EDataCalViewPrivate *priv;
399
g_return_if_fail (object != NULL);
400
g_return_if_fail (IS_QUERY (object));
402
query = QUERY (object);
406
g_object_unref (priv->backend);
408
while (priv->listeners) {
409
ListenerData *ld = priv->listeners->data;
412
bonobo_object_release_unref (ld->listener, NULL);
413
if (ld->component_listener)
414
g_object_unref (ld->component_listener);
415
priv->listeners = g_list_remove (priv->listeners, ld);
419
if (priv->matched_objects)
420
g_hash_table_destroy (priv->matched_objects);
423
g_object_unref (priv->sexp);
427
if (G_OBJECT_CLASS (parent_class)->finalize)
428
(* G_OBJECT_CLASS (parent_class)->finalize) (object);
432
* e_data_cal_view_new:
433
* @backend: Calendar backend that the query object will monitor.
434
* @ql: Listener for query results.
435
* @sexp: Sexp that defines the query.
437
* Creates a new query engine object that monitors a calendar backend.
439
* Return value: A newly-created query object, or NULL on failure.
186
priv->adds = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD);
187
priv->changes = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD);
188
priv->removes = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD);
190
priv->ids = g_hash_table_new_full (id_hash, id_equal, (GDestroyNotify)e_cal_component_free_id, NULL);
442
194
e_data_cal_view_new (ECalBackend *backend,
443
GNOME_Evolution_Calendar_CalViewListener ql,
444
ECalBackendSExp *sexp)
195
const gchar *path, ECalBackendSExp *sexp)
446
197
EDataCalView *query;
448
query = g_object_new (E_DATA_CAL_VIEW_TYPE, "backend", backend, "listener", ql,
199
query = g_object_new (E_DATA_CAL_VIEW_TYPE, "backend", backend, "sexp", sexp, NULL);
200
query->priv->path = g_strdup (path);
202
dbus_g_connection_register_g_object (connection, path, G_OBJECT (query));
455
* e_data_cal_view_add_listener:
456
* @query: A #EDataCalView object.
457
* @ql: A CORBA query listener to add to the list of listeners.
459
* Adds the given CORBA listener to a #EDataCalView object. This makes the view
460
* object notify that listener when notifying the other listeners already attached
464
e_data_cal_view_add_listener (EDataCalView *query, GNOME_Evolution_Calendar_CalViewListener ql)
467
EDataCalViewPrivate *priv;
468
CORBA_Environment ev;
470
g_return_if_fail (IS_QUERY (query));
471
g_return_if_fail (ql != CORBA_OBJECT_NIL);
475
ld = g_new0 (ListenerData, 1);
477
CORBA_exception_init (&ev);
478
ld->listener = CORBA_Object_duplicate (ql, &ev);
479
CORBA_exception_free (&ev);
481
ld->component_listener = e_component_listener_new (ld->listener);
482
g_signal_connect (G_OBJECT (ld->component_listener), "component_died",
483
G_CALLBACK (listener_died_cb), query);
485
priv->listeners = g_list_prepend (priv->listeners, ld);
208
* e_data_cal_view_get_dbus_path:
209
* @view: an #EDataCalView
211
* Returns the D-Bus path for @view.
213
* Returns: the D-Bus path for @view
218
e_data_cal_view_get_dbus_path (EDataCalView *view)
220
g_return_val_if_fail (E_IS_DATA_CAL_VIEW (view), NULL);
222
return view->priv->path;
226
reset_array (GArray *array)
231
/* Free stored strings */
232
for (i = 0; i < array->len; i++) {
233
tmp = g_array_index (array, gchar *, i);
237
/* Force the array size to 0 */
238
g_array_set_size (array, 0);
242
send_pending_adds (EDataCalView *view)
244
EDataCalViewPrivate *priv = view->priv;
246
if (priv->adds->len == 0)
249
g_signal_emit (view, signals[OBJECTS_ADDED], 0, priv->adds->data);
250
reset_array (priv->adds);
254
send_pending_changes (EDataCalView *view)
256
EDataCalViewPrivate *priv = view->priv;
258
if (priv->changes->len == 0)
261
g_signal_emit (view, signals[OBJECTS_MODIFIED], 0, priv->changes->data);
262
reset_array (priv->changes);
266
send_pending_removes (EDataCalView *view)
268
EDataCalViewPrivate *priv = view->priv;
270
if (priv->removes->len == 0)
273
/* TODO: send ECalComponentIds as a list of pairs */
274
g_signal_emit (view, signals[OBJECTS_REMOVED], 0, priv->removes->data);
275
reset_array (priv->removes);
279
notify_add (EDataCalView *view, gchar *obj)
281
EDataCalViewPrivate *priv = view->priv;
284
send_pending_changes (view);
285
send_pending_removes (view);
287
if (priv->adds->len == THRESHOLD) {
288
send_pending_adds (view);
290
g_array_append_val (priv->adds, obj);
292
comp = e_cal_component_new_from_string (obj);
293
g_hash_table_insert (priv->ids,
294
e_cal_component_get_id (comp),
295
GUINT_TO_POINTER (1));
296
g_object_unref (comp);
300
notify_change (EDataCalView *view, gchar *obj)
302
EDataCalViewPrivate *priv = view->priv;
304
send_pending_adds (view);
305
send_pending_removes (view);
307
g_array_append_val (priv->changes, obj);
311
notify_remove (EDataCalView *view, ECalComponentId *id)
313
EDataCalViewPrivate *priv = view->priv;
316
send_pending_adds (view);
317
send_pending_changes (view);
319
/* TODO: store ECalComponentId instead of just uid*/
320
uid = g_strdup (id->uid);
321
g_array_append_val (priv->removes, uid);
323
g_hash_table_remove (priv->ids, id);
327
notify_done (EDataCalView *view)
329
EDataCalViewPrivate *priv = view->priv;
331
send_pending_adds (view);
332
send_pending_changes (view);
333
send_pending_removes (view);
335
g_signal_emit (view, signals[DONE], 0, priv->done_status);
339
impl_EDataCalView_start (EDataCalView *query, GError **error)
341
EDataCalViewPrivate *priv;
345
if (!priv->started) {
346
priv->started = TRUE;
347
e_cal_backend_start_query (priv->backend, query);
354
e_data_cal_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
357
EDataCalViewPrivate *priv;
359
query = QUERY (object);
362
switch (property_id) {
364
priv->backend = E_CAL_BACKEND (g_value_dup_object (value));
367
priv->sexp = E_CAL_BACKEND_SEXP (g_value_dup_object (value));
370
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
376
e_data_cal_view_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
379
EDataCalViewPrivate *priv;
381
query = QUERY (object);
384
switch (property_id) {
386
g_value_set_object (value, priv->backend);
389
g_value_set_object (value, priv->sexp);
392
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
398
e_data_cal_view_dispose (GObject *object)
401
EDataCalViewPrivate *priv;
403
g_return_if_fail (object != NULL);
404
g_return_if_fail (IS_QUERY (object));
406
query = QUERY (object);
410
g_object_unref (priv->backend);
411
priv->backend = NULL;
415
g_object_unref (priv->sexp);
419
(* G_OBJECT_CLASS (e_data_cal_view_parent_class)->dispose) (object);
423
e_data_cal_view_finalize (GObject *object)
426
EDataCalViewPrivate *priv;
428
g_return_if_fail (object != NULL);
429
g_return_if_fail (IS_QUERY (object));
431
query = QUERY (object);
434
g_hash_table_destroy (priv->ids);
438
(* G_OBJECT_CLASS (e_data_cal_view_parent_class)->finalize) (object);