/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* e-source-backend-summary-setup.c - Backend Summary Data Configuration.
*
* Copyright (C) 2012 Intel Corporation
*
* This library is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see .
*
* Authors: Tristan Van Berkom
*/
/**
* SECTION: e-source-backend-summary-setup
* @include: libebook-contacts/libebook-contacts.h
* @short_description: #ESource extension to configure summary fields
*
* The #ESourceBackendSummarySetup extension configures which #EContactFields
* should be in the summary and which of those fields should be optimized for
* quicker search results.
*
* Access the extension as follows:
*
* |[
* #include
*
* ESourceBackendSummarySetup *extension;
*
* extension = e_source_get_extension (source, E_SOURCE_EXTENSION_BACKEND_SUMMARY_SETUP);
* ]|
*
* The summary configuration is expected to be setup in only one way for
* a given #ESource at creation time. Any configurations made after creation of the
* book in question will be ignored.
*
**/
#include "e-source-backend-summary-setup.h"
#include "e-book-contacts-enumtypes.h"
struct _ESourceBackendSummarySetupPrivate {
GMutex property_lock;
gchar *summary_fields;
gchar *indexed_fields;
};
enum {
PROP_0,
PROP_SUMMARY_FIELDS,
PROP_INDEXED_FIELDS
};
G_DEFINE_TYPE_WITH_PRIVATE (
ESourceBackendSummarySetup,
e_source_backend_summary_setup,
E_TYPE_SOURCE_EXTENSION)
static gchar *
source_backend_summary_setup_dup_literal_fields (ESourceBackendSummarySetup *extension,
gint which)
{
gchar *duplicate = NULL;
g_mutex_lock (&extension->priv->property_lock);
switch (which) {
case PROP_SUMMARY_FIELDS:
duplicate = g_strdup (extension->priv->summary_fields);
break;
case PROP_INDEXED_FIELDS:
duplicate = g_strdup (extension->priv->indexed_fields);
break;
default:
g_return_val_if_reached (NULL);
break;
}
g_mutex_unlock (&extension->priv->property_lock);
return duplicate;
}
static void
source_backend_summary_setup_set_literal_fields (ESourceBackendSummarySetup *extension,
const gchar *literal_fields,
gint which)
{
const gchar *property_name;
gchar **target;
switch (which) {
case PROP_SUMMARY_FIELDS:
target = &(extension->priv->summary_fields);
property_name = "summary-fields";
break;
case PROP_INDEXED_FIELDS:
target = &(extension->priv->indexed_fields);
property_name = "indexed-fields";
break;
default:
g_return_if_reached ();
break;
}
g_mutex_lock (&extension->priv->property_lock);
if (e_util_strcmp0 (*target, literal_fields) == 0) {
g_mutex_unlock (&extension->priv->property_lock);
return;
}
g_free (*target);
*target = e_util_strdup_strip (literal_fields);
g_mutex_unlock (&extension->priv->property_lock);
g_object_notify (G_OBJECT (extension), property_name);
}
static void
source_backend_summary_setup_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
switch (property_id) {
case PROP_SUMMARY_FIELDS:
case PROP_INDEXED_FIELDS:
source_backend_summary_setup_set_literal_fields (
E_SOURCE_BACKEND_SUMMARY_SETUP (object),
g_value_get_string (value), property_id);
return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
source_backend_summary_setup_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
switch (property_id) {
case PROP_SUMMARY_FIELDS:
case PROP_INDEXED_FIELDS:
g_value_take_string (
value,
source_backend_summary_setup_dup_literal_fields (
E_SOURCE_BACKEND_SUMMARY_SETUP (object),
property_id));
return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
source_backend_summary_setup_finalize (GObject *object)
{
ESourceBackendSummarySetupPrivate *priv;
priv = E_SOURCE_BACKEND_SUMMARY_SETUP (object)->priv;
g_mutex_clear (&priv->property_lock);
g_free (priv->summary_fields);
g_free (priv->indexed_fields);
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_source_backend_summary_setup_parent_class)->
finalize (object);
}
static void
e_source_backend_summary_setup_class_init (ESourceBackendSummarySetupClass *class)
{
GObjectClass *object_class;
ESourceExtensionClass *extension_class;
object_class = G_OBJECT_CLASS (class);
object_class->get_property = source_backend_summary_setup_get_property;
object_class->set_property = source_backend_summary_setup_set_property;
object_class->finalize = source_backend_summary_setup_finalize;
extension_class = E_SOURCE_EXTENSION_CLASS (class);
extension_class->name = E_SOURCE_EXTENSION_BACKEND_SUMMARY_SETUP;
g_object_class_install_property (
object_class,
PROP_SUMMARY_FIELDS,
g_param_spec_string (
"summary-fields",
"Summary Fields",
"The list of quick reference summary fields",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_EXPLICIT_NOTIFY |
G_PARAM_STATIC_STRINGS |
E_SOURCE_PARAM_SETTING));
g_object_class_install_property (
object_class,
PROP_INDEXED_FIELDS,
g_param_spec_string (
"indexed-fields",
"Indexed Fields",
"The list of summary fields which are to be "
"given indexes in the underlying database",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_EXPLICIT_NOTIFY |
G_PARAM_STATIC_STRINGS |
E_SOURCE_PARAM_SETTING));
}
static void
e_source_backend_summary_setup_init (ESourceBackendSummarySetup *extension)
{
extension->priv = e_source_backend_summary_setup_get_instance_private (extension);
g_mutex_init (&extension->priv->property_lock);
}
static EContactField *
source_backend_summary_setup_get_fields_array (ESourceBackendSummarySetup *extension,
gint *n_fields,
gint which)
{
EContactField field;
EContactField *fields = NULL;
gchar *literal_fields;
gchar **split = NULL;
gint n_ret_fields = 0, i;
literal_fields = source_backend_summary_setup_dup_literal_fields (extension, which);
if (literal_fields)
split = g_strsplit (literal_fields, ":", 0);
if (split) {
n_ret_fields = g_strv_length (split);
fields = g_new (EContactField, n_ret_fields);
for (i = 0; i < n_ret_fields; i++) {
field = e_contact_field_id (split[i]);
if (field == 0)
g_warning ("Unrecognized field '%s' in ESourceBackendSummarySetup fields", split[i]);
fields[i] = field;
}
g_strfreev (split);
}
g_free (literal_fields);
*n_fields = n_ret_fields;
return fields;
}
static void
e_source_backend_summary_setup_set_fields_array (ESourceBackendSummarySetup *extension,
EContactField *fields,
gint n_fields,
gint which)
{
gint i;
GString *string;
gboolean malformed = FALSE;
string = g_string_new ("");
for (i = 0; i < n_fields; i++) {
const gchar *field_name = e_contact_field_name (fields[i]);
if (field_name == NULL) {
g_warning ("Invalid EContactField given to ESourceBackendSummarySetup");
malformed = TRUE;
break;
}
if (i > 0)
g_string_append_c (string, ':');
g_string_append (string, field_name);
}
if (malformed == FALSE)
source_backend_summary_setup_set_literal_fields (extension, string->str, which);
g_string_free (string, TRUE);
}
static void
e_source_backend_summary_setup_set_fields_va_list (ESourceBackendSummarySetup *extension,
va_list var_args,
gint which)
{
GString *string;
gboolean malformed = FALSE, first_field = TRUE;
EContactField field;
string = g_string_new ("");
field = va_arg (var_args, EContactField);
while (field > 0) {
const gchar *field_name = e_contact_field_name (field);
if (field_name == NULL) {
g_warning ("Invalid EContactField given to ESourceBackendSummarySetup");
malformed = TRUE;
break;
}
if (!first_field)
g_string_append_c (string, ':');
else
first_field = FALSE;
g_string_append (string, field_name);
field = va_arg (var_args, EContactField);
}
if (malformed == FALSE)
source_backend_summary_setup_set_literal_fields (extension, string->str, which);
g_string_free (string, TRUE);
}
/**
* e_source_backend_summary_setup_get_summary_fields:
* @extension: An #ESourceBackendSummarySetup
* @n_fields: (out): A return location for the number of #EContactFields in the returned array.
*
* Fetches the #EContactFields which are configured to be a part of the summary.
*
* If there are no configured summary fields, the default configuration is assumed
*
* Returns: (transfer full): An array of #EContactFields @n_fields long, should be freed with g_free() when done.
*
* Since: 3.8
*/
EContactField *
e_source_backend_summary_setup_get_summary_fields (ESourceBackendSummarySetup *extension,
gint *n_fields)
{
g_return_val_if_fail (E_IS_SOURCE_BACKEND_SUMMARY_SETUP (extension), NULL);
g_return_val_if_fail (n_fields != NULL, NULL);
return source_backend_summary_setup_get_fields_array (extension, n_fields, PROP_SUMMARY_FIELDS);
}
/**
* e_source_backend_summary_setup_set_summary_fieldsv:
* @extension: An #ESourceBackendSummarySetup
* @fields: The array of #EContactFields to set as summary fields
* @n_fields: The number of #EContactFields in @fields
*
* Sets the summary fields configured for the given addressbook.
*
* The fields %E_CONTACT_UID and %E_CONTACT_REV are not optional,
* they will be stored in the summary regardless of the configured summary.
*
* An empty summary configuration is assumed to be the default summary
* configuration.
*
* Only #EContactFields with the type #G_TYPE_STRING or #G_TYPE_BOOLEAN
* are currently supported as summary fields.
*
* Since: 3.8
*/
void
e_source_backend_summary_setup_set_summary_fieldsv (ESourceBackendSummarySetup *extension,
EContactField *fields,
gint n_fields)
{
g_return_if_fail (E_IS_SOURCE_BACKEND_SUMMARY_SETUP (extension));
g_return_if_fail (n_fields >= 0);
e_source_backend_summary_setup_set_fields_array (extension, fields, n_fields, PROP_SUMMARY_FIELDS);
}
/**
* e_source_backend_summary_setup_set_summary_fields:
* @extension: An #ESourceBackendSummarySetup
* @...: A 0 terminated list of #EContactFields to set as summary fields
*
* Like e_source_backend_summary_setup_set_summary_fieldsv(), but takes a literal
* list of #EContactFields for convenience.
*
* To configure the address book summary fields with main phone nubmer fields:
*
* |[
* #include
*
* ESourceBackendSummarySetup *extension;
*
* extension = e_source_get_extension (source, E_SOURCE_EXTENSION_BACKEND_SUMMARY_SETUP);
*
* e_source_backend_summary_setup_set_summary_fields (extension, E_CONTACT_FULL_NAME, E_CONTACT_EMAIL, 0);
* ]|
*
* Since: 3.8
*/
void
e_source_backend_summary_setup_set_summary_fields (ESourceBackendSummarySetup *extension,
...)
{
va_list var_args;
g_return_if_fail (E_IS_SOURCE_BACKEND_SUMMARY_SETUP (extension));
va_start (var_args, extension);
e_source_backend_summary_setup_set_fields_va_list (extension, var_args, PROP_SUMMARY_FIELDS);
va_end (var_args);
}
/**
* e_source_backend_summary_setup_get_indexed_fields:
* @extension: An #ESourceBackendSummarySetup
* @types: (out) (transfer full): A return location for the set of #EBookIndexTypes corresponding
* to each returned field, should be freed with g_free() when no longer needed.
* @n_fields: (out): The number of elements in the returned arrays.
*
* Fetches the #EContactFields configured to be indexed, with thier respective #EBookIndexTypes.
*
* Returns: (transfer full): The array of indexed #EContactFields.
*
* Since: 3.8
*/
EContactField *
e_source_backend_summary_setup_get_indexed_fields (ESourceBackendSummarySetup *extension,
EBookIndexType **types,
gint *n_fields)
{
EContactField *ret_fields;
EBookIndexType *ret_types;
gboolean malformed = FALSE;
gchar **split, **index_split;
gchar *literal_indexes;
gint ret_n_fields;
gint i;
g_return_val_if_fail (E_IS_SOURCE_BACKEND_SUMMARY_SETUP (extension), NULL);
g_return_val_if_fail (types != NULL, NULL);
g_return_val_if_fail (n_fields != NULL, NULL);
literal_indexes = source_backend_summary_setup_dup_literal_fields (extension, PROP_INDEXED_FIELDS);
if (!literal_indexes) {
*types = NULL;
*n_fields = 0;
return NULL;
}
split = g_strsplit (literal_indexes, ":", 0);
ret_n_fields = g_strv_length (split);
ret_fields = g_new0 (EContactField, ret_n_fields);
ret_types = g_new0 (EBookIndexType, ret_n_fields);
for (i = 0; i < ret_n_fields && malformed == FALSE; i++) {
index_split = g_strsplit (split[i], ",", 2);
if (index_split[0] && index_split[1]) {
gint interpreted_enum = 0;
ret_fields[i] = e_contact_field_id (index_split[0]);
if (!e_enum_from_string (E_TYPE_BOOK_INDEX_TYPE,
index_split[1], &interpreted_enum)) {
g_warning ("Unknown index type '%s' encountered in indexed fields", index_split[1]);
malformed = TRUE;
}
if (ret_fields[i] <= 0 || ret_fields[i] >= E_CONTACT_FIELD_LAST) {
g_warning ("Unknown contact field '%s' encountered in indexed fields", index_split[0]);
malformed = TRUE;
}
ret_types[i] = interpreted_enum;
} else {
g_warning ("Malformed index definition '%s'", split[i]);
malformed = TRUE;
}
g_strfreev (index_split);
}
if (malformed) {
g_free (ret_fields);
g_free (ret_types);
ret_n_fields = 0;
ret_fields = NULL;
ret_types = NULL;
}
g_strfreev (split);
g_free (literal_indexes);
*n_fields = ret_n_fields;
*types = ret_types;
return ret_fields;
}
/**
* e_source_backend_summary_setup_set_indexed_fieldsv:
* @extension: An #ESourceBackendSummarySetup
* @fields: The array of #EContactFields to set indexes for
* @types: The array of #EBookIndexTypes defining what types of indexes to create
* @n_fields: The number elements in the passed @fields, @rule_types and @rules arrays.
*
* Defines indexes for quick reference for the given given #EContactFields in the addressbook.
*
* The same #EContactField may be specified multiple times to create multiple indexes
* with different characteristics. If an #E_BOOK_INDEX_PREFIX index is created it will
* be used for #E_BOOK_QUERY_BEGINS_WITH queries. An #E_BOOK_INDEX_SUFFIX index
* will be constructed efficiently for suffix matching and will be used for
* #E_BOOK_QUERY_ENDS_WITH queries. Similar an #E_BOOK_INDEX_PHONE index will optimize
* #E_BOOK_QUERY_EQUALS_PHONE_NUMBER searches.
*
* The specified indexed fields must also be a part of the summary, any indexed fields
* specified that are not already a part of the summary will be ignored.
*
* Since: 3.8
*/
void
e_source_backend_summary_setup_set_indexed_fieldsv (ESourceBackendSummarySetup *extension,
EContactField *fields,
EBookIndexType *types,
gint n_fields)
{
GString *string;
gboolean malformed = FALSE;
gint i;
g_return_if_fail (E_IS_SOURCE_BACKEND_SUMMARY_SETUP (extension));
g_return_if_fail (types != NULL || n_fields <= 0);
g_return_if_fail (fields != NULL || n_fields <= 0);
if (n_fields <= 0) {
source_backend_summary_setup_set_literal_fields (extension, NULL, PROP_INDEXED_FIELDS);
return;
}
string = g_string_new (NULL);
for (i = 0; i < n_fields && malformed == FALSE; i++) {
const gchar *field;
const gchar *type;
field = e_contact_field_name (fields[i]);
type = e_enum_to_string (E_TYPE_BOOK_INDEX_TYPE, types[i]);
if (!field) {
g_warning ("Invalid contact field specified in indexed fields");
malformed = TRUE;
} else if (!type) {
g_warning ("Invalid index type specified in indexed fields");
malformed = TRUE;
} else {
if (i > 0)
g_string_append_c (string, ':');
g_string_append_printf (string, "%s,%s", field, type);
}
}
if (!malformed)
source_backend_summary_setup_set_literal_fields (extension, string->str, PROP_INDEXED_FIELDS);
g_string_free (string, TRUE);
}
/**
* e_source_backend_summary_setup_set_indexed_fields:
* @extension: An #ESourceBackendSummarySetup
* @...: A list of #EContactFields, #EBookIndexType pairs terminated by 0.
*
* Like e_source_backend_summary_setup_set_indexed_fieldsv(), but takes a literal list of
* of indexes.
*
* To give the 'fullname' field an index for prefix and suffix searches:
*
* |[
* #include
*
* ESourceBackendSummarySetup *extension;
*
* extension = e_source_get_extension (source, E_SOURCE_EXTENSION_BACKEND_SUMMARY_SETUP);
*
* e_source_backend_summary_setup_set_indexed_fields (extension,
* E_CONTACT_FULL_NAME, E_BOOK_INDEX_PREFIX,
* E_CONTACT_FULL_NAME, E_BOOK_INDEX_SUFFIX,
* 0);
* ]|
*
* Since: 3.8
*/
void
e_source_backend_summary_setup_set_indexed_fields (ESourceBackendSummarySetup *extension,
...)
{
GString *string;
gboolean malformed = FALSE, first = TRUE;
va_list var_args;
EContactField field_in;
EBookIndexType type_in;
g_return_if_fail (E_IS_SOURCE_BACKEND_SUMMARY_SETUP (extension));
string = g_string_new (NULL);
va_start (var_args, extension);
field_in = va_arg (var_args, EContactField);
while (field_in > 0 && malformed == FALSE) {
const gchar *field;
const gchar *type;
field = e_contact_field_name (field_in);
if (field == NULL) {
g_warning ("Invalid contact field specified in "
"e_source_backend_summary_setup_set_indexed_fields()");
malformed = TRUE;
break;
}
type_in = va_arg (var_args, EBookIndexType);
type = e_enum_to_string (E_TYPE_BOOK_INDEX_TYPE, type_in);
if (type == NULL) {
g_warning ("Invalid index type "
"e_source_backend_summary_setup_set_indexed_fields()");
malformed = TRUE;
break;
}
if (!first)
g_string_append_c (string, ':');
else
first = FALSE;
g_string_append_printf (string, "%s,%s", field, type);
/* Continue loop until first 0 found... */
field_in = va_arg (var_args, EContactField);
}
va_end (var_args);
if (!malformed)
source_backend_summary_setup_set_literal_fields (extension, string->str, PROP_INDEXED_FIELDS);
g_string_free (string, TRUE);
}