[evolution-data-server/openismus-work-master] EDataBookCursor: New cursor step() API
- From: Tristan Van Berkom <tvb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server/openismus-work-master] EDataBookCursor: New cursor step() API
- Date: Sat, 19 Oct 2013 18:55:06 +0000 (UTC)
commit c7c7e80ab1b0df977ded93b7870c30e4e9625c64
Author: Tristan Van Berkom <tristanvb openismus com>
Date: Fri Oct 18 22:40:40 2013 +0200
EDataBookCursor: New cursor step() API
addressbook/libedata-book/e-data-book-cursor.c | 278 ++++++++++++++----------
addressbook/libedata-book/e-data-book-cursor.h | 37 ++--
2 files changed, 182 insertions(+), 133 deletions(-)
---
diff --git a/addressbook/libedata-book/e-data-book-cursor.c b/addressbook/libedata-book/e-data-book-cursor.c
index 6f9f70e..e174769 100644
--- a/addressbook/libedata-book/e-data-book-cursor.c
+++ b/addressbook/libedata-book/e-data-book-cursor.c
@@ -69,28 +69,71 @@
* #EBookBackendClass.create_cursor().
* </para>
* <para>
- * Cursor position is always set to last result which
- * was traversed in the most recent query. After moving the
- * cursor through the next batch of results, the last result
- * should always be saved as the new current cursor state, unless
- * the end of the contact list is reached and the requested amount
- * of contacts could not be returned, in which case the cursor
- * should reset itself to a null state (the cursor walks off the
- * end of the results into a reset state).
+ * Initially, the cursor state is assumed to be clear and
+ * positioned naturally at the beginning so that the first
+ * calls to #EDataBookCursorClass.step() using the
+ * %E_BOOK_CURSOR_ORIGIN_CURRENT origin would respond in the
+ * same way as the %E_BOOK_CURSOR_ORIGIN_BEGIN origin would.
* </para>
* <para>
- * The cursor must track two states at all times, one
- * state which is the current cursor position, and one
- * state which was the previous cursor position in order
- * to satisfy the %E_BOOK_CURSOR_ORIGIN_PREVIOUS origin
- * in a call to #EDataBookCursorClass.move_by().
+ * Unless the %E_BOOK_CURSOR_STEP_FETCH flag is not specified
+ * in calls to #EDataBookCursorClass.step(), the cursor state
+ * should be always be set to the last contact which was traversed
+ * in every call to #EDataBookCursorClass.step(). In the case
+ * that #EDataBookCursorClass.step() was asked to step beyond the
+ * bounderies of the list, i.e. when stepping passed the end
+ * of the list of before the beginning, then the cursor state
+ * can be cleared and the implementation must track whether
+ * the cursor is at the beginning or the end of the list.
* </para>
* <para>
- * Calls to #EDataBookCursorClass.move_by() with the
- * %E_BOOK_CURSOR_ORIGIN_RESET origin resets both current
- * and previous cursor states before proceeding to move.
- * Calls to #EDataBookCursorClass.set_alphabetic_index() also
- * effect both cursor states.
+ * The task of actually collecting the cursor state from a
+ * contact should be done using an #ECollator created for
+ * the locale in which your #EBookBackend is configured for.
+ * </para>
+ * <example>
+ * <title>Collecting sort keys for a given contact</title>
+ * <programlisting><![CDATA[
+ * static void
+ * update_state_from_contact (EBookBackendSmth *smth,
+ * EBookBackendSmthCursor *cursor,
+ * EContact *contact)
+ * {
+ * gint i;
+ *
+ * clear_state (smth, cursor);
+ *
+ * // For each sort key the cursor was created for
+ * for (i = 0; i < cursor->n_sort_fields; i++) {
+ *
+ * // Using an ECollator created for the locale
+ * // set on your EBookBackend...
+ * const gchar *string = e_contact_get_const (contact, cursor->sort_fields[i]);
+ *
+ * // Generate a sort key for each value
+ * if (string)
+ * cursor->state->values[i] =
+ * e_collator_generate_key (smth->collator,
+ * string, NULL);
+ * else
+ * cursor->state->values[i] = g_strdup ("");
+ * }
+ *
+ * state->last_uid = e_contact_get (contact, E_CONTACT_UID);
+ * }
+ * ]]></programlisting>
+ * </example>
+ * <para>
+ * Using the strings collected above for a given contact,
+ * two contacts can easily be compared for equality in
+ * a locale sensitive way, using strcmp() directly on
+ * the generated sort keys.
+ * </para>
+ * <para>
+ * Calls to #EDataBookCursorClass.step() with the
+ * %E_BOOK_CURSOR_ORIGIN_BEGIN or %E_BOOK_CURSOR_ORIGIN_END reset
+ * the cursor state before fetching results from either the
+ * beginning or ending of the result list respectively.
* </para>
* </refsect2>
*
@@ -203,18 +246,18 @@ static gboolean data_book_cursor_compare_contact (EDataBookCursor *cursor,
EContact *contact,
gint *result,
gboolean *matches_sexp);
-static void calculate_move_by_position (EDataBookCursor *cursor,
+static void calculate_step_position (EDataBookCursor *cursor,
EBookCursorOrigin origin,
gint count,
gint results);
/* D-Bus callbacks */
-static gint data_book_cursor_handle_move_by (EDBusAddressBookCursor *dbus_object,
+static gint data_book_cursor_handle_step (EDBusAddressBookCursor *dbus_object,
GDBusMethodInvocation *invocation,
const gchar *revision,
+ EBookCursorStepFlags flags,
EBookCursorOrigin origin,
gint count,
- gboolean fetch_results,
EDataBookCursor *cursor);
static gboolean data_book_cursor_handle_set_alphabetic_index (EDBusAddressBookCursor *dbus_object,
GDBusMethodInvocation *invocation,
@@ -444,77 +487,73 @@ data_book_cursor_compare_contact (EDataBookCursor *cursor,
}
static void
-calculate_move_by_position (EDataBookCursor *cursor,
- EBookCursorOrigin origin,
- gint count,
- gint results)
+calculate_step_position (EDataBookCursor *cursor,
+ EBookCursorOrigin origin,
+ gint count,
+ gint results)
{
EDataBookCursorPrivate *priv = cursor->priv;
- GError *error = NULL;
- gint new_position;
+ gint new_position = priv->position;
+ gint offset = results;
+
+ /* The return value of the step() function is the number of contacts traversed,
+ * but here we want the number of units which were successfuly traversed, i.e.
+ * when move from the 1 position to the 0 position, or move from the last contact
+ * off of the end of the list, the position is still effected by 1 even
+ * though the step() function returns 0.
+ */
+ if (count < 0)
+ offset = -offset;
+
+ if (offset == 0 && count > 0 && priv->position == priv->total)
+ offset = 1;
+ else if (offset == 0 && count < 0 && priv->position == 1)
+ offset = -1;
+ /* Don't assert the boundaries of values here, we
+ * did that in e_data_book_cursor_step() already.
+ */
switch (origin) {
case E_BOOK_CURSOR_ORIGIN_CURRENT:
-
- if (count < 0 && priv->position == 0)
- new_position = (priv->total + 1) + count;
- else
- new_position = priv->position + count;
-
- /* If we ran off the end of the total query, reset to 0 */
- if (new_position < 0 || new_position > priv->total)
- new_position = 0;
-
- data_book_cursor_set_values (cursor, priv->total, new_position);
+ new_position = priv->position + offset;
break;
- case E_BOOK_CURSOR_ORIGIN_PREVIOUS:
- /* We don't manually track the previous position, so for now
- * we need to recalculate the position entirely
- */
- if (!e_data_book_cursor_recalculate (cursor, &error)) {
- g_warning ("Failed to recalculate the cursor value "
- "after moving the cursor: %s",
- error->message);
- g_clear_error (&error);
- }
+ case E_BOOK_CURSOR_ORIGIN_BEGIN:
+ new_position = offset;
break;
- case E_BOOK_CURSOR_ORIGIN_RESET:
-
- if (count < 0)
- new_position = (priv->total + 1) + count;
- else
- new_position = count;
-
- /* If we ran off the end of the total query, reset to 0 */
- if (new_position < 0 || new_position > priv->total)
- new_position = 0;
- data_book_cursor_set_values (cursor, priv->total, new_position);
+ case E_BOOK_CURSOR_ORIGIN_END:
+ new_position = (priv->total + 1) + offset;
break;
-
}
+
+ new_position = CLAMP (new_position, 0, priv->total + 1);
+ data_book_cursor_set_values (cursor, priv->total, new_position);
}
/************************************************
* D-Bus Callbacks *
************************************************/
static gboolean
-data_book_cursor_handle_move_by (EDBusAddressBookCursor *dbus_object,
- GDBusMethodInvocation *invocation,
- const gchar *revision,
- EBookCursorOrigin origin,
- gint count,
- gboolean fetch_results,
- EDataBookCursor *cursor)
+data_book_cursor_handle_step (EDBusAddressBookCursor *dbus_object,
+ GDBusMethodInvocation *invocation,
+ const gchar *revision,
+ EBookCursorStepFlags flags,
+ EBookCursorOrigin origin,
+ gint count,
+ EDataBookCursor *cursor)
{
GSList *results = NULL;
GError *error = NULL;
gint n_results;
- n_results = e_data_book_cursor_move_by (cursor, revision, origin, count,
- fetch_results ? &results : NULL,
- &error);
+ n_results = e_data_book_cursor_step (cursor,
+ revision,
+ flags,
+ origin,
+ count,
+ &results,
+ &error);
if (n_results < 0) {
g_dbus_method_invocation_return_gerror (invocation, error);
@@ -537,14 +576,14 @@ data_book_cursor_handle_move_by (EDBusAddressBookCursor *dbus_object,
}
- e_dbus_address_book_cursor_complete_move_by (dbus_object,
- invocation,
- n_results,
- strv ?
- (const gchar *const *)strv :
- empty_str,
- cursor->priv->total,
- cursor->priv->position);
+ e_dbus_address_book_cursor_complete_step (dbus_object,
+ invocation,
+ n_results,
+ strv ?
+ (const gchar *const *)strv :
+ empty_str,
+ cursor->priv->total,
+ cursor->priv->position);
g_strfreev (strv);
@@ -740,73 +779,79 @@ e_data_book_cursor_set_sexp (EDataBookCursor *cursor,
}
/**
- * e_data_book_cursor_move_by:
+ * e_data_book_cursor_step:
* @cursor: an #EDataBookCursor
* @revision_guard: The expected current addressbook revision, or %NULL
- * @origin: the #EBookCursorOrigin for this move
+ * @flags: The #EBookCursorStepFlags for this step
+ * @origin: The #EBookCursorOrigin from whence to step
* @count: a positive or negative amount of contacts to try and fetch
* @results: (out) (allow-none) (element-type utf8) (transfer full):
- * A return location to store the results, or %NULL to move the cursor without retrieving any results.
+ * A return location to store the results, or %NULL if %E_BOOK_CURSOR_STEP_FETCH is not specified in %flags
* @error: (out) (allow-none): return location for a #GError, or %NULL
*
- * Moves @cursor through the results by @count and fetch a maximum of @count contacts.
+ * Steps @cursor through it's sorted query by a maximum of @count contacts
+ * starting from @origin.
*
- * If @count is negative, then the cursor will move backwards.
- *
- * If @cursor is in an empty state, or @origin is %E_BOOK_CURSOR_ORIGIN_RESET,
- * then @count contacts will be fetched from the beginning of the cursor's query
- * results, or from the ending of the query results for a negative value of @count.
+ * If @count is negative, then the cursor will move through the list in reverse.
*
* If @cursor reaches the beginning or end of the query results, then the
* returned list might not contain the amount of desired contacts, or might
- * return no results if the cursor currently points to the last contact.
- * This is not considered an error condition.
+ * return no results if the cursor currently points to the last contact.
+ * Reaching the end of the list is not considered an error condition. Attempts
+ * to step beyond the end of the list after having reached the end of the list
+ * will however trigger an %E_CLIENT_ERROR_END_OF_LIST error.
+ *
+ * If %E_BOOK_CURSOR_STEP_FETCH is specified in %flags, a pointer to
+ * a %NULL #GSList pointer should be provided for the @results parameter.
*
- * If @results is specified, it should be a pointer to a %NULL #GSList,
- * the result list will be stored to @results and should be freed with g_slist_free()
+ * The result list will be stored to @results and should be freed with g_slist_free()
* and all elements freed with g_free().
*
* If a @revision_guard is specified, the cursor implementation will issue an
* %E_CLIENT_ERROR_OUT_OF_SYNC error if the @revision_guard does not match
* the current addressbook revision.
*
- * Returns: The number of contacts which the cursor has moved by if successfull.
- * Otherwise -1 is returned and @error is set.
+ * Returns: The number of contacts traversed if successfull, otherwise -1 is
+ * returned and @error is set.
*
* Since: 3.12
*/
gint
-e_data_book_cursor_move_by (EDataBookCursor *cursor,
- const gchar *revision_guard,
- EBookCursorOrigin origin,
- gint count,
- GSList **results,
- GError **error)
+e_data_book_cursor_step (EDataBookCursor *cursor,
+ const gchar *revision_guard,
+ EBookCursorStepFlags flags,
+ EBookCursorOrigin origin,
+ gint count,
+ GSList **results,
+ GError **error)
{
gint retval;
g_return_val_if_fail (E_IS_DATA_BOOK_CURSOR (cursor), FALSE);
+ g_return_val_if_fail ((flags & E_BOOK_CURSOR_STEP_FETCH) == 0 ||
+ (results != NULL && *results == NULL), -1);
- if (!E_DATA_BOOK_CURSOR_GET_CLASS (cursor)->move_by) {
+ if (!E_DATA_BOOK_CURSOR_GET_CLASS (cursor)->step) {
g_set_error_literal (error,
E_CLIENT_ERROR,
E_CLIENT_ERROR_NOT_SUPPORTED,
- _("Cursor does not support moves"));
+ _("Cursor does not support step"));
return FALSE;
}
g_object_ref (cursor);
- retval = (* E_DATA_BOOK_CURSOR_GET_CLASS (cursor)->move_by) (cursor,
- revision_guard,
- origin,
- count,
- results,
- error);
+ retval = (* E_DATA_BOOK_CURSOR_GET_CLASS (cursor)->step) (cursor,
+ revision_guard,
+ flags,
+ origin,
+ count,
+ results,
+ error);
g_object_unref (cursor);
- if (retval > 0) {
- /* Calculate new cursor position and notify change */
- calculate_move_by_position (cursor, origin, count, retval);
+ if (retval >= 0 && (flags & E_BOOK_CURSOR_STEP_MOVE) != 0) {
+
+ calculate_step_position (cursor, origin, count, retval);
}
return retval;
@@ -824,7 +869,7 @@ e_data_book_cursor_move_by (EDataBookCursor *cursor,
* into the alphabet active in the @locale of the addressbook.
*
* After setting the target to an alphabetic index, for example the
- * index for letter 'E', then further calls to e_data_book_cursor_move_by()
+ * index for letter 'E', then further calls to e_data_book_cursor_step()
* will return results starting with the letter 'E' (or results starting
* with the last result in 'D', if moving in a negative direction).
*
@@ -969,9 +1014,10 @@ e_data_book_cursor_load_locale (EDataBookCursor *cursor,
g_free (priv->locale);
priv->locale = g_strdup (local_locale);
- if (e_data_book_cursor_move_by (cursor, NULL,
- E_BOOK_CURSOR_ORIGIN_RESET,
- 0, NULL, &local_error) < 0) {
+ if (e_data_book_cursor_step (cursor, NULL,
+ E_BOOK_CURSOR_STEP_MOVE,
+ E_BOOK_CURSOR_ORIGIN_BEGIN,
+ 0, NULL, &local_error) < 0) {
g_warning ("Error resetting cursor position after locale change: %s",
local_error->message);
g_clear_error (&local_error);
@@ -1137,8 +1183,8 @@ e_data_book_cursor_register_gdbus_object (EDataBookCursor *cursor,
if (!priv->dbus_object) {
priv->dbus_object = e_dbus_address_book_cursor_skeleton_new ();
- g_signal_connect (priv->dbus_object, "handle-move-by",
- G_CALLBACK (data_book_cursor_handle_move_by), cursor);
+ g_signal_connect (priv->dbus_object, "handle-step",
+ G_CALLBACK (data_book_cursor_handle_step), cursor);
g_signal_connect (priv->dbus_object, "handle-set-alphabetic-index",
G_CALLBACK (data_book_cursor_handle_set_alphabetic_index), cursor);
g_signal_connect (priv->dbus_object, "handle-set-query",
diff --git a/addressbook/libedata-book/e-data-book-cursor.h b/addressbook/libedata-book/e-data-book-cursor.h
index 1704adc..eb7a879 100644
--- a/addressbook/libedata-book/e-data-book-cursor.h
+++ b/addressbook/libedata-book/e-data-book-cursor.h
@@ -75,16 +75,17 @@ typedef gboolean (*EDataBookCursorSetSexpFunc) (EDataBookCursor *cursor,
GError **error);
/**
- * EDataBookCursorMoveByFunc:
+ * EDataBookCursorStepFunc:
* @cursor: an #EDataBookCursor
* @revision_guard: (allow-none): The expected current addressbook revision, or %NULL
- * @origin: the #EBookCursorOrigin for this move
+ * @flags: The #EBookCursorStepFlags for this step
+ * @origin: The #EBookCursorOrigin from whence to step
* @count: a positive or negative amount of contacts to try and fetch
* @results: (out) (allow-none) (element-type utf8) (transfer full):
- * A return location to store the results, or %NULL to move the cursor without retrieving any results.
+ * A return location to store the results, or %NULL if %E_BOOK_CURSOR_STEP_FETCH is not specified in %flags
* @error: (out) (allow-none): return location for a #GError, or %NULL
*
- * Method type for #EDataBookCursorClass.move_by()
+ * Method type for #EDataBookCursorClass.step()
*
* As all cursor methods may be called either by the addressbook service or
* directly by a client in Direct Read Access mode, it is important that the
@@ -101,19 +102,20 @@ typedef gboolean (*EDataBookCursorSetSexpFunc) (EDataBookCursor *cursor,
* single atomic operation (the data read back from the store must be the correct
* data for the given addressbook revision).</para></note>
*
- * See e_data_book_cursor_move_by() for more details on the expected behaviour of this method.
+ * See e_data_book_cursor_step() for more details on the expected behaviour of this method.
*
- * Returns: The number of contacts which the cursor has moved by if successfull.
- * Otherwise -1 is returned and @error is set.
+ * Returns: The number of contacts traversed if successfull, otherwise -1 is
+ * returned and @error is set.
*
* Since: 3.12
*/
-typedef gint (*EDataBookCursorMoveByFunc) (EDataBookCursor *cursor,
- const gchar *revision_guard,
- EBookCursorOrigin origin,
- gint count,
- GSList **results,
- GError **error);
+typedef gint (*EDataBookCursorStepFunc) (EDataBookCursor *cursor,
+ const gchar *revision_guard,
+ EBookCursorStepFlags flags,
+ EBookCursorOrigin origin,
+ gint count,
+ GSList **results,
+ GError **error);
/**
* EDataBookCursorSetAlphabetIndexFunc:
@@ -160,7 +162,7 @@ typedef gboolean (*EDataBookCursorSetAlphabetIndexFunc) (EDataBookCursor *cu
* a position that is before and after the entire result set. The cursor
* position should be %0 at creation time, and should start again from
* the symbolic %0 position whenever %E_BOOK_CURSOR_ORIGIN_RESET is
- * specified in the #EDataBookCursorClass.move_by() method (or whenever
+ * specified in the #EDataBookCursorClass.step() method (or whenever
* moving the cursor beyond the end of the result set).
*
* This method is called by e_data_book_cursor_recalculate() and in some
@@ -247,7 +249,7 @@ struct _EDataBookCursor {
/**
* EDataBookCursorClass:
* @set_sexp: The #EDataBookCursorSetSexpFunc delegate to set the search expression
- * @move_by: The #EDataBookCursorMoveByFunc delegate to navigate the cursor
+ * @step: The #EDataBookCursorStepFunc delegate to navigate the cursor
* @set_alphabetic_index: The #EDataBookCursorSetAlphabetIndexFunc delegate to set the alphabetic position
* @get_position: The #EDataBookCursorGetPositionFunc delegate to calculate the current total and position
values
* @compare_contact: The #EDataBookCursorCompareContactFunc delegate to compare an #EContact with the the
cursor position
@@ -263,7 +265,7 @@ struct _EDataBookCursorClass {
/*< public >*/
EDataBookCursorSetSexpFunc set_sexp;
- EDataBookCursorMoveByFunc move_by;
+ EDataBookCursorStepFunc step;
EDataBookCursorSetAlphabetIndexFunc set_alphabetic_index;
EDataBookCursorGetPositionFunc get_position;
EDataBookCursorCompareContactFunc compare_contact;
@@ -278,8 +280,9 @@ gint e_data_book_cursor_get_position (EDataBookCurso
gboolean e_data_book_cursor_set_sexp (EDataBookCursor *cursor,
const gchar *sexp,
GError **error);
-gint e_data_book_cursor_move_by (EDataBookCursor *cursor,
+gint e_data_book_cursor_step (EDataBookCursor *cursor,
const gchar *revision_guard,
+ EBookCursorStepFlags flags,
EBookCursorOrigin origin,
gint count,
GSList **results,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]