[evolution-data-server/openismus-work-3-8: 58/112] EBookBackendSqliteDB: Cursor API change.



commit 2aeb45c54ff09a9a8c4a65737787687b2c7a2fd0
Author: Tristan Van Berkom <tristanvb openismus com>
Date:   Tue Jun 11 19:01:24 2013 +0900

    EBookBackendSqliteDB: Cursor API change.
    
    Removed e_book_backend_sqlite_cursor_set_target_contact() and added
    an enumeration parameter to e_book_backend_sqlitedb_cursor_move_by()
    
    Moving the cursor now has 3 possible "origins":
    
      o EBSDB_CURSOR_ORIGIN_CURRENT: Fetch results and move from the current
                                     cursor position
    
      o EBSDB_CURSOR_ORIGIN_PREVIOUS: Fetch results and move from the previous
                                      cursor position, practical for refreshing
                                      a result set after the addressbook changes
    
      o EBSDB_CURSOR_ORIGIN_RESET: Fetch results from the beginning (or end,
                                   if moving backwards through results).
    
    To achieve the EBSDB_CURSOR_ORIGIN_PREVIOUS origin, the cursor now
    holds on to two cursor states at all times (the current cursor state
    and previous cursor state).

 .../libedata-book/e-book-backend-sqlitedb.c        |  179 +++++++++++---------
 .../libedata-book/e-book-backend-sqlitedb.h        |   24 +++-
 2 files changed, 121 insertions(+), 82 deletions(-)
