1 /*-*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* Evolution calendar - Live view client object
4 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
5 * Copyright (C) 2009 Intel Corporation
7 * Authors: Federico Mena-Quintero <federico@ximian.com>
8 * Ross Burton <ross@linux.intel.com>
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of version 2 of the GNU Lesser General Public
12 * License as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28 #include <glib/gi18n-lib.h>
31 #include "e-cal-client.h"
32 #include "e-cal-client-view.h"
33 #include "e-cal-client-view-private.h"
35 #include "libedataserver/e-gdbus-marshallers.h"
37 #include "e-gdbus-cal-view.h"
39 #define E_CAL_CLIENT_VIEW_GET_PRIVATE(obj) \
40 (G_TYPE_INSTANCE_GET_PRIVATE \
41 ((obj), E_TYPE_CAL_CLIENT_VIEW, ECalClientViewPrivate))
43 G_DEFINE_TYPE (ECalClientView, e_cal_client_view, G_TYPE_OBJECT);
45 /* Private part of the ECalClientView structure */
46 struct _ECalClientViewPrivate {
47 GDBusProxy *gdbus_calview;
69 static guint signals[LAST_SIGNAL];
72 build_object_list (const gchar * const *seq)
78 for (i = 0; seq[i]; i++) {
81 comp = icalcomponent_new_from_string ((gchar *) seq[i]);
85 list = g_slist_prepend (list, comp);
88 return g_slist_reverse (list);
92 build_id_list (const gchar * const *seq)
99 for (i = 0; seq[i]; i++) {
101 id = g_new (ECalComponentId, 1);
103 /* match encoding as in notify_remove() in e-data-cal-view.c: <uid>[\n<rid>] */
104 eol = strchr (seq[i], '\n');
106 id->uid = g_strndup (seq[i], eol - seq[i]);
107 id->rid = g_strdup (eol + 1);
109 id->uid = g_strdup (seq[i]);
113 list = g_slist_prepend (list, id);
116 return g_slist_reverse (list);
120 objects_added_cb (EGdbusCalView *gdbus_calview,
121 const gchar * const *objects,
122 ECalClientView *view)
126 g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
128 if (!view->priv->running)
133 list = build_object_list (objects);
135 g_signal_emit (G_OBJECT (view), signals[OBJECTS_ADDED], 0, list);
137 g_slist_foreach (list, (GFunc) icalcomponent_free, NULL);
140 g_object_unref (view);
144 objects_modified_cb (EGdbusCalView *gdbus_calview,
145 const gchar * const *objects,
146 ECalClientView *view)
150 g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
152 if (!view->priv->running)
157 list = build_object_list (objects);
159 g_signal_emit (G_OBJECT (view), signals[OBJECTS_MODIFIED], 0, list);
161 g_slist_foreach (list, (GFunc) icalcomponent_free, NULL);
164 g_object_unref (view);
168 objects_removed_cb (EGdbusCalView *gdbus_calview,
169 const gchar * const *uids,
170 ECalClientView *view)
174 g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
176 if (!view->priv->running)
181 list = build_id_list (uids);
183 g_signal_emit (G_OBJECT (view), signals[OBJECTS_REMOVED], 0, list);
185 g_slist_foreach (list, (GFunc) e_cal_component_free_id, NULL);
188 g_object_unref (view);
192 progress_cb (EGdbusCalView *gdbus_calview,
194 const gchar *message,
195 ECalClientView *view)
197 g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
199 if (!view->priv->running)
202 g_signal_emit (G_OBJECT (view), signals[PROGRESS], 0, percent, message);
206 complete_cb (EGdbusCalView *gdbus_calview,
207 const gchar * const *arg_error,
208 ECalClientView *view)
210 GError *error = NULL;
212 g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
214 if (!view->priv->running)
217 g_return_if_fail (e_gdbus_templates_decode_error (arg_error, &error));
219 g_signal_emit (G_OBJECT (view), signals[COMPLETE], 0, error);
222 g_error_free (error);
225 /* Object initialization function for the calendar view */
227 e_cal_client_view_init (ECalClientView *view)
229 view->priv = E_CAL_CLIENT_VIEW_GET_PRIVATE (view);
230 view->priv->running = FALSE;
234 cal_client_view_set_property (GObject *object,
239 ECalClientView *view;
240 ECalClientViewPrivate *priv;
242 view = E_CAL_CLIENT_VIEW (object);
245 switch (property_id) {
247 /* gdbus_calview can be set only once */
248 g_return_if_fail (priv->gdbus_calview == NULL);
250 priv->gdbus_calview = g_object_ref (g_value_get_pointer (value));
251 g_signal_connect (priv->gdbus_calview, "objects-added", G_CALLBACK (objects_added_cb), view);
252 g_signal_connect (priv->gdbus_calview, "objects-modified", G_CALLBACK (objects_modified_cb), view);
253 g_signal_connect (priv->gdbus_calview, "objects-removed", G_CALLBACK (objects_removed_cb), view);
254 g_signal_connect (priv->gdbus_calview, "progress", G_CALLBACK (progress_cb), view);
255 g_signal_connect (priv->gdbus_calview, "complete", G_CALLBACK (complete_cb), view);
258 priv->client = E_CAL_CLIENT (g_value_dup_object (value));
261 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
267 cal_client_view_get_property (GObject *object,
272 ECalClientView *view;
273 ECalClientViewPrivate *priv;
275 view = E_CAL_CLIENT_VIEW (object);
278 switch (property_id) {
280 g_value_set_pointer (value, priv->gdbus_calview);
283 g_value_set_object (value, priv->client);
286 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
291 /* Finalize handler for the calendar view */
293 cal_client_view_finalize (GObject *object)
295 ECalClientView *view;
296 ECalClientViewPrivate *priv;
298 g_return_if_fail (E_IS_CAL_CLIENT_VIEW (object));
300 view = E_CAL_CLIENT_VIEW (object);
303 if (priv->gdbus_calview != NULL) {
304 GError *error = NULL;
306 g_signal_handlers_disconnect_matched (priv->gdbus_calview, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, view);
307 e_gdbus_cal_view_call_dispose_sync (priv->gdbus_calview, NULL, &error);
308 g_object_unref (priv->gdbus_calview);
309 priv->gdbus_calview = NULL;
312 g_warning ("Failed to dispose cal view: %s", error->message);
313 g_error_free (error);
318 g_object_unref (priv->client);
322 /* Chain up to parent's finalize() method. */
323 G_OBJECT_CLASS (e_cal_client_view_parent_class)->finalize (object);
326 /* Class initialization function for the calendar view */
328 e_cal_client_view_class_init (ECalClientViewClass *class)
330 GObjectClass *object_class;
332 object_class = (GObjectClass *) class;
334 object_class->set_property = cal_client_view_set_property;
335 object_class->get_property = cal_client_view_get_property;
336 object_class->finalize = cal_client_view_finalize;
338 g_type_class_add_private (class, sizeof (ECalClientViewPrivate));
340 g_object_class_install_property (object_class, PROP_VIEW,
341 g_param_spec_pointer ("view", "The GDBus view proxy", NULL,
342 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
344 g_object_class_install_property (object_class, PROP_CLIENT,
345 g_param_spec_object ("client", "The e-cal-client for the view", NULL, E_TYPE_CAL_CLIENT,
346 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
348 * ECalClientView::objects-added:
350 * @objects: (type GSList) (transfer none) (element-type long):
352 signals[OBJECTS_ADDED] =
353 g_signal_new ("objects-added",
354 G_TYPE_FROM_CLASS (class),
356 G_STRUCT_OFFSET (ECalClientViewClass, objects_added),
358 g_cclosure_marshal_VOID__POINTER,
359 G_TYPE_NONE, 1, G_TYPE_POINTER);
361 * ECalClientView::objects-modified:
363 * @objects: (type GSList) (transfer none) (element-type long):
365 signals[OBJECTS_MODIFIED] =
366 g_signal_new ("objects-modified",
367 G_TYPE_FROM_CLASS (class),
369 G_STRUCT_OFFSET (ECalClientViewClass, objects_modified),
371 g_cclosure_marshal_VOID__POINTER,
372 G_TYPE_NONE, 1, G_TYPE_POINTER);
374 * ECalClientView::objects-removed:
376 * @objects: (type GSList) (transfer none) (element-type ECalComponentId):
378 signals[OBJECTS_REMOVED] =
379 g_signal_new ("objects-removed",
380 G_TYPE_FROM_CLASS (class),
382 G_STRUCT_OFFSET (ECalClientViewClass, objects_removed),
384 g_cclosure_marshal_VOID__POINTER,
385 G_TYPE_NONE, 1, G_TYPE_POINTER);
388 g_signal_new ("progress",
389 G_TYPE_FROM_CLASS (class),
391 G_STRUCT_OFFSET (ECalClientViewClass, progress),
393 e_gdbus_marshallers_VOID__UINT_STRING,
394 G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
397 g_signal_new ("complete",
398 G_TYPE_FROM_CLASS (class),
400 G_STRUCT_OFFSET (ECalClientViewClass, complete),
402 g_cclosure_marshal_VOID__BOXED,
403 G_TYPE_NONE, 1, G_TYPE_ERROR);
407 * _e_cal_client_view_new:
408 * @client: An #ECalClient object.
409 * @gdbuc_calview: The GDBus object for the view.
411 * Creates a new view object by issuing the view creation request to the
414 * Returns: A newly-created view object, or NULL if the request failed.
417 _e_cal_client_view_new (ECalClient *client,
418 EGdbusCalView *gdbus_calview)
420 ECalClientView *view;
422 view = g_object_new (E_TYPE_CAL_CLIENT_VIEW,
424 "view", gdbus_calview,
431 * e_cal_client_view_get_client
432 * @view: A #ECalClientView object.
434 * Get the #ECalClient associated with this view.
436 * Returns: the associated client.
441 e_cal_client_view_get_client (ECalClientView *view)
443 g_return_val_if_fail (E_IS_CAL_CLIENT_VIEW (view), NULL);
445 return view->priv->client;
449 * e_cal_client_view_is_running:
450 * @view: an #ECalClientView
452 * Retunrs: Whether view is running. Not running views are ignoring
453 * all events sent from the server.
458 e_cal_client_view_is_running (ECalClientView *view)
460 g_return_val_if_fail (E_IS_CAL_CLIENT_VIEW (view), FALSE);
462 return view->priv->running;
466 * e_cal_client_view_start:
467 * @view: An #ECalClientView object.
470 * Starts a live query to the calendar/tasks backend.
475 e_cal_client_view_start (ECalClientView *view,
478 ECalClientViewPrivate *priv;
480 g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
484 if (priv->gdbus_calview) {
485 GError *local_error = NULL;
487 priv->running = TRUE;
488 if (!e_gdbus_cal_view_call_start_sync (priv->gdbus_calview, NULL, &local_error))
489 priv->running = FALSE;
491 e_client_unwrap_dbus_error (E_CLIENT (priv->client), local_error, error);
493 /* do not translate this string, it should ideally never happen */
494 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR, "Cannot start view, D-Bus proxy gone");
499 * e_cal_client_view_stop:
500 * @view: An #ECalClientView object.
503 * Stops a live query to the calendar/tasks backend.
508 e_cal_client_view_stop (ECalClientView *view,
511 ECalClientViewPrivate *priv;
513 g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
516 priv->running = FALSE;
518 if (priv->gdbus_calview) {
519 GError *local_error = NULL;
521 e_gdbus_cal_view_call_stop_sync (priv->gdbus_calview, NULL, &local_error);
523 e_client_unwrap_dbus_error (E_CLIENT (priv->client), local_error, error);
525 /* do not translate this string, it should ideally never happen */
526 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR, "Cannot stop view, D-Bus proxy gone");
531 * e_cal_client_view_set_fields_of_interest:
532 * @view: An #ECalClientView object
533 * @fields_of_interest: List of field names in which the client is interested
536 * Client can instruct server to which fields it is interested in only, thus
537 * the server can return less data over the wire. The server can still return
538 * complete objects, this is just a hint to it that the listed fields will
539 * be used only. The UID/RID fields are returned always. Initial views has no fields
540 * of interest and using %NULL for @fields_of_interest will unset any previous
543 * Some backends can use summary information of its cache to create artifical
544 * objects, which will omit stored object parsing. If this cannot be done then
545 * it will simply return object as is stored in the cache.
548 e_cal_client_view_set_fields_of_interest (ECalClientView *view,
549 const GSList *fields_of_interest,
552 ECalClientViewPrivate *priv;
554 g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
558 if (priv->gdbus_calview) {
559 GError *local_error = NULL;
562 strv = e_client_util_slist_to_strv (fields_of_interest);
563 e_gdbus_cal_view_call_set_fields_of_interest_sync (priv->gdbus_calview, (const gchar * const *) strv, NULL, &local_error);
566 e_client_unwrap_dbus_error (E_CLIENT (priv->client), local_error, error);
568 /* do not translate this string, it should ideally never happen */
569 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR, "Cannot set fields of interest, D-Bus proxy gone");
574 * e_cal_client_view_set_flags:
575 * @view: an #ECalClientView
576 * @flags: the #ECalClientViewFlags for @view.
577 * @error: a return location for a #GError, or %NULL.
579 * Sets the @flags which control the behaviour of @view.
584 e_cal_client_view_set_flags (ECalClientView *view,
585 ECalClientViewFlags flags,
588 ECalClientViewPrivate *priv;
590 g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
594 if (priv->gdbus_calview) {
595 GError *local_error = NULL;
597 e_gdbus_cal_view_call_set_flags_sync (priv->gdbus_calview, flags, NULL, &local_error);
599 e_client_unwrap_dbus_error (E_CLIENT (priv->client), local_error, error);
601 /* do not translate this string, it should ideally never happen */
602 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR, "Cannot set fields of interest, D-Bus proxy gone");