EDataBookCursor

EDataBookCursor — The abstract cursor API

Types and Values

Object Hierarchy

    GObject
    ╰── EDataBookCursor
        ╰── EDataBookCursorSqlite

Includes

#include <libedata-book/libedata-book.h>

Description

The EDataBookCursor API is the high level cursor API on the addressbook server, it can respond to client requests directly when opened in direct read access mode, otherwise it will implement the org.gnome.evolution.dataserver.AddressBookCursor D-Bus interface when instantiated by the addressbook server.

EDataBookCursor is an implementation detail for backends who wish to implement cursors. If you need to use the client API to iterate over contacts stored in Evolution Data Server; you should be using EBookClientCursor instead.

Implementing Cursors

In order for an addressbook backend to implement cursors, it must first be locale aware, persist a current locale setting and implement the EBookBackendClass.set_locale() and EBookBackendClass.get_locale() methods.

The backend indicates that it supports cursors by implementing the EBookBackendClass.create_cursor() and returning an EDataBookCursor, any backend implementing EBookBackendClass.create_cursor() should also implement EBookBackendClass.delete_cursor().

For backends which use EBookBackendSqliteDB to store contacts, an EDataBookCursorSqlite can be used as a cursor implementation.

Implementing a concrete cursor class for your own addressbook backend is a matter of implementing all of the virtual methods on the EDataBookCursorClass vtable, each virtual method has documentation describing how each of the methods should be implemented.


Tracking Cursor State

The cursor state itself is defined as an array of sort keys and an E_CONTACT_UID value. There should be one sort key stored for each contact field which was passed to EBookBackendClass.create_cursor().

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.

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.

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.

Example 2. Collecting sort keys for a given contact

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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);
}


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.

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.


Implementing Localized Sorting

To implement localized sorting in an addressbook backend, an ECollator can be used. The ECollator provides all the functionality needed to respond to the cursor methods.

When storing contacts in your backend, sort keys should be generated for any fields which might be used as sort key parameters for a cursor, keys for these fields should be generated with e_collator_generate_key() using an ECollator created for the locale in which your addressbook is currently configured (undesired fields may be rejected at cursor creation time with an E_CLIENT_ERROR_INVALID_QUERY error).

The generated sort keys can then be used with strcmp() in order to compare results with the currently stored cursor state. These comparisons should compare contact fields in order of precedence in the array of sort fields which the cursor was configured with. If two contacts match exactly, then the E_CONTACT_UID value is used to determine which contact sorts above or below the other.

When your sort keys are generated using ECollator, you can easily use e_collator_generate_key_for_index() to implement EDataBookCursorClass.set_alphabetic_index() and set the cursor position before (below) a given letter in the active alphabet. The key generated for an alphabetic index is guaranteed to sort below any word starting with the given letter, and above any word starting with the preceeding letter.


Direct Read Access

In order to support cursors in backends which support Direct Read Access mode, the underlying addressbook data must be written atomically along with each new revision attribute. The cursor mechanics rely on this atomicity in order to avoid any race conditions and ensure that data read back from the addressbook is current and up to date.


Backend Tasks

Backends have ownership of the cursors which they create and have some responsibility when supporting cursors.

As mentioned above, in Direct Read Access mode (if supported), all revision writes and addressbook modifications must be committed atomically.

Beyond that, it is the responsibility of the backend to call e_data_book_cursor_contact_added() and e_data_book_cursor_contact_removed() whenever the addressbook is modified. When a contact is modified but not added or removed, then e_data_book_cursor_contact_removed() should be called with the old existing contact and then e_data_book_cursor_contact_added() should be called with the new contact. This will automatically update the cursor total and position status.

Note that if it's too much trouble to load the existing contact data when a contact is modified, then e_data_book_cursor_recalculate() can be called instead. This will use the EDataBookCursorClass.get_position() method recalculate current cursor position from scratch.

Functions

EDataBookCursorSetSexpFunc ()

gboolean
(*EDataBookCursorSetSexpFunc) (EDataBookCursor *cursor,
                               const gchar *sexp,
                               GError **error);

Method type for EDataBookCursorClass.set_sexp()

A cursor implementation must implement this in order to modify the search expression for cursor . After this is called, the position and total will be recalculated.

If the cursor implementation is unable to deal with the EContactFields referred to in sexp , then an E_CLIENT_ERROR_INVALID_QUERY error should be set to indicate this.

