Top |
Functions
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 |
||
sexp |
the search expression to set, or |
[allow-none] |
error |
[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 |
||
revision_guard |
The expected current addressbook revision, or |
[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 |
[out][allow-none][element-type utf8][transfer full] |
cancellable |
A GCancellable. |
[allow-none] |
error |
[out][allow-none] |
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 |
||
index |
the alphabetic index |
|
locale |
the locale in which |
|
error |
[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 |
||
total |
The total number of contacts matching |
[out] |
position |
The current position of |
[out] |
cancellable |
A GCancellable. |
[allow-none] |
error |
[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 |
||
contact |
the EContact to compare with |
|
matches_sexp |
return location to set whether |
[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 |
||
locale |
return location to store the newly loaded locale. |
[out][transfer full] |
error |
[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
.
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.
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.
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 |
||
sexp |
the search expression to set. |
[allow-none] |
cancellable |
A GCancellable. |
[allow-none] |
error |
[out][allow-none] |
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 |
||
revision_guard |
The expected current addressbook revision, or |
|
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 |
[out][allow-none][element-type utf8][transfer full] |
cancellable |
A GCancellable. |
[allow-none] |
error |
[out][allow-none] |
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
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 |
||
index |
the alphabetic index |
|
locale |
the locale in which |
|
cancellable |
A GCancellable. |
[allow-none] |
error |
[out][allow-none] |
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.
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 |
||
locale |
return location for the locale. |
[out][allow-none] |
cancellable |
A GCancellable. |
[allow-none] |
error |
[out][allow-none] |
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.
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.
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 |
||
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] |
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 |
The EDataBookCursorSetSexpFunc delegate to set the search expression |
|
EDataBookCursorStepFunc |
The EDataBookCursorStepFunc delegate to navigate the cursor |
|
EDataBookCursorSetAlphabetIndexFunc |
The EDataBookCursorSetAlphabetIndexFunc delegate to set the alphabetic position |
|
EDataBookCursorGetPositionFunc |
The EDataBookCursorGetPositionFunc delegate to calculate the current total and position values |
|
EDataBookCursorCompareContactFunc |
The EDataBookCursorCompareContactFunc delegate to compare an EContact with the the cursor position |
|
EDataBookCursorLoadLocaleFunc |
The EDataBookCursorLoadLocaleFunc delegate used to reload the locale setting |
Since: 3.12