/* Evolution calendar - Live search query implementation * * Copyright (C) 2001 Ximian, Inc. * * Author: Federico Mena-Quintero * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "query.h" /* Private part of the Query structure */ struct _QueryPrivate { /* The backend we are monitoring */ CalBackend *backend; /* The listener we report to */ GNOME_Evolution_Calendar_QueryListener listener; EComponentListener *component_listener; /* Sexp that defines the query */ CalBackendObjectSExp *sexp; }; static void query_class_init (QueryClass *class); static void query_init (Query *query, QueryClass *class); static void query_finalize (GObject *object); static BonoboObjectClass *parent_class; BONOBO_TYPE_FUNC_FULL (Query, GNOME_Evolution_Calendar_Query, BONOBO_TYPE_OBJECT, query); /* Property IDs */ enum props { PROP_0, PROP_BACKEND, PROP_LISTENER, PROP_SEXP }; static void listener_died_cb (EComponentListener *cl, gpointer data) { Query *query = QUERY (data); QueryPrivate *priv; priv = query->priv; g_object_unref (priv->component_listener); priv->component_listener = NULL; bonobo_object_release_unref (priv->listener, NULL); priv->listener = NULL; } static void impl_Query_start (PortableServer_Servant servant, CORBA_Environment *ev) { Query *query; QueryPrivate *priv; query = QUERY (bonobo_object_from_servant (servant)); priv = query->priv; cal_backend_start_query (priv->backend, query); } static void query_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { Query *query; QueryPrivate *priv; CORBA_Environment ev; query = QUERY (object); priv = query->priv; switch (property_id) { case PROP_BACKEND: priv->backend = CAL_BACKEND (g_value_dup_object (value)); break; case PROP_LISTENER: CORBA_exception_init (&ev); priv->listener = CORBA_Object_duplicate (g_value_get_pointer (value), &ev); CORBA_exception_free (&ev); priv->component_listener = e_component_listener_new (priv->listener); g_signal_connect (G_OBJECT (priv->component_listener), "component_died", G_CALLBACK (listener_died_cb), query); break; case PROP_SEXP: priv->sexp = CAL_BACKEND_OBJECT_SEXP (g_value_dup_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void query_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { Query *query; QueryPrivate *priv; query = QUERY (object); priv = query->priv; switch (property_id) { case PROP_BACKEND: g_value_set_object (value, priv->backend); case PROP_LISTENER: g_value_set_pointer (value, priv->listener); break; case PROP_SEXP: g_value_set_object (value, priv->sexp); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } /* Class initialization function for the live search query */ static void query_class_init (QueryClass *klass) { GObjectClass *object_class; POA_GNOME_Evolution_Calendar_Query__epv *epv = &klass->epv; GParamSpec *param; object_class = (GObjectClass *) klass; parent_class = g_type_class_peek_parent (klass); object_class->set_property = query_set_property; object_class->get_property = query_get_property; object_class->finalize = query_finalize; epv->start = impl_Query_start; param = g_param_spec_object ("backend", NULL, NULL, CAL_BACKEND_TYPE, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_property (object_class, PROP_BACKEND, param); param = g_param_spec_pointer ("listener", NULL, NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_property (object_class, PROP_LISTENER, param); param = g_param_spec_object ("sexp", NULL, NULL, CAL_TYPE_BACKEND_OBJECT_SEXP, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_property (object_class, PROP_SEXP, param); } /* Object initialization function for the live search query */ static void query_init (Query *query, QueryClass *class) { QueryPrivate *priv; priv = g_new0 (QueryPrivate, 1); query->priv = priv; priv->backend = NULL; priv->listener = NULL; priv->component_listener = NULL; priv->sexp = NULL; } /* Finalize handler for the live search query */ static void query_finalize (GObject *object) { Query *query; QueryPrivate *priv; g_return_if_fail (object != NULL); g_return_if_fail (IS_QUERY (object)); query = QUERY (object); priv = query->priv; if (priv->backend) g_object_unref (priv->backend); if (priv->listener != NULL) bonobo_object_release_unref (priv->listener, NULL); if (priv->component_listener != NULL) g_object_unref (priv->component_listener); if (priv->sexp) g_object_unref (priv->sexp); g_free (priv); if (G_OBJECT_CLASS (parent_class)->finalize) (* G_OBJECT_CLASS (parent_class)->finalize) (object); } /** * query_new: * @backend: Calendar backend that the query object will monitor. * @ql: Listener for query results. * @sexp: Sexp that defines the query. * * Creates a new query engine object that monitors a calendar backend. * * Return value: A newly-created query object, or NULL on failure. **/ Query * query_new (CalBackend *backend, GNOME_Evolution_Calendar_QueryListener ql, CalBackendObjectSExp *sexp) { Query *query; query = g_object_new (QUERY_TYPE, "backend", backend, "listener", ql, "sexp", sexp, NULL); return query; } /** * query_get_sexp * @query: A #Query object. * * Get the expression used for the given query. * * Returns: the query expression used to search. */ const char * query_get_text (Query *query) { g_return_val_if_fail (IS_QUERY (query), NULL); return cal_backend_object_sexp_text (query->priv->sexp); } CalBackendObjectSExp * query_get_object_sexp (Query *query) { g_return_val_if_fail (IS_QUERY (query), NULL); return query->priv->sexp; } gboolean query_object_matches (Query *query, const char *object) { QueryPrivate *priv; g_return_val_if_fail (query != NULL, FALSE); g_return_val_if_fail (IS_QUERY (query), FALSE); g_return_val_if_fail (object != NULL, FALSE); priv = query->priv; return cal_backend_object_sexp_match_object (priv->sexp, object, priv->backend); } void query_notify_objects_added (Query *query, const GList *objects) { QueryPrivate *priv; GNOME_Evolution_Calendar_stringlist obj_list; CORBA_Environment ev; const GList *l; int num_objs, i; g_return_if_fail (query != NULL); g_return_if_fail (IS_QUERY (query)); priv = query->priv; g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); CORBA_exception_init (&ev); num_objs = g_list_length ((GList*)objects); obj_list._buffer = GNOME_Evolution_Calendar_stringlist_allocbuf (num_objs); obj_list._maximum = num_objs; obj_list._length = num_objs; for (l = objects, i = 0; l; l = l->next, i++) obj_list._buffer[i] = CORBA_string_dup (l->data); GNOME_Evolution_Calendar_QueryListener_notifyObjectsAdded (priv->listener, &obj_list, &ev); CORBA_free (obj_list._buffer); if (BONOBO_EX (&ev)) g_warning (G_STRLOC ": could not notify the listener of object addition"); CORBA_exception_free (&ev); } void query_notify_objects_added_1 (Query *query, const char *object) { QueryPrivate *priv; GList objects; g_return_if_fail (query != NULL); g_return_if_fail (IS_QUERY (query)); priv = query->priv; g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); objects.next = objects.prev = NULL; objects.data = (gpointer)object; query_notify_objects_added (query, &objects); } void query_notify_objects_modified (Query *query, const GList *objects) { QueryPrivate *priv; GNOME_Evolution_Calendar_CalObjUIDSeq obj_list; CORBA_Environment ev; const GList *l; int num_objs, i; g_return_if_fail (query != NULL); g_return_if_fail (IS_QUERY (query)); priv = query->priv; g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); CORBA_exception_init (&ev); num_objs = g_list_length ((GList*)objects); obj_list._buffer = GNOME_Evolution_Calendar_stringlist_allocbuf (num_objs); obj_list._maximum = num_objs; obj_list._length = num_objs; for (l = objects, i = 0; l; l = l->next, i++) obj_list._buffer[i] = CORBA_string_dup (l->data); GNOME_Evolution_Calendar_QueryListener_notifyObjectsModified (priv->listener, &obj_list, &ev); CORBA_free (obj_list._buffer); if (BONOBO_EX (&ev)) g_warning (G_STRLOC ": could not notify the listener of object modification"); CORBA_exception_free (&ev); } void query_notify_objects_modified_1 (Query *query, const char *object) { QueryPrivate *priv; GList objects; g_return_if_fail (query != NULL); g_return_if_fail (IS_QUERY (query)); priv = query->priv; g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); objects.next = objects.prev = NULL; objects.data = (gpointer)object; query_notify_objects_modified (query, &objects); } void query_notify_objects_removed (Query *query, const GList *uids) { QueryPrivate *priv; GNOME_Evolution_Calendar_CalObjUIDSeq uid_list; CORBA_Environment ev; const GList *l; int num_uids, i; g_return_if_fail (query != NULL); g_return_if_fail (IS_QUERY (query)); priv = query->priv; g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); CORBA_exception_init (&ev); num_uids = g_list_length ((GList*)uids); uid_list._buffer = GNOME_Evolution_Calendar_CalObjUIDSeq_allocbuf (num_uids); uid_list._maximum = num_uids; uid_list._length = num_uids; for (l = uids, i = 0; l; l = l->next, i ++) uid_list._buffer[i] = CORBA_string_dup (l->data); GNOME_Evolution_Calendar_QueryListener_notifyObjectsRemoved (priv->listener, &uid_list, &ev); CORBA_free (uid_list._buffer); if (BONOBO_EX (&ev)) g_warning (G_STRLOC ": could not notify the listener of object removal"); CORBA_exception_free (&ev); } void query_notify_objects_removed_1 (Query *query, const char *uid) { QueryPrivate *priv; GList uids; g_return_if_fail (query != NULL); g_return_if_fail (IS_QUERY (query)); priv = query->priv; g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); uids.next = uids.prev = NULL; uids.data = (gpointer)uid; query_notify_objects_removed (query, &uids); } void query_notify_query_progress (Query *query, const char *message, int percent) { QueryPrivate *priv; CORBA_Environment ev; g_return_if_fail (query != NULL); g_return_if_fail (IS_QUERY (query)); priv = query->priv; g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); CORBA_exception_init (&ev); GNOME_Evolution_Calendar_QueryListener_notifyQueryProgress (priv->listener, message, percent, &ev); if (BONOBO_EX (&ev)) g_warning (G_STRLOC ": could not notify the listener of query progress"); CORBA_exception_free (&ev); } void query_notify_query_done (Query *query, GNOME_Evolution_Calendar_CallStatus status) { QueryPrivate *priv; CORBA_Environment ev; g_return_if_fail (query != NULL); g_return_if_fail (IS_QUERY (query)); priv = query->priv; g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); CORBA_exception_init (&ev); GNOME_Evolution_Calendar_QueryListener_notifyQueryDone (priv->listener, status, &ev); if (BONOBO_EX (&ev)) g_warning (G_STRLOC ": could not notify the listener of query completion"); CORBA_exception_free (&ev); }