Parameters

cursor

an EDataBookCursor

 

sexp

the search expression to set, or NULL for unfiltered results.

[allow-none]

error

return location for a GError, or NULL.

[out][allow-none]

Returns

TRUE on Success, otherwise FALSE is returned if any error occurred and error is set to reflect the error which occurred.

Since: 3.12


EDataBookCursorStepFunc ()

gint
(*EDataBookCursorStepFunc) (EDataBookCursor *cursor,
                            const gchar *revision_guard,
                            EBookCursorStepFlags flags,
                            EBookCursorOrigin origin,
                            gint count,
                            GSList **results,
                            GCancellable *cancellable,
                            GError **error);

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 operation be an atomic transaction with the underlying database.

The revision_guard , if specified, will be set to the CLIENT_BACKEND_PROPERTY_REVISION value at the time which the given client issued the call to move the cursor. If the revision_guard provided by the client does not match the stored addressbook revision, then an E_CLIENT_ERROR_OUT_OF_SYNC error should be set to indicate that the revision was out of sync while attempting to move the cursor.

If the addressbook backend supports direct read access, then the revision comparison and reading of the data store must be coupled into a single atomic operation (the data read back from the store must be the correct data for the given addressbook revision).

See e_data_book_cursor_step() for more details on the expected behaviour of this method.

Parameters

cursor

an EDataBookCursor

 

revision_guard

The expected current addressbook revision, or NULL.

[allow-none]

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

A return location to store the results, or NULL if E_BOOK_CURSOR_STEP_FETCH is not specified in flags.

[out][allow-none][element-type utf8][transfer full]

cancellable

A GCancellable.

[allow-none]

error

return location for a GError, or NULL.

[out][allow-none]

Returns

The number of contacts traversed if successfull, otherwise -1 is returned and error is set.

Since: 3.12


EDataBookCursorSetAlphabetIndexFunc ()

gboolean
(*EDataBookCursorSetAlphabetIndexFunc)
                               (EDataBookCursor *cursor,
                                gint index,
                                const gchar *locale,
                                GError **error);

Method type for EDataBookCursorClass.set_alphabetic_index()

Sets the cursor state to point to an

index into the active alphabet.

The implementing class must check that locale matches the current locale setting of the underlying database and report an E_CLIENT_ERROR_OUT_OF_SYNC error in the case that the locales do not match.

Parameters

cursor

an EDataBookCursor

 

index

the alphabetic index

 

locale

the locale in which index is expected to be a valid alphabetic index

 

error

return location for a GError, or NULL.

[out][allow-none]

Returns

TRUE on Success, otherwise FALSE is returned if any error occurred and error is set to reflect the error which occurred.

Since: 3.12


EDataBookCursorGetPositionFunc ()

gboolean
(*EDataBookCursorGetPositionFunc) (EDataBookCursor *cursor,
                                   gint *total,
                                   gint *position,
                                   GCancellable *cancellable,
                                   GError **error);

Method type for EDataBookCursorClass.get_position()

Cursor implementations must implement this to count the total results matching cursor 's query expression and to calculate the amount of contacts leading up to the current cursor state (cursor inclusive).

A cursor position is defined as an integer which is inclusive of the current contact to which it points (if the cursor points to an exact contact). A position of 0 indicates that the cursor is situated in 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_BEGIN is specified in the EDataBookCursorClass.step() method (or whenever moving the cursor beyond the end of the result set).

If the cursor is positioned beyond the end of the list, then the position should be the total amount of contacts available in the list (as returned through the total argument) plus one.

This method is called by e_data_book_cursor_recalculate() and in some other cases where cursor 's current position and total must be recalculated from scratch.

Parameters

cursor

an EDataBookCursor

 

total

The total number of contacts matching cursor 's query expression.

[out]

position

The current position of cursor in it's result list.

[out]

cancellable

A GCancellable.

[allow-none]

error

return location for a GError, or NULL.

[out][allow-none]

Returns

TRUE on Success, otherwise FALSE is returned if any error occurred and error is set to reflect the error which occurred.

Since: 3.12


EDataBookCursorCompareContactFunc ()

gint
(*EDataBookCursorCompareContactFunc) (EDataBookCursor *cursor,
                                      EContact *contact,
                                      gboolean *matches_sexp);

Method type for EDataBookCursorClass.compare_contact()