---
diff --git a/addressbook/libedata-book/e-book-backend-sqlitedb.c 
b/addressbook/libedata-book/e-book-backend-sqlitedb.c
index 08d7d0d..9bdaf6b 100644
--- a/addressbook/libedata-book/e-book-backend-sqlitedb.c
+++ b/addressbook/libedata-book/e-book-backend-sqlitedb.c
@@ -5197,6 +5197,17 @@ e_book_backend_sqlitedb_get_locale (EBookBackendSqliteDB *ebsdb,
 /******************************************************************
  *                          EbSdbCursor apis                       *
  ******************************************************************/
+typedef struct {
+       gchar        **values;        /* The cursor position, results will be returned after this position */
+       gchar         *last_uid;      /* The cursor contact UID position, used as a tie breaker */
+} CursorState;
+
+typedef enum {
+       STATE_PREVIOUS,
+       STATE_CURRENT,
+       N_CURSOR_STATES
+} CursorStateType;
+
 struct _EbSdbCursor {
        gchar         *folderid;      /* The folderid for this cursor */
 
@@ -5208,11 +5219,9 @@ struct _EbSdbCursor {
 
        EContactField *sort_fields;   /* The fields to sort in a query in the order or sort priority */
        EBookSortType *sort_types;    /* The sort method to use for each field */
-       gchar        **values;        /* The current cursor position, results will be returned after this 
position */
-
        gint           n_sort_fields; /* The amound of sort fields */
 
-       gchar         *last_uid;      /* The current cursor contact UID position, used as a tie breaker */
+       CursorState    state[N_CURSOR_STATES];
 };
 
 static void
@@ -5291,6 +5300,7 @@ ebsdb_cursor_new (EBookBackendSqliteDB *ebsdb,
                  guint                 n_sort_fields)
 {
        EbSdbCursor *cursor = g_slice_new0 (EbSdbCursor);
+       gint i;
 
        cursor->folderid = g_strdup (folderid);
 
@@ -5311,30 +5321,56 @@ ebsdb_cursor_new (EBookBackendSqliteDB *ebsdb,
        cursor->n_sort_fields = n_sort_fields;
        cursor->sort_fields   = g_memdup (sort_fields, sizeof (EContactField) * n_sort_fields);
        cursor->sort_types    = g_memdup (sort_types,  sizeof (EBookSortType) * n_sort_fields);
-       cursor->values        = g_new0 (gchar *, n_sort_fields);
+
+       for (i = 0; i < N_CURSOR_STATES; i++)
+               cursor->state[i].values = g_new0 (gchar *, n_sort_fields);
 
        return cursor;
 }
 
 static void
-ebsdb_cursor_clear_state (EbSdbCursor *cursor)
+ebsdb_cursor_clear_state (EbSdbCursor      *cursor,
+                         CursorStateType   state_type)
 {
        gint i;
 
        for (i = 0; i < cursor->n_sort_fields; i++) {
-               g_free (cursor->values[i]);
-               cursor->values[i] = NULL;
+               g_free (cursor->state[state_type].values[i]);
+               cursor->state[state_type].values[i] = NULL;
        }
 
-       g_free (cursor->last_uid);
-       cursor->last_uid = NULL;
+       g_free (cursor->state[state_type].last_uid);
+       cursor->state[state_type].last_uid = NULL;
+}
+
+static void
+ebsdb_cursor_swap_state (EbSdbCursor      *cursor)
+{
+       gchar **tmp_values;
+       gchar  *tmp_last_uid;
+
+       /* Swap the current values and the previous values */
+       tmp_values = cursor->state[STATE_CURRENT].values;
+       cursor->state[STATE_CURRENT].values  = cursor->state[STATE_PREVIOUS].values;
+       cursor->state[STATE_PREVIOUS].values = tmp_values;
+
+       /* Swap the current uid and the previous uid */
+       tmp_last_uid = cursor->state[STATE_CURRENT].last_uid;
+       cursor->state[STATE_CURRENT].last_uid  = cursor->state[STATE_PREVIOUS].last_uid;
+       cursor->state[STATE_PREVIOUS].last_uid = tmp_last_uid;
 }
 
 static void
 ebsdb_cursor_free (EbSdbCursor *cursor)
 {
+       gint i;
+
        if (cursor) {
-               ebsdb_cursor_clear_state (cursor);
+
+               for (i = 0; i < N_CURSOR_STATES; i++) {
+                       ebsdb_cursor_clear_state (cursor, i);
+                       g_free (cursor->state[i].values);
+               }
 
                g_free (cursor->folderid);
                g_free (cursor->select_vcards);
@@ -5344,7 +5380,6 @@ ebsdb_cursor_free (EbSdbCursor *cursor)
                g_free (cursor->reverse_order);
                g_free (cursor->sort_fields);
                g_free (cursor->sort_types);
-               g_free (cursor->values);
 
                g_slice_free (EbSdbCursor, cursor);
        }
@@ -5357,20 +5392,22 @@ ebsdb_cursor_set_state_from_contact (EBookBackendSqliteDB *ebsdb,
 {
        gint i;
 
-       ebsdb_cursor_clear_state (cursor);
+       /* Push the current state into the previous state and clear the current state */
+       ebsdb_cursor_swap_state (cursor);
+       ebsdb_cursor_clear_state (cursor, STATE_CURRENT);
 
        for (i = 0; i < cursor->n_sort_fields; i++) {
                const gchar *string = e_contact_get_const (contact, cursor->sort_fields[i]);
 
                if (string)
-                       cursor->values[i] =
+                       cursor->state[STATE_CURRENT].values[i] =
                                e_collator_generate_key (ebsdb->priv->collator,
                                                         string, NULL);
                else
-                       cursor->values[i] = g_strdup ("");
+                       cursor->state[STATE_CURRENT].values[i] = g_strdup ("");
        }
 
-       cursor->last_uid = e_contact_get (contact, E_CONTACT_UID);
+       cursor->state[STATE_CURRENT].last_uid = e_contact_get (contact, E_CONTACT_UID);
 }
 
 static void
@@ -5380,13 +5417,11 @@ ebsdb_cursor_set_state (EBookBackendSqliteDB *ebsdb,
 {
        EContact *contact;
 
-       if (vcard) {
-               contact = e_contact_new_from_vcard (vcard);
-               ebsdb_cursor_set_state_from_contact (ebsdb, cursor, contact);
-               g_object_unref (contact);
-       } else {
-               ebsdb_cursor_clear_state (cursor);
-       }
+       g_assert (vcard);
+
+       contact = e_contact_new_from_vcard (vcard);
+       ebsdb_cursor_set_state_from_contact (ebsdb, cursor, contact);
+       g_object_unref (contact);
 }
 
 #define GREATER_OR_LESS(cursor, index, reverse)                                \
@@ -5431,8 +5466,8 @@ ebsdb_cursor_constraints (EBookBackendSqliteDB *ebsdb,
                gchar   *stmt;
 
                /* Break once we hit a NULL value */
-               if ((i  < cursor->n_sort_fields && cursor->values[i] == NULL) ||
-                   (i == cursor->n_sort_fields && cursor->last_uid  == NULL))
+               if ((i  < cursor->n_sort_fields && cursor->state[STATE_CURRENT].values[i] == NULL) ||
+                   (i == cursor->n_sort_fields && cursor->state[STATE_CURRENT].last_uid  == NULL))
                        break;
 
                /* Between each qualifier, add an 'OR' */
@@ -5447,7 +5482,8 @@ ebsdb_cursor_constraints (EBookBackendSqliteDB *ebsdb,
                        field_name = summary_dbname_from_field (ebsdb, cursor->sort_fields[j]);
 
                        stmt = sqlite3_mprintf ("summary.%s_localized = %Q",
-                                               field_name, cursor->values[j]);
+                                               field_name,
+                                               cursor->state[STATE_CURRENT].values[j]);
 
                        g_string_append (string, stmt);
                        g_string_append (string, " AND ");
@@ -5468,13 +5504,13 @@ ebsdb_cursor_constraints (EBookBackendSqliteDB *ebsdb,
                        /* Append the UID tie breaker */
                        stmt = sqlite3_mprintf ("summary.uid %c %Q",
                                                reverse ? '<' : '>',
-                                               cursor->last_uid);
+                                               cursor->state[STATE_CURRENT].last_uid);
                        g_string_append (string, stmt);
                        sqlite3_free (stmt);
 
                        if (include_current_uid) {
                                stmt = sqlite3_mprintf (" OR summary.uid = %Q",
-                                                       cursor->last_uid);
+                                                       cursor->state[STATE_CURRENT].last_uid);
                                g_string_append (string, stmt);
                                g_string_append_c (string, ')');
                                sqlite3_free (stmt);
@@ -5490,8 +5526,8 @@ ebsdb_cursor_constraints (EBookBackendSqliteDB *ebsdb,
                         */
                        gboolean include_exact_match =
                                (reverse == FALSE &&
-                                ((i + 1 < cursor->n_sort_fields && cursor->values[i + 1] == NULL) ||
-                                 (i + 1 == cursor->n_sort_fields && cursor->last_uid == NULL)));
+                                ((i + 1 < cursor->n_sort_fields && cursor->state[STATE_CURRENT].values[i + 
1] == NULL) ||
+                                 (i + 1 == cursor->n_sort_fields && cursor->state[STATE_CURRENT].last_uid == 
NULL)));
 
                        if (include_exact_match)
                                g_string_append_c (string, '(');
@@ -5502,7 +5538,7 @@ ebsdb_cursor_constraints (EBookBackendSqliteDB *ebsdb,
                        stmt = sqlite3_mprintf ("summary.%s_localized %c %Q",
                                                field_name,
                                                GREATER_OR_LESS (cursor, i, reverse),
-                                               cursor->values[i]);
+                                               cursor->state[STATE_CURRENT].values[i]);
 
                        g_string_append (string, stmt);
                        sqlite3_free (stmt);
@@ -5510,7 +5546,7 @@ ebsdb_cursor_constraints (EBookBackendSqliteDB *ebsdb,
                        if (include_exact_match) {
 
                                stmt = sqlite3_mprintf (" OR summary.%s_localized = %Q",
-                                                       field_name, cursor->values[i]);
+                                                       field_name, cursor->state[STATE_CURRENT].values[i]);
 
                                g_string_append (string, stmt);
                                g_string_append_c (string, ')');
@@ -5575,7 +5611,7 @@ cursor_count_position_locked (EBookBackendSqliteDB *ebsdb,
        }
 
        /* Add the cursor constraints (if any) */
-       if (cursor->values[0] != NULL) {
+       if (cursor->state[STATE_CURRENT].values[0] != NULL) {
                gchar  *constraints = NULL;
 
                if (!cursor->query)
@@ -5697,6 +5733,7 @@ e_book_backend_sqlitedb_cursor_free (EBookBackendSqliteDB *ebsdb,
  * e_book_backend_sqlitedb_cursor_move_by:
  * @ebsdb: An #EBookBackendSqliteDB
  * @cursor: The #EbSdbCursor to use
+ * @origin: The #EbSdbCurorOrigin for this move
  * @count: A positive or negative amount of contacts to try and fetch
  * @error: A return location to story any error that might be reported.
  *
@@ -5704,9 +5741,9 @@ e_book_backend_sqlitedb_cursor_free (EBookBackendSqliteDB *ebsdb,
  *
  * If @count is negative, then the cursor will move backwards.
  *
- * If @cursor is in an empty state, 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 @cursor is in an empty state, or @origin is %EBSDB_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 @cursor reaches the beginning or end of the query results, then the
  * returned list might not contain the amount of desired contacts, or might
@@ -5721,6 +5758,7 @@ e_book_backend_sqlitedb_cursor_free (EBookBackendSqliteDB *ebsdb,
 GSList *
 e_book_backend_sqlitedb_cursor_move_by (EBookBackendSqliteDB *ebsdb,
                                        EbSdbCursor          *cursor,
+                                       EbSdbCurorOrigin      origin,
                                        gint                  count,
                                        GError              **error)
 {
@@ -5732,6 +5770,23 @@ e_book_backend_sqlitedb_cursor_move_by (EBookBackendSqliteDB *ebsdb,
        g_return_val_if_fail (cursor != NULL, NULL);
        g_return_val_if_fail (count != 0, NULL);
 
+       /* Every query starts with the STATE_CURRENT position, first
+        * fix up the cursor state according to 'origin'
+        */
+       switch (origin) {
+       case EBSDB_CURSOR_ORIGIN_CURRENT:
+               /* Do nothing, normal operation */
+               break;
+       case EBSDB_CURSOR_ORIGIN_PREVIOUS:
+               /* Swap the previous state into the current state first */
+               ebsdb_cursor_swap_state (cursor);
+               break;
+       case EBSDB_CURSOR_ORIGIN_RESET:
+               /* Clear the current state before executing the query */
+               ebsdb_cursor_clear_state (cursor, STATE_CURRENT);
+               break;
+       }
+
        query = g_string_new (cursor->select_vcards);
 
        /* Add the filter constraints (if any) */
@@ -5744,7 +5799,7 @@ e_book_backend_sqlitedb_cursor_move_by (EBookBackendSqliteDB *ebsdb,
        }
 
        /* Add the cursor constraints (if any) */
-       if (cursor->values[0] != NULL) {
+       if (cursor->state[STATE_CURRENT].values[0] != NULL) {
                gchar  *constraints = NULL;
 
                if (!cursor->query)
@@ -5788,10 +5843,12 @@ e_book_backend_sqlitedb_cursor_move_by (EBookBackendSqliteDB *ebsdb,
        /* If there was no error, update the internal cursor state */
        if (success) {
 
-               if (g_slist_length (results) < ABS (count))
-                       /* We've reached the end, clear the state */
-                       ebsdb_cursor_clear_state (cursor);
-               else {
+               if (g_slist_length (results) < ABS (count)) {
+                       /* We've reached the end, clear the current state, allow
+                        * a repeat query from the previously recorded position */
+                       ebsdb_cursor_swap_state (cursor);
+                       ebsdb_cursor_clear_state (cursor, STATE_CURRENT);
+               } else {
                        /* Set the cursor state to the last result */
                        GSList *last = g_slist_last (results);
                        EbSdbSearchData *data = last->data;
@@ -5804,39 +5861,6 @@ e_book_backend_sqlitedb_cursor_move_by (EBookBackendSqliteDB *ebsdb,
 }
 
 /**
- * e_book_backend_sqlitedb_cursor_set_target_contact:
- * @ebsdb: An #EBookBackendSqliteDB
- * @cursor: The #EbSdbCursor to modify
- * @contact: (allow-none): An #EContact
- *
- * Sets the current cursor position to @contact.
- *
- * After setting the target to a specific contact position,
- * calls to e_book_backend_sqlitedb_cursor_move_by() will return
- * results after @contact (or before @contact, if moving the cursor
- * with a negative @count).
- *
- * If @contact is %NULL, then the cursor position will be reset
- * to initial values (i.e. the beginning or end of the results).
- *
- * Since: 3.10
- */
-void
-e_book_backend_sqlitedb_cursor_set_target_contact (EBookBackendSqliteDB *ebsdb,
-                                                  EbSdbCursor          *cursor,
-                                                  EContact             *contact)
-{
-       g_return_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb));
-       g_return_if_fail (contact == NULL || E_IS_CONTACT (contact));
-       g_return_if_fail (cursor != NULL);
-
-       if (contact)
-               ebsdb_cursor_set_state_from_contact (ebsdb, cursor, contact);
-       else
-               ebsdb_cursor_clear_state (cursor);
-}
-
-/**
  * e_book_backend_sqlitedb_cursor_set_target_alphabetic_index:
  * @ebsdb: An #EBookBackendSqliteDB
  * @cursor: The #EbSdbCursor to modify
@@ -5873,11 +5897,10 @@ e_book_backend_sqlitedb_cursor_set_target_alphabetic_index (EBookBackendSqliteDB
                                     NULL, NULL, NULL);
        g_return_if_fail (index < n_labels);
 
-       ebsdb_cursor_clear_state (cursor);
+       ebsdb_cursor_clear_state (cursor, STATE_CURRENT);
        if (cursor->n_sort_fields > 0)
-               cursor->values[0] =
-                       e_collator_generate_key_for_index (ebsdb->priv->collator,
-                                                          index);
+               cursor->state[STATE_CURRENT].values[0] =
+                       e_collator_generate_key_for_index (ebsdb->priv->collator, index);
 }
 
 /**
@@ -5950,7 +5973,7 @@ e_book_backend_sqlitedb_cursor_calculate (EBookBackendSqliteDB *ebsdb,
        g_return_val_if_fail (cursor != NULL, FALSE);
 
        /* If we're in a clear cursor state, then the position is 0 */
-       if (position && cursor->values[0] == NULL) {
+       if (position && cursor->state[STATE_CURRENT].values[0] == NULL) {
                *position = 0;
 
                /* Mark the local pointer NULL, no need to calculate this anymore */
diff --git a/addressbook/libedata-book/e-book-backend-sqlitedb.h 
b/addressbook/libedata-book/e-book-backend-sqlitedb.h
index 500c0cc..3f8d4ec 100644
--- a/addressbook/libedata-book/e-book-backend-sqlitedb.h
+++ b/addressbook/libedata-book/e-book-backend-sqlitedb.h
@@ -121,6 +121,25 @@ typedef struct {
  */
 typedef struct _EbSdbCursor EbSdbCursor;
 
+/**
+ * EbSdbCurorOrigin:
+ * @EBSDB_CURSOR_ORIGIN_CURRENT:  The current cursor position
+ * @EBSDB_CURSOR_ORIGIN_PREVIOUS: The previously recorded cursor position, this can be used to repeat the 
previous query
+ * @EBSDB_CURSOR_ORIGIN_RESET:    The beginning of the cursor results (or end of the results, if navigating 
in reverse).
+ *
+ * Defines the behaviour of e_book_backend_sqlitedb_cursor_move_by().
+ *
+ * The cursor always saves the previous cursor position as well as
+ * the new cursor position after performing a move. This allows
+ * cursor queries to be repeated in the case where content may have
+ * changed but the same content window should be refreshed in a UI.
+ */
+typedef enum {
+       EBSDB_CURSOR_ORIGIN_CURRENT,
+       EBSDB_CURSOR_ORIGIN_PREVIOUS,
+       EBSDB_CURSOR_ORIGIN_RESET
+} EbSdbCurorOrigin;
+
 GType          e_book_backend_sqlitedb_get_type
                                                (void) G_GNUC_CONST;
 GQuark          e_book_backend_sqlitedb_error_quark
@@ -313,12 +332,9 @@ void            e_book_backend_sqlitedb_cursor_free
 GSList         *e_book_backend_sqlitedb_cursor_move_by
                                                 (EBookBackendSqliteDB *ebsdb,
                                                 EbSdbCursor          *cursor,
+                                                EbSdbCurorOrigin      origin,
                                                 gint                  count,
                                                 GError              **error);
-void            e_book_backend_sqlitedb_cursor_set_target_contact
-                                                (EBookBackendSqliteDB *ebsdb,
-                                                EbSdbCursor          *cursor,
-                                                EContact             *contact);
 void            e_book_backend_sqlitedb_cursor_set_target_alphabetic_index
                                                 (EBookBackendSqliteDB *ebsdb,
                                                 EbSdbCursor          *cursor,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]