aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--calendar/ChangeLog21
-rw-r--r--calendar/gui/cal-search-bar.c2
-rw-r--r--calendar/gui/comp-editor-factory.c96
-rw-r--r--calendar/idl/evolution-calendar.idl3
-rw-r--r--calendar/pcs/query.c126
5 files changed, 207 insertions, 41 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog
index bc8b72e02f..8887a33474 100644
--- a/calendar/ChangeLog
+++ b/calendar/ChangeLog
@@ -1,3 +1,24 @@
+2001-08-28 Federico Mena Quintero <federico@ximian.com>
+
+ Fixes bug #7879, a query may receive an update notification from
+ the backend before the query itself gets populated.
+
+ * pcs/query.c (ensure_sexp): New function; ensures that the esexp
+ is created and notifies of parse errors. It is the bulk of
+ start_query_cb() but put in a separate function so that we can
+ share it elsewhere.
+ (start_query_cb): Use ensure_sexp().
+ (process_component_cb): Oops, notify of a successfully finished
+ query.
+ (match_component): Call ensure_sexp(). This function can be
+ called by the backend notification callbacks before the query is
+ populated, so we need to make sure the esexp exists here.
+
+2001-08-22 Federico Mena Quintero <federico@ximian.com>
+
+ * gui/cal-search-bar.c (cal_search_bar_construct): Set the
+ "category is" criterion as the default for the calendar and tasks.
+
2001-08-22 Federico Mena Quintero <federico@ximian.com>
* gui/dialogs/recurrence-page.c (recurrence_page_fill_widgets):
diff --git a/calendar/gui/cal-search-bar.c b/calendar/gui/cal-search-bar.c
index e35ba63181..cca017ee8d 100644
--- a/calendar/gui/cal-search-bar.c
+++ b/calendar/gui/cal-search-bar.c
@@ -467,6 +467,8 @@ cal_search_bar_construct (CalSearchBar *cal_search)
e_search_bar_construct (E_SEARCH_BAR (cal_search), search_menu_items, search_option_items);
make_suboptions (cal_search);
+ e_search_bar_set_ids (E_SEARCH_BAR (cal_search), SEARCH_CATEGORY_IS, CATEGORIES_ALL);
+
return cal_search;
}
diff --git a/calendar/gui/comp-editor-factory.c b/calendar/gui/comp-editor-factory.c
index 8c32bb3059..b235fcbdd0 100644
--- a/calendar/gui/comp-editor-factory.c
+++ b/calendar/gui/comp-editor-factory.c
@@ -28,7 +28,28 @@
-/* An client we have open */
+/* A pending request */
+
+typedef enum {
+ REQUEST_EXISTING,
+ REQUEST_NEW
+} RequestType;
+
+typedef struct {
+ RequestType type;
+
+ union {
+ struct {
+ char *uid;
+ } existing;
+
+ struct {
+ CalObjType type;
+ } new;
+ } u;
+} Request;
+
+/* A client we have open */
typedef struct {
/* Uri of the calendar, used as key in the clients hash table */
GnomeVFSURI *uri;
@@ -39,8 +60,8 @@ typedef struct {
/* Hash table of components that belong to this client */
GHashTable *uid_comp_hash;
- /* Number of times this client has been opened */
- int refcount;
+ /* Pending requests; they are pending if the client is still being opened */
+ GSList *pending;
} OpenClient;
/* A component that is being edited */
@@ -112,17 +133,56 @@ comp_editor_factory_init (CompEditorFactory *factory)
priv->uri_client_hash = g_hash_table_new (gnome_vfs_uri_hash, gnome_vfs_uri_hequal);
}
+/* Used from g_hash_table_foreach(); frees a component structure */
+static void
+free_component_cb (gpointer key, gpointer value, gpointer data)
+{
+ Component *c;
+
+ c = value;
+
+ c->parent = NULL;
+ c->uid = NULL;
+
+ cal_component_unref (c->comp);
+ c->comp = NULL;
+
+ g_free (c);
+}
+
/* Used from g_hash_table_foreach(); frees a client structure */
static void
free_client_cb (gpointer key, gpointer value, gpointer data)
{
OpenClient *oc;
+ GSList *l;
oc = value;
gnome_vfs_uri_unref (oc->uri);
+ oc->uri = NULL;
+
cal_client_unref (oc->client);
+ oc->client = NULL;
+
+ g_hash_table_foreach (oc->uid_comp_hash, free_component_cb, NULL);
g_hash_table_destroy (oc->uid_comp_hash);
+ oc->uid_comp_hash = NULL;
+
+ for (l = oc->pending; l; l = l->next) {
+ Request *r;
+
+ r = l->data;
+
+ if (r->type == REQUEST_EXISTING) {
+ g_assert (r->u.existing.uid != NULL);
+ g_free (r->u.existing.uid);
+ }
+
+ g_free (r);
+ }
+ g_slist_free (oc->pending);
+ oc->pending = NULL;
g_free (oc);
}
@@ -153,11 +213,12 @@ comp_editor_factory_destroy (GtkObject *object)
-/* Creates a new OpenClient structure by synchronously (!) opening a calendar
- * client. Returns NULL if it could not open it.
+/* Creates a new OpenClient structure and queues the component editing/creation
+ * process until the client is open. Returns NULL if it could not issue the
+ * open request.
*/
static OpenClient *
-open_client (GnomeVFSURI *uri)
+open_client (GnomeVFSURI *uri, gboolean only_if_exists)
{
CalClient *client;
@@ -165,15 +226,28 @@ open_client (GnomeVFSURI *uri)
if (!client)
return NULL;
- gtk_signal_connect (GTK_OBJECT (client), "cal_opened",
- GTK_SIGNAL_FUNC (cal_opened_cb), NULL);
-
oc = g_new (OpenClient, 1);
+
+ gnome_vfs_uri_ref (uri);
oc->uri = uri;
+
oc->client = client;
oc->uid_comp_hash = g_hash_table_new (g_str_hash, g_str_equal);
- oc->refcount = 1;
-
+ oc->pending = NULL;
+
+ gtk_signal_connect (GTK_OBJECT (oc->client), "cal_opened",
+ GTK_SIGNAL_FUNC (cal_opened_cb), oc);
+
+ if (!cal_client_open_calendar (oc->client, uri, only_if_exists)) {
+ gnome_vfs_uri_unref (oc->uri);
+ gtk_object_unref (GTK_OBJECT (oc->client));
+ g_hash_table_destroy (oc->uid_comp_hash);
+ g_free (oc);
+
+ return NULL;
+ }
+
+ return oc;
}
static void
diff --git a/calendar/idl/evolution-calendar.idl b/calendar/idl/evolution-calendar.idl
index 7f4a850ecb..c236f26649 100644
--- a/calendar/idl/evolution-calendar.idl
+++ b/calendar/idl/evolution-calendar.idl
@@ -288,12 +288,11 @@ module Calendar {
interface CompEditorFactory : Bonobo::Unknown {
exception InvalidURI {};
exception BackendContactError {};
- exception NotFound {};
exception UnsupportedType {};
/* Loads a calendar and opens an editor for the specified object */
void editExisting (in string uri, in CalObjUID uid)
- raises (InvalidURI, BackendContactError, NotFound, UnsupportedType);
+ raises (InvalidURI, BackendContactError);
/* Loads a calendar and creates a new component of the specified type */
void editNew (in string uri, in CalObjType type)
diff --git a/calendar/pcs/query.c b/calendar/pcs/query.c
index ae76ec9795..1b991a85ea 100644
--- a/calendar/pcs/query.c
+++ b/calendar/pcs/query.c
@@ -36,6 +36,14 @@
+/* States of a query */
+typedef enum {
+ QUERY_START_PENDING, /* the query is not populated yet */
+ QUERY_IN_PROGRESS, /* the query is populated; components are still being processed */
+ QUERY_DONE, /* the query is done, but still accepts object changes */
+ QUERY_PARSE_ERROR /* a parse error occurred when initially creating the ESexp */
+} QueryState;
+
/* Private part of the Query structure */
struct _QueryPrivate {
/* The backend we are monitoring */
@@ -48,8 +56,9 @@ struct _QueryPrivate {
char *sexp;
ESExp *esexp;
- /* Idle handler ID for asynchronous queries */
+ /* Idle handler ID for asynchronous queries and the current state */
guint idle_id;
+ QueryState state;
/* List of UIDs that we still have to process */
GList *pending_uids;
@@ -110,6 +119,9 @@ query_init (Query *query)
priv->ql = CORBA_OBJECT_NIL;
priv->sexp = NULL;
+ priv->idle_id = 0;
+ priv->state = QUERY_START_PENDING;
+
priv->pending_uids = NULL;
priv->uids = g_hash_table_new (g_str_hash, g_str_equal);
@@ -954,6 +966,66 @@ create_sexp (Query *query)
return esexp;
}
+/* Ensures that the sexp has been parsed and the ESexp has been created. If a
+ * parse error occurs, it sets the query state to QUERY_PARSE_ERROR and returns
+ * FALSE.
+ */
+static gboolean
+ensure_sexp (Query *query)
+{
+ QueryPrivate *priv;
+
+ priv = query->priv;
+
+ if (priv->state == QUERY_PARSE_ERROR)
+ g_assert_not_reached (); /* we should already have terminated everything */
+
+ if (priv->esexp)
+ return TRUE;
+
+ /* Compile the query string */
+
+ priv->esexp = create_sexp (query);
+
+ g_assert (priv->sexp != NULL);
+ e_sexp_input_text (priv->esexp, priv->sexp, strlen (priv->sexp));
+
+ if (e_sexp_parse (priv->esexp) == -1) {
+ const char *error_str;
+ CORBA_Environment ev;
+
+ /* Change the state and disconnect from any notifications */
+
+ priv->state = QUERY_PARSE_ERROR;
+ gtk_signal_disconnect_by_data (GTK_OBJECT (priv->backend), query);
+
+ /* Report the error to the listener */
+
+ error_str = e_sexp_error (priv->esexp);
+ g_assert (error_str != NULL);
+
+ CORBA_exception_init (&ev);
+ GNOME_Evolution_Calendar_QueryListener_notifyQueryDone (
+ priv->ql,
+ GNOME_Evolution_Calendar_QueryListener_PARSE_ERROR,
+ error_str,
+ &ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION)
+ g_message ("ensure_sexp(): Could not notify the listener of "
+ "a parse error");
+
+ CORBA_exception_free (&ev);
+
+ e_sexp_unref (priv->esexp);
+ priv->esexp = NULL;
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
/* Evaluates the query sexp on the specified component and notifies the listener
* as appropriate.
*/
@@ -967,6 +1039,11 @@ match_component (Query *query, const char *uid,
priv = query->priv;
+ g_assert (priv->state != QUERY_PARSE_ERROR);
+
+ if (!ensure_sexp (query))
+ return;
+
comp = cal_backend_get_object_component (priv->backend, uid);
g_assert (comp != NULL);
gtk_object_ref (GTK_OBJECT (comp));
@@ -1041,9 +1118,26 @@ process_component_cb (gpointer data)
/* No more components? */
if (!priv->pending_uids) {
+ CORBA_Environment ev;
+
g_assert (priv->n_pending == 0);
priv->idle_id = 0;
+ priv->state = QUERY_DONE;
+
+ CORBA_exception_init (&ev);
+ GNOME_Evolution_Calendar_QueryListener_notifyQueryDone (
+ priv->ql,
+ GNOME_Evolution_Calendar_QueryListener_SUCCESS,
+ "",
+ &ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION)
+ g_message ("process_component_cb(): Could not notify the listener of "
+ "a finished query");
+
+ CORBA_exception_free (&ev);
+
return FALSE;
}
@@ -1087,12 +1181,14 @@ populate_query (Query *query)
priv = query->priv;
g_assert (priv->idle_id == 0);
+ g_assert (priv->state == QUERY_START_PENDING);
priv->pending_uids = cal_backend_get_uids (priv->backend, CALOBJ_TYPE_ANY);
priv->pending_total = g_list_length (priv->pending_uids);
priv->n_pending = priv->pending_total;
priv->idle_id = g_idle_add (process_component_cb, query);
+ priv->state = QUERY_IN_PROGRESS;
}
/* Idle handler for starting a query */
@@ -1101,40 +1197,14 @@ start_query_cb (gpointer data)
{
Query *query;
QueryPrivate *priv;
- CORBA_Environment ev;
query = QUERY (data);
priv = query->priv;
priv->idle_id = 0;
- priv->esexp = create_sexp (query);
-
- /* Compile the query string */
-
- g_assert (priv->sexp != NULL);
- e_sexp_input_text (priv->esexp, priv->sexp, strlen (priv->sexp));
-
- if (e_sexp_parse (priv->esexp) == -1) {
- const char *error_str;
-
- error_str = e_sexp_error (priv->esexp);
- g_assert (error_str != NULL);
-
- CORBA_exception_init (&ev);
- GNOME_Evolution_Calendar_QueryListener_notifyQueryDone (
- priv->ql,
- GNOME_Evolution_Calendar_QueryListener_PARSE_ERROR,
- error_str,
- &ev);
-
- if (ev._major != CORBA_NO_EXCEPTION)
- g_message ("start_query_cb(): Could not notify the listener of "
- "a parse error");
-
- CORBA_exception_free (&ev);
+ if (!ensure_sexp (query))
return FALSE;
- }
/* Populate the query with UIDs so that we can process them asynchronously */