Cursor implementations must implement this in order to compare a contact with the current cursor state.

This is called when the addressbook backends notify active cursors that the addressbook has been modified with e_data_book_cursor_contact_added() and e_data_book_cursor_contact_removed().

Parameters

cursor

an EDataBookCursor

 

contact

the EContact to compare with cursor

 

matches_sexp

return location to set whether contact matched cursor 's search expression.

[out][allow-none]

Returns

A value that is less than, equal to, or greater than zero if contact is found, respectively, to be less than, to match, or be greater than the current value of cursor .

Since: 3.12


EDataBookCursorLoadLocaleFunc ()

gboolean
(*EDataBookCursorLoadLocaleFunc) (EDataBookCursor *cursor,
                                  gchar **locale,
                                  GError **error);

Method type for EDataBookCursorClass.load_locale()

Fetches the locale setting from cursor 's addressbook

If the locale setting has changed, the cursor must reload any internal locale specific data and ensure that comparisons of sort keys will function properly in the new locale.

Upon locale changes, the implementation need not worry about updating it's current cursor state, the cursor state will be reset automatically for you.

Parameters

cursor

an EDataBookCursor

 

locale

return location to store the newly loaded locale.

[out][transfer full]

error

return location for a GError, or NULL.

[out][allow-none]

Returns

TRUE on Success, otherwise FALSE is returned if any error occurred and error is set to reflect the error which occurred.

Since: 3.12


e_data_book_cursor_get_backend ()

struct _EBookBackend *
e_data_book_cursor_get_backend (EDataBookCursor *cursor);

Gets the backend which created and owns cursor .

Parameters

cursor

an EDataBookCursor

 

Returns

The EBookBackend owning cursor .

[transfer none]

Since: 3.12


e_data_book_cursor_get_total ()

gint
e_data_book_cursor_get_total (EDataBookCursor *cursor);

Fetch the total number of contacts which match cursor 's query expression.

Parameters

cursor

an EDataBookCursor

 

Returns

the total contacts for cursor

Since: 3.12


e_data_book_cursor_get_position ()

gint
e_data_book_cursor_get_position (EDataBookCursor *cursor);

Fetch the current position of cursor in its result list.

Parameters

cursor

an EDataBookCursor

 

Returns

the current position of cursor

Since: 3.12


e_data_book_cursor_set_sexp ()

gboolean
e_data_book_cursor_set_sexp (EDataBookCursor *cursor,
                             const gchar *sexp,
                             GCancellable *cancellable,
                             GError **error);

Sets the search expression for the cursor

Parameters

cursor

an EDataBookCursor

 

sexp

the search expression to set.

[allow-none]

cancellable

A GCancellable.

[allow-none]

error

return location for a GError, or NULL.

[out][allow-none]

Returns

TRUE on success, otherwise FALSE is returned and error is set.

Since: 3.12


e_data_book_cursor_step ()

gint
e_data_book_cursor_step (EDataBookCursor *cursor,
                         const gchar *revision_guard,
                         EBookCursorStepFlags flags,
                         EBookCursorOrigin origin,
                         gint count,
                         GSList **results,
                         GCancellable *cancellable,
                         GError **error);

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 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. 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_QUERY_REFUSED 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.

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.

An explanation of how stepping is expected to behave can be found in the user facing reference documentation.

Parameters

cursor

an EDataBookCursor

 

revision_guard

The expected current addressbook revision, or NULL

 

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

A return location to store the results, or NULL if E_BOOK_CURSOR_STEP_FETCH is not specified in flags.

[out][allow-none][element-type utf8][transfer full]

cancellable

A GCancellable.

[allow-none]

error

return location for a GError, or NULL.

[out][allow-none]

Returns

The number of contacts traversed if successful, otherwise -1 is returned and error is set.

Since: 3.12


e_data_book_cursor_set_alphabetic_index ()

gboolean
e_data_book_cursor_set_alphabetic_index
                               (EDataBookCursor *cursor,
                                gint index,
                                const gchar *locale,
                                GCancellable *cancellable,
                                GError **error);

Sets the cursor position to an

Alphabetic Index

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_step() will return results starting with the letter 'E' (or results starting with the last result in 'D', if moving in a negative direction).

The passed index must be a valid index in locale , if by some chance the addressbook backend has changed into a new locale after this call has been issued, an E_CLIENT_ERROR_OUT_OF_SYNC error will be issued indicating that there was a locale mismatch.

