efl/src/lib/elementary/elm_prefs.c

1863 lines
48 KiB
C

#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#ifdef _WIN32
# include <evil_private.h> /* strsep */
#endif
#define EFL_ACCESS_OBJECT_PROTECTED
#include <Elementary.h>
#include "elm_priv.h"
#include "elm_prefs_eo.h"
#include "elm_widget_prefs.h"
#include "elm_prefs_edd.x"
#define MY_CLASS ELM_PREFS_CLASS
#define MY_CLASS_NAME "Elm_Prefs"
#define MY_CLASS_NAME_LEGACY "elm_prefs"
static const char SIG_PAGE_CHANGED[] = "page,changed";
static const char SIG_PAGE_SAVED[] = "page,saved";
static const char SIG_PAGE_RESET[] = "page,reset";
static const char SIG_PAGE_LOADED[] = "page,loaded";
static const char SIG_ITEM_CHANGED[] = "item,changed";
static const char SIG_ACTION[] = "action";
static const Evas_Smart_Cb_Description _elm_prefs_smart_callbacks[] = {
{ SIG_PAGE_CHANGED, "s" },
{ SIG_PAGE_SAVED, "s" },
{ SIG_PAGE_RESET, "s" },
{ SIG_PAGE_LOADED, "s" },
{ SIG_ITEM_CHANGED, "s" },
{ SIG_ACTION, "ss" },
{ NULL, NULL}
};
static int _elm_prefs_init_count = 0;
static Eina_Hash *_elm_prefs_page_widgets_map = NULL;
static const Elm_Prefs_Page_Iface *_elm_prefs_page_default_widget = NULL;
static Eina_Hash *_elm_prefs_item_widgets_map = NULL;
static Eina_Hash *_elm_prefs_item_type_widgets_map = NULL;
static const Elm_Prefs_Item_Iface *_elm_prefs_item_default_widget = NULL;
static void _elm_prefs_values_get_default(Elm_Prefs_Page_Node *,
Eina_Bool);
static Eina_Bool _prefs_item_widget_value_from_self(Elm_Prefs_Item_Node *,
Eina_Bool);
EOLIAN static void
_elm_prefs_efl_canvas_group_group_add(Eo *obj, Elm_Prefs_Data *_pd EINA_UNUSED)
{
efl_canvas_group_add(efl_super(obj, MY_CLASS));
}
static void _item_free(Elm_Prefs_Item_Node *it);
static void
_page_free(Elm_Prefs_Page_Node *p)
{
Elm_Prefs_Item_Node *it;
if (!p) return;
eina_stringshare_del(p->name);
eina_stringshare_del(p->title);
eina_stringshare_del(p->sub_title);
eina_stringshare_del(p->widget);
eina_stringshare_del(p->style);
eina_stringshare_del(p->icon);
evas_object_del(p->w_obj);
EINA_LIST_FREE(p->items, it)
_item_free(it);
free(p);
}
static void
_item_free(Elm_Prefs_Item_Node *it)
{
switch (it->type)
{
case ELM_PREFS_TYPE_ACTION:
case ELM_PREFS_TYPE_BOOL:
case ELM_PREFS_TYPE_INT:
case ELM_PREFS_TYPE_FLOAT:
case ELM_PREFS_TYPE_LABEL:
case ELM_PREFS_TYPE_DATE:
case ELM_PREFS_TYPE_RESET:
case ELM_PREFS_TYPE_SAVE:
case ELM_PREFS_TYPE_SEPARATOR:
case ELM_PREFS_TYPE_SWALLOW:
break;
case ELM_PREFS_TYPE_PAGE:
eina_stringshare_del(it->spec.p.source);
_page_free(it->subpage);
it->w_obj = NULL;
break;
case ELM_PREFS_TYPE_TEXT:
case ELM_PREFS_TYPE_TEXTAREA:
eina_stringshare_del(it->spec.s.placeholder);
eina_stringshare_del(it->spec.s.accept);
eina_stringshare_del(it->spec.s.deny);
break;
default:
ERR("bad item (type = %d), skipping it", it->type);
break;
}
eina_stringshare_del(it->name);
eina_stringshare_del(it->label);
eina_stringshare_del(it->icon);
eina_stringshare_del(it->style);
eina_stringshare_del(it->widget);
evas_object_del(it->w_obj); /* we have to delete them ourselves
* because of _prefs_item_del_cb() --
* it'll need the parent alive, to
* gather its smart data bit */
free(it);
}
static Eina_Bool
_elm_prefs_save(void *data)
{
ELM_PREFS_DATA_GET(data, sd);
ELM_WIDGET_DATA_GET_OR_RETURN(data, wd, ECORE_CALLBACK_CANCEL);
if (!sd->dirty || !sd->prefs_data) goto end;
if (!elm_prefs_data_autosave_get(sd->prefs_data))
{
elm_prefs_data_save(sd->prefs_data, NULL, NULL);
efl_event_callback_legacy_call
(data, ELM_PREFS_EVENT_PAGE_SAVED, (char *)sd->root->name);
}
sd->dirty = EINA_FALSE;
end:
sd->saving_poller = NULL;
return ECORE_CALLBACK_CANCEL;
}
static void
_root_node_free(Elm_Prefs_Data *sd)
{
_page_free(sd->root);
}
static Eina_Bool
_prefs_data_types_match(const Eina_Value_Type *t,
Elm_Prefs_Item_Type epd_t)
{
return (t == EINA_VALUE_TYPE_UCHAR && epd_t == ELM_PREFS_TYPE_BOOL) ||
(t == EINA_VALUE_TYPE_INT && epd_t == ELM_PREFS_TYPE_INT) ||
(t == EINA_VALUE_TYPE_FLOAT && epd_t == ELM_PREFS_TYPE_FLOAT) ||
(t == EINA_VALUE_TYPE_TIMEVAL && epd_t == ELM_PREFS_TYPE_DATE) ||
(t == EINA_VALUE_TYPE_STRINGSHARE &&
(epd_t == ELM_PREFS_TYPE_PAGE ||
epd_t == ELM_PREFS_TYPE_TEXT ||
epd_t == ELM_PREFS_TYPE_TEXTAREA));
}
static Eina_Bool
_prefs_data_type_fix(Elm_Prefs_Item_Node *it,
Eina_Value *value)
{
Eina_Value v;
Eina_Bool setup_err = EINA_FALSE;
switch (it->type)
{
case ELM_PREFS_TYPE_BOOL:
if (!eina_value_setup(&v, EINA_VALUE_TYPE_UCHAR))
setup_err = EINA_TRUE;
break;
case ELM_PREFS_TYPE_INT:
if (!eina_value_setup(&v, EINA_VALUE_TYPE_INT))
setup_err = EINA_TRUE;
break;
case ELM_PREFS_TYPE_FLOAT:
if (!eina_value_setup(&v, EINA_VALUE_TYPE_FLOAT))
setup_err = EINA_TRUE;
break;
case ELM_PREFS_TYPE_DATE:
if (!eina_value_setup(&v, EINA_VALUE_TYPE_TIMEVAL))
setup_err = EINA_TRUE;
break;
case ELM_PREFS_TYPE_PAGE:
case ELM_PREFS_TYPE_TEXT:
case ELM_PREFS_TYPE_TEXTAREA:
if (!eina_value_setup(&v, EINA_VALUE_TYPE_STRINGSHARE))
setup_err = EINA_TRUE;
break;
default:
ERR("bad item (type = %d) found, skipping it", it->type);
return EINA_FALSE;
}
if (setup_err) return EINA_FALSE;
if (!eina_value_convert(value, &v) || !eina_value_copy(&v, value))
{
ERR("problem converting mismatching item (%s) value",
it->name);
return EINA_FALSE;
}
eina_value_flush(&v);
return EINA_TRUE;
}
static Eina_Bool
_prefs_item_widget_value_from_data(Elm_Prefs_Data *sd,
Elm_Prefs_Item_Node *it,
Eina_Value *value)
{
char buf[PATH_MAX];
const Eina_Value_Type *t = eina_value_type_get(value);
if ((it->type <= ELM_PREFS_TYPE_UNKNOWN) ||
(it->type > ELM_PREFS_TYPE_SWALLOW))
{
ERR("bad item (type = %d) found on page %s, skipping it",
it->type, sd->page);
return EINA_FALSE;
}
snprintf(buf, sizeof(buf), "%s:%s", it->page->name, it->name);
if (!_prefs_data_types_match(t, it->type))
{
if (!_prefs_data_type_fix(it, value)) return EINA_FALSE;
else
{
Eina_Bool v_set;
sd->changing_from_ui = EINA_TRUE;
v_set = elm_prefs_data_value_set(sd->prefs_data,
buf, it->type, value);
sd->changing_from_ui = EINA_FALSE;
if (!v_set) return EINA_FALSE;
}
}
if (!it->available)
{
ERR("widget of item %s has been deleted, we can't set values on it",
it->name);
return EINA_FALSE;
}
if (!it->w_impl->value_set(it->w_obj, value))
{
ERR("failed to set value on widget of item %s", it->name);
return EINA_FALSE;
}
return EINA_TRUE;
}
static void
_elm_prefs_mark_as_dirty(Eo *obj)
{
ELM_PREFS_DATA_GET(obj, sd);
sd->dirty = EINA_TRUE;
if (sd->autosave)
{
if (sd->saving_poller) return;
sd->saving_poller = ecore_poller_add
(ECORE_POLLER_CORE, 1, _elm_prefs_save, obj);
}
}
static void
_elm_prefs_item_changed_report(Eo *obj,
Elm_Prefs_Item_Node *it)
{
char buf[PATH_MAX];
ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
snprintf(buf, sizeof(buf), "%s:%s", it->page->name, it->name);
efl_event_callback_legacy_call
(obj, ELM_PREFS_EVENT_ITEM_CHANGED, buf);
}
static Elm_Prefs_Item_Node *
_elm_prefs_page_item_by_name(Elm_Prefs_Page_Node *p,
char **path)
{
Elm_Prefs_Item_Node *it;
Eina_List *l;
char *token;
token = strsep(path, ":");
EINA_LIST_FOREACH(p->items, l, it)
{
if (strcmp(it->name, token)) continue;
if (!*path)
return it;
else if (it->type == ELM_PREFS_TYPE_PAGE)
return _elm_prefs_page_item_by_name(it->subpage, path);
}
return NULL;
}
static Elm_Prefs_Item_Node *
_elm_prefs_item_node_by_name(Elm_Prefs_Data *sd,
const char *name)
{
char buf[PATH_MAX];
char *token;
char *aux = buf;
strncpy(buf, name, PATH_MAX - 1);
buf[PATH_MAX - 1] = '\0';
token = strsep(&aux, ":");
if (strcmp(sd->root->name, token))
return NULL; // first token should be the current page name
return _elm_prefs_page_item_by_name(sd->root, &aux);
}
static Eina_List *
_elm_prefs_item_list_node_by_name(Elm_Prefs_Data *sd,
const char *name)
{
Elm_Prefs_Item_Node *it;
Eina_List *l;
EINA_LIST_FOREACH(sd->root->items, l, it)
if (!strcmp(it->name, name)) return l;
return NULL;
}
static void
_prefs_data_item_changed_cb(void *cb_data,
Elm_Prefs_Data_Event_Type type EINA_UNUSED,
Elm_Prefs_Data *prefs_data,
void *event_info)
{
Elm_Prefs_Data_Event_Changed *evt = event_info;
Eo *obj = cb_data;
Elm_Prefs_Item_Node *it;
Eina_Value value;
ELM_PREFS_DATA_GET(obj, sd);
if (sd->changing_from_ui) return;
it = _elm_prefs_item_node_by_name(sd, evt->key);
if (!it) return;
if (elm_prefs_data_value_get(prefs_data, evt->key, NULL, &value))
{
if (!_prefs_item_widget_value_from_data(sd, it, &value)) goto end;
_elm_prefs_item_changed_report(obj, it);
_elm_prefs_mark_as_dirty(obj);
}
else
ERR("failed to fetch value from data after changed event");
end:
eina_value_flush(&value);
return;
}
static void
_prefs_data_autosaved_cb(void *cb_data,
Elm_Prefs_Data_Event_Type type EINA_UNUSED,
Elm_Prefs_Data *data EINA_UNUSED,
void *event_info)
{
ELM_PREFS_DATA_GET(cb_data, sd);
ELM_WIDGET_DATA_GET_OR_RETURN(cb_data, wd);
efl_event_callback_legacy_call
(cb_data, ELM_PREFS_EVENT_PAGE_SAVED, event_info);
sd->dirty = EINA_FALSE;
}
static Eina_Bool
_elm_prefs_data_cbs_add(Eo *obj,
Elm_Prefs_Data *prefs_data)
{
if (!elm_prefs_data_event_callback_add
(prefs_data, ELM_PREFS_DATA_EVENT_ITEM_CHANGED,
_prefs_data_item_changed_cb, obj) ||
!elm_prefs_data_event_callback_add
(prefs_data, ELM_PREFS_DATA_EVENT_GROUP_AUTOSAVED,
_prefs_data_autosaved_cb, obj))
{
ERR("error while adding item changed event callback to "
"prefs data handle, keeping previous data");
return EINA_FALSE;
}
return EINA_TRUE;
}
static void
_elm_prefs_data_cbs_del(Eo *obj)
{
ELM_PREFS_DATA_GET(obj, sd);
if (!sd->prefs_data) return;
if (!elm_prefs_data_event_callback_del
(sd->prefs_data, ELM_PREFS_DATA_EVENT_ITEM_CHANGED,
_prefs_data_item_changed_cb, obj))
ERR("error while removing item changed event callback from "
"prefs data handle");
if (!elm_prefs_data_event_callback_del
(sd->prefs_data, ELM_PREFS_DATA_EVENT_GROUP_AUTOSAVED,
_prefs_data_autosaved_cb, obj))
ERR("error while removing page autosave event callback from "
"prefs data handle");
}
EOLIAN static void
_elm_prefs_efl_canvas_group_group_del(Eo *obj, Elm_Prefs_Data *sd)
{
sd->delete_me = EINA_TRUE;
if (sd->saving_poller) ecore_poller_del(sd->saving_poller);
_elm_prefs_data_cbs_del(obj);
if (sd->root)
{
elm_prefs_data_version_set(sd->prefs_data, sd->root->version);
_elm_prefs_save(obj);
_root_node_free(sd);
}
if (sd->prefs_data) elm_prefs_data_unref(sd->prefs_data);
eina_stringshare_del(sd->file);
eina_stringshare_del(sd->page);
efl_canvas_group_del(efl_super(obj, MY_CLASS));
}
EAPI Evas_Object *
elm_prefs_add(Evas_Object *parent)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
if (!_elm_prefs_init_count)
{
CRI("prefs_iface module is not loaded! you can't"
" create prefs widgets");
return NULL;
}
return elm_legacy_add(MY_CLASS, parent);
}
EOLIAN static Eo *
_elm_prefs_efl_object_constructor(Eo *obj, Elm_Prefs_Data *_pd EINA_UNUSED)
{
obj = efl_constructor(efl_super(obj, MY_CLASS));
efl_canvas_object_type_set(obj, MY_CLASS_NAME_LEGACY);
evas_object_smart_callbacks_descriptions_set(obj, _elm_prefs_smart_callbacks);
efl_access_object_role_set(obj, EFL_ACCESS_ROLE_REDUNDANT_OBJECT);
return obj;
}
static Eina_Bool
_elm_prefs_item_has_value(Elm_Prefs_Item_Node *it)
{
return (it->type != ELM_PREFS_TYPE_ACTION) &&
(it->type != ELM_PREFS_TYPE_LABEL) &&
(it->type != ELM_PREFS_TYPE_RESET) &&
(it->type != ELM_PREFS_TYPE_SAVE) &&
(it->type != ELM_PREFS_TYPE_PAGE) &&
(it->type != ELM_PREFS_TYPE_SEPARATOR) &&
(it->type != ELM_PREFS_TYPE_SWALLOW);
}
static void
_item_changed_cb(Evas_Object *it_obj)
{
char buf[PATH_MAX];
Elm_Prefs_Item_Node *it = evas_object_data_get(it_obj, "prefs_item");
/* some widgets mark themselves changed as early as in their add()
* interface methods */
if (!it) return;
snprintf(buf, sizeof(buf), "%s:%s", it->page->name, it->name);
ELM_PREFS_DATA_GET(it->prefs, sd);
ELM_WIDGET_DATA_GET_OR_RETURN(it->prefs, wd);
if (sd->values_fetching) goto end;
/* we use the changed cb on ACTION/RESET/SAVE items specially */
if (it->type == ELM_PREFS_TYPE_ACTION)
{
efl_event_callback_legacy_call
(it->prefs, ELM_PREFS_EVENT_ACTION, buf);
return;
}
else if (it->type == ELM_PREFS_TYPE_RESET)
{
_elm_prefs_values_get_default(sd->root, EINA_TRUE);
_elm_prefs_mark_as_dirty(it->prefs);
return;
}
else if (it->type == ELM_PREFS_TYPE_SAVE)
{
if (sd->saving_poller) return;
sd->saving_poller = ecore_poller_add
(ECORE_POLLER_CORE, 1, _elm_prefs_save, it->prefs);
return;
}
if (!it->persistent || !_elm_prefs_item_has_value(it)) return;
if (it->w_impl->value_validate &&
!it->w_impl->value_validate(it->w_obj))
{
if (sd->prefs_data)
{
Eina_Value value;
// Restoring to the last valid value.
if (!elm_prefs_data_value_get(sd->prefs_data, buf, NULL, &value))
goto restore_fail;
if (!it->w_impl->value_set(it->w_obj, &value))
{
eina_value_flush(&value);
goto restore_fail;
}
}
else
{
if (!_prefs_item_widget_value_from_self(it, EINA_FALSE))
goto restore_fail;
}
return;
}
end:
if (sd->prefs_data)
{
Eina_Value value;
if (!it->w_impl->value_get(it->w_obj, &value))
ERR("failed to fetch value from widget of item %s", buf);
else
{
sd->changing_from_ui = EINA_TRUE;
elm_prefs_data_value_set(sd->prefs_data, buf, it->type, &value);
eina_value_flush(&value);
sd->changing_from_ui = EINA_FALSE;
}
}
if (!sd->values_fetching) _elm_prefs_item_changed_report(it->prefs, it);
_elm_prefs_mark_as_dirty(it->prefs);
return;
restore_fail:
ERR("failed to restore the last valid value from widget of item %s",
buf);
}
static Eina_Bool
_prefs_item_widget_value_from_self(Elm_Prefs_Item_Node *it,
Eina_Bool mark_changed)
{
Eina_Value value;
if (!_elm_prefs_item_has_value(it)) return EINA_TRUE;
switch (it->type)
{
case ELM_PREFS_TYPE_BOOL:
if (!eina_value_setup(&value, EINA_VALUE_TYPE_UCHAR)) goto err;
if (!eina_value_set(&value, it->spec.b.def))
{
eina_value_flush(&value);
goto err;
}
break;
case ELM_PREFS_TYPE_INT:
if (!eina_value_setup(&value, EINA_VALUE_TYPE_INT)) goto err;
if (!eina_value_set(&value, it->spec.i.def))
{
eina_value_flush(&value);
goto err;
}
break;
case ELM_PREFS_TYPE_FLOAT:
if (!eina_value_setup(&value, EINA_VALUE_TYPE_FLOAT)) goto err;
if (!eina_value_set(&value, it->spec.f.def))
{
eina_value_flush(&value);
goto err;
}
break;
case ELM_PREFS_TYPE_DATE:
{
struct timeval val;
struct tm t;
memset(&t, 0, sizeof t);
memset(&val, 0, sizeof val);
t.tm_year = it->spec.d.def.y - 1900;
t.tm_mon = it->spec.d.def.m - 1;
t.tm_mday = it->spec.d.def.d;
val.tv_sec = mktime(&t);
if (!eina_value_setup(&value, EINA_VALUE_TYPE_TIMEVAL)) goto err;
if (!eina_value_set(&value, val))
{
eina_value_flush(&value);
goto err;
}
}
break;
case ELM_PREFS_TYPE_TEXT:
case ELM_PREFS_TYPE_TEXTAREA:
if (!eina_value_setup(&value, EINA_VALUE_TYPE_STRINGSHARE)) goto err;
if (!eina_value_set(&value, it->spec.s.placeholder))
{
eina_value_flush(&value);
goto err;
}
break;
case ELM_PREFS_TYPE_PAGE:
case ELM_PREFS_TYPE_SEPARATOR: //page is the value setter for separators
case ELM_PREFS_TYPE_SWALLOW: //prefs is the value setter for swallows
return EINA_TRUE;
default:
ERR("bad item (type = %d) found, skipping it", it->type);
return EINA_FALSE;
}
if (!it->available)
{
ERR("widget of item %s has been deleted, we can't set values on it",
it->name);
eina_value_flush(&value);
return EINA_FALSE;
}
if (!it->w_impl->value_set(it->w_obj, &value)) goto err;
else
{
if (mark_changed) _item_changed_cb(it->w_obj);
eina_value_flush(&value);
return EINA_TRUE;
}
err:
ERR("failed to set value on widget of item %s", it->name);
return EINA_FALSE;
}
static Eina_Bool
_elm_prefs_page_widget_new(Evas_Object *obj,
Elm_Prefs_Page_Node *page)
{
page->parent = obj;
if (page->widget)
{
page->w_impl =
eina_hash_find(_elm_prefs_page_widgets_map, page->widget);
if (!page->w_impl)
{
ERR("widget %s is not eligible to implement page %s,"
"trying default widget for pages",
page->widget, page->name);
}
else goto wid_found;
}
else
INF("no explicit widget declared for page %s,"
" trying default widget for pages", page->name);
page->w_impl = _elm_prefs_page_default_widget;
ERR("no widget bound to this page, fallbacking to default widget");
wid_found:
page->w_obj = page->w_impl->add(page->w_impl, obj);
if (!page->w_obj)
{
ERR("error while adding UI element to prefs widget %p", obj);
return EINA_FALSE;
}
if (page->title && page->w_impl->title_set)
{
if (!page->w_impl->title_set(page->w_obj, page->title))
{
ERR("failed to set title %s on page %s",
page->title, page->name);
}
}
if (page->sub_title && page->w_impl->sub_title_set)
{
if (!page->w_impl->sub_title_set(page->w_obj, page->sub_title))
{
ERR("failed to set sub_title %s on page %s",
page->sub_title, page->name);
}
}
if (page->icon && page->w_impl->icon_set)
{
if (!page->w_impl->icon_set(page->w_obj, page->icon))
{
ERR("failed to set icon %s on page %s",
page->icon, page->name);
}
}
evas_object_data_set(page->w_obj, "prefs_page", page);
evas_object_show(page->w_obj);
return EINA_TRUE;
}
static void
_elm_prefs_item_external_label_inject(Elm_Prefs_Item_Node *it)
{
Evas_Object *label = elm_label_add(it->w_obj);
elm_layout_text_set(label, NULL, it->label);
evas_object_data_set(it->w_obj, "label_widget", label);
evas_object_show(label);
}
static void
_elm_prefs_item_external_icon_inject(Elm_Prefs_Item_Node *it)
{
Evas_Object *icon = elm_icon_add(it->w_obj);
elm_icon_standard_set(icon, it->icon);
elm_image_resizable_set(icon, EINA_FALSE, EINA_FALSE);
evas_object_data_set(it->w_obj, "icon_widget", icon);
evas_object_show(icon);
}
static void
_elm_prefs_item_properties_apply(Elm_Prefs_Item_Node *item)
{
if (item->label)
{
if (item->w_impl->label_set)
{
if (!item->w_impl->label_set(item->w_obj, item->label))
{
ERR("failed to set label %s on item %s through widget"
" implementation method, fallbacking to page's "
"method", item->label, item->name);
_elm_prefs_item_external_label_inject(item);
}
}
else
_elm_prefs_item_external_label_inject(item);
}
if (item->icon)
{
if (item->w_impl->icon_set)
{
if (!item->w_impl->icon_set(item->w_obj, item->icon))
{
ERR("failed to set icon %s on item %s through widget"
" implementation method, fallbacking to page's "
"method", item->label, item->name);
_elm_prefs_item_external_icon_inject(item);
}
}
else
_elm_prefs_item_external_icon_inject(item);
}
if (item->w_impl->editable_set &&
!item->w_impl->editable_set(item->w_obj, item->editable))
{
ERR("failed to set editability (%d) on item %s",
item->editable, item->name);
}
if (item->style && !elm_object_style_set(item->w_obj, item->style))
{
ERR("failed to set style %s on item %s",
item->style, item->name);
}
}
static Eina_Bool
_elm_prefs_item_widget_new(Evas_Object *obj,
Elm_Prefs_Page_Node *parent,
Elm_Prefs_Item_Node *item)
{
item->prefs = obj;
item->available = EINA_TRUE;
item->page = parent;
if (item->widget)
{
item->w_impl =
eina_hash_find(_elm_prefs_item_widgets_map, item->widget);
if (!item->w_impl)
{
ERR("widget %s is not eligible to implement item of"
" type %d, trying default widget for that type",
item->widget, item->type);
}
else goto wid_found;
}
else
INF("no explicit item widget declared for %s,"
" trying default widget for its type (%d)", item->name, item->type);
item->w_impl =
eina_hash_find(_elm_prefs_item_type_widgets_map, &item->type);
if (!item->w_impl)
{
item->w_impl = _elm_prefs_item_default_widget;
ERR("no widget bound to this type, fallbacking to "
"default widget");
}
wid_found:
item->w_obj = item->w_impl->add(
item->w_impl, obj, item->type, item->spec, _item_changed_cb);
if (!item->w_obj)
{
ERR("error while adding UI element to prefs widget %p", obj);
return EINA_FALSE;
}
evas_object_data_set(item->w_obj, "prefs_item", item);
_elm_prefs_item_properties_apply(item);
evas_object_show(item->w_obj);
return EINA_TRUE;
}
static Elm_Prefs_Page_Node *
_elm_prefs_page_load(Evas_Object *obj,
const char *pname)
{
Eet_File *eet_file;
Elm_Prefs_Page_Node *ret = NULL;
ELM_PREFS_CHECK(obj) NULL;
EINA_SAFETY_ON_NULL_RETURN_VAL(pname, NULL);
ELM_PREFS_DATA_GET(obj, sd);
eet_file = eet_open(sd->file, EET_FILE_MODE_READ);
if (eet_file)
{
ret = eet_data_read(eet_file, _page_edd, pname);
eet_close(eet_file);
if (!ret)
ERR("problem while reading from file %s, key %s", sd->file, pname);
else
ret->prefs = obj;
}
else
ERR("failed to load from requested epb file (%s)", sd->file);
return ret;
}
static Eina_Bool
_elm_prefs_page_populate(Elm_Prefs_Page_Node *page,
Evas_Object *parent)
{
Elm_Prefs_Page_Node *subpage;
Elm_Prefs_Item_Node *it;
Eina_List *l;
EINA_SAFETY_ON_NULL_RETURN_VAL(page, EINA_FALSE);
if (!_elm_prefs_page_widget_new(parent, page)) goto err;
EINA_LIST_FOREACH(page->items, l, it)
{
if ((it->type <= ELM_PREFS_TYPE_UNKNOWN) ||
(it->type > ELM_PREFS_TYPE_SWALLOW))
{
ERR("bad item (type = %d) found on page %s, skipping it",
it->type, page->name);
continue;
}
else if (it->type == ELM_PREFS_TYPE_PAGE)
{
subpage = _elm_prefs_page_load(page->prefs, it->spec.p.source);
if (!subpage)
{
ERR("subpage %s could not be created inside %s, skipping it",
it->name, page->name);
continue;
}
eina_stringshare_del(subpage->name);
subpage->name = eina_stringshare_printf("%s:%s",
page->name, it->name);
if (!_elm_prefs_page_populate(subpage, page->w_obj))
{
_page_free(subpage);
goto err;
}
it->prefs = page->prefs;
it->page = page;
it->w_obj = subpage->w_obj;
it->w_impl = NULL;
it->available = EINA_TRUE;
it->subpage = subpage;
}
else if (!_elm_prefs_item_widget_new(page->prefs, page, it)) goto err;
if (it->visible && !page->w_impl->item_pack
(page->w_obj, it->w_obj, it->type, it->w_impl))
{
ERR("item %s could not be packed inside page %s",
it->name, page->name);
goto err;
}
}
return EINA_TRUE;
err:
EINA_LIST_FOREACH(page->items, l, it)
{
ELM_SAFE_FREE(it->w_obj, evas_object_del);
it->w_impl = NULL;
}
ELM_SAFE_FREE(page->w_obj, evas_object_del);
page->w_impl = NULL;
return EINA_FALSE;
}
static void
_elm_prefs_values_get_default(Elm_Prefs_Page_Node *page,
Eina_Bool mark_changed)
{
Eina_List *l;
Elm_Prefs_Item_Node *it;
EINA_LIST_FOREACH(page->items, l, it)
{
if (it->type == ELM_PREFS_TYPE_PAGE)
_elm_prefs_values_get_default(it->subpage, mark_changed);
else
_prefs_item_widget_value_from_self(it, mark_changed);
}
}
static void
_elm_prefs_values_get_user(Elm_Prefs_Data *sd,
Elm_Prefs_Page_Node *p)
{
char buf[PATH_MAX];
Eina_List *l;
Eina_Value value;
Elm_Prefs_Item_Node *it;
if (!sd->file) return;
EINA_LIST_FOREACH(p->items, l, it)
{
Eina_Bool get_err = EINA_FALSE, set_err = EINA_FALSE;
if (it->type == ELM_PREFS_TYPE_PAGE)
{
Elm_Prefs_Page_Node *subp = it->subpage;
if (!elm_prefs_data_value_get
(sd->prefs_data, subp->name, NULL, &value))
{
INF("failed to fetch value for item %s on user data, "
"writing UI value back on it", it->name);
if (eina_value_setup(&value, EINA_VALUE_TYPE_STRINGSHARE) &&
eina_value_set(&value, subp->name))
{
sd->changing_from_ui = EINA_TRUE;
elm_prefs_data_value_set
(sd->prefs_data, subp->name, it->type, &value);
sd->changing_from_ui = EINA_FALSE;
}
}
_elm_prefs_values_get_user(sd, subp);
eina_value_flush(&value);
continue;
}
if (!_elm_prefs_item_has_value(it)) continue;
if (!it->persistent) continue;
snprintf(buf, sizeof(buf), "%s:%s", p->name, it->name);
if (!elm_prefs_data_value_get(sd->prefs_data, buf, NULL, &value))
get_err = EINA_TRUE;
else if (!_prefs_item_widget_value_from_data(sd, it, &value))
set_err = EINA_TRUE;
if (get_err || set_err)
{
if (get_err)
INF("failed to fetch value for item %s on user data, "
"writing UI value back on it", it->name);
/* force writing back our default value for it */
if (it->available)
{
if (!it->w_impl->value_get(it->w_obj, &value))
ERR("failed to fetch value from widget of item %s",
it->name);
else
{
sd->changing_from_ui = EINA_TRUE;
elm_prefs_data_value_set
(sd->prefs_data, buf, it->type, &value);
sd->changing_from_ui = EINA_FALSE;
}
}
}
eina_value_flush(&value);
}
}
EOLIAN static Eina_Bool
_elm_prefs_data_set(Eo *obj, Elm_Prefs_Data *sd, Elm_Prefs_Data *prefs_data)
{
if (!sd->root) return EINA_FALSE;
if (prefs_data && !_elm_prefs_data_cbs_add(obj, prefs_data))
return EINA_FALSE;
if (sd->prefs_data)
{
_elm_prefs_data_cbs_del(obj);
elm_prefs_data_unref(sd->prefs_data);
}
sd->prefs_data = prefs_data;
if (!sd->prefs_data)
{
INF("resetting prefs to default values");
_elm_prefs_values_get_default(sd->root, EINA_FALSE);
goto end;
}
elm_prefs_data_ref(sd->prefs_data);
sd->values_fetching = EINA_TRUE;
_elm_prefs_values_get_user(sd, sd->root);
sd->values_fetching = EINA_FALSE;
end:
efl_event_callback_legacy_call
(obj, ELM_PREFS_EVENT_PAGE_CHANGED, (char *)sd->root->name);
return EINA_TRUE;
}
EOLIAN static Elm_Prefs_Data*
_elm_prefs_data_get(const Eo *obj EINA_UNUSED, Elm_Prefs_Data *sd)
{
if (!sd->root) return NULL;
else return sd->prefs_data;
}
EOLIAN static void
_elm_prefs_autosave_set(Eo *obj, Elm_Prefs_Data *_pd EINA_UNUSED, Eina_Bool autosave)
{
ELM_PREFS_DATA_GET(obj, sd);
autosave = !!autosave;
if (sd->autosave != autosave)
sd->autosave = autosave;
else
return;
if ((sd->autosave) && (sd->dirty))
{
if (sd->saving_poller) return;
sd->saving_poller = ecore_poller_add
(ECORE_POLLER_CORE, 1, _elm_prefs_save, obj);
}
else if ((!sd->autosave) && (sd->saving_poller))
{
ecore_poller_del(sd->saving_poller);
sd->saving_poller = NULL;
_elm_prefs_save(obj);
}
}
EOLIAN static Eina_Bool
_elm_prefs_autosave_get(const Eo *obj EINA_UNUSED, Elm_Prefs_Data *sd)
{
return sd->autosave;
}
EOLIAN static void
_elm_prefs_reset(Eo *obj EINA_UNUSED, Elm_Prefs_Data *sd, Elm_Prefs_Reset_Mode mode)
{
EINA_SAFETY_ON_NULL_RETURN(sd->root);
if (mode == ELM_PREFS_RESET_DEFAULTS)
_elm_prefs_values_get_default(sd->root, EINA_TRUE);
else if (mode == ELM_PREFS_RESET_LAST)
WRN("ELM_PREFS_RESET_LAST not implemented yet");
}
static Elm_Prefs_Item_Node *
_elm_prefs_item_api_entry_common(const Evas_Object *obj,
const char *it_name)
{
Elm_Prefs_Item_Node *ret;
ELM_PREFS_CHECK(obj) NULL;
ELM_PREFS_DATA_GET(obj, sd);
EINA_SAFETY_ON_NULL_RETURN_VAL(it_name, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(sd->root, NULL);
ret = _elm_prefs_item_node_by_name(sd, it_name);
if (!ret) ERR("item with name %s does not exist on file %s",
it_name, sd->file);
return ret;
}
EOLIAN static Eina_Bool
_elm_prefs_item_value_set(Eo *obj, Elm_Prefs_Data *_pd EINA_UNUSED, const char *name, const Eina_Value *value)
{
const Eina_Value_Type *t, *def_t;
Elm_Prefs_Item_Node *it;
Eina_Value it_val;
it = _elm_prefs_item_api_entry_common(obj, name);
if (!it) return EINA_FALSE;
if (!_elm_prefs_item_has_value(it))
{
ERR("item %s has no underlying value, you can't operate on it",
it->name);
return EINA_FALSE;
}
EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
t = eina_value_type_get(value);
if (!t) return EINA_FALSE;
if (!it->available)
{
ERR("widget of item %s has been deleted, we can't set values on it",
it->name);
return EINA_FALSE;
}
if (!it->w_impl->value_get(it->w_obj, &it_val))
{
ERR("failed to fetch value from widget of item %s", it->name);
goto err;
}
def_t = eina_value_type_get(&it_val);
if ((t != def_t) && (!eina_value_convert(value, &it_val)))
{
eina_value_flush(&it_val);
ERR("failed to convert value to proper type");
goto err;
}
else if (!eina_value_copy(value, &it_val) ||
(!it->w_impl->value_set(it->w_obj, &it_val)))
{
eina_value_flush(&it_val);
ERR("failed to set value on widget of item %s", it->name);
goto err;
}
eina_value_flush(&it_val);
return EINA_TRUE;
err:
return EINA_FALSE;
}
EOLIAN static Eina_Bool
_elm_prefs_item_value_get(const Eo *obj, Elm_Prefs_Data *_pd EINA_UNUSED, const char *name, Eina_Value *value)
{
Elm_Prefs_Item_Node *it;
it = _elm_prefs_item_api_entry_common(obj, name);
if (!it) return EINA_FALSE;
if (!_elm_prefs_item_has_value(it))
{
ERR("item %s has no underlying value, you can't operate on it",
it->name);
return EINA_FALSE;
}
if (!value) return EINA_FALSE;
if (!it->available)
{
ERR("widget of item %s has been deleted, we can't set values on it",
it->name);
return EINA_FALSE;
}
if (!it->w_impl->value_get(it->w_obj, value))
{
ERR("failed to fetch value from widget of item %s", it->name);
return EINA_FALSE;
}
return EINA_TRUE;
}
EOLIAN static const Evas_Object*
_elm_prefs_item_object_get(Eo *obj, Elm_Prefs_Data *_pd EINA_UNUSED, const char *name)
{
Elm_Prefs_Item_Node *it;
it = _elm_prefs_item_api_entry_common(obj, name);
if (!it) return NULL;
else return it->w_obj;
}
EOLIAN static void
_elm_prefs_item_visible_set(Eo *obj EINA_UNUSED, Elm_Prefs_Data *sd, const char *name, Eina_Bool visible)
{
Elm_Prefs_Item_Node *it;
Eina_List *l;
Evas_Object *lbl, *icon;
EINA_SAFETY_ON_NULL_RETURN(name);
EINA_SAFETY_ON_NULL_RETURN(sd->root);
l = _elm_prefs_item_list_node_by_name(sd, name);
if (!l) return;
it = eina_list_data_get(l);
visible = !!visible;
if (it->visible == visible) return;
it->visible = visible;
if (!it->available)
{
ERR("widget of item %s has been deleted, we can't act on it",
it->name);
return;
}
lbl = evas_object_data_get(it->w_obj, "label_widget");
icon = evas_object_data_get(it->w_obj, "icon_widget");
if (!it->visible)
{
if (!it->page->w_impl->item_unpack(it->page->w_obj, it->w_obj))
{
ERR("failed to unpack item %s from page %s!",
it->name, it->page->name);
}
else
{
if (lbl) evas_object_hide(lbl);
if (icon) evas_object_hide(icon);
evas_object_hide(it->w_obj);
}
}
else if (it->available)
{
Eina_List *p_l;
if ((p_l = eina_list_prev(l)))
{
Elm_Prefs_Item_Node *p_it = eina_list_data_get(p_l);
if (!it->page->w_impl->item_pack_after
(it->page->w_obj, it->w_obj,
p_it->w_obj, it->type, it->w_impl))
{
ERR("failed to pack item %s on page %s!",
it->name, it->page->name);
}
}
else if ((p_l = eina_list_next(l)))
{
Elm_Prefs_Item_Node *n_it = eina_list_data_get(p_l);
if (!it->page->w_impl->item_pack_before
(it->page->w_obj, it->w_obj,
n_it->w_obj, it->type, it->w_impl))
{
ERR("failed to pack item %s on page %s!",
it->name, it->page->name);
}
}
else if (!it->page->w_impl->item_pack
(it->page->w_obj, it->w_obj, it->type, it->w_impl))
ERR("failed to pack item %s on page %s!", it->name, it->page->name);
if (lbl) evas_object_show(lbl);
if (icon) evas_object_show(icon);
evas_object_show(it->w_obj);
}
}
EOLIAN static Eina_Bool
_elm_prefs_item_visible_get(const Eo *obj, Elm_Prefs_Data *_pd EINA_UNUSED, const char *name)
{
Elm_Prefs_Item_Node *it;
it = _elm_prefs_item_api_entry_common(obj, name);
if (!it) return EINA_FALSE;
if (!it->available)
{
ERR("widget of item %s has been deleted, we can't act on it",
it->name);
return EINA_FALSE;
}
return it->visible;
}
EOLIAN static void
_elm_prefs_item_disabled_set(Eo *obj, Elm_Prefs_Data *_pd EINA_UNUSED, const char *name, Eina_Bool disabled)
{
Elm_Prefs_Item_Node *it;
it = _elm_prefs_item_api_entry_common(obj, name);
if (!it) return;
if (!it->available)
{
ERR("widget of item %s has been deleted, we can't act on it",
it->name);
return;
}
elm_object_disabled_set(it->w_obj, disabled);
}
EOLIAN static Eina_Bool
_elm_prefs_item_disabled_get(const Eo *obj, Elm_Prefs_Data *_pd EINA_UNUSED, const char *name)
{
Elm_Prefs_Item_Node *it;
it = _elm_prefs_item_api_entry_common(obj, name);
if (!it) return EINA_FALSE;
if (!it->available)
{
ERR("widget of item %s has been deleted, we can't act on it",
it->name);
return EINA_FALSE;
}
return elm_object_disabled_get(it->w_obj);
}
EOLIAN static void
_elm_prefs_item_editable_set(Eo *obj, Elm_Prefs_Data *_pd EINA_UNUSED, const char *name, Eina_Bool editable)
{
Elm_Prefs_Item_Node *it;
it = _elm_prefs_item_api_entry_common(obj, name);
if (!it) return;
if (!it->w_impl->editable_set)
{
ERR("the item %s does not implement the 'editable' "
"property (using widget %s)", it->name, it->widget);
return;
}
it->w_impl->editable_set(it->w_obj, editable);
}
EOLIAN static Eina_Bool
_elm_prefs_item_editable_get(const Eo *obj, Elm_Prefs_Data *_pd EINA_UNUSED, const char *name)
{
Elm_Prefs_Item_Node *it;
it = _elm_prefs_item_api_entry_common(obj, name);
if (!it) return EINA_FALSE;
if (!it->w_impl->editable_get)
{
ERR("the item %s does not implement the 'editable' "
"property (using widget %s)", it->name, it->widget);
return EINA_FALSE;
}
return it->w_impl->editable_get(it->w_obj);
}
EOLIAN static Eina_Bool
_elm_prefs_item_swallow(Eo *obj, Elm_Prefs_Data *_pd EINA_UNUSED, const char *name, Evas_Object *child)
{
Eina_Value v;
Eina_Bool ret = EINA_FALSE;
Elm_Prefs_Item_Node *it = _elm_prefs_item_api_entry_common(obj, name);
if (!it) return EINA_FALSE;
if (it->type != ELM_PREFS_TYPE_SWALLOW)
{
ERR("item %s does not match a SWALLOW item", name);
return EINA_FALSE;
}
if (!eina_value_setup(&v, EINA_VALUE_TYPE_UINT64)) return EINA_FALSE;
if (!eina_value_set(&v, child))
{
eina_value_flush(&v);
return EINA_FALSE;
}
ret = it->w_impl->value_set(it->w_obj, &v);
eina_value_flush(&v);
return ret;
}
EOLIAN static Evas_Object*
_elm_prefs_item_unswallow(Eo *obj, Elm_Prefs_Data *_pd EINA_UNUSED, const char *name)
{
Eina_Value v;
Evas_Object *ret = NULL;
Elm_Prefs_Item_Node *it = _elm_prefs_item_api_entry_common(obj, name);
if (!it) return NULL;
if (it->type != ELM_PREFS_TYPE_SWALLOW)
{
ERR("item %s does not match a SWALLOW item", name);
return NULL;
}
if (!(it->w_impl->value_get(it->w_obj, &v))) return NULL;
if (eina_value_type_get(&v) != EINA_VALUE_TYPE_UINT64 ||
!eina_value_get(&v, ret))
{
eina_value_flush(&v);
return NULL;
}
eina_value_flush(&v);
return ret;
}
static unsigned int
elm_prefs_item_iface_abi_version_get(void)
{
return ELM_PREFS_ITEM_IFACE_ABI_VERSION;
}
EAPI void
elm_prefs_item_iface_register(const Elm_Prefs_Item_Iface_Info *array)
{
const Elm_Prefs_Item_Iface_Info *itr;
unsigned int abi_version = elm_prefs_item_iface_abi_version_get();
if (!array)
return;
for (itr = array; itr->widget_name; itr++)
{
const Elm_Prefs_Item_Type *t_itr;
if (itr->info->abi_version != abi_version)
{
ERR("external prefs widget interface '%s' (%p) has incorrect ABI "
"version. got %#x where %#x was expected.",
itr->widget_name, itr->info, itr->info->abi_version,
abi_version);
continue;
}
/* FIXME: registering the 1st, for now */
if (!_elm_prefs_item_default_widget)
_elm_prefs_item_default_widget = itr->info;
eina_hash_direct_add
(_elm_prefs_item_widgets_map, itr->widget_name, itr->info);
for (t_itr = itr->info->types;
*t_itr != ELM_PREFS_TYPE_UNKNOWN; t_itr++)
eina_hash_add(_elm_prefs_item_type_widgets_map, t_itr, itr->info);
}
}
EAPI void
elm_prefs_item_iface_unregister(const Elm_Prefs_Item_Iface_Info *array)
{
const Elm_Prefs_Item_Iface_Info *itr;
if (!array)
return;
for (itr = array; itr->widget_name; itr++)
{
const Elm_Prefs_Item_Type *t_itr;
eina_hash_del(_elm_prefs_item_widgets_map, itr->widget_name, itr->info);
for (t_itr = itr->info->types;
*t_itr != ELM_PREFS_TYPE_UNKNOWN; t_itr++)
eina_hash_del
(_elm_prefs_item_type_widgets_map, t_itr, itr->info);
}
}
static unsigned int
elm_prefs_page_iface_abi_version_get(void)
{
return ELM_PREFS_PAGE_IFACE_ABI_VERSION;
}
EAPI void
elm_prefs_page_iface_register(const Elm_Prefs_Page_Iface_Info *array)
{
const Elm_Prefs_Page_Iface_Info *itr;
unsigned int abi_version = elm_prefs_page_iface_abi_version_get();
if (!array)
return;
for (itr = array; itr->widget_name; itr++)
{
if (itr->info->abi_version != abi_version)
{
ERR("external prefs widget interface '%s' (%p) has incorrect ABI "
"version. got %#x where %#x was expected.",
itr->widget_name, itr->info, itr->info->abi_version,
abi_version);
continue;
}
/* FIXME: registering the 1st, for now */
if (!_elm_prefs_page_default_widget)
_elm_prefs_page_default_widget = itr->info;
eina_hash_direct_add
(_elm_prefs_page_widgets_map, itr->widget_name, itr->info);
}
}
EAPI void
elm_prefs_page_iface_unregister(const Elm_Prefs_Page_Iface_Info *array)
{
const Elm_Prefs_Page_Iface_Info *itr;
if (!array)
return;
for (itr = array; itr->widget_name; itr++)
eina_hash_del
(_elm_prefs_page_widgets_map, itr->widget_name, itr->info);
}
/* TODO: evaluate if it's sane to handle it better */
/* static void */
/* _prefs_page_del_cb(void *data EINA_UNUSED, */
/* Evas *evas EINA_UNUSED, */
/* Evas_Object *obj, */
/* void *event_info EINA_UNUSED) */
/* { */
/* Elm_Prefs_Page_Node *page; */
/* evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _prefs_page_del_cb); */
/* page = evas_object_data_get(obj, "prefs_page"); */
/* ELM_PREFS_DATA_GET(page->prefs, sd); */
/* if (!sd->delete_me) */
/* { */
/* Eina_List *l; */
/* Elm_Prefs_Item_Node *it; */
/* /\* force writing back the value for it *\/ */
/* EINA_LIST_FOREACH(page->items, l, it) */
/* _item_changed_cb(it->w_obj); */
/* } */
/* evas_object_data_del(obj, "prefs_page"); */
/* page->w_obj = NULL; */
/* } */
static void
_prefs_item_del_cb(void *data EINA_UNUSED,
Evas *evas EINA_UNUSED,
Evas_Object *obj,
void *event_info EINA_UNUSED)
{
Elm_Prefs_Item_Node *it;
Evas_Object *lbl, *icon;
evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _prefs_item_del_cb);
it = evas_object_data_get(obj, "prefs_item");
lbl = evas_object_data_del(it->w_obj, "label_widget");
evas_object_del(lbl);
icon = evas_object_data_del(it->w_obj, "icon_widget");
evas_object_del(icon);
ELM_PREFS_DATA_GET(it->prefs, sd);
if (!sd->delete_me)
/* force writing back the value for it */
_item_changed_cb(obj);
evas_object_data_del(obj, "prefs_item");
it->available = EINA_FALSE;
it->w_obj = NULL;
}
EAPI Eina_Bool
elm_prefs_item_widget_common_add(Evas_Object *prefs EINA_UNUSED,
Evas_Object *obj)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
evas_object_event_callback_add
(obj, EVAS_CALLBACK_DEL, _prefs_item_del_cb, NULL);
return EINA_TRUE;
}
EAPI Eina_Bool
elm_prefs_page_widget_common_add(Evas_Object *prefs EINA_UNUSED,
Evas_Object *obj)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
/* evas_object_event_callback_add */
/* (obj, EVAS_CALLBACK_DEL, _prefs_page_del_cb, NULL); */
return EINA_TRUE;
}
Eina_Bool
_elm_prefs_init(void)
{
Elm_Module *m;
if (++_elm_prefs_init_count != 1)
return EINA_TRUE;
_elm_prefs_descriptors_init();
_elm_prefs_data_init();
if (!(m = _elm_module_find_as("prefs_iface")))
{
WRN("prefs iface module could not be loaded,"
" the prefs widget won't function");
--_elm_prefs_init_count;
_elm_prefs_descriptors_shutdown();
_elm_prefs_data_shutdown();
return EINA_FALSE;
}
_elm_prefs_page_widgets_map = eina_hash_string_superfast_new(NULL);
_elm_prefs_item_widgets_map = eina_hash_string_superfast_new(NULL);
_elm_prefs_item_type_widgets_map = eina_hash_int32_new(NULL);
m->init_func(m);
return EINA_TRUE;
}
void
_elm_prefs_shutdown(void)
{
if (_elm_prefs_init_count <= 0)
{
EINA_LOG_ERR("Init count not greater than 0 in shutdown.");
return;
}
if (--_elm_prefs_init_count != 0) return;
_elm_prefs_descriptors_shutdown();
_elm_prefs_data_shutdown();
eina_hash_free(_elm_prefs_page_widgets_map);
eina_hash_free(_elm_prefs_item_widgets_map);
eina_hash_free(_elm_prefs_item_type_widgets_map);
/* all modules shutdown calls will taken place elsewhere */
}
static void
_elm_prefs_class_constructor(Efl_Class *klass)
{
evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
}
EAPI Eina_Bool
elm_prefs_file_set(Eo *obj, const char *file, const char *page)
{
Elm_Prefs_Data *sd = efl_data_scope_get(obj, MY_CLASS);
const char *prefix;
EINA_SAFETY_ON_NULL_RETURN_VAL(sd, EINA_FALSE);
if (!_elm_prefs_init_count)
{
CRI("prefs_iface module is not loaded! you can't"
" create prefs widgets");
return EINA_FALSE;
}
prefix = elm_app_data_dir_get();
if (!strlen(prefix))
{
WRN("we could not figure out the program's data"
" dir, fallbacking to local directory.");
prefix = ".";
}
if (!file)
sd->file = eina_stringshare_printf("%s/%s", prefix, "preferences.epb");
else
{
if (eina_file_path_relative(file))
sd->file = eina_stringshare_printf("%s/%s", prefix, file);
else
sd->file = eina_stringshare_add(file);
}
sd->page = eina_stringshare_add(page ? page : "main");
sd->root = _elm_prefs_page_load(obj, sd->page);
if (!sd->root) return EINA_FALSE;
if (!_elm_prefs_page_populate(sd->root, obj))
{
_root_node_free(sd);
sd->root = NULL;
return EINA_FALSE;
}
elm_widget_resize_object_set(obj, sd->root->w_obj);
_elm_prefs_values_get_default(sd->root, EINA_FALSE);
efl_event_callback_legacy_call
(obj, ELM_PREFS_EVENT_PAGE_LOADED, (char *)sd->root->name);
return EINA_TRUE;
}
EAPI Eina_Bool
elm_prefs_file_get(const Eo *obj, const char **file, const char **page)
{
Elm_Prefs_Data *sd = efl_data_scope_get(obj, MY_CLASS);
EINA_SAFETY_ON_NULL_RETURN_VAL(sd, EINA_FALSE);
if (file) *file = sd->file;
if (page) *page = sd->page;
return EINA_TRUE;
}
/* Internal EO APIs and hidden overrides */
#define ELM_PREFS_EXTRA_OPS \
EFL_CANVAS_GROUP_ADD_DEL_OPS(elm_prefs)
#include "elm_prefs_eo.c"