Parameters

cursor

an EDataBookCursor

 

index

the alphabetic index

 

locale

the locale in which index is expected to be a valid alphabetic index

 

cancellable

A GCancellable.

[allow-none]

error

return location for a GError, or NULL.

[out][allow-none]

Returns

TRUE on success, otherwise FALSE is returned and error is set.

Since: 3.12


e_data_book_cursor_recalculate ()

gboolean
e_data_book_cursor_recalculate (EDataBookCursor *cursor,
                                GCancellable *cancellable,
                                GError **error);

Recalculates the cursor's total and position, this is meant for cursor created in Direct Read Access mode to synchronously recalculate the position and total values when the addressbook revision has changed.

Parameters

cursor

an EDataBookCursor

 

cancellable

A GCancellable.

[allow-none]

error

return location for a GError, or NULL.

[out][allow-none]

Returns

TRUE on success, otherwise FALSE is returned and error is set.

Since: 3.12


e_data_book_cursor_load_locale ()

gboolean
e_data_book_cursor_load_locale (EDataBookCursor *cursor,
                                gchar **locale,
                                GCancellable *cancellable,
                                GError **error);

Load the current locale setting from the cursor's underlying database.

Addressbook backends implementing cursors should call this function on all active cursor when the locale setting changes.

This will implicitly reset cursor 's state and position.

Parameters

cursor

an EDataBookCursor

 

locale

return location for the locale.

[out][allow-none]

cancellable

A GCancellable.

[allow-none]

error

return location for a GError, or NULL.

[out][allow-none]

Returns

TRUE on success, otherwise FALSE is returned and error is set.

Since: 3.12


e_data_book_cursor_contact_added ()

void
e_data_book_cursor_contact_added (EDataBookCursor *cursor,
                                  EContact *contact);

Should be called by addressbook backends whenever a contact is added.

Parameters

cursor

an EDataBookCursor

 

contact

the EContact which was added to the addressbook

 

Since: 3.12


e_data_book_cursor_contact_removed ()

void
e_data_book_cursor_contact_removed (EDataBookCursor *cursor,
                                    EContact *contact);

Should be called by addressbook backends whenever a contact is removed.

Parameters

cursor

an EDataBookCursor

 

contact

the EContact which was removed from the addressbook

 

Since: 3.12


e_data_book_cursor_register_gdbus_object ()

gboolean
e_data_book_cursor_register_gdbus_object
                               (EDataBookCursor *cursor,
                                GDBusConnection *connection,
                                const gchar *object_path,
                                GError **error);

Places cursor on the connection at object_path

Parameters

cursor

an EDataBookCursor

 

connection

the GDBusConnection to register with

 

object_path

the object path to place the direct access configuration data

 

error

a location to store any error which might occur while registering.

[out][allow-none]

Returns

TRUE on success, otherwise FALSE is returned and error is set.

Since: 3.12

Types and Values

struct EDataBookCursor

struct EDataBookCursor;

An opaque handle for an addressbook cursor

Since: 3.12


struct EDataBookCursorClass

struct EDataBookCursorClass {
	EDataBookCursorSetSexpFunc set_sexp;
	EDataBookCursorStepFunc step;
	EDataBookCursorSetAlphabetIndexFunc set_alphabetic_index;
	EDataBookCursorGetPositionFunc get_position;
	EDataBookCursorCompareContactFunc compare_contact;
	EDataBookCursorLoadLocaleFunc load_locale;
};

Methods to implement on an EDataBookCursor concrete class.

Members

EDataBookCursorSetSexpFunc set_sexp;

The EDataBookCursorSetSexpFunc delegate to set the search expression

 

EDataBookCursorStepFunc step;

The EDataBookCursorStepFunc delegate to navigate the cursor

 

EDataBookCursorSetAlphabetIndexFunc set_alphabetic_index;

The EDataBookCursorSetAlphabetIndexFunc delegate to set the alphabetic position

 

EDataBookCursorGetPositionFunc get_position;

The EDataBookCursorGetPositionFunc delegate to calculate the current total and position values

 

EDataBookCursorCompareContactFunc compare_contact;

The EDataBookCursorCompareContactFunc delegate to compare an EContact with the the cursor position

 

EDataBookCursorLoadLocaleFunc load_locale;

The EDataBookCursorLoadLocaleFunc delegate used to reload the locale setting

 

Since: 